diff --git a/AUTHORS b/AUTHORS
index b658b97..ccc712f8 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -49,6 +49,7 @@
 Andrew Tulloch <andrew@tullo.ch>
 Anish Patankar <anish.p@samsung.com>
 Ankit Kumar <ankit2.kumar@samsung.com>
+Anne Kao <annekao94@gmail.com>
 Anssi Hannula <anssi.hannula@iki.fi>
 Antonio Gomes <a1.gomes@sisa.samsung.com>
 Anuj Kumar Sharma <anujk.sharma@samsung.com>
@@ -235,6 +236,7 @@
 James Vega <vega.james@gmail.com>
 James Wei <james.wei@intel.com>
 James Willcox <jwillcox@litl.com>
+Jan Sauer <jan@jansauer.de>
 Janwar Dinata <j.dinata@gmail.com>
 Jared Shumway <jaredshumway94@gmail.com>
 Jared Sohn <jared.sohn@gmail.com>
diff --git a/DEPS b/DEPS
index 0e247909..e89d95e 100644
--- a/DEPS
+++ b/DEPS
@@ -30,27 +30,15 @@
   # Use this googlecode_url variable only if there is an internal mirror for it.
   # If you do not know, use the full path while defining your new deps entry.
   'googlecode_url': 'http://%s.googlecode.com/svn',
-  'sourceforge_url': 'http://svn.code.sf.net/p/%(repo)s/code',
-  'llvm_url': 'http://src.chromium.org/llvm-project',
-  'llvm_git': 'https://llvm.googlesource.com',
-  'webkit_trunk': 'http://src.chromium.org/blink/trunk',
-  'webkit_revision': 'c189b79fada8084bde27587f4590b881076046ae', # from svn revision 196690
+  'webkit_revision': '83a722e32ca143f0b9d2c9bd338421a769ff78dc', # from svn revision 196982
   'chromium_git': 'https://chromium.googlesource.com',
-  'chromiumos_git': 'https://chromium.googlesource.com/chromiumos',
-  'pdfium_git': 'https://pdfium.googlesource.com',
-  'skia_git': 'https://skia.googlesource.com',
-  'boringssl_git': 'https://boringssl.googlesource.com',
   'libvpx_revision': 'a43631169b4200f2000c8cfa82404ce507e31486',
   'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
-  'skia_revision': '0963f5dab079627c5523ce6a443af27a33e361f7',
+  'skia_revision': '0a24297be4737f5fe23b3b918b193260e64ab32d',
   # Three lines of non-changing comments so that
-  # the commit queue can handle CLs rolling Skia
-  # and V8 without interference from each other.
-  'v8_branch': 'trunk',
-  'v8_revision': 'a50f5ef40866cf5f8ebdca98f4a99e902bdbb2c4',
-  # Three lines of non-changing comments so that
-  # the commit queue can handle CLs rolling WebRTC
-  # and V8 without interference from each other.
+  # the commit queue can handle CLs rolling V8
+  # and whatever else without interference from each other.
+  'v8_revision': 'a4c400c9d98b1a6f7e0df7d64eca67dab11ca5bf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -58,7 +46,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '6e0302a87d447b260688ac0d4ad1b932a363ddbf',
+  'angle_revision': '6ffeb744a6b9ca6c9e73cff7365d22dff75fd639',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -66,7 +54,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '7bb4d8dc9e825f484e180205254aee1488cc34dc',
+  'pdfium_revision': '6f0a64a1bf18ab6636404cdfb883897459083a4d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -94,7 +82,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'ac4a825a3a3fda9c4884c7f6c82b895b3ae6085e',
+  'nacl_revision': '22fcd7c6a995b92434432aafe8ba49858bd7f5d3',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -129,16 +117,16 @@
    Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8',
 
   'src/third_party/crashpad/crashpad':
-   Var('chromium_git') + '/crashpad/crashpad.git' + '@' + '00c42ae7bdcf40d15c02b87e088c1eb565a51333',
+   Var('chromium_git') + '/crashpad/crashpad.git' + '@' + '797adb320680a4a8ad39428075cca287e04b111f',
 
   'src/third_party/trace-viewer':
-   Var('chromium_git') + '/external/trace-viewer.git' + '@' + 'cd91381c069ce9a6db35f335999759fab6dac7b9',
+   Var('chromium_git') + '/external/trace-viewer.git' + '@' + '6e52f2a8beb07923b042e4b6e04b211097338b04',
 
   'src/third_party/WebKit':
    Var('chromium_git') + '/chromium/blink.git' + '@' +  Var('webkit_revision'),
 
   'src/third_party/icu':
-   Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '9939a5d5314b6d59d5fb070902d73304c2482f88',
+   Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'a05f412f70489b77da0ddeb8baa31c68e3eff2c6',
 
   'src/third_party/libexif/sources':
    Var('chromium_git') + '/chromium/deps/libexif/sources.git' + '@' + 'ed98343daabd7b4497f97fda972e132e6877c48a',
@@ -198,10 +186,10 @@
    Var('chromium_git') + '/chromium/deps/libvpx.git' + '@' +  Var('libvpx_revision'),
 
   'src/third_party/ffmpeg':
-   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'c0f05636c4472e5d3c0045ec34464aec46c5fb70',
+   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '0ec2f1eee82359bb9c02a912feb1914a3a169cbe',
 
   'src/third_party/libjingle/source/talk':
-    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '78b410bcd08fe61fb91c4e1a307f5f0c7b5f8001', # commit position 9384
+    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '8538c304d7677f2191f97844e11640faee38d38e', # commit position 9415
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/usrsctplib.git' + '@' + '36444a999739e9e408f8f587cb4c3ffeef2e50ac', # from svn revision 9215
@@ -213,7 +201,7 @@
    Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + '4671120cd8558ce62ee8672ebf3eb6f5216f909b',
 
   'src/third_party/libjpeg_turbo':
-   Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '8ee9bdd068effcf5fe876e401829eadb94569750',
+   Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + 'f4631b6ee8b1dbb05e51ae335a7886f9ac598ab6',
 
   'src/third_party/flac':
    Var('chromium_git') + '/chromium/deps/flac.git' + '@' + '0635a091379d9677f1ddde5f2eec85d0f096f219',
@@ -225,7 +213,7 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '95797c571819af56d1c15beebc503c57e8ca1df4', # commit position 9390
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'e0cc456a6412d8cc554f4daf0ebc1836f0566663', # commit position 9413
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
@@ -234,7 +222,7 @@
     Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' + '@' + 'f572e8e42e22cfcf5ab0aea26574f408943edfa4', # from svn 248
 
   'src/third_party/libyuv':
-    Var('chromium_git') + '/external/libyuv.git' + '@' + '632c50f29cdacb8c5872ce9938444b676b4a0c81', # from svn revision 1407
+    Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '632c50f29cdacb8c5872ce9938444b676b4a0c81', # from svn revision 1407
 
   'src/third_party/smhasher/src':
     Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f',
@@ -281,7 +269,7 @@
     Var('chromium_git') + '/external/py_trace_event.git' + '@' + 'dd463ea9e2c430de2b9e53dea57a77b4c3ac9b30',
 
   'src/third_party/dom_distiller_js/dist':
-    Var('chromium_git') + '/external/github.com/chromium/dom-distiller-dist.git' + '@' + '4948eb81dc84578e58a59b8ef493ce946cd00b0f',
+    Var('chromium_git') + '/external/github.com/chromium/dom-distiller-dist.git' + '@' + 'f93cf9c2817926a92f4f347b20fa840a1998d5f3',
 }
 
 
@@ -387,7 +375,7 @@
 
     # For Linux and Chromium OS.
     'src/third_party/cros_system_api':
-     Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '3b950126eee9cb1c55ab36c2dd5a89bfb05b5034',
+     Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'ba08c21a075ab091ca9bdc783435c2aec8c6f807',
 
     # Note that this is different from Android's freetype repo.
     'src/third_party/freetype2/src':
@@ -413,10 +401,10 @@
   },
   'android': {
     'src/third_party/android_protobuf/src':
-     Var('chromium_git') + '/external/android_protobuf.git' + '@' + '94f522f907e3f34f70d9e7816b947e62fddbb267',
+     Var('chromium_git') + '/external/android_protobuf.git' + '@' + '999188d0dc72e97f7fe08bb756958a2cf090f4e7',
 
     'src/third_party/android_tools':
-     Var('chromium_git') + '/android_tools.git' + '@' + 'a3afc68f31ed9b32954954da95c855ee73820bd1',
+     Var('chromium_git') + '/android_tools.git' + '@' + 'ed3dde6470c39b196c70f0c20374894d169754ec',
 
     'src/third_party/apache-mime4j':
      Var('chromium_git') + '/chromium/deps/apache-mime4j.git' + '@' + '28cb1108bff4b6cf0a2e86ff58b3d025934ebe3a',
@@ -428,7 +416,7 @@
      Var('chromium_git') + '/chromium/deps/findbugs.git' + '@' + '7f69fa78a6db6dc31866d09572a0e356e921bf12',
 
     'src/third_party/freetype-android/src':
-     Var('chromium_git') + '/chromium/src/third_party/freetype.git' + '@' + 'd1028db70bea988d1022e4d463de66581c696160',
+     Var('chromium_git') + '/chromium/src/third_party/freetype2.git' + '@' + 'e186230678ee8e4ea4ac4797ece8125761e3225a',
 
    'src/third_party/elfutils/src':
      Var('chromium_git') + '/external/elfutils.git' + '@' + '249673729a7e5dbd5de4f3760bdcaa3d23d154d7',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 4d5c853..0293bf0 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -1304,6 +1304,77 @@
       black_list=_EXCLUDED_PATHS + input_api.DEFAULT_BLACK_LIST)
 
 
+def _CheckAndroidCrLogUsage(input_api, output_api):
+  """Checks that new logs using org.chromium.base.Log:
+    - Are using 'TAG' as variable name for the tags (warn)
+    - Are using the suggested name format for the tags: "cr.<PackageTag>" (warn)
+    - Are using a tag that is shorter than 23 characters (error)
+  """
+  cr_log_import_pattern = input_api.re.compile(
+      r'^import org\.chromium\.base\.Log;$', input_api.re.MULTILINE);
+  # Extract the tag from lines like `Log.d(TAG, "*");` or `Log.d("TAG", "*");`
+  cr_log_pattern = input_api.re.compile(r'^\s*Log\.\w\((?P<tag>\"?\w+\"?)\,')
+  log_decl_pattern = input_api.re.compile(
+      r'^\s*private static final String TAG = "(?P<name>(.*)")',
+      input_api.re.MULTILINE)
+  log_name_pattern = input_api.re.compile(r'^cr[.\w]*')
+
+  REF_MSG = ('See base/android/java/src/org/chromium/base/README_logging.md '
+            'or contact dgn@chromium.org for more info.')
+  sources = lambda x: input_api.FilterSourceFile(x, white_list=(r'.*\.java$',))
+  tag_errors = []
+  tag_decl_errors = []
+  tag_length_errors = []
+
+  for f in input_api.AffectedSourceFiles(sources):
+    file_content = input_api.ReadFile(f)
+    has_modified_logs = False
+
+    # Per line checks
+    if cr_log_import_pattern.search(file_content):
+      for line_num, line in f.ChangedContents():
+
+        # Check if the new line is doing some logging
+        match = cr_log_pattern.search(line)
+        if match:
+          has_modified_logs = True
+
+          # Make sure it uses "TAG"
+          if not match.group('tag') == 'TAG':
+            tag_errors.append("%s:%d" % (f.LocalPath(), line_num))
+
+    # Per file checks
+    if has_modified_logs:
+      # Make sure the tag is using the "cr" prefix and is not too long
+      match = log_decl_pattern.search(file_content)
+      tag_name = match.group('name') if match else ''
+      if not log_name_pattern.search(tag_name ):
+        tag_decl_errors.append(f.LocalPath())
+      if len(tag_name) > 23:
+        tag_length_errors.append(f.LocalPath())
+
+  results = []
+  if tag_decl_errors:
+    results.append(output_api.PresubmitPromptWarning(
+        'Please define your tags using the suggested format: .\n'
+        '"private static final String TAG = "cr.<package tag>".\n' + REF_MSG,
+        tag_decl_errors))
+
+  if tag_length_errors:
+    results.append(output_api.PresubmitError(
+        'The tag length is restricted by the system to be at most '
+        '23 characters.\n' + REF_MSG,
+        tag_length_errors))
+
+  if tag_errors:
+    results.append(output_api.PresubmitPromptWarning(
+        'Please use a variable named "TAG" for your log tags.\n' + REF_MSG,
+        tag_errors))
+
+  return results
+
+
+# TODO(dgn): refactor with _CheckAndroidCrLogUsage
 def _CheckNoNewUtilLogUsage(input_api, output_api):
   """Checks that new logs are using org.chromium.base.Log."""
 
@@ -1410,7 +1481,8 @@
 def _CheckNoDeprecatedCSS(input_api, output_api):
   """ Make sure that we don't use deprecated CSS
       properties, functions or values. Our external
-      documentation is ignored by the hooks as it
+      documentation and iOS CSS for dom distiller
+      (reader mode) are ignored by the hooks as it
       needs to be consumed by WebKit. """
   results = []
   file_inclusion_pattern = (r".+\.css$",)
@@ -1419,6 +1491,7 @@
                 input_api.DEFAULT_BLACK_LIST +
                 (r"^chrome/common/extensions/docs",
                  r"^chrome/docs",
+                 r"^components/dom_distiller/core/css/distilledpage_ios.css",
                  r"^native_client_sdk"))
   file_filter = lambda f: input_api.FilterSourceFile(
       f, white_list=file_inclusion_pattern, black_list=black_list)
@@ -1456,6 +1529,14 @@
   return results
 
 
+def _AndroidSpecificOnUploadChecks(input_api, output_api):
+  """Groups checks that target android code."""
+  results = []
+  results.extend(_CheckNoNewUtilLogUsage(input_api, output_api))
+  results.extend(_CheckAndroidCrLogUsage(input_api, output_api))
+  return results
+
+
 def _CommonChecks(input_api, output_api):
   """Checks common to both upload and commit."""
   results = []
@@ -1728,7 +1809,7 @@
   results.extend(
       input_api.canned_checks.CheckGNFormatted(input_api, output_api))
   results.extend(_CheckUmaHistogramChanges(input_api, output_api))
-  results.extend(_CheckNoNewUtilLogUsage(input_api, output_api))
+  results.extend(_AndroidSpecificOnUploadChecks(input_api, output_api))
   return results
 
 
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index 195fe4f..613fd41c 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -859,6 +859,77 @@
     self.assertTrue('HasAndroidLog.java' in warnings[0].items[0])
     self.assertTrue('HasExplicitLog.java' in warnings[0].items[1])
 
+  def testCheckAndroidCrLogUsage(self):
+    mock_input_api = MockInputApi()
+    mock_output_api = MockOutputApi()
+
+    mock_input_api.files = [
+      MockAffectedFile('RandomStuff.java', [
+        'random stuff'
+      ]),
+      MockAffectedFile('HasCorrectTag.java', [
+        'import org.chromium.base.Log;',
+        'some random stuff',
+        'private static final String TAG = "cr.Foo";',
+        'Log.d(TAG, "foo");',
+      ]),
+      MockAffectedFile('HasShortCorrectTag.java', [
+        'import org.chromium.base.Log;',
+        'some random stuff',
+        'private static final String TAG = "cr";',
+        'Log.d(TAG, "foo");',
+      ]),
+      MockAffectedFile('HasNoTagDecl.java', [
+        'import org.chromium.base.Log;',
+        'some random stuff',
+        'Log.d(TAG, "foo");',
+      ]),
+      MockAffectedFile('HasIncorrectTagDecl.java', [
+        'import org.chromium.base.Log;',
+        'private static final String TAHG = "cr.Foo";',
+        'some random stuff',
+        'Log.d(TAG, "foo");',
+      ]),
+      MockAffectedFile('HasInlineTag.java', [
+        'import org.chromium.base.Log;',
+        'some random stuff',
+        'private static final String TAG = "cr.Foo";',
+        'Log.d("TAG", "foo");',
+      ]),
+      MockAffectedFile('HasIncorrectTag.java', [
+        'import org.chromium.base.Log;',
+        'some random stuff',
+        'private static final String TAG = "rubbish";',
+        'Log.d(TAG, "foo");',
+      ]),
+      MockAffectedFile('HasTooLongTag.java', [
+        'import org.chromium.base.Log;',
+        'some random stuff',
+        'private static final String TAG = "cr.24_charachers_long___";',
+        'Log.d(TAG, "foo");',
+      ]),
+    ]
+
+    msgs = PRESUBMIT._CheckAndroidCrLogUsage(
+        mock_input_api, mock_output_api)
+
+    self.assertEqual(3, len(msgs))
+
+    # Declaration format
+    self.assertEqual(3, len(msgs[0].items))
+    self.assertTrue('HasNoTagDecl.java' in msgs[0].items)
+    self.assertTrue('HasIncorrectTagDecl.java' in msgs[0].items)
+    self.assertTrue('HasIncorrectTag.java' in msgs[0].items)
+
+    # Tag length
+    self.assertEqual(1, len(msgs[1].items))
+    self.assertTrue('HasTooLongTag.java' in msgs[1].items)
+
+    # Tag must be a variable named TAG
+    self.assertEqual(1, len(msgs[2].items))
+    self.assertTrue('HasInlineTag.java:4' in msgs[2].items)
+
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/WATCHLISTS b/WATCHLISTS
index e04da3e..4316700 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -924,7 +924,6 @@
     'chromeos_net' : ['stevenjb+watch@chromium.org'],
     'chromeos_power' : ['derat+watch@chromium.org'],
     'chromeos_login' : ['dzhioev+watch@chromium.org'],
-    'chromeos_webui': ['nkostylev+watch@chromium.org'],
     'clang_update': ['ukai+watch@chromium.org',
                      'dmikurube+clang@chromium.org',
                      'eugenis+clang@chromium.org',
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index bbd23c6..efb52db 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -15,6 +15,16 @@
         '<(DEPTH)/third_party/WebKit/public/blink_resources.gyp:blink_resources',
         '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources',
       ],
+      'variables': {
+        'conditions': [
+          ['target_arch=="arm" or target_arch=="ia32" or target_arch=="mipsel"', {
+            'arch_suffix':'32'
+          }],
+          ['target_arch=="arm64" or target_arch=="x64" or target_arch=="mips64el"', {
+            'arch_suffix':'64'
+          }],
+        ],
+      },
       'actions': [
         {
           'action_name': 'repack_android_webview_pack',
@@ -51,52 +61,36 @@
             '<@(locales)',
           ],
         },
-      ],
-      'conditions': [
-        ['v8_use_external_startup_data==1', {
-          'variables': {
-            'conditions': [
-              ['(target_arch=="arm" or target_arch=="ia32" or target_arch=="mipsel")', {
-                'arch_suffix':'32'
-              }],
-              ['(target_arch=="arm64" or target_arch=="x64" or target_arch=="mips64el")', {
-                'arch_suffix':'64'
-              }],
-            ],
-          },
-          'actions': [
-            {
-              'action_name': 'rename_snapshot_blob',
-              'inputs': [
-                '<(PRODUCT_DIR)/snapshot_blob.bin',
-              ],
-              'outputs': [
-                '<(PRODUCT_DIR)/snapshot_blob_<(arch_suffix).bin',
-              ],
-              'action': [
-                'python',
-                '<(DEPTH)/build/cp.py',
-                '<@(_inputs)',
-                '<@(_outputs)',
-              ],
-            },
-            {
-              'action_name': 'rename_natives_blob',
-              'inputs': [
-                '<(PRODUCT_DIR)/natives_blob.bin',
-              ],
-              'outputs': [
-                '<(PRODUCT_DIR)/natives_blob_<(arch_suffix).bin',
-              ],
-              'action': [
-                'python',
-                '<(DEPTH)/build/cp.py',
-                '<@(_inputs)',
-                '<@(_outputs)',
-              ],
-            },
+        {
+          'action_name': 'rename_snapshot_blob',
+          'inputs': [
+            '<(PRODUCT_DIR)/snapshot_blob.bin',
           ],
-        }],
+          'outputs': [
+            '<(PRODUCT_DIR)/snapshot_blob_<(arch_suffix).bin',
+          ],
+          'action': [
+            'python',
+            '<(DEPTH)/build/cp.py',
+            '<@(_inputs)',
+            '<@(_outputs)',
+          ],
+        },
+        {
+          'action_name': 'rename_natives_blob',
+          'inputs': [
+            '<(PRODUCT_DIR)/natives_blob.bin',
+          ],
+          'outputs': [
+            '<(PRODUCT_DIR)/natives_blob_<(arch_suffix).bin',
+          ],
+          'action': [
+            'python',
+            '<(DEPTH)/build/cp.py',
+            '<@(_inputs)',
+            '<@(_outputs)',
+          ],
+        },
       ],
     },
     {
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 2cff426..1c4d6328 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -382,7 +382,8 @@
     bool opener_suppressed,
     content::ResourceContext* context,
     int render_process_id,
-    int opener_id,
+    int opener_render_view_id,
+    int opener_render_frame_id,
     bool* no_javascript_access) {
   // We unconditionally allow popup windows at this stage and will give
   // the embedder the opporunity to handle displaying of the popup in
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 6d8852d..2f0e472 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -117,7 +117,8 @@
                        bool opener_suppressed,
                        content::ResourceContext* context,
                        int render_process_id,
-                       int opener_id,
+                       int opener_render_view_id,
+                       int opener_render_frame_id,
                        bool* no_javascript_access) override;
   void ResourceDispatcherHostCreated() override;
   net::NetLog* GetNetLog() override;
diff --git a/android_webview/browser/aw_render_thread_context_provider.cc b/android_webview/browser/aw_render_thread_context_provider.cc
index 9b6e5d4..e928975 100644
--- a/android_webview/browser/aw_render_thread_context_provider.cc
+++ b/android_webview/browser/aw_render_thread_context_provider.cc
@@ -157,12 +157,6 @@
   return &context_lock_;
 }
 
-bool AwRenderThreadContextProvider::IsContextLost() {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-
-  return destroyed_;
-}
-
 void AwRenderThreadContextProvider::VerifyContexts() {
 }
 
diff --git a/android_webview/browser/aw_render_thread_context_provider.h b/android_webview/browser/aw_render_thread_context_provider.h
index 7501a1b..24c1463 100644
--- a/android_webview/browser/aw_render_thread_context_provider.h
+++ b/android_webview/browser/aw_render_thread_context_provider.h
@@ -44,7 +44,6 @@
   void InvalidateGrContext(uint32_t state) override;
   void SetupLock() override;
   base::Lock* GetLock() override;
-  bool IsContextLost() override;
   void VerifyContexts() override;
   void DeleteCachedResources() override;
   bool DestroyedOnMainThread() override;
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc
index b3fbe01..61a9192 100644
--- a/android_webview/browser/browser_view_renderer.cc
+++ b/android_webview/browser/browser_view_renderer.cc
@@ -414,6 +414,16 @@
   UpdateCompositorIsActive();
 }
 
+void BrowserViewRenderer::OnComputeScroll(base::TimeTicks animation_time) {
+  if (pending_fling_animation_.is_null())
+    return;
+  TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnComputeScroll");
+  DCHECK(!pending_fling_animation_.is_null());
+  AnimationCallback animation = pending_fling_animation_;
+  pending_fling_animation_.Reset();
+  animation.Run(animation_time);
+}
+
 void BrowserViewRenderer::ReleaseHardware() {
   DCHECK(hardware_enabled_);
   ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
@@ -551,8 +561,8 @@
   return scroll_offset_dip_;
 }
 
-bool BrowserViewRenderer::IsExternalFlingActive() const {
-  return client_->IsFlingActive();
+bool BrowserViewRenderer::IsExternalScrollActive() const {
+  return client_->IsSmoothScrollingActive();
 }
 
 void BrowserViewRenderer::UpdateRootLayerState(
@@ -606,6 +616,15 @@
   return state;
 }
 
+void BrowserViewRenderer::SetNeedsAnimateScroll(
+    const AnimationCallback& scroll_animation) {
+  pending_fling_animation_ = scroll_animation;
+  // No need to reschedule the fallback tick here because the compositor is
+  // fine with the animation not being ticked. The invalidate could happen some
+  // time later, or not at all.
+  client_->PostInvalidate();
+}
+
 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
                                         gfx::Vector2dF latest_overscroll_delta,
                                         gfx::Vector2dF current_fling_velocity) {
@@ -618,7 +637,10 @@
       scaled_overscroll_delta + overscroll_rounding_error_);
   overscroll_rounding_error_ =
       scaled_overscroll_delta - rounded_overscroll_delta;
-  client_->DidOverscroll(rounded_overscroll_delta);
+  gfx::Vector2dF fling_velocity_pixels =
+      gfx::ScaleVector2d(current_fling_velocity, physical_pixel_scale);
+
+  client_->DidOverscroll(rounded_overscroll_delta, fling_velocity_pixels);
 }
 
 void BrowserViewRenderer::PostInvalidate() {
diff --git a/android_webview/browser/browser_view_renderer.h b/android_webview/browser/browser_view_renderer.h
index 477a039..83955ee 100644
--- a/android_webview/browser/browser_view_renderer.h
+++ b/android_webview/browser/browser_view_renderer.h
@@ -74,6 +74,7 @@
   void OnSizeChanged(int width, int height);
   void OnAttachedToWindow(int width, int height);
   void OnDetachedFromWindow();
+  void OnComputeScroll(base::TimeTicks animation_time);
 
   // Sets the scale for logical<->physical pixel conversions.
   void SetDipScale(float dip_scale);
@@ -106,7 +107,9 @@
                             float page_scale_factor,
                             float min_page_scale_factor,
                             float max_page_scale_factor) override;
-  bool IsExternalFlingActive() const override;
+  bool IsExternalScrollActive() const override;
+  void SetNeedsAnimateScroll(
+      const AnimationCallback& scroll_animation) override;
   void DidOverscroll(gfx::Vector2dF accumulated_overscroll,
                      gfx::Vector2dF latest_overscroll_delta,
                      gfx::Vector2dF current_fling_velocity) override;
@@ -179,6 +182,11 @@
 
   gfx::Size size_;
 
+  // Used to drive a fling animation as requested by the compositor. This acts
+  // as a single-shot animation; the compositor will continually post an
+  // animation callback as long as they're required.
+  AnimationCallback pending_fling_animation_;
+
   // Current scroll offset in CSS pixels.
   gfx::Vector2dF scroll_offset_dip_;
 
diff --git a/android_webview/browser/browser_view_renderer_client.h b/android_webview/browser/browser_view_renderer_client.h
index c4bf8f2..a31455f4 100644
--- a/android_webview/browser/browser_view_renderer_client.h
+++ b/android_webview/browser/browser_view_renderer_client.h
@@ -41,7 +41,7 @@
   virtual void ScrollContainerViewTo(gfx::Vector2d new_value) = 0;
 
   // Is a Android view system managed fling in progress?
-  virtual bool IsFlingActive() const = 0;
+  virtual bool IsSmoothScrollingActive() const = 0;
 
   // Sets the following:
   // view's scroll offset cap to |max_scroll_offset|,
@@ -55,7 +55,8 @@
                                  float max_page_scale_factor) = 0;
 
   // Handle overscroll.
-  virtual void DidOverscroll(gfx::Vector2d overscroll_delta) = 0;
+  virtual void DidOverscroll(gfx::Vector2d overscroll_delta,
+                             gfx::Vector2dF overscroll_velocity) = 0;
 
   // Visible for testing
   // Called when the parent draw constraints in browser view renderer gets
diff --git a/android_webview/browser/test/rendering_test.cc b/android_webview/browser/test/rendering_test.cc
index a717413a..bac469e4 100644
--- a/android_webview/browser/test/rendering_test.cc
+++ b/android_webview/browser/test/rendering_test.cc
@@ -93,7 +93,7 @@
   return gfx::Point();
 }
 
-bool RenderingTest::IsFlingActive() const {
+bool RenderingTest::IsSmoothScrollingActive() const {
   return false;
 }
 
diff --git a/android_webview/browser/test/rendering_test.h b/android_webview/browser/test/rendering_test.h
index c0f65e2..1e212b7 100644
--- a/android_webview/browser/test/rendering_test.h
+++ b/android_webview/browser/test/rendering_test.h
@@ -36,13 +36,14 @@
   void DetachFunctorFromView() override;
   gfx::Point GetLocationOnScreen() override;
   void ScrollContainerViewTo(gfx::Vector2d new_value) override {}
-  bool IsFlingActive() const override;
+  bool IsSmoothScrollingActive() const override;
   void UpdateScrollState(gfx::Vector2d max_scroll_offset,
                          gfx::SizeF contents_size_dip,
                          float page_scale_factor,
                          float min_page_scale_factor,
                          float max_page_scale_factor) override {}
-  void DidOverscroll(gfx::Vector2d overscroll_delta) override {}
+  void DidOverscroll(gfx::Vector2d overscroll_delta,
+                     gfx::Vector2dF overscroll_velocity) override {}
   void ParentDrawConstraintsUpdated(
       const ParentCompositorDrawConstraints& draw_constraints) override {}
   // WindowHooks overrides.
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java
index 4fd2fc8..476c817 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java
@@ -192,7 +192,7 @@
     }
 
     @Override
-    public boolean isExternalFlingActive() {
-        return mAwContents.isFlingActive();
+    public boolean isExternalScrollActive() {
+        return mAwContents.isSmoothScrollingActive();
     }
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 9060c09..ded92a5 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Base64;
 import android.util.Log;
@@ -33,6 +34,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
+import android.view.animation.AnimationUtils;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.webkit.GeolocationPermissions;
@@ -553,6 +555,11 @@
         public void invalidate() {
             postInvalidateOnAnimation();
         }
+
+        @Override
+        public void cancelFling() {
+            mContentViewCore.cancelFling(SystemClock.uptimeMillis());
+        }
     }
 
     //--------------------------------------------------------------------------------------------
@@ -575,12 +582,7 @@
 
         @Override
         public void onFlingCancelGesture() {
-            mScrollOffsetManager.onFlingCancelGesture();
-        }
-
-        @Override
-        public void onUnhandledFlingStartEvent(int velocityX, int velocityY) {
-            mScrollOffsetManager.onUnhandledFlingStartEvent(velocityX, velocityY);
+            mScrollOffsetManager.finishScroll();
         }
 
         @Override
@@ -1936,7 +1938,14 @@
      */
     public void flingScroll(int velocityX, int velocityY) {
         if (TRACE) Log.d(TAG, "flingScroll");
-        mScrollOffsetManager.flingScroll(velocityX, velocityY);
+        // Cancel the current smooth scroll, if there is one.
+        mScrollOffsetManager.finishScroll();
+        // TODO(hush): crbug.com/493765. A hit test at 0, 0 may not
+        // target the scroll at root scrolling layer.  Instead, we
+        // should add a method flingRootLayer to ContentViewCore
+        // and call it here to specifically target the scroll at
+        // the root layer.
+        mContentViewCore.fling(SystemClock.uptimeMillis(), 0, 0, -velocityX, -velocityY);
     }
 
     /**
@@ -2549,8 +2558,8 @@
     }
 
     @CalledByNative
-    public boolean isFlingActive() {
-        return mScrollOffsetManager.isFlingActive();
+    public boolean isSmoothScrollingActive() {
+        return mScrollOffsetManager.isSmoothScrollingActive();
     }
 
     @CalledByNative
@@ -2571,14 +2580,22 @@
     }
 
     @CalledByNative
-    private void didOverscroll(int deltaX, int deltaY) {
-        if (mOverScrollGlow != null) {
-            mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY);
-        }
-
+    private void didOverscroll(int deltaX, int deltaY, float velocityX, float velocityY) {
         mScrollOffsetManager.overScrollBy(deltaX, deltaY);
 
-        if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) {
+        if (mOverScrollGlow == null) return;
+
+        mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY);
+        final int oldX = mContainerView.getScrollX();
+        final int oldY = mContainerView.getScrollY();
+        final int x = oldX + deltaX;
+        final int y = oldY + deltaY;
+        final int scrollRangeX = mScrollOffsetManager.computeMaximumHorizontalScrollOffset();
+        final int scrollRangeY = mScrollOffsetManager.computeMaximumVerticalScrollOffset();
+        mOverScrollGlow.absorbGlow(x, y, oldX, oldY, scrollRangeX, scrollRangeY,
+                (float) Math.hypot(velocityX, velocityY));
+
+        if (mOverScrollGlow.isAnimating()) {
             postInvalidateOnAnimation();
         }
     }
@@ -2987,7 +3004,13 @@
 
         @Override
         public void computeScroll() {
-            mScrollOffsetManager.computeScrollAndAbsorbGlow(mOverScrollGlow);
+            if (mScrollOffsetManager.isSmoothScrollingActive()) {
+                mScrollOffsetManager.computeScrollAndAbsorbGlow(mOverScrollGlow);
+            } else {
+                if (isDestroyed()) return;
+                nativeOnComputeScroll(
+                        mNativeAwContents, AnimationUtils.currentAnimationTimeMillis());
+            }
         }
     }
 
@@ -3026,6 +3049,8 @@
             long nativeAwContents, String path, ValueCallback<String> callback);
 
     private native void nativeAddVisitedLinks(long nativeAwContents, String[] visitedLinks);
+    private native void nativeOnComputeScroll(
+            long nativeAwContents, long currentAnimationTimeMillis);
     private native boolean nativeOnDraw(long nativeAwContents, Canvas canvas,
             boolean isHardwareAccelerated, int scrollX, int scrollY,
             int visibleLeft, int visibleTop, int visibleRight, int visibleBottom);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java b/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java
index 9ed9a14..cb10f3a5 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java
@@ -46,6 +46,8 @@
         int getContainerViewScrollY();
 
         void invalidate();
+
+        void cancelFling();
     }
 
     private final Delegate mDelegate;
@@ -65,9 +67,6 @@
     // Whether we're in the middle of processing a touch event.
     private boolean mProcessingTouchEvent;
 
-    // Don't skip computeScrollAndAbsorbGlow just because isFling is called in between.
-    private boolean mWasFlinging;
-
     // Whether (and to what value) to update the native side scroll offset after we've finished
     // processing a touch event.
     private boolean mApplyDeferredNativeScroll;
@@ -163,10 +162,10 @@
                 scrollRangeX, scrollRangeY, mProcessingTouchEvent);
     }
 
-    public boolean isFlingActive() {
-        boolean flinging = mScroller.computeScrollOffset();
-        mWasFlinging |= flinging;
-        return flinging;
+    // This is used temporarily until animateScrollTo path of Android WebView (pageUp, pageDown)
+    // is unified with Chrome smooth scrolling.
+    public boolean isSmoothScrollingActive() {
+        return !mScroller.isFinished();
     }
 
     // Called by the native side to over-scroll the container view.
@@ -252,39 +251,16 @@
     }
 
     // Called whenever some other touch interaction requires the fling gesture to be canceled.
-    public void onFlingCancelGesture() {
+    public void finishScroll() {
         // TODO(mkosiba): Support speeding up a fling by flinging again.
         // http://crbug.com/265841
         mScroller.forceFinished(true);
     }
 
-    // Called when a fling gesture is not handled by the renderer.
-    // We explicitly ask the renderer not to handle fling gestures targeted at the root
-    // scroll layer.
-    public void onUnhandledFlingStartEvent(int velocityX, int velocityY) {
-        flingScroll(-velocityX, -velocityY);
-    }
-
-    // Starts the fling animation. Called both as a response to a fling gesture and as via the
-    // public WebView#flingScroll(int, int) API.
-    public void flingScroll(int velocityX, int velocityY) {
-        final int scrollX = mDelegate.getContainerViewScrollX();
-        final int scrollY = mDelegate.getContainerViewScrollY();
-        final int scrollRangeX = computeMaximumHorizontalScrollOffset();
-        final int scrollRangeY = computeMaximumVerticalScrollOffset();
-
-        mScroller.fling(scrollX, scrollY, velocityX, velocityY,
-                0, scrollRangeX, 0, scrollRangeY);
-        mDelegate.invalidate();
-    }
-
     // Called immediately before the draw to update the scroll offset.
     public void computeScrollAndAbsorbGlow(OverScrollGlow overScrollGlow) {
-        if (!mScroller.computeScrollOffset() && !mWasFlinging) {
-            return;
-        }
-        mWasFlinging = false;
-
+        assert isSmoothScrollingActive();
+        mScroller.computeScrollOffset();
         final int oldX = mDelegate.getContainerViewScrollX();
         final int oldY = mDelegate.getContainerViewScrollY();
         int x = mScroller.getCurrX();
@@ -323,6 +299,9 @@
 
         if (dx == 0 && dy == 0) return false;
 
+        // The scroll will be handled by AwScrollOffsetManager instead of the compositor.
+        // So stop the current fling (either by flingScroll() or by user finger).
+        mDelegate.cancelFling();
         mScroller.startScroll(scrollX, scrollY, dx, dy, computeDurationInMilliSec(dx, dy));
         mDelegate.invalidate();
 
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
index 0f84cc5..4528484 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
@@ -83,6 +83,7 @@
         mContentsClient.onUnhandledKeyEvent(event);
     }
 
+    @SuppressLint("NewApi") // AudioManager#dispatchMediaKeyEvent requires API level 19.
     /**
      * Redispatches unhandled media keys. This allows bluetooth headphones with play/pause or
      * other buttons to function correctly.
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
index 6227e425..b9add33 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
@@ -130,15 +130,7 @@
             @Override
             public AwScrollOffsetManager createScrollOffsetManager(
                     AwScrollOffsetManager.Delegate delegate, OverScroller overScroller) {
-                return new AwScrollOffsetManager(delegate, overScroller) {
-                    @Override
-                    public void onUnhandledFlingStartEvent(int velocityX, int velocityY) {
-                        // Intentional no-op. The synthetic scroll gestures this test creates all
-                        // happen at the same time which triggers the fling detection logic.
-                        // NOTE: this simply disables handling the gesture, flinging the AwContents
-                        // via the flingScroll API is still possible.
-                    }
-                };
+                return new AwScrollOffsetManager(delegate, overScroller);
             }
             @Override
             public AwTestContainerView createAwTestContainerView(AwTestRunnerActivity activity,
@@ -745,10 +737,6 @@
         }
 
         @Override
-        public void onUnhandledFlingStartEvent(int velocityX, int velocityY) {
-        }
-
-        @Override
         public void onScrollUpdateGestureConsumed() {
             mOnScrollUpdateGestureConsumedHelper.notifyCalled();
         }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java
index 4cf7e1ff..525c4f6 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java
@@ -95,6 +95,10 @@
         public void invalidate() {
             mInvalidateCount += 1;
         }
+
+        @Override
+        public void cancelFling() {
+        }
     }
 
     private void simulateScrolling(AwScrollOffsetManager offsetManager,
@@ -349,24 +353,6 @@
 
     @SmallTest
     @Feature({"AndroidWebView"})
-    public void testFlingScroll() {
-        TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
-        OverScroller scroller = new OverScroller(getInstrumentation().getContext());
-        AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
-
-        offsetManager.flingScroll(0, 101);
-        assertTrue(!scroller.isFinished());
-        assertTrue(delegate.getInvalidateCount() == 1);
-        assertEquals(101, (int) scroller.getCurrVelocity());
-
-        offsetManager.flingScroll(111, 0);
-        assertTrue(!scroller.isFinished());
-        assertTrue(delegate.getInvalidateCount() == 2);
-        assertEquals(111, (int) scroller.getCurrVelocity());
-    }
-
-    @SmallTest
-    @Feature({"AndroidWebView"})
     public void testRequestChildRectangleOnScreenDontScrollIfAlreadyThere() {
         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
         OverScroller scroller = new OverScroller(getInstrumentation().getContext());
diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc
index fa67e9f..90d2389 100644
--- a/android_webview/lib/main/aw_main_delegate.cc
+++ b/android_webview/lib/main/aw_main_delegate.cc
@@ -104,7 +104,6 @@
   // content_main_runner that reads these values tries to do so.
   // In multi-process mode this code would live in
   // AwContentBrowserClient::GetAdditionalMappedFilesForChildProcess.
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
 #ifdef __LP64__
   const char kNativesFileName[] = "assets/natives_blob_64.bin";
   const char kSnapshotFileName[] = "assets/snapshot_blob_64.bin";
@@ -119,7 +118,6 @@
       kV8NativesDataDescriptor, kNativesFileName));
   CHECK(base::android::RegisterApkAssetWithGlobalDescriptors(
       kV8SnapshotDataDescriptor, kSnapshotFileName));
-#endif
   CHECK(base::android::RegisterApkAssetWithGlobalDescriptors(
       kAndroidICUDataDescriptor, "assets/icudtl.dat"));
 
diff --git a/android_webview/native/android_protocol_handler.cc b/android_webview/native/android_protocol_handler.cc
index c80d9bd..aaadb14cc 100644
--- a/android_webview/native/android_protocol_handler.cc
+++ b/android_webview/native/android_protocol_handler.cc
@@ -252,8 +252,8 @@
     return false;
 
   const std::string& url = request->url().spec();
-  if (!StartsWithASCII(url, asset_prefix_, /*case_sensitive=*/ true) &&
-      !StartsWithASCII(url, resource_prefix_, /*case_sensitive=*/ true)) {
+  if (!base::StartsWithASCII(url, asset_prefix_, /*case_sensitive=*/ true) &&
+      !base::StartsWithASCII(url, resource_prefix_, /*case_sensitive=*/ true)) {
     return false;
   }
 
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 9026eb9a..c6acbad 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -940,6 +940,15 @@
   render_view_host_ext_->SetBackgroundColor(color);
 }
 
+void AwContents::OnComputeScroll(JNIEnv* env,
+                                 jobject obj,
+                                 jlong animation_time_millis) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  browser_view_renderer_.OnComputeScroll(
+      base::TimeTicks() +
+      base::TimeDelta::FromMilliseconds(animation_time_millis));
+}
+
 jlong AwContents::ReleasePopupAwContents(JNIEnv* env, jobject obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return reinterpret_cast<intptr_t>(pending_contents_.release());
@@ -969,13 +978,13 @@
       env, obj.obj(), new_value.x(), new_value.y());
 }
 
-bool AwContents::IsFlingActive() const {
+bool AwContents::IsSmoothScrollingActive() const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
   if (obj.is_null())
     return false;
-  return Java_AwContents_isFlingActive(env, obj.obj());
+  return Java_AwContents_isSmoothScrollingActive(env, obj.obj());
 }
 
 void AwContents::UpdateScrollState(gfx::Vector2d max_scroll_offset,
@@ -999,14 +1008,16 @@
                                     max_page_scale_factor);
 }
 
-void AwContents::DidOverscroll(gfx::Vector2d overscroll_delta) {
+void AwContents::DidOverscroll(gfx::Vector2d overscroll_delta,
+                               gfx::Vector2dF overscroll_velocity) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
   if (obj.is_null())
     return;
-  Java_AwContents_didOverscroll(
-      env, obj.obj(), overscroll_delta.x(), overscroll_delta.y());
+  Java_AwContents_didOverscroll(env, obj.obj(), overscroll_delta.x(),
+                                overscroll_delta.y(), overscroll_velocity.x(),
+                                overscroll_velocity.y());
 }
 
 void AwContents::SetDipScale(JNIEnv* env, jobject obj, jfloat dip_scale) {
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index 30d252a..8a40357 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -118,6 +118,7 @@
   jboolean RestoreFromOpaqueState(JNIEnv* env, jobject obj, jbyteArray state);
   void FocusFirstNode(JNIEnv* env, jobject obj);
   void SetBackgroundColor(JNIEnv* env, jobject obj, jint color);
+  void OnComputeScroll(JNIEnv* env, jobject obj, jlong animation_time_millis);
   bool OnDraw(JNIEnv* env,
               jobject obj,
               jobject canvas,
@@ -199,13 +200,15 @@
   void OnNewPicture() override;
   gfx::Point GetLocationOnScreen() override;
   void ScrollContainerViewTo(gfx::Vector2d new_value) override;
-  bool IsFlingActive() const override;
+  bool IsSmoothScrollingActive() const override;
   void UpdateScrollState(gfx::Vector2d max_scroll_offset,
                          gfx::SizeF contents_size_dip,
                          float page_scale_factor,
                          float min_page_scale_factor,
                          float max_page_scale_factor) override;
-  void DidOverscroll(gfx::Vector2d overscroll_delta) override;
+  void DidOverscroll(gfx::Vector2d overscroll_delta,
+                     gfx::Vector2dF overscroll_velocity) override;
+
   void ParentDrawConstraintsUpdated(
       const ParentCompositorDrawConstraints& draw_constraints) override {}
 
diff --git a/android_webview/native/aw_media_url_interceptor.cc b/android_webview/native/aw_media_url_interceptor.cc
index a2c1cdd..96d3298 100644
--- a/android_webview/native/aw_media_url_interceptor.cc
+++ b/android_webview/native/aw_media_url_interceptor.cc
@@ -19,7 +19,7 @@
       std::string(url::kStandardSchemeSeparator) +
       android_webview::kAndroidAssetPath);
 
-  if (StartsWithASCII(url, asset_file_prefix, true)) {
+  if (base::StartsWithASCII(url, asset_file_prefix, true)) {
     std::string filename(url);
     ReplaceFirstSubstringAfterOffset(
         &filename, 0, asset_file_prefix, "assets/");
diff --git a/android_webview/snapshot_copying.gypi b/android_webview/snapshot_copying.gypi
index 0a23a8cf..01c6285 100644
--- a/android_webview/snapshot_copying.gypi
+++ b/android_webview/snapshot_copying.gypi
@@ -3,7 +3,7 @@
     'snapshot_additional_input_paths': [],
     'snapshot_copy_files': [],
     'conditions': [
-      ['v8_use_external_startup_data==1 and (target_arch=="arm" or target_arch=="ia32" or target_arch=="mipsel")', {
+      ['target_arch=="arm" or target_arch=="ia32" or target_arch=="mipsel"', {
         'snapshot_additional_input_paths': [
           '<(asset_location)/natives_blob_32.bin',
           '<(asset_location)/snapshot_blob_32.bin',
@@ -13,7 +13,7 @@
           '<(PRODUCT_DIR)/snapshot_blob_32.bin',
         ],
       }],
-      ['v8_use_external_startup_data==1 and (target_arch=="arm64" or target_arch=="x64" or target_arch=="mips64el")', {
+      ['target_arch=="arm64" or target_arch=="x64" or target_arch=="mips64el"', {
         'snapshot_additional_input_paths': [
           '<(asset_location)/natives_blob_64.bin',
           '<(asset_location)/snapshot_blob_64.bin',
diff --git a/apps/BUILD.gn b/apps/BUILD.gn
index 5c409c2b..a719964 100644
--- a/apps/BUILD.gn
+++ b/apps/BUILD.gn
@@ -63,10 +63,12 @@
       "ui/views/app_window_frame_view.h",
     ]
     deps += [
-      "//extensions/browser",
       "//ui/strings",
       "//ui/views",
     ]
+    if (enable_extensions) {
+      deps += [ "//extensions/browser" ]
+    }
   }
 
   # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
diff --git a/apps/apps.gypi b/apps/apps.gypi
index 7badfe3..130cb8c 100644
--- a/apps/apps.gypi
+++ b/apps/apps.gypi
@@ -75,7 +75,6 @@
         ],
         ['toolkit_views==1', {
           'dependencies': [
-            '../extensions/extensions.gyp:extensions_browser',
             '../ui/strings/ui_strings.gyp:ui_strings',
             '../ui/views/views.gyp:views',
           ],
@@ -84,6 +83,11 @@
             ['exclude', 'ui/views/'],
           ],
         }],
+        ['toolkit_views==1 and enable_extensions==1', {
+          'dependencies': [
+            '../extensions/extensions.gyp:extensions_browser',
+          ],
+        }],
       ],
       # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
       'msvs_disabled_warnings': [ 4267, ],
diff --git a/apps/custom_launcher_page_contents.cc b/apps/custom_launcher_page_contents.cc
index 20744b3..8888993 100644
--- a/apps/custom_launcher_page_contents.cc
+++ b/apps/custom_launcher_page_contents.cc
@@ -30,14 +30,10 @@
 
 void CustomLauncherPageContents::Initialize(content::BrowserContext* context,
                                             const GURL& url) {
-  extension_function_dispatcher_.reset(
-      new extensions::ExtensionFunctionDispatcher(context, this));
-
   web_contents_.reset(
       content::WebContents::Create(content::WebContents::CreateParams(
           context, content::SiteInstance::CreateForURL(context, url))));
 
-  Observe(web_contents());
   web_contents_->GetMutableRendererPrefs()
       ->browser_handles_all_top_level_requests = true;
   web_contents_->GetRenderViewHost()->SyncRendererPrefs();
@@ -135,30 +131,4 @@
   return helper_->CheckMediaAccessPermission(security_origin, type);
 }
 
-bool CustomLauncherPageContents::OnMessageReceived(
-    const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(CustomLauncherPageContents, message)
-  IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-  IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-extensions::WindowController*
-CustomLauncherPageContents::GetExtensionWindowController() const {
-  return NULL;
-}
-
-content::WebContents* CustomLauncherPageContents::GetAssociatedWebContents()
-    const {
-  return web_contents();
-}
-
-void CustomLauncherPageContents::OnRequest(
-    const ExtensionHostMsg_Request_Params& params) {
-  extension_function_dispatcher_->Dispatch(params,
-                                           web_contents_->GetRenderViewHost());
-}
-
 }  // namespace apps
diff --git a/apps/custom_launcher_page_contents.h b/apps/custom_launcher_page_contents.h
index 919bbe3..cd4164c 100644
--- a/apps/custom_launcher_page_contents.h
+++ b/apps/custom_launcher_page_contents.h
@@ -7,8 +7,6 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "content/public/browser/web_contents_delegate.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "extensions/browser/extension_function_dispatcher.h"
 
 class GURL;
 
@@ -27,10 +25,7 @@
 // implementation for this class should create and maintain the WebContents for
 // the page, and handle any message passing between the web contents and the
 // extension system.
-class CustomLauncherPageContents
-    : public content::WebContentsDelegate,
-      public content::WebContentsObserver,
-      public extensions::ExtensionFunctionDispatcher::Delegate {
+class CustomLauncherPageContents : public content::WebContentsDelegate {
  public:
   CustomLauncherPageContents(scoped_ptr<extensions::AppDelegate> app_delegate,
                              const std::string& extension_id);
@@ -73,18 +68,7 @@
                                   content::MediaStreamType type) override;
 
  private:
-  // content::WebContentsObserver overrides:
-  bool OnMessageReceived(const IPC::Message& message) override;
-
-  // extensions::ExtensionFunctionDispatcher::Delegate overrides:
-  extensions::WindowController* GetExtensionWindowController() const override;
-  content::WebContents* GetAssociatedWebContents() const override;
-
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
-
   scoped_ptr<content::WebContents> web_contents_;
-  scoped_ptr<extensions::ExtensionFunctionDispatcher>
-      extension_function_dispatcher_;
   scoped_ptr<extensions::AppDelegate> app_delegate_;
   scoped_ptr<extensions::AppWebContentsHelper> helper_;
 
diff --git a/apps/ui/views/app_window_frame_view.cc b/apps/ui/views/app_window_frame_view.cc
index 60645d0..4b6246b 100644
--- a/apps/ui/views/app_window_frame_view.cc
+++ b/apps/ui/views/app_window_frame_view.cc
@@ -20,7 +20,6 @@
 #include "ui/strings/grit/ui_strings.h"  // Accessibility names
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/layout/grid_layout.h"
-#include "ui/views/views_delegate.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index e4c3d66..371fcc2 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -779,37 +779,31 @@
 #if defined(OS_WIN)
   MSG msg1 = { NULL, WM_KEYDOWN, ui::VKEY_A, 0 };
   ui::KeyEvent key_event1(msg1);
-  key_event1.SetTranslated(true);
   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&key_event1);
   EXPECT_TRUE(key_event1.handled() || details.dispatcher_destroyed);
 
   MSG msg2 = { NULL, WM_CHAR, L'A', 0 };
   ui::KeyEvent key_event2(msg2);
-  key_event2.SetTranslated(true);
   details = dispatcher->OnEventFromSource(&key_event2);
   EXPECT_FALSE(key_event2.handled() || details.dispatcher_destroyed);
 
   MSG msg3 = { NULL, WM_KEYUP, ui::VKEY_A, 0 };
   ui::KeyEvent key_event3(msg3);
-  key_event3.SetTranslated(true);
   details = dispatcher->OnEventFromSource(&key_event3);
   EXPECT_FALSE(key_event3.handled() || details.dispatcher_destroyed);
 #elif defined(USE_X11)
   ui::ScopedXI2Event key_event;
   key_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, 0);
   ui::KeyEvent key_event1(key_event);
-  key_event1.SetTranslated(true);
   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&key_event1);
   EXPECT_TRUE(key_event1.handled() || details.dispatcher_destroyed);
 
   ui::KeyEvent key_event2('A', ui::VKEY_A, ui::EF_NONE);
-  key_event2.SetTranslated(true);
   details = dispatcher->OnEventFromSource(&key_event2);
   EXPECT_FALSE(key_event2.handled() || details.dispatcher_destroyed);
 
   key_event.InitKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_A, 0);
   ui::KeyEvent key_event3(key_event);
-  key_event3.SetTranslated(true);
   details = dispatcher->OnEventFromSource(&key_event3);
   EXPECT_FALSE(key_event3.handled() || details.dispatcher_destroyed);
 #endif
diff --git a/ash/accelerators/magnifier_key_scroller.cc b/ash/accelerators/magnifier_key_scroller.cc
index eeeda2d..2e33950 100644
--- a/ash/accelerators/magnifier_key_scroller.cc
+++ b/ash/accelerators/magnifier_key_scroller.cc
@@ -9,6 +9,7 @@
 #include "ash/magnifier/magnification_controller.h"
 #include "ash/shell.h"
 #include "base/command_line.h"
+#include "ui/events/event.h"
 
 namespace ash {
 namespace {
diff --git a/ash/accelerators/magnifier_key_scroller_unittest.cc b/ash/accelerators/magnifier_key_scroller_unittest.cc
index 8555369..69f2273 100644
--- a/ash/accelerators/magnifier_key_scroller_unittest.cc
+++ b/ash/accelerators/magnifier_key_scroller_unittest.cc
@@ -9,6 +9,7 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/test/test_window_delegate.h"
+#include "ui/events/event.h"
 #include "ui/events/test/event_generator.h"
 
 namespace ash {
diff --git a/ash/accelerators/spoken_feedback_toggler.cc b/ash/accelerators/spoken_feedback_toggler.cc
index 53f6e6e..32ef929 100644
--- a/ash/accelerators/spoken_feedback_toggler.cc
+++ b/ash/accelerators/spoken_feedback_toggler.cc
@@ -7,6 +7,7 @@
 #include "ash/accelerators/key_hold_detector.h"
 #include "ash/accessibility_delegate.h"
 #include "ash/shell.h"
+#include "ui/events/event.h"
 
 namespace ash {
 namespace {
diff --git a/ash/ash.gyp b/ash/ash.gyp
index 6ef24a1..bb33bfb 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -168,6 +168,8 @@
       'magnifier/magnification_controller.h',
       'magnifier/partial_magnification_controller.cc',
       'magnifier/partial_magnification_controller.h',
+      'metrics/desktop_task_switch_metric_recorder.cc',
+      'metrics/desktop_task_switch_metric_recorder.h',
       'metrics/task_switch_metrics_recorder.cc',
       'metrics/task_switch_metrics_recorder.h',
       'metrics/task_switch_time_tracker.cc',
@@ -815,6 +817,7 @@
       'keyboard_overlay/keyboard_overlay_delegate_unittest.cc',
       'keyboard_overlay/keyboard_overlay_view_unittest.cc',
       'magnifier/magnification_controller_unittest.cc',
+      'metrics/desktop_task_switch_metric_recorder_unittest.cc',
       'metrics/task_switch_metrics_recorder_unittest.cc',
       'metrics/task_switch_time_tracker_unittest.cc',
       'metrics/user_metrics_recorder_unittest.cc',
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index d997e0c..cfcba1a 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -258,16 +258,19 @@
       </message>
 
       <message name="IDS_ASH_STATUS_TRAY_CAST" desc="The label used as the header in the cast popup.">
-        Cast
+        Cast screen
       </message>
       <message name="IDS_ASH_STATUS_TRAY_CAST_CAST_DESKTOP" desc="The label used in the tray popup to tell the user we are casting the desktop.">
-        Casting desktop
+        Casting screen to $1
       </message>
       <message name="IDS_ASH_STATUS_TRAY_CAST_CAST_TAB" desc="The title label used in the tray popup to tell the user we are casting a tab.">
-        Casting $1
+        Casting $1 to $2
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_CAST_CAST_UNKNOWN" desc="The label used when we have detected we are casting but do not know what we are casting or who we are casting to.">
+        Casting to an unknown receiver
       </message>
       <message name="IDS_ASH_STATUS_TRAY_CAST_DESKTOP" desc="The label used in the tray popup to notify that desktop may be cast.">
-        Cast desktop to
+        Cast devices available
       </message>
       <message name="IDS_ASH_STATUS_TRAY_CAST_NO_DEVICE" desc="The label used in the tray popup to notify that no cast devices are available.">
         No cast devices
@@ -278,12 +281,6 @@
       <message name="IDS_ASH_STATUS_TRAY_CAST_STOP" desc="The label used in the tray popup to stop casting.">
         Stop
       </message>
-      <message name="IDS_ASH_STATUS_TRAY_CAST_UNKNOWN_CAST_TYPE" desc="The label used when we have detected we are casting but do not know if we are casting a tab or the desktop.">
-        Casting
-      </message>
-      <message name="IDS_ASH_STATUS_TRAY_CAST_UNKNOWN_RECEIVER" desc="The label used when we have detected we are casting but do not know the name of the receiver.">
-        Unknown receiver
-      </message>
 
       <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH" desc="The label used as the header in the bluetooth popup.">
         Bluetooth
diff --git a/ash/ash_unittests.isolate b/ash/ash_unittests.isolate
index 40e3e79..4866e71 100644
--- a/ash/ash_unittests.isolate
+++ b/ash/ash_unittests.isolate
@@ -41,7 +41,6 @@
     ['OS=="linux"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
         ],
       },
@@ -49,7 +48,6 @@
     ['OS=="win"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/osmesa.dll',
         ],
       },
diff --git a/ash/content/display/DEPS b/ash/content/display/DEPS
index 07d93bc0..5f741582 100644
--- a/ash/content/display/DEPS
+++ b/ash/content/display/DEPS
@@ -5,7 +5,7 @@
   "+content/public/browser/browser_thread.h",
   "+content/public/browser/web_contents.h",
   "+third_party/qcms/src/qcms.h",
-  "+third_party/WebKit/public/platform/WebScreenOrientationLockType.h",
+  "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
 ]
 
 specific_include_rules = {
diff --git a/ash/content/display/screen_orientation_controller_chromeos.h b/ash/content/display/screen_orientation_controller_chromeos.h
index 93a100dc..32d78fb 100644
--- a/ash/content/display/screen_orientation_controller_chromeos.h
+++ b/ash/content/display/screen_orientation_controller_chromeos.h
@@ -15,7 +15,7 @@
 #include "chromeos/accelerometer/accelerometer_reader.h"
 #include "chromeos/accelerometer/accelerometer_types.h"
 #include "content/public/browser/screen_orientation_delegate.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 #include "ui/aura/window_observer.h"
 #include "ui/gfx/display.h"
 #include "ui/wm/public/activation_change_observer.h"
diff --git a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
index 487d44c..6bff5b1 100644
--- a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
+++ b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
@@ -22,7 +22,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_context.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 #include "ui/aura/window.h"
 #include "ui/gfx/display.h"
 #include "ui/message_center/message_center.h"
@@ -135,7 +135,7 @@
 }
 
 content::WebContents* ScreenOrientationControllerTest::CreateWebContents() {
-  return views::ViewsDelegate::views_delegate->CreateWebContents(
+  return views::ViewsDelegate::GetInstance()->CreateWebContents(
       ash_test_helper()->test_shell_delegate()->GetActiveBrowserContext(),
       nullptr);
 }
@@ -143,7 +143,7 @@
 content::WebContents*
 ScreenOrientationControllerTest::CreateSecondaryWebContents() {
   secondary_browser_context_.reset(new content::TestBrowserContext());
-  return views::ViewsDelegate::views_delegate->CreateWebContents(
+  return views::ViewsDelegate::GetInstance()->CreateWebContents(
       secondary_browser_context_.get(), nullptr);
 }
 
diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc
index f34ae1fe..9e352fe7 100644
--- a/ash/display/display_controller.cc
+++ b/ash/display/display_controller.cc
@@ -26,6 +26,7 @@
 #include "ash/shell_delegate.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/wm/coordinate_conversion.h"
+#include "ash/wm/window_util.h"
 #include "base/command_line.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
@@ -38,6 +39,7 @@
 #include "ui/aura/window_property.h"
 #include "ui/aura/window_tracker.h"
 #include "ui/aura/window_tree_host.h"
+#include "ui/base/ime/input_method_factory.h"
 #include "ui/compositor/compositor.h"
 #include "ui/gfx/display.h"
 #include "ui/gfx/screen.h"
@@ -867,6 +869,16 @@
   UpdateMouseLocationAfterDisplayChange();
 }
 
+bool DisplayController::DispatchKeyEventPostIME(const ui::KeyEvent& event) {
+  // Getting the active root window to dispatch the event. This isn't
+  // significant as the event will be sent to the window resolved by
+  // aura::client::FocusClient which is FocusController in ash.
+  aura::Window* active_window = wm::GetActiveWindow();
+  aura::Window* root_window = active_window ? active_window->GetRootWindow()
+                                            : Shell::GetPrimaryRootWindow();
+  return root_window->GetHost()->DispatchKeyEventPostIME(event);
+}
+
 AshWindowTreeHost* DisplayController::AddWindowTreeHostForDisplay(
     const gfx::Display& display,
     const AshWindowTreeHostInitParams& init_params) {
@@ -879,6 +891,11 @@
       display.id() == DisplayManager::kUnifiedDisplayId;
   AshWindowTreeHost* ash_host = AshWindowTreeHost::Create(params_with_bounds);
   aura::WindowTreeHost* host = ash_host->AsWindowTreeHost();
+  if (!input_method_) {  // Singleton input method instance for Ash.
+    input_method_ = ui::CreateInputMethod(this, host->GetAcceleratedWidget());
+    input_method_->OnFocus();
+  }
+  host->SetSharedInputMethod(input_method_.get());
 
   host->window()->SetName(base::StringPrintf(
       "%sRootWindow-%d", params_with_bounds.offscreen ? "Offscreen" : "",
diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h
index 40e3ed2..8ef6d057 100644
--- a/ash/display/display_controller.h
+++ b/ash/display/display_controller.h
@@ -19,6 +19,8 @@
 #include "base/time/time.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host_observer.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/input_method_delegate.h"
 #include "ui/gfx/display_observer.h"
 #include "ui/gfx/geometry/point.h"
 
@@ -51,7 +53,8 @@
 // display, keeping them in sync with display configuration changes.
 class ASH_EXPORT DisplayController : public gfx::DisplayObserver,
                                      public aura::WindowTreeHostObserver,
-                                     public DisplayManager::Delegate {
+                                     public DisplayManager::Delegate,
+                                     public ui::internal::InputMethodDelegate {
  public:
   class ASH_EXPORT Observer {
    public:
@@ -163,6 +166,9 @@
   void PreDisplayConfigurationChange(bool clear_focus) override;
   void PostDisplayConfigurationChange() override;
 
+  // ui::internal::InputMethodDelegate overrides:
+  bool DispatchKeyEventPostIME(const ui::KeyEvent& event) override;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(DisplayControllerTest, BoundsUpdated);
   FRIEND_TEST_ALL_PREFIXES(DisplayControllerTest, SecondaryDisplayLayout);
@@ -218,6 +224,8 @@
   scoped_ptr<CursorWindowController> cursor_window_controller_;
   scoped_ptr<MirrorWindowController> mirror_window_controller_;
 
+  scoped_ptr<ui::InputMethod> input_method_;
+
   // Stores the current cursor location (in native coordinates and screen
   // coordinates respectively). The locations are used to restore the cursor
   // location when the display configuration changes and to determine whether
diff --git a/ash/display/mouse_cursor_event_filter.cc b/ash/display/mouse_cursor_event_filter.cc
index 38b1cbd..fb24f2cf 100644
--- a/ash/display/mouse_cursor_event_filter.cc
+++ b/ash/display/mouse_cursor_event_filter.cc
@@ -10,6 +10,7 @@
 #include "ash/display/display_manager.h"
 #include "ash/display/mouse_warp_controller.h"
 #include "ash/shell.h"
+#include "ui/events/event.h"
 
 namespace ash {
 
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
index bab52ee..795265ba 100644
--- a/ash/drag_drop/drag_drop_controller.cc
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -26,7 +26,6 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/path.h"
-#include "ui/views/views_delegate.h"
 #include "ui/views/widget/native_widget_aura.h"
 #include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/public/drag_drop_delegate.h"
diff --git a/ash/drag_drop/drag_drop_controller_unittest.cc b/ash/drag_drop/drag_drop_controller_unittest.cc
index bb3cc97..20513e1 100644
--- a/ash/drag_drop/drag_drop_controller_unittest.cc
+++ b/ash/drag_drop/drag_drop_controller_unittest.cc
@@ -29,7 +29,6 @@
 #include "ui/gfx/animation/linear_animation.h"
 #include "ui/gfx/image/image_skia_rep.h"
 #include "ui/views/view.h"
-#include "ui/views/views_delegate.h"
 #include "ui/views/widget/native_widget_aura.h"
 #include "ui/views/widget/native_widget_delegate.h"
 #include "ui/views/widget/widget.h"
diff --git a/ash/host/ash_window_tree_host_unified.cc b/ash/host/ash_window_tree_host_unified.cc
index 2e9db76..685e20c 100644
--- a/ash/host/ash_window_tree_host_unified.cc
+++ b/ash/host/ash_window_tree_host_unified.cc
@@ -181,8 +181,4 @@
   mirroring_hosts_.erase(iter);
 }
 
-ui::EventProcessor* AshWindowTreeHostUnified::GetEventProcessor() {
-  return dispatcher();
-}
-
 }  // namespace ash
diff --git a/ash/host/ash_window_tree_host_unified.h b/ash/host/ash_window_tree_host_unified.h
index 843ff03..2f8b042 100644
--- a/ash/host/ash_window_tree_host_unified.h
+++ b/ash/host/ash_window_tree_host_unified.h
@@ -26,8 +26,7 @@
 // compositor.
 class AshWindowTreeHostUnified : public AshWindowTreeHost,
                                  public aura::WindowTreeHost,
-                                 public aura::WindowObserver,
-                                 public ui::EventSource {
+                                 public aura::WindowObserver {
  public:
   explicit AshWindowTreeHostUnified(const gfx::Rect& initial_bounds);
   ~AshWindowTreeHostUnified() override;
@@ -65,9 +64,6 @@
   // aura::WindowObserver:
   void OnWindowDestroying(aura::Window* window) override;
 
-  // ui::EventSource:
-  ui::EventProcessor* GetEventProcessor() override;
-
   std::vector<AshWindowTreeHost*> mirroring_hosts_;
 
   gfx::Rect bounds_;
diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc
index fee51d2..812e0c1 100644
--- a/ash/magnifier/magnification_controller.cc
+++ b/ash/magnifier/magnification_controller.cc
@@ -17,7 +17,6 @@
 #include "base/command_line.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/timer/timer.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
@@ -75,6 +74,12 @@
       gfx::ToCeiledPoint(host_location_3f.AsPointF()));
 }
 
+ui::InputMethod* GetInputMethod(aura::Window* root_window) {
+  if (root_window->GetHost())
+    return root_window->GetHost()->GetInputMethod();
+  return nullptr;
+}
+
 }  // namespace
 
 namespace ash {
@@ -242,8 +247,6 @@
 
   ScrollDirection scroll_direction_;
 
-  ui::InputMethod* input_method_;  // Not owned.
-
   // Timer for moving magnifier window when it fires.
   base::OneShotTimer<MagnificationControllerImpl> move_magnifier_timer_;
 
@@ -268,7 +271,6 @@
       move_cursor_after_animation_(false),
       scale_(kNonMagnifiedScale),
       scroll_direction_(SCROLL_NONE),
-      input_method_(NULL),
       disable_move_magnifier_delay_(false) {
   Shell::GetInstance()->AddPreTargetHandler(this);
   root_window_->AddObserver(this);
@@ -276,8 +278,9 @@
 }
 
 MagnificationControllerImpl::~MagnificationControllerImpl() {
-  if (input_method_)
-    input_method_->RemoveObserver(this);
+  ui::InputMethod* input_method = GetInputMethod(root_window_);
+  if (input_method)
+    input_method->RemoveObserver(this);
 
   root_window_->RemoveObserver(this);
 
@@ -584,13 +587,10 @@
 
 void MagnificationControllerImpl::SetEnabled(bool enabled) {
   Shell* shell = Shell::GetInstance();
+  ui::InputMethod* input_method = GetInputMethod(root_window_);
   if (enabled) {
-    if (!input_method_) {
-      input_method_ =
-          root_window_->GetProperty(aura::client::kRootWindowInputMethodKey);
-      if (input_method_)
-        input_method_->AddObserver(this);
-    }
+    if (!is_enabled_ && input_method)
+      input_method->AddObserver(this);
 
     float scale =
         Shell::GetInstance()->accessibility_delegate()->
@@ -611,10 +611,8 @@
     if (!is_enabled_)
       return;
 
-    if (input_method_) {
-      input_method_->RemoveObserver(this);
-      input_method_ = NULL;
-    }
+    if (input_method)
+      input_method->RemoveObserver(this);
 
     RedrawKeepingMousePosition(kNonMagnifiedScale, true);
     is_enabled_ = enabled;
diff --git a/ash/magnifier/magnification_controller_unittest.cc b/ash/magnifier/magnification_controller_unittest.cc
index c36a9d6..aeb89df 100644
--- a/ash/magnifier/magnification_controller_unittest.cc
+++ b/ash/magnifier/magnification_controller_unittest.cc
@@ -9,7 +9,6 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/test/display_manager_test_api.h"
 #include "base/strings/stringprintf.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
 #include "ui/aura/test/aura_test_utils.h"
 #include "ui/aura/window_tree_host.h"
@@ -150,10 +149,7 @@
 
   ui::InputMethod* GetInputMethod() {
     DCHECK(text_input_view_);
-    return text_input_view_->GetWidget()
-        ->GetNativeWindow()
-        ->GetRootWindow()
-        ->GetProperty(aura::client::kRootWindowInputMethodKey);
+    return text_input_view_->GetWidget()->GetHostInputMethod();
   }
 
   DISALLOW_COPY_AND_ASSIGN(MagnificationControllerTest);
diff --git a/ash/metrics/desktop_task_switch_metric_recorder.cc b/ash/metrics/desktop_task_switch_metric_recorder.cc
new file mode 100644
index 0000000..89360667
--- /dev/null
+++ b/ash/metrics/desktop_task_switch_metric_recorder.cc
@@ -0,0 +1,38 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/metrics/desktop_task_switch_metric_recorder.h"
+
+#include "ash/metrics/user_metrics_recorder.h"
+#include "ash/shell.h"
+#include "ash/wm/window_util.h"
+#include "ui/wm/public/activation_client.h"
+
+namespace ash {
+
+DesktopTaskSwitchMetricRecorder::DesktopTaskSwitchMetricRecorder()
+    : last_active_task_window_(nullptr) {
+  Shell::GetInstance()->activation_client()->AddObserver(this);
+}
+
+DesktopTaskSwitchMetricRecorder::~DesktopTaskSwitchMetricRecorder() {
+  Shell::GetInstance()->activation_client()->RemoveObserver(this);
+}
+
+void DesktopTaskSwitchMetricRecorder::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
+  if (gained_active && wm::IsWindowUserPositionable(gained_active)) {
+    if (last_active_task_window_ != gained_active &&
+        reason == aura::client::ActivationChangeObserver::ActivationReason::
+                      INPUT_EVENT) {
+      Shell::GetInstance()->metrics()->RecordUserMetricsAction(
+          UMA_DESKTOP_SWITCH_TASK);
+    }
+    last_active_task_window_ = gained_active;
+  }
+}
+
+}  // namespace ash
diff --git a/ash/metrics/desktop_task_switch_metric_recorder.h b/ash/metrics/desktop_task_switch_metric_recorder.h
new file mode 100644
index 0000000..67bbb0038
--- /dev/null
+++ b/ash/metrics/desktop_task_switch_metric_recorder.h
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_METRICS_DESKTOP_TASK_SWITCH_METRIC_RECORDER_H_
+#define ASH_METRICS_DESKTOP_TASK_SWITCH_METRIC_RECORDER_H_
+
+#include "ash/ash_export.h"
+#include "base/macros.h"
+#include "ui/wm/public/activation_change_observer.h"
+
+namespace ash {
+
+class UserMetricsRecorder;
+
+// Tracks metrics for task switches caused by the user activating a task window
+// by clicking or tapping on it.
+class ASH_EXPORT DesktopTaskSwitchMetricRecorder
+    : public aura::client::ActivationChangeObserver {
+ public:
+  explicit DesktopTaskSwitchMetricRecorder();
+  ~DesktopTaskSwitchMetricRecorder() override;
+
+  // aura::client::ActivationChangeObserver:
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
+
+ private:
+  // Tracks the last active task window.
+  aura::Window* last_active_task_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(DesktopTaskSwitchMetricRecorder);
+};
+
+}  // namespace ash
+
+#endif  // ASH_METRICS_DESKTOP_TASK_SWITCH_METRIC_RECORDER_H_
diff --git a/ash/metrics/desktop_task_switch_metric_recorder_unittest.cc b/ash/metrics/desktop_task_switch_metric_recorder_unittest.cc
new file mode 100644
index 0000000..59ec7f9
--- /dev/null
+++ b/ash/metrics/desktop_task_switch_metric_recorder_unittest.cc
@@ -0,0 +1,338 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/metrics/desktop_task_switch_metric_recorder.h"
+
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/user_action_tester.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/layer_type.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/wm/public/activation_client.h"
+#include "ui/wm/public/window_types.h"
+
+using aura::client::ActivationChangeObserver;
+
+namespace ash {
+namespace {
+
+const char kDesktopTaskSwitchUserAction[] = "Desktop_SwitchTask";
+
+// Test fixture for the DesktopTaskSwitchMetricsRecorder class. NOTE: This
+// fixture extends AshTestBase so that the UserMetricsRecorder instance required
+// by the test target can be obtained through Shell::GetInstance()->metrics()
+// and the test target is not the same instance as the one owned by the
+// UserMetricsRecorder instance.
+class DesktopTaskSwitchMetricRecorderTest : public test::AshTestBase {
+ public:
+  DesktopTaskSwitchMetricRecorderTest();
+  ~DesktopTaskSwitchMetricRecorderTest() override;
+
+  // test::AshTestBase:
+  void SetUp() override;
+  void TearDown() override;
+
+  // Resets the recorded user action counts.
+  void ResetActionCounts();
+
+  // Returns the number of times the "Desktop_SwitchTask" user action was
+  // recorded.
+  int GetActionCount() const;
+
+  // Creates a positionable window such that wm::IsWindowUserPositionable(...)
+  // would retun true.
+  scoped_ptr<aura::Window> CreatePositionableWindow() const;
+
+  // Creates a non-positionable window such that
+  // wm::IsWindowUserPositionable(...) would retun false.
+  scoped_ptr<aura::Window> CreateNonPositionableWindow() const;
+
+  // Wrapper to notify the test target's OnWindowActivated(...) method that
+  // |window| was activated due to an INPUT_EVENT.
+  void ActiveTaskWindowWithUserInput(aura::Window* window);
+
+ protected:
+  // Records UMA user action counts.
+  scoped_ptr<base::UserActionTester> user_action_tester_;
+
+  // The test target.
+  scoped_ptr<DesktopTaskSwitchMetricRecorder> metrics_recorder_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DesktopTaskSwitchMetricRecorderTest);
+};
+
+DesktopTaskSwitchMetricRecorderTest::DesktopTaskSwitchMetricRecorderTest() {
+}
+
+DesktopTaskSwitchMetricRecorderTest::~DesktopTaskSwitchMetricRecorderTest() {
+}
+
+void DesktopTaskSwitchMetricRecorderTest::SetUp() {
+  test::AshTestBase::SetUp();
+  metrics_recorder_.reset(new DesktopTaskSwitchMetricRecorder);
+  user_action_tester_.reset(new base::UserActionTester);
+}
+
+void DesktopTaskSwitchMetricRecorderTest::TearDown() {
+  user_action_tester_.reset();
+  metrics_recorder_.reset();
+  test::AshTestBase::TearDown();
+}
+
+void DesktopTaskSwitchMetricRecorderTest::ActiveTaskWindowWithUserInput(
+    aura::Window* window) {
+  metrics_recorder_->OnWindowActivated(
+      ActivationChangeObserver::ActivationReason::INPUT_EVENT, window, nullptr);
+}
+
+void DesktopTaskSwitchMetricRecorderTest::ResetActionCounts() {
+  user_action_tester_->ResetCounts();
+}
+
+int DesktopTaskSwitchMetricRecorderTest::GetActionCount() const {
+  return user_action_tester_->GetActionCount(kDesktopTaskSwitchUserAction);
+}
+
+scoped_ptr<aura::Window>
+DesktopTaskSwitchMetricRecorderTest::CreatePositionableWindow() const {
+  scoped_ptr<aura::Window> window(new aura::Window(
+      aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate()));
+  window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+  window->Init(ui::LAYER_NOT_DRAWN);
+  return window.Pass();
+}
+
+scoped_ptr<aura::Window>
+DesktopTaskSwitchMetricRecorderTest::CreateNonPositionableWindow() const {
+  scoped_ptr<aura::Window> window(new aura::Window(
+      aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate()));
+  window->SetType(ui::wm::WINDOW_TYPE_UNKNOWN);
+  window->Init(ui::LAYER_NOT_DRAWN);
+  return window.Pass();
+}
+
+// Verify user action is recorded when a positionable window is activated given
+// that a null window was activated last.
+TEST_F(DesktopTaskSwitchMetricRecorderTest,
+       ActivatePositionableWindowWhenNullWindowWasActivatedLast) {
+  scoped_ptr<aura::Window> null_window;
+  scoped_ptr<aura::Window> positionable_window =
+      CreatePositionableWindow().Pass();
+
+  ActiveTaskWindowWithUserInput(null_window.get());
+  ResetActionCounts();
+
+  ActiveTaskWindowWithUserInput(positionable_window.get());
+  EXPECT_EQ(1, GetActionCount());
+}
+
+// Verify user action is recorded whena positionable window is activated given
+// a different positionable window was activated last.
+TEST_F(
+    DesktopTaskSwitchMetricRecorderTest,
+    ActivatePositionableWindowWhenADifferentPositionableWindowWasActivatedLast) {
+  scoped_ptr<aura::Window> positionable_window_1 =
+      CreatePositionableWindow().Pass();
+  scoped_ptr<aura::Window> positionable_window_2 =
+      CreatePositionableWindow().Pass();
+
+  ActiveTaskWindowWithUserInput(positionable_window_1.get());
+  ResetActionCounts();
+
+  ActiveTaskWindowWithUserInput(positionable_window_2.get());
+  EXPECT_EQ(1, GetActionCount());
+}
+
+// Verify user action is not recorded when a positionable window is activated
+// given the same positionable window was activated last.
+TEST_F(
+    DesktopTaskSwitchMetricRecorderTest,
+    ActivatePositionableWindowWhenTheSamePositionableWindowWasActivatedLast) {
+  scoped_ptr<aura::Window> positionable_window =
+      CreatePositionableWindow().Pass();
+
+  ActiveTaskWindowWithUserInput(positionable_window.get());
+  ResetActionCounts();
+
+  ActiveTaskWindowWithUserInput(positionable_window.get());
+  EXPECT_EQ(0, GetActionCount());
+}
+
+// Verify user action is recorded when a positionable window is activated given
+// a non-positionable window was activated last.
+TEST_F(DesktopTaskSwitchMetricRecorderTest,
+       ActivatePositionableWindowWhenANonPositionableWindowWasActivatedLast) {
+  scoped_ptr<aura::Window> non_positionable_window =
+      CreateNonPositionableWindow().Pass();
+  scoped_ptr<aura::Window> positionable_window =
+      CreatePositionableWindow().Pass();
+
+  ActiveTaskWindowWithUserInput(non_positionable_window.get());
+  ResetActionCounts();
+
+  ActiveTaskWindowWithUserInput(positionable_window.get());
+  EXPECT_EQ(1, GetActionCount());
+}
+
+// Verify user action is not recorded when a non-positionable window is
+// activated between two activations of the same positionable window.
+TEST_F(DesktopTaskSwitchMetricRecorderTest,
+       ActivateNonPositionableWindowBetweenTwoPositionableWindowActivations) {
+  scoped_ptr<aura::Window> positionable_window =
+      CreatePositionableWindow().Pass();
+  scoped_ptr<aura::Window> non_positionable_window =
+      CreateNonPositionableWindow().Pass();
+
+  ActiveTaskWindowWithUserInput(positionable_window.get());
+  ResetActionCounts();
+
+  ActiveTaskWindowWithUserInput(non_positionable_window.get());
+  EXPECT_EQ(0, GetActionCount());
+
+  ActiveTaskWindowWithUserInput(positionable_window.get());
+  EXPECT_EQ(0, GetActionCount());
+}
+
+// Verify user action is not recorded when a null window is activated.
+TEST_F(DesktopTaskSwitchMetricRecorderTest, ActivateNullWindow) {
+  scoped_ptr<aura::Window> positionable_window =
+      CreatePositionableWindow().Pass();
+  scoped_ptr<aura::Window> null_window = nullptr;
+
+  ActiveTaskWindowWithUserInput(positionable_window.get());
+  ResetActionCounts();
+
+  ActiveTaskWindowWithUserInput(null_window.get());
+  EXPECT_EQ(0, GetActionCount());
+}
+
+// Verify user action is not recorded when a non-positionable window is
+// activated.
+TEST_F(DesktopTaskSwitchMetricRecorderTest, ActivateNonPositionableWindow) {
+  scoped_ptr<aura::Window> positionable_window =
+      CreatePositionableWindow().Pass();
+  scoped_ptr<aura::Window> non_positionable_window =
+      CreateNonPositionableWindow().Pass();
+
+  ActiveTaskWindowWithUserInput(positionable_window.get());
+  ResetActionCounts();
+
+  ActiveTaskWindowWithUserInput(non_positionable_window.get());
+  EXPECT_EQ(0, GetActionCount());
+}
+
+// Verify user action is not recorded when the ActivationReason is not an
+// INPUT_EVENT.
+TEST_F(DesktopTaskSwitchMetricRecorderTest,
+       ActivatePositionableWindowWithNonInputEventReason) {
+  scoped_ptr<aura::Window> positionable_window_1 =
+      CreatePositionableWindow().Pass();
+  scoped_ptr<aura::Window> positionable_window_2 =
+      CreatePositionableWindow().Pass();
+
+  ActiveTaskWindowWithUserInput(positionable_window_1.get());
+  ResetActionCounts();
+
+  metrics_recorder_->OnWindowActivated(
+      ActivationChangeObserver::ActivationReason::ACTIVATION_CLIENT,
+      positionable_window_2.get(), nullptr);
+  EXPECT_EQ(0, GetActionCount());
+}
+
+// Test fixture to test the integration of the DesktopTaskSwitchMetricsRecorder
+// class with ash::Shell environment.
+class DesktopTaskSwitchMetricRecorderWithShellIntegrationTest
+    : public test::AshTestBase {
+ public:
+  DesktopTaskSwitchMetricRecorderWithShellIntegrationTest();
+  ~DesktopTaskSwitchMetricRecorderWithShellIntegrationTest() override;
+
+  // test::AshTestBase:
+  void SetUp() override;
+  void TearDown() override;
+
+  // Returns the number of times the "Desktop_SwitchTask" user action was
+  // recorded.
+  int GetActionCount() const;
+
+  // Creates a positionable window with the given |bounds| such that
+  // wm::IsWindowUserPositionable(...) would retun true.
+  aura::Window* CreatePositionableWindowInShellWithBounds(
+      const gfx::Rect& bounds);
+
+ protected:
+  // Records UMA user action counts.
+  scoped_ptr<base::UserActionTester> user_action_tester_;
+
+  // Delegate used when creating new windows using the
+  // CreatePositionableWindowInShellWithBounds(...) method.
+  aura::test::TestWindowDelegate test_window_delegate_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(
+      DesktopTaskSwitchMetricRecorderWithShellIntegrationTest);
+};
+
+DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::
+    DesktopTaskSwitchMetricRecorderWithShellIntegrationTest() {
+}
+
+DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::
+    ~DesktopTaskSwitchMetricRecorderWithShellIntegrationTest() {
+}
+
+void DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::SetUp() {
+  test::AshTestBase::SetUp();
+  user_action_tester_.reset(new base::UserActionTester);
+}
+
+void DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::TearDown() {
+  user_action_tester_.reset();
+  test::AshTestBase::TearDown();
+}
+
+int DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::GetActionCount()
+    const {
+  return user_action_tester_->GetActionCount(kDesktopTaskSwitchUserAction);
+}
+
+aura::Window* DesktopTaskSwitchMetricRecorderWithShellIntegrationTest::
+    CreatePositionableWindowInShellWithBounds(const gfx::Rect& bounds) {
+  return CreateTestWindowInShellWithDelegate(&test_window_delegate_, 0, bounds);
+}
+
+// Verify a user action is recorded when a positionable window is activated by
+// a INPUT_EVENT.
+TEST_F(DesktopTaskSwitchMetricRecorderWithShellIntegrationTest,
+       ActivatePositionableWindowWithInputEvent) {
+  aura::Window* positionable_window =
+      CreatePositionableWindowInShellWithBounds(gfx::Rect(0, 0, 10, 10));
+
+  ui::test::EventGenerator event_generator(Shell::GetPrimaryRootWindow());
+
+  event_generator.MoveMouseToCenterOf(positionable_window);
+  event_generator.ClickLeftButton();
+
+  EXPECT_EQ(1, GetActionCount());
+}
+
+// Verify a user action is not recorded when a positionable window is activated
+// by a non INPUT_EVENT.
+TEST_F(DesktopTaskSwitchMetricRecorderWithShellIntegrationTest,
+       ActivatePositionableWindowWithNonInputEvent) {
+  aura::Window* positionable_window =
+      CreatePositionableWindowInShellWithBounds(gfx::Rect(0, 0, 10, 10));
+
+  Shell::GetInstance()->activation_client()->ActivateWindow(
+      positionable_window);
+
+  EXPECT_EQ(0, GetActionCount());
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/metrics/task_switch_metrics_recorder.cc b/ash/metrics/task_switch_metrics_recorder.cc
index b8b57fe..69718dc7 100644
--- a/ash/metrics/task_switch_metrics_recorder.cc
+++ b/ash/metrics/task_switch_metrics_recorder.cc
@@ -10,6 +10,11 @@
 
 namespace {
 
+const char kAshTaskSwitchHistogramName[] = "Ash.TimeBetweenTaskSwitches";
+
+const char kDesktopHistogramName[] =
+    "Ash.Desktop.TimeBetweenNavigateToTaskSwitches";
+
 const char kShelfHistogramName[] =
     "Ash.Shelf.TimeBetweenNavigateToTaskSwitches";
 
@@ -28,8 +33,12 @@
 const char* GetHistogramName(
     TaskSwitchMetricsRecorder::TaskSwitchSource task_switch_source) {
   switch (task_switch_source) {
+    case TaskSwitchMetricsRecorder::kAny:
+      return kAshTaskSwitchHistogramName;
     case TaskSwitchMetricsRecorder::kAppList:
       return kAppListHistogramName;
+    case TaskSwitchMetricsRecorder::kDesktop:
+      return kDesktopHistogramName;
     case TaskSwitchMetricsRecorder::kOverviewMode:
       return kOverviewModeHistogramName;
     case TaskSwitchMetricsRecorder::kShelf:
@@ -53,6 +62,15 @@
 
 void TaskSwitchMetricsRecorder::OnTaskSwitch(
     TaskSwitchSource task_switch_source) {
+  DCHECK_NE(task_switch_source, kAny);
+  if (task_switch_source != kAny) {
+    OnTaskSwitchInternal(task_switch_source);
+    OnTaskSwitchInternal(kAny);
+  }
+}
+
+void TaskSwitchMetricsRecorder::OnTaskSwitchInternal(
+    TaskSwitchSource task_switch_source) {
   TaskSwitchTimeTracker* task_switch_time_tracker =
       FindTaskSwitchTimeTracker(task_switch_source);
   if (!task_switch_time_tracker)
diff --git a/ash/metrics/task_switch_metrics_recorder.h b/ash/metrics/task_switch_metrics_recorder.h
index b2103be..c1ee339 100644
--- a/ash/metrics/task_switch_metrics_recorder.h
+++ b/ash/metrics/task_switch_metrics_recorder.h
@@ -10,6 +10,10 @@
 #include "ash/ash_export.h"
 #include "base/containers/scoped_ptr_hash_map.h"
 
+namespace aura {
+class Window;
+}  // namespace aura
+
 namespace ash {
 
 class TaskSwitchTimeTracker;
@@ -21,9 +25,16 @@
  public:
   // Enumeration of the different user interfaces that could be the source of
   // a task switch. Note this is not necessarily comprehensive of all sources.
+  // TODO(bruthig): Convert enum format from kValue to VALUE.
   enum TaskSwitchSource {
+    // Task switches caused by any two sources in this enum. NOTE: This value
+    // should NOT be used outside of this class.
+    kAny,
     // Task switches from selecting items in the app list.
     kAppList,
+    // Task switches caused by the user activating a task window by clicking or
+    // tapping on it.
+    kDesktop,
     // Task switches caused by selecting a window from overview mode which is
     // different from the previously-active window.
     kOverviewMode,
@@ -38,19 +49,30 @@
   TaskSwitchMetricsRecorder();
   virtual ~TaskSwitchMetricsRecorder();
 
-  // Notifies |this| that a "navigate to" task switch has occurred. A
-  // "navigate to" operation is defined by a task switch where the specific task
-  // that becomes active is user-predictable (ie Alt+Tab accelerator, launching
-  // a new window via the shelf, etc). Contrast to a "navigate away" operation
-  // which is defined as a user interaction that navigates away from a specified
-  // task and the next task that becomes active is likely not user-predictable
-  // (ie. closing or minimizing a window, closing a tab, etc).
+  // Notifies |this| that a "navigate to" task switch has occurred from the
+  // specified |task_switch_source|. The metrics associated with
+  // TaskSwitchSource::kAny source will be updated as well.
+  //
+  // NOTE: A |task_switch_source| value of TaskSwitchSource::kAny should not be
+  // used and behavior is undefined if it is.
+  //
+  // A "navigate to" operation is defined by a task switch where the specific
+  // task that becomes active is user-predictable (e.g., Alt+Tab accelerator,
+  // launching a new window via the shelf, etc). Contrast to a "navigate away"
+  // operation which is defined as a user interaction that navigates away from a
+  // specified task and the next task that becomes active is likely not
+  // user-predictable (e.g., closing or minimizing a window, closing a tab,
+  // etc).
   //
   // Will add an entry to |histogram_map_| when called for the first time for
   // each |task_switch_source| value.
   void OnTaskSwitch(TaskSwitchSource task_switch_source);
 
  private:
+  // Internal implementation of OnTaskSwitch(TaskSwitchSource) that will accept
+  // the TaskSwitchSource::kAny value.
+  void OnTaskSwitchInternal(TaskSwitchSource task_switch_source);
+
   // Returns the TaskSwitchTimeTracker associated with the specified
   // |task_switch_source|. May return nullptr if mapping does not exist yet.
   TaskSwitchTimeTracker* FindTaskSwitchTimeTracker(
diff --git a/ash/metrics/task_switch_metrics_recorder_unittest.cc b/ash/metrics/task_switch_metrics_recorder_unittest.cc
index 90a0db1..5c2ef7b 100644
--- a/ash/metrics/task_switch_metrics_recorder_unittest.cc
+++ b/ash/metrics/task_switch_metrics_recorder_unittest.cc
@@ -62,6 +62,31 @@
 
 }  // namespace
 
+// Verifies that task switches from a non kAny source also add data to the
+// Ash.TimeBetweenTaskSwitches histogram.
+TEST_F(TaskSwitchMetricsRecorderTest,
+       VerifyTaskSwitchesRecordInAllTaskSwitchHistogram) {
+  const std::string kHistogramName = "Ash.TimeBetweenTaskSwitches";
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kShelf);
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kShelf);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 1);
+}
+
+// Verifies that the TaskSwitchMetricsRecorder::kDesktop source adds data to the
+// Ash.Desktop.TimeBetweenNavigateToTaskSwitches histogram.
+TEST_F(TaskSwitchMetricsRecorderTest, VerifyTaskSwitchesForDesktopAreRecorded) {
+  const std::string kHistogramName =
+      "Ash.Desktop.TimeBetweenNavigateToTaskSwitches";
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kDesktop);
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kDesktop);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 1);
+
+  OnTaskSwitch(TaskSwitchMetricsRecorder::kDesktop);
+  histogram_tester_->ExpectTotalCount(kHistogramName, 2);
+}
+
 // Verifies that the TaskSwitchMetricsRecorder::kWindowCycleController source
 // adds data to the Ash.WindowCycleController.TimeBetweenTaskSwitches histogram.
 TEST_F(TaskSwitchMetricsRecorderTest,
diff --git a/ash/metrics/user_metrics_recorder.cc b/ash/metrics/user_metrics_recorder.cc
index cfc4d8e..213cdae 100644
--- a/ash/metrics/user_metrics_recorder.cc
+++ b/ash/metrics/user_metrics_recorder.cc
@@ -4,6 +4,7 @@
 
 #include "ash/metrics/user_metrics_recorder.h"
 
+#include "ash/metrics/desktop_task_switch_metric_recorder.h"
 #include "ash/session/session_state_delegate.h"
 #include "ash/shelf/shelf_delegate.h"
 #include "ash/shelf/shelf_item_types.h"
@@ -236,6 +237,11 @@
     case ash::UMA_CLOSE_THROUGH_CONTEXT_MENU:
       base::RecordAction(base::UserMetricsAction("CloseFromContextMenu"));
       break;
+    case ash::UMA_DESKTOP_SWITCH_TASK:
+      base::RecordAction(base::UserMetricsAction("Desktop_SwitchTask"));
+      task_switch_metrics_recorder_.OnTaskSwitch(
+          TaskSwitchMetricsRecorder::kDesktop);
+      break;
     case ash::UMA_DRAG_MAXIMIZE_LEFT:
       base::RecordAction(base::UserMetricsAction("WindowDrag_MaximizeLeft"));
       break;
@@ -358,6 +364,9 @@
       base::RecordAction(
           base::UserMetricsAction("StatusArea_CapsLock_Popup"));
       break;
+    case ash::UMA_STATUS_AREA_CAST_STOP_CAST:
+      base::RecordAction(base::UserMetricsAction("StatusArea_Cast_StopCast"));
+      break;
     case ash::UMA_STATUS_AREA_CONNECT_TO_CONFIGURED_NETWORK:
       base::RecordAction(
           base::UserMetricsAction("StatusArea_Network_ConnectConfigured"));
@@ -397,6 +406,10 @@
     case ash::UMA_STATUS_AREA_DETAILED_CAST_VIEW:
       base::RecordAction(base::UserMetricsAction("StatusArea_Cast_Detailed"));
       break;
+    case ash::UMA_STATUS_AREA_DETAILED_CAST_VIEW_LAUNCH_CAST:
+      base::RecordAction(
+          base::UserMetricsAction("StatusArea_Cast_Detailed_Launch_Cast"));
+      break;
     case ash::UMA_STATUS_AREA_DETAILED_DRIVE_VIEW:
       base::RecordAction(
           base::UserMetricsAction("StatusArea_Drive_Detailed"));
@@ -598,6 +611,19 @@
   }
 }
 
+void UserMetricsRecorder::OnShellInitialized() {
+  // Lazy creation of the DesktopTaskSwitchMetricRecorder because it accesses
+  // Shell::GetInstance() which is not available when |this| is instantiated.
+  if (!desktop_task_switch_metric_recorder_) {
+    desktop_task_switch_metric_recorder_.reset(
+        new DesktopTaskSwitchMetricRecorder());
+  }
+}
+
+void UserMetricsRecorder::OnShellShuttingDown() {
+  desktop_task_switch_metric_recorder_.reset();
+}
+
 void UserMetricsRecorder::RecordPeriodicMetrics() {
   ShelfLayoutManager* manager =
       ShelfLayoutManager::ForShelf(Shell::GetPrimaryRootWindow());
diff --git a/ash/metrics/user_metrics_recorder.h b/ash/metrics/user_metrics_recorder.h
index 7bb6f9d..fb6669d6 100644
--- a/ash/metrics/user_metrics_recorder.h
+++ b/ash/metrics/user_metrics_recorder.h
@@ -7,10 +7,13 @@
 
 #include "ash/ash_export.h"
 #include "ash/metrics/task_switch_metrics_recorder.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/timer/timer.h"
 
 namespace ash {
 
+class DesktopTaskSwitchMetricRecorder;
+
 namespace test {
 class UserMetricsRecorderTestAPI;
 }
@@ -27,6 +30,7 @@
   UMA_ACCEL_RESTART_POWER_BUTTON,
   UMA_ACCEL_SHUT_DOWN_POWER_BUTTON,
   UMA_CLOSE_THROUGH_CONTEXT_MENU,
+  UMA_DESKTOP_SWITCH_TASK,
   UMA_DRAG_MAXIMIZE_LEFT,
   UMA_DRAG_MAXIMIZE_RIGHT,
   UMA_GESTURE_OVERVIEW,
@@ -59,6 +63,7 @@
   UMA_STATUS_AREA_CAPS_LOCK_DISABLED_BY_CLICK,
   UMA_STATUS_AREA_CAPS_LOCK_ENABLED_BY_CLICK,
   UMA_STATUS_AREA_CAPS_LOCK_POPUP,
+  UMA_STATUS_AREA_CAST_STOP_CAST,
   UMA_STATUS_AREA_CONNECT_TO_CONFIGURED_NETWORK,
   UMA_STATUS_AREA_CONNECT_TO_UNCONFIGURED_NETWORK,
   UMA_STATUS_AREA_CONNECT_TO_VPN,
@@ -69,6 +74,7 @@
   UMA_STATUS_AREA_DETAILED_BLUETOOTH_VIEW,
   UMA_STATUS_AREA_DETAILED_BRIGHTNESS_VIEW,
   UMA_STATUS_AREA_DETAILED_CAST_VIEW,
+  UMA_STATUS_AREA_DETAILED_CAST_VIEW_LAUNCH_CAST,
   UMA_STATUS_AREA_DETAILED_DRIVE_VIEW,
   UMA_STATUS_AREA_DETAILED_NETWORK_VIEW,
   UMA_STATUS_AREA_DETAILED_VPN_VIEW,
@@ -153,6 +159,12 @@
     return task_switch_metrics_recorder_;
   }
 
+  // Informs |this| that the Shell has been initialized.
+  void OnShellInitialized();
+
+  // Informs |this| that the Shell is going to be shut down.
+  void OnShellShuttingDown();
+
  private:
   friend class test::UserMetricsRecorderTestAPI;
 
@@ -179,6 +191,11 @@
 
   TaskSwitchMetricsRecorder task_switch_metrics_recorder_;
 
+  // Metric recorder to track how often task windows are activated by mouse
+  // clicks or touchscreen taps.
+  scoped_ptr<DesktopTaskSwitchMetricRecorder>
+      desktop_task_switch_metric_recorder_;
+
   DISALLOW_COPY_AND_ASSIGN(UserMetricsRecorder);
 };
 
diff --git a/ash/shell.cc b/ash/shell.cc
index 8393cda6..7e55fe8 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -108,7 +108,6 @@
 #include "ui/wm/core/accelerator_filter.h"
 #include "ui/wm/core/compound_event_filter.h"
 #include "ui/wm/core/focus_controller.h"
-#include "ui/wm/core/input_method_event_filter.h"
 #include "ui/wm/core/nested_accelerator_controller.h"
 #include "ui/wm/core/shadow_controller.h"
 #include "ui/wm/core/visibility_controller.h"
@@ -660,6 +659,8 @@
 Shell::~Shell() {
   TRACE_EVENT0("shutdown", "ash::Shell::Destructor");
 
+  user_metrics_recorder_->OnShellShuttingDown();
+
   delegate_->PreShutdown();
 
   views::FocusManagerFactory::Install(NULL);
@@ -680,7 +681,6 @@
   speech_feedback_handler_.reset();
 #endif
   RemovePreTargetHandler(overlay_filter_.get());
-  RemovePreTargetHandler(input_method_filter_.get());
   RemovePreTargetHandler(accelerator_filter_.get());
   RemovePreTargetHandler(event_transformation_handler_.get());
   RemovePreTargetHandler(toplevel_window_event_handler_.get());
@@ -809,7 +809,7 @@
   new_window_delegate_.reset();
   media_delegate_.reset();
 
-  keyboard::KeyboardController::ResetInstance(NULL);
+  keyboard::KeyboardController::ResetInstance(nullptr);
 
 #if defined(OS_CHROMEOS)
   display_color_manager_.reset();
@@ -935,10 +935,6 @@
   AddPreTargetHandler(overlay_filter_.get());
   AddShellObserver(overlay_filter_.get());
 
-  input_method_filter_.reset(new ::wm::InputMethodEventFilter(
-      root_window->GetHost()->GetAcceleratedWidget()));
-  AddPreTargetHandler(input_method_filter_.get());
-
   accelerator_filter_.reset(new ::wm::AcceleratorFilter(
       scoped_ptr< ::wm::AcceleratorDelegate>(new AcceleratorDelegate).Pass(),
       accelerator_controller_->accelerator_history()));
@@ -1085,6 +1081,8 @@
   // order to create mirror window. Run it after the main message loop
   // is started.
   display_manager_->CreateMirrorWindowAsyncIfAny();
+
+  user_metrics_recorder_->OnShellInitialized();
 }
 
 void Shell::InitKeyboard() {
@@ -1110,7 +1108,6 @@
   DCHECK(drag_drop_controller_.get());
 
   aura::client::SetFocusClient(root_window, focus_client_.get());
-  input_method_filter_->SetInputMethodPropertyInRootWindow(root_window);
   aura::client::SetActivationClient(root_window, activation_client_);
   ::wm::FocusController* focus_controller =
       static_cast< ::wm::FocusController*>(activation_client_);
diff --git a/ash/shell.h b/ash/shell.h
index bba346ba..db196e6 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -65,7 +65,6 @@
 namespace wm {
 class AcceleratorFilter;
 class CompoundEventFilter;
-class InputMethodEventFilter;
 class NestedAcceleratorController;
 class ShadowController;
 class VisibilityController;
@@ -346,9 +345,6 @@
   }
 
   DisplayManager* display_manager() { return display_manager_.get(); }
-  ::wm::InputMethodEventFilter* input_method_filter() {
-    return input_method_filter_.get();
-  }
   ::wm::CompoundEventFilter* env_filter() {
     return env_filter_.get();
   }
@@ -706,9 +702,6 @@
   // An event filter that pre-handles global accelerators.
   scoped_ptr< ::wm::AcceleratorFilter> accelerator_filter_;
 
-  // An event filter that pre-handles all key events to send them to an IME.
-  scoped_ptr< ::wm::InputMethodEventFilter> input_method_filter_;
-
   scoped_ptr<DisplayManager> display_manager_;
 
   scoped_ptr<LocaleNotificationController> locale_notification_controller_;
diff --git a/ash/shell/content_client/shell_browser_main_parts.cc b/ash/shell/content_client/shell_browser_main_parts.cc
index a7a7c57..1845c76 100644
--- a/ash/shell/content_client/shell_browser_main_parts.cc
+++ b/ash/shell/content_client/shell_browser_main_parts.cc
@@ -108,8 +108,8 @@
       false, net_log_.get()));
 
   // A ViewsDelegate is required.
-  if (!views::ViewsDelegate::views_delegate)
-    views::ViewsDelegate::views_delegate = new ShellViewsDelegate;
+  if (!views::ViewsDelegate::GetInstance())
+    views_delegate_.reset(new ShellViewsDelegate);
 
   delegate_ = new ash::shell::ShellDelegateImpl;
   // The global message center state must be initialized absent
@@ -159,6 +159,8 @@
 
   aura::Env::DeleteInstance();
 
+  views_delegate_.reset();
+
   // The keyboard may have created a WebContents. The WebContents is destroyed
   // with the UI, and it needs the BrowserContext to be alive during its
   // destruction. So destroy all of the UI elements before destroying the
diff --git a/ash/shell/content_client/shell_browser_main_parts.h b/ash/shell/content_client/shell_browser_main_parts.h
index 8968431..539354e 100644
--- a/ash/shell/content_client/shell_browser_main_parts.h
+++ b/ash/shell/content_client/shell_browser_main_parts.h
@@ -22,6 +22,10 @@
 class NetLog;
 }
 
+namespace views {
+class ViewsDelegate;
+}
+
 namespace wm {
 class WMState;
 }
@@ -53,6 +57,7 @@
  private:
   scoped_ptr<net::NetLog> net_log_;
   scoped_ptr<content::ShellBrowserContext> browser_context_;
+  scoped_ptr<views::ViewsDelegate> views_delegate_;
   scoped_ptr<ash::shell::WindowWatcher> window_watcher_;
   ShellDelegateImpl* delegate_;  // owned by Shell
   scoped_ptr<wm::WMState> wm_state_;
diff --git a/ash/shell/keyboard_controller_proxy_stub.cc b/ash/shell/keyboard_controller_proxy_stub.cc
index 220d69e6..f1e9fed 100644
--- a/ash/shell/keyboard_controller_proxy_stub.cc
+++ b/ash/shell/keyboard_controller_proxy_stub.cc
@@ -6,9 +6,10 @@
 
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
+#include "ash/wm/window_util.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
 #include "ui/base/ime/mock_input_method.h"
-#include "ui/wm/core/input_method_event_filter.h"
 
 using namespace content;
 
@@ -36,7 +37,10 @@
 }
 
 ui::InputMethod* KeyboardControllerProxyStub::GetInputMethod() {
-  return Shell::GetInstance()->input_method_filter()->input_method();
+  aura::Window* active_window = wm::GetActiveWindow();
+  aura::Window* root_window = active_window ? active_window->GetRootWindow()
+                                            : Shell::GetPrimaryRootWindow();
+  return root_window->GetHost()->GetInputMethod();
 }
 
 void KeyboardControllerProxyStub::RequestAudioInput(
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index ce07345..4cd2172 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -24,7 +24,6 @@
 #include "components/user_manager/user_info_impl.h"
 #include "ui/app_list/app_list_view_delegate.h"
 #include "ui/aura/window.h"
-#include "ui/wm/core/input_method_event_filter.h"
 
 namespace ash {
 namespace shell {
diff --git a/ash/system/cast/tray_cast.cc b/ash/system/cast/tray_cast.cc
index 7d5dd57..46201db 100644
--- a/ash/system/cast/tray_cast.cc
+++ b/ash/system/cast/tray_cast.cc
@@ -60,6 +60,7 @@
       const CastConfigDelegate::ReceiversAndActivites& receivers_activities);
 
   CastConfigDelegate* cast_config_delegate_;
+  base::WeakPtrFactory<CastSelectDefaultView> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(CastSelectDefaultView);
 };
 
@@ -68,7 +69,8 @@
     CastConfigDelegate* cast_config_delegate,
     bool show_more)
     : TrayItemMore(owner, show_more),
-      cast_config_delegate_(cast_config_delegate) {
+      cast_config_delegate_(cast_config_delegate),
+      weak_ptr_factory_(this) {
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   SetImage(rb.GetImageNamed(IDR_AURA_UBER_TRAY_CAST).ToImageSkia());
 
@@ -99,8 +101,9 @@
       cast_config_delegate_->HasCastExtension() == false)
     return;
 
-  cast_config_delegate_->GetReceiversAndActivities(base::Bind(
-      &CastSelectDefaultView::UpdateLabelCallback, base::Unretained(this)));
+  cast_config_delegate_->GetReceiversAndActivities(
+      base::Bind(&CastSelectDefaultView::UpdateLabelCallback,
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
 // This view is displayed when the screen is actively being casted; it allows
@@ -120,22 +123,23 @@
       const CastConfigDelegate::ReceiversAndActivites& receivers_activities);
 
   // Overridden from views::View.
+  int GetHeightForWidth(int width) const override;
   void Layout() override;
-  // Overridden from views::ButtonListener
+
+  // Overridden from views::ButtonListener.
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
   CastConfigDelegate* cast_config_delegate_;
   views::ImageView* icon_;
-  views::View* label_container_;
-  views::Label* title_;
-  views::Label* details_;
+  views::Label* label_;
   TrayPopupLabelButton* stop_button_;
+  base::WeakPtrFactory<CastCastView> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CastCastView);
 };
 
 CastCastView::CastCastView(CastConfigDelegate* cast_config_delegate)
-    : cast_config_delegate_(cast_config_delegate) {
+    : cast_config_delegate_(cast_config_delegate), weak_ptr_factory_(this) {
   // We will initialize the primary tray view which shows a stop button here.
 
   set_background(views::Background::CreateSolidBackground(kBackgroundColor));
@@ -148,29 +152,14 @@
       bundle.GetImageNamed(IDR_AURA_UBER_TRAY_CAST_ENABLED).ToImageSkia());
   AddChildView(icon_);
 
-  // The view has two labels, one above the other. The top label (|title_|)
-  // specifies that we are, say, "Casting desktop". The bottom label
-  // (|details_|) specifies where we are casting to, ie, "SomeRandom cast"
-  label_container_ = new views::View;
-  label_container_->SetLayoutManager(
-      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
-
-  title_ = new views::Label;
-  title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  title_->SetFontList(bundle.GetFontList(ui::ResourceBundle::BoldFont));
-  title_->SetText(
-      bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_CAST_UNKNOWN_CAST_TYPE));
-  label_container_->AddChildView(title_);
-
-  details_ = new views::Label;
-  details_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  details_->SetMultiLine(false);
-  details_->SetEnabledColor(kHeaderTextColorNormal);
-  details_->SetText(
-      bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_CAST_UNKNOWN_RECEIVER));
-  label_container_->AddChildView(details_);
-
-  AddChildView(label_container_);
+  // The label which describes both what we are casting (ie, the desktop) and
+  // where we are casting it to.
+  label_ = new views::Label;
+  label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  label_->SetMultiLine(true);
+  label_->SetText(
+      bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_CAST_CAST_UNKNOWN));
+  AddChildView(label_);
 
   // Add the stop bottom on the far-right. We customize how this stop button is
   // displayed inside of |Layout()|.
@@ -186,6 +175,18 @@
 CastCastView::~CastCastView() {
 }
 
+int CastCastView::GetHeightForWidth(int width) const {
+  // We are reusing the cached label_->bounds() calculation which was
+  // done inside of Layout(). Due to the way this object is initialized,
+  // Layout() will always get initially invoked with the dummy text
+  // (which will compute the proper label width) and then when we know
+  // the cast receiver we will update the label text, which will cause
+  // this method to get invoked.
+  return std::max(views::View::GetHeightForWidth(width),
+                  GetInsets().height() +
+                      label_->GetHeightForWidth(label_->bounds().width()));
+}
+
 void CastCastView::Layout() {
   views::View::Layout();
 
@@ -197,18 +198,12 @@
   stop_button_->SetBoundsRect(stop_bounds);
 
   // Adjust the label's bounds in case it got cut off by |stop_button_|.
-  if (label_container_->bounds().Intersects(stop_button_->bounds())) {
-    gfx::Rect label_bounds = label_container_->bounds();
+  if (label_->bounds().Intersects(stop_button_->bounds())) {
+    gfx::Rect label_bounds = label_->bounds();
     label_bounds.set_width(stop_button_->x() - kTrayPopupPaddingBetweenItems -
-                           label_container_->x());
-    label_container_->SetBoundsRect(label_bounds);
+                           label_->x());
+    label_->SetBoundsRect(label_bounds);
   }
-
-  // Center the label.
-  // TODO(jdufault): Why doesn't this happen automatically?
-  const int extra_height =
-      height() - label_container_->GetPreferredSize().height();
-  label_container_->SetY(extra_height / 2);
 }
 
 void CastCastView::UpdateLabel() {
@@ -216,8 +211,8 @@
       cast_config_delegate_->HasCastExtension() == false)
     return;
 
-  cast_config_delegate_->GetReceiversAndActivities(
-      base::Bind(&CastCastView::UpdateLabelCallback, base::Unretained(this)));
+  cast_config_delegate_->GetReceiversAndActivities(base::Bind(
+      &CastCastView::UpdateLabelCallback, weak_ptr_factory_.GetWeakPtr()));
 }
 
 void CastCastView::UpdateLabelCallback(
@@ -230,17 +225,17 @@
       // what we are actually casting - either the desktop, a tab, or a fallback
       // that catches everything else (ie, an extension tab).
       if (activity.tab_id == CastConfigDelegate::Activity::TabId::DESKTOP) {
-        title_->SetText(
-            l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_CAST_DESKTOP));
+        label_->SetText(l10n_util::GetStringFUTF16(
+            IDS_ASH_STATUS_TRAY_CAST_CAST_DESKTOP, receiver.name));
       } else if (activity.tab_id >= 0) {
-        title_->SetText(l10n_util::GetStringFUTF16(
-            IDS_ASH_STATUS_TRAY_CAST_CAST_TAB, activity.title));
+        label_->SetText(l10n_util::GetStringFUTF16(
+            IDS_ASH_STATUS_TRAY_CAST_CAST_TAB, activity.title, receiver.name));
       } else {
-        // We will fallback to whatever the extension provides us
-        title_->SetText(activity.title);
+        label_->SetText(
+            l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_CAST_UNKNOWN));
       }
 
-      details_->SetText(receiver.name);
+      PreferredSizeChanged();
       Layout();
       break;
     }
@@ -251,6 +246,8 @@
                                  const ui::Event& event) {
   DCHECK(sender == stop_button_);
   cast_config_delegate_->StopCasting();
+  Shell::GetInstance()->metrics()->RecordUserMetricsAction(
+      ash::UMA_STATUS_AREA_CAST_STOP_CAST);
 }
 
 // This view by itself does very little. It acts as a front-end for managing
@@ -272,6 +269,7 @@
 
  private:
   // Overridden from views::View.
+  void ChildPreferredSizeChanged(views::View* child) override;
   void Layout() override;
 
   // Only one of |select_view_| or |cast_view_| will be displayed at any given
@@ -318,6 +316,10 @@
   InvalidateLayout();
 }
 
+void CastDuplexView::ChildPreferredSizeChanged(views::View* child) {
+  PreferredSizeChanged();
+}
+
 void CastDuplexView::Layout() {
   views::View::Layout();
 
@@ -405,10 +407,11 @@
 
   CastConfigDelegate* cast_config_delegate_;
   user::LoginStatus login_;
-  views::View* options_;
+  views::View* options_ = nullptr;
   CastConfigDelegate::ReceiversAndActivites receivers_and_activities_;
   // A mapping from the view pointer to the associated activity id
   std::map<views::View*, std::string> receiver_activity_map_;
+  base::WeakPtrFactory<CastDetailedView> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CastDetailedView);
 };
@@ -419,7 +422,7 @@
     : TrayDetailsView(owner),
       cast_config_delegate_(cast_config_delegate),
       login_(login),
-      options_(nullptr) {
+      weak_ptr_factory_(this) {
   CreateItems();
   UpdateReceiverList();
 }
@@ -434,8 +437,9 @@
 }
 
 void CastDetailedView::UpdateReceiverList() {
-  cast_config_delegate_->GetReceiversAndActivities(base::Bind(
-      &CastDetailedView::UpdateReceiverListCallback, base::Unretained(this)));
+  cast_config_delegate_->GetReceiversAndActivities(
+      base::Bind(&CastDetailedView::UpdateReceiverListCallback,
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
 void CastDetailedView::UpdateReceiverListCallback(
@@ -523,6 +527,8 @@
     auto it = receiver_activity_map_.find(sender);
     if (it != receiver_activity_map_.end()) {
       cast_config_delegate_->CastToReceiver(it->second);
+      Shell::GetInstance()->metrics()->RecordUserMetricsAction(
+          ash::UMA_STATUS_AREA_DETAILED_CAST_VIEW_LAUNCH_CAST);
     }
   }
 }
diff --git a/ash/test/shell_test_api.cc b/ash/test/shell_test_api.cc
index c24fa17..b85bcab9 100644
--- a/ash/test/shell_test_api.cc
+++ b/ash/test/shell_test_api.cc
@@ -23,11 +23,6 @@
   return shell_->GetPrimaryRootWindowController()->root_window_layout();
 }
 
-wm::InputMethodEventFilter*
-ShellTestApi::input_method_event_filter() {
-  return shell_->input_method_filter_.get();
-}
-
 SystemGestureEventFilter* ShellTestApi::system_gesture_event_filter() {
   return shell_->system_gesture_filter_.get();
 }
diff --git a/ash/test/shell_test_api.h b/ash/test/shell_test_api.h
index 16cc576..5afd594d 100644
--- a/ash/test/shell_test_api.h
+++ b/ash/test/shell_test_api.h
@@ -7,10 +7,6 @@
 
 #include "base/basictypes.h"
 
-namespace wm {
-class InputMethodEventFilter;
-}  // namespace wm
-
 namespace ash {
 class AppListController;
 class AshNativeCursorManager;
@@ -33,7 +29,6 @@
   explicit ShellTestApi(Shell* shell);
 
   RootWindowLayoutManager* root_window_layout();
-  ::wm::InputMethodEventFilter* input_method_event_filter();
   SystemGestureEventFilter* system_gesture_event_filter();
   WorkspaceController* workspace_controller();
   ScreenPositionController* screen_position_controller();
diff --git a/ash/utility/partial_screenshot_controller.cc b/ash/utility/partial_screenshot_controller.cc
index 18f8e4e..602fde4 100644
--- a/ash/utility/partial_screenshot_controller.cc
+++ b/ash/utility/partial_screenshot_controller.cc
@@ -12,6 +12,7 @@
 #include "ash/shell_window_ids.h"
 #include "base/stl_util.h"
 #include "ui/compositor/paint_recorder.h"
+#include "ui/events/event.h"
 #include "ui/events/event_handler.h"
 #include "ui/gfx/canvas.h"
 #include "ui/wm/core/cursor_manager.h"
diff --git a/ash/wm/cursor_manager_chromeos.cc b/ash/wm/cursor_manager_chromeos.cc
index af38d5c4..3a1162f 100644
--- a/ash/wm/cursor_manager_chromeos.cc
+++ b/ash/wm/cursor_manager_chromeos.cc
@@ -5,6 +5,7 @@
 #include "ash/wm/cursor_manager_chromeos.h"
 
 #include "base/logging.h"
+#include "ui/events/event.h"
 #include "ui/keyboard/keyboard_util.h"
 #include "ui/wm/core/cursor_manager.h"
 #include "ui/wm/core/native_cursor_manager.h"
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc
index 4448812..9a9d520 100644
--- a/ash/wm/lock_state_controller.cc
+++ b/ash/wm/lock_state_controller.cc
@@ -493,9 +493,9 @@
   // Increase lock timeout for slower hardware, see http://crbug.com/350628
   const std::string board = base::SysInfo::GetLsbReleaseBoard();
   if (board == "x86-mario" ||
-      StartsWithASCII(board, "x86-alex", true /* case_sensitive */) ||
-      StartsWithASCII(board, "x86-zgb", true /* case_sensitive */) ||
-      StartsWithASCII(board, "daisy", true /* case_sensitive */)) {
+      base::StartsWithASCII(board, "x86-alex", true /* case_sensitive */) ||
+      base::StartsWithASCII(board, "x86-zgb", true /* case_sensitive */) ||
+      base::StartsWithASCII(board, "daisy", true /* case_sensitive */)) {
     timeout *= 2;
   }
 // Times out on ASAN bots.
diff --git a/ash/wm/overlay_event_filter.cc b/ash/wm/overlay_event_filter.cc
index b349bf9..a728b9e 100644
--- a/ash/wm/overlay_event_filter.cc
+++ b/ash/wm/overlay_event_filter.cc
@@ -23,13 +23,6 @@
   if (!delegate_)
     return;
 
-  // Do not consume a translated key event which is generated by an IME (e.g.,
-  // ui::VKEY_PROCESSKEY) since the key event is generated in response to a key
-  // press or release before showing the ovelay. This is important not to
-  // confuse key event handling JavaScript code in a page.
-  if (event->IsTranslated())
-    return;
-
   if (delegate_ && delegate_->IsCancelingKeyEvent(event))
     Cancel();
 
diff --git a/ash/wm/power_button_controller.cc b/ash/wm/power_button_controller.cc
index 5899b8a..509239d 100644
--- a/ash/wm/power_button_controller.cc
+++ b/ash/wm/power_button_controller.cc
@@ -134,10 +134,8 @@
 }
 
 void PowerButtonController::OnKeyEvent(ui::KeyEvent* event) {
-  if (event->key_code() == ui::VKEY_VOLUME_DOWN) {
-    volume_down_pressed_ = event->type() == ui::ET_KEY_PRESSED ||
-                           event->type() == ui::ET_TRANSLATED_KEY_PRESS;
-  }
+  if (event->key_code() == ui::VKEY_VOLUME_DOWN)
+    volume_down_pressed_ = event->type() == ui::ET_KEY_PRESSED;
 }
 
 #if defined(OS_CHROMEOS)
diff --git a/ash/wm/resize_handle_window_targeter.cc b/ash/wm/resize_handle_window_targeter.cc
index 28bd0e2..8ee6924c 100644
--- a/ash/wm/resize_handle_window_targeter.cc
+++ b/ash/wm/resize_handle_window_targeter.cc
@@ -8,6 +8,7 @@
 #include "ash/wm/immersive_fullscreen_controller.h"
 #include "ash/wm/window_state.h"
 #include "ui/aura/window.h"
+#include "ui/events/event.h"
 
 namespace ash {
 
@@ -48,10 +49,9 @@
   window_ = NULL;
 }
 
-ui::EventTarget* ResizeHandleWindowTargeter::FindTargetForLocatedEvent(
-    ui::EventTarget* root,
+aura::Window* ResizeHandleWindowTargeter::FindTargetForLocatedEvent(
+    aura::Window* window,
     ui::LocatedEvent* event) {
-  aura::Window* window = static_cast<aura::Window*>(root);
   if (window == window_) {
     gfx::Insets insets;
     if (immersive_controller_ && immersive_controller_->IsEnabled() &&
@@ -77,23 +77,25 @@
         return window_;
     }
   }
-  return aura::WindowTargeter::FindTargetForLocatedEvent(root, event);
+  return aura::WindowTargeter::FindTargetForLocatedEvent(window, event);
 }
 
 bool ResizeHandleWindowTargeter::SubtreeShouldBeExploredForEvent(
-    ui::EventTarget* target,
+    aura::Window* window,
     const ui::LocatedEvent& event) {
-  if (target == window_) {
+  if (window == window_) {
     // Defer to the parent's targeter on whether |window_| should be able to
     // receive the event.
-    ui::EventTarget* parent = target->GetParentTarget();
+    ui::EventTarget* parent =
+        static_cast<ui::EventTarget*>(window)->GetParentTarget();
     if (parent) {
-      ui::EventTargeter* targeter = parent->GetEventTargeter();
+      aura::WindowTargeter* targeter =
+          static_cast<aura::WindowTargeter*>(parent->GetEventTargeter());
       if (targeter)
-        return targeter->SubtreeShouldBeExploredForEvent(target, event);
+        return targeter->SubtreeShouldBeExploredForEvent(window, event);
     }
   }
-  return aura::WindowTargeter::SubtreeShouldBeExploredForEvent(target, event);
+  return aura::WindowTargeter::SubtreeShouldBeExploredForEvent(window, event);
 }
 
 }  // namespace ash
diff --git a/ash/wm/resize_handle_window_targeter.h b/ash/wm/resize_handle_window_targeter.h
index c6b789e..24c2e32e 100644
--- a/ash/wm/resize_handle_window_targeter.h
+++ b/ash/wm/resize_handle_window_targeter.h
@@ -35,9 +35,9 @@
   void OnWindowDestroying(aura::Window* window) override;
 
   // aura::WindowTargeter:
-  ui::EventTarget* FindTargetForLocatedEvent(ui::EventTarget* root,
-                                             ui::LocatedEvent* event) override;
-  bool SubtreeShouldBeExploredForEvent(ui::EventTarget* target,
+  aura::Window* FindTargetForLocatedEvent(aura::Window* window,
+                                          ui::LocatedEvent* event) override;
+  bool SubtreeShouldBeExploredForEvent(aura::Window* window,
                                        const ui::LocatedEvent& event) override;
 
   // The targeter does not take ownership of |window_| or
diff --git a/ash/wm/window_manager_unittest.cc b/ash/wm/window_manager_unittest.cc
index 4c0552d..bccc084 100644
--- a/ash/wm/window_manager_unittest.cc
+++ b/ash/wm/window_manager_unittest.cc
@@ -5,7 +5,6 @@
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
 #include "ash/test/test_activation_delegate.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/client/cursor_client_observer.h"
@@ -23,7 +22,6 @@
 #include "ui/events/test/test_event_handler.h"
 #include "ui/gfx/screen.h"
 #include "ui/wm/core/compound_event_filter.h"
-#include "ui/wm/core/input_method_event_filter.h"
 #include "ui/wm/public/activation_client.h"
 #include "ui/wm/public/activation_delegate.h"
 
@@ -134,12 +132,6 @@
 };
 
 TEST_F(WindowManagerTest, Focus) {
-  // The IME event filter interferes with the basic key event propagation we
-  // attempt to do here, so we remove it.
-  test::ShellTestApi shell_test(Shell::GetInstance());
-  Shell::GetInstance()->RemovePreTargetHandler(
-      shell_test.input_method_event_filter());
-
   aura::Window* root_window = Shell::GetPrimaryRootWindow();
   root_window->SetBounds(gfx::Rect(0, 0, 510, 510));
 
@@ -651,12 +643,6 @@
 }
 
 TEST_F(WindowManagerTest, AdditionalFilters) {
-  // The IME event filter interferes with the basic key event propagation we
-  // attempt to do here, so we remove it.
-  test::ShellTestApi shell_test(Shell::GetInstance());
-  Shell::GetInstance()->RemovePreTargetHandler(
-      shell_test.input_method_event_filter());
-
   aura::Window* root_window = Shell::GetPrimaryRootWindow();
 
   // Creates a window and make it active
diff --git a/ash/wm/window_modality_controller_unittest.cc b/ash/wm/window_modality_controller_unittest.cc
index 765d12d7..977e70c 100644
--- a/ash/wm/window_modality_controller_unittest.cc
+++ b/ash/wm/window_modality_controller_unittest.cc
@@ -184,9 +184,15 @@
       gfx::Rect(0, 0, 100, 100)));
   scoped_ptr<aura::Window> w11(CreateTestWindowInShellWithDelegate(&d, -11,
       gfx::Rect(20, 20, 50, 50)));
+  scoped_ptr<aura::Window> w111(
+      CreateTestWindowInShellWithDelegate(&d, -111, gfx::Rect(20, 20, 50, 50)));
 
   ::wm::AddTransientChild(w1.get(), w11.get());
 
+  // Add a non-modal child to the modal window in order to ensure modality still
+  // works in this case. This is a regression test for https://crbug.com/456697.
+  ::wm::AddTransientChild(w11.get(), w111.get());
+
   {
     // Clicking a point within w1 should activate that window.
     ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index 6db10ec..89c26af 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -134,8 +134,7 @@
 
 void WorkspaceLayoutManager::OnKeyboardBoundsChanging(
     const gfx::Rect& new_bounds) {
-  ui::InputMethod* input_method =
-      root_window_->GetProperty(aura::client::kRootWindowInputMethodKey);
+  ui::InputMethod* input_method = root_window_->GetHost()->GetInputMethod();
   ui::TextInputClient* text_input_client = input_method->GetTextInputClient();
   if (!text_input_client)
     return;
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 7e2fe9b..84a2251 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -1020,8 +1020,7 @@
     } else {
       aura::Window* root_window =
           ash::Shell::GetInstance()->GetPrimaryRootWindow();
-      ui::InputMethod* input_method =
-          root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
+      ui::InputMethod* input_method = root_window->GetHost()->GetInputMethod();
       input_method->SetFocusedTextInputClient(text_input_client);
     }
   }
@@ -1033,8 +1032,7 @@
     } else {
       aura::Window* root_window =
           ash::Shell::GetInstance()->GetPrimaryRootWindow();
-      ui::InputMethod* input_method =
-          root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
+      ui::InputMethod* input_method = root_window->GetHost()->GetInputMethod();
       input_method->SetFocusedTextInputClient(NULL);
     }
   }
diff --git a/base/BUILD.gn b/base/BUILD.gn
index ed510865..8a32ed63 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -177,6 +177,7 @@
     "containers/linked_list.h",
     "containers/mru_cache.h",
     "containers/scoped_ptr_hash_map.h",
+    "containers/scoped_ptr_map.h",
     "containers/small_map.h",
     "containers/stack_container.h",
     "cpu.cc",
@@ -371,6 +372,8 @@
     "posix/file_descriptor_shuffle.cc",
     "posix/global_descriptors.cc",
     "posix/global_descriptors.h",
+    "posix/safe_strerror.cc",
+    "posix/safe_strerror.h",
     "posix/unix_domain_socket_linux.cc",
     "posix/unix_domain_socket_linux.h",
     "power_monitor/power_monitor.cc",
@@ -408,8 +411,6 @@
     "rand_util_win.cc",
     "run_loop.cc",
     "run_loop.h",
-    "safe_strerror_posix.cc",
-    "safe_strerror_posix.h",
     "scoped_generic.h",
     "scoped_native_library.cc",
     "scoped_native_library.h",
@@ -1100,6 +1101,7 @@
     "containers/linked_list_unittest.cc",
     "containers/mru_cache_unittest.cc",
     "containers/scoped_ptr_hash_map_unittest.cc",
+    "containers/scoped_ptr_map_unittest.cc",
     "containers/small_map_unittest.cc",
     "containers/stack_container_unittest.cc",
     "cpu_unittest.cc",
diff --git a/base/android/build_info.h b/base/android/build_info.h
index d6155b9..093b832 100644
--- a/base/android/build_info.h
+++ b/base/android/build_info.h
@@ -23,7 +23,8 @@
   SDK_VERSION_JELLY_BEAN_MR2 = 18,
   SDK_VERSION_KITKAT = 19,
   SDK_VERSION_KITKAT_WEAR = 20,
-  SDK_VERSION_LOLLIPOP = 21
+  SDK_VERSION_LOLLIPOP = 21,
+  SDK_VERSION_LOLLIPOP_MR1 = 22
 };
 
 // BuildInfo is a singleton class that stores android build and device
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
index c87d02d..d7c7b05 100644
--- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
+++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
@@ -12,6 +12,7 @@
 import android.view.Window;
 
 import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 
@@ -60,7 +61,20 @@
                     && args[0] instanceof KeyEvent) {
                 return dispatchKeyEvent((KeyEvent) args[0]);
             } else {
-                return method.invoke(mCallback, args);
+                try {
+                    return method.invoke(mCallback, args);
+                } catch (InvocationTargetException e) {
+                    // Special-case for when a method is not defined on the underlying
+                    // Window.Callback object. Because we're using a Proxy to forward all method
+                    // calls, this breaks the Android framework's handling for apps built against
+                    // an older SDK. The framework expects an AbstractMethodError but due to
+                    // reflection it becomes wrapped inside an InvocationTargetException. Undo the
+                    // wrapping to signal the framework accordingly.
+                    if (e.getCause() instanceof AbstractMethodError) {
+                        throw e.getCause();
+                    }
+                    throw e;
+                }
             }
         }
 
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java
index b7fd774..55392302 100644
--- a/base/android/java/src/org/chromium/base/Log.java
+++ b/base/android/java/src/org/chromium/base/Log.java
@@ -23,8 +23,6 @@
  * </p>
  */
 public class Log {
-    private static final String BASE_TAG = "cr";
-
     /** Convenience property, same as {@link android.util.Log#ASSERT}. */
     public static final int ASSERT = android.util.Log.ASSERT;
 
@@ -72,10 +70,12 @@
      *
      * @see android.util.Log#isLoggable(String, int)
      * @throws IllegalArgumentException if the tag is too long.
+     * @deprecated Directly use a string (e.g. "cr.Tag") in your class. See http://crbug.com/485772
      */
+    @Deprecated
     public static String makeTag(String groupTag) {
-        if (TextUtils.isEmpty(groupTag)) return BASE_TAG;
-        String tag = BASE_TAG + "." + groupTag;
+        if (TextUtils.isEmpty(groupTag)) return "cr";
+        String tag = "cr." + groupTag;
         if (tag.length() > 23) {
             throw new IllegalArgumentException(
                     "The full tag (" + tag + ") is longer than 23 characters.");
@@ -95,16 +95,14 @@
      * than 7 parameters, consider building your log message using a function annotated with
      * {@link NoSideEffects}.
      *
-     * @param tag Used to identify the source of a log message. Should be created using
-     *            {@link #makeTag(String)}.
-     *
+     * @param tag Used to identify the source of a log message.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @param args Arguments referenced by the format specifiers in the format string. If the last
      *             one is a {@link Throwable}, its trace will be printed.
      */
     private static void verbose(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.VERBOSE)) {
+        if (Log.isLoggable(tag, Log.VERBOSE)) {
             String message = formatLogWithStack(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
@@ -167,16 +165,14 @@
      * than 7 parameters, consider building your log message using a function annotated with
      * {@link NoSideEffects}.
      *
-     * @param tag Used to identify the source of a log message. Should be created using
-     *            {@link #makeTag(String)}.
-     *
+     * @param tag Used to identify the source of a log message.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @param args Arguments referenced by the format specifiers in the format string. If the last
      *             one is a {@link Throwable}, its trace will be printed.
      */
     private static void debug(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.VERBOSE)) {
+        if (isLoggable(tag, Log.DEBUG)) {
             String message = formatLogWithStack(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
@@ -233,15 +229,14 @@
     /**
      * Sends an {@link android.util.Log#INFO} log message.
      *
-     * @param tag Used to identify the source of a log message. Should be created using
-     *            {@link #makeTag(String)}.
+     * @param tag Used to identify the source of a log message.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @param args Arguments referenced by the format specifiers in the format string. If the last
      *             one is a {@link Throwable}, its trace will be printed.
      */
     public static void i(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.INFO)) {
+        if (Log.isLoggable(tag, Log.INFO)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
@@ -255,15 +250,14 @@
     /**
      * Sends a {@link android.util.Log#WARN} log message.
      *
-     * @param tag Used to identify the source of a log message. Should be created using
-     *            {@link #makeTag(String)}.
+     * @param tag Used to identify the source of a log message.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @param args Arguments referenced by the format specifiers in the format string. If the last
      *             one is a {@link Throwable}, its trace will be printed.
      */
     public static void w(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.WARN)) {
+        if (Log.isLoggable(tag, Log.WARN)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
@@ -277,15 +271,14 @@
     /**
      * Sends an {@link android.util.Log#ERROR} log message.
      *
-     * @param tag Used to identify the source of a log message. Should be created using
-     *            {@link #makeTag(String)}.
+     * @param tag Used to identify the source of a log message.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @param args Arguments referenced by the format specifiers in the format string. If the last
      *             one is a {@link Throwable}, its trace will be printed.
      */
     public static void e(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.ERROR)) {
+        if (Log.isLoggable(tag, Log.ERROR)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
@@ -303,15 +296,14 @@
      *
      * @see android.util.Log#wtf(String, String, Throwable)
      *
-     * @param tag Used to identify the source of a log message. Should be created using
-     *            {@link #makeTag(String)}.
+     * @param tag Used to identify the source of a log message.
      * @param messageTemplate The message you would like logged. It is to be specified as a format
      *                        string.
      * @param args Arguments referenced by the format specifiers in the format string. If the last
      *             one is a {@link Throwable}, its trace will be printed.
      */
     public static void wtf(String tag, String messageTemplate, Object... args) {
-        if (android.util.Log.isLoggable(tag, android.util.Log.ERROR)) {
+        if (Log.isLoggable(tag, Log.ASSERT)) {
             String message = formatLog(messageTemplate, args);
             Throwable tr = getThrowableToLog(args);
             if (tr != null) {
diff --git a/base/android/java/src/org/chromium/base/MemoryPressureListener.java b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
index e7c2030a..7979287b 100644
--- a/base/android/java/src/org/chromium/base/MemoryPressureListener.java
+++ b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
@@ -72,10 +72,10 @@
         } else if (ACTION_TRIM_MEMORY.equals(action)) {
             simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
         } else if (ACTION_TRIM_MEMORY_RUNNING_CRITICAL.equals(action)) {
-            simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_MODERATE);
-        } else if (ACTION_TRIM_MEMORY_MODERATE.equals(action)) {
             simulateTrimMemoryPressureSignal(activity,
                     ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL);
+        } else if (ACTION_TRIM_MEMORY_MODERATE.equals(action)) {
+            simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_MODERATE);
         } else {
             return false;
         }
diff --git a/base/android/java/src/org/chromium/base/README_logging.md b/base/android/java/src/org/chromium/base/README_logging.md
index d7fbcb4..a680ce1b 100644
--- a/base/android/java/src/org/chromium/base/README_logging.md
+++ b/base/android/java/src/org/chromium/base/README_logging.md
@@ -9,7 +9,7 @@
 
 Usage:
 
-    private static final String TAG = Log.makeTag("YourModuleTag");
+    private static final String TAG = "cr.YourModuleTag";
     ...
     Log.i(TAG, "Logged INFO message.");
     Log.d(TAG, "Some DEBUG info: %s", data);
@@ -43,6 +43,20 @@
 Level here is either `VERBOSE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `ASSERT`, or `SUPPRESS`
 By default, the level for all tags is `INFO`.
 
+### An exception trace is printed when the exception is the last parameter ###
+
+As with `java.util.Log`, putting a throwable as last parameter will dump the corresponding stack
+trace:
+
+    Log.i(TAG, "An error happened: %s", e)
+
+    I/cr.YourModuleTag: ( 999): An error happened: This is the exception's message
+    I/cr.YourModuleTag: ( 999): java.lang.Exception: This is the exception's message
+    I/cr.YourModuleTag: ( 999):     at foo.bar.MyClass.test(MyClass.java:42)
+    I/cr.YourModuleTag: ( 999):     ...
+
+Having the exception as last parameter doesn't prevent it from being used for string formatting.
+
 ### Logging Best Practices
 
 #### Rule #1: Never log PII (Personal Identification Information):
diff --git a/base/android/junit/src/org/chromium/base/LogTest.java b/base/android/junit/src/org/chromium/base/LogTest.java
index 46bdc67..ac98001e 100644
--- a/base/android/junit/src/org/chromium/base/LogTest.java
+++ b/base/android/junit/src/org/chromium/base/LogTest.java
@@ -9,6 +9,7 @@
 import static org.junit.Assert.assertTrue;
 
 import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.annotation.Config;
@@ -88,12 +89,138 @@
         assertEquals("Bar MyThrowable MyOtherThrowable", logs.get(logs.size() - 1).msg);
     }
 
+    public void verboseLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.VERBOSE);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(Log.INFO, logs.get(3).type);
+        assertEquals(Log.DEBUG, logs.get(4).type);
+        assertEquals(Log.VERBOSE, logs.get(5).type);
+        assertEquals(6, logs.size());
+    }
+
+    @Test
+    public void debugLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.DEBUG);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(Log.INFO, logs.get(3).type);
+        assertEquals(Log.DEBUG, logs.get(4).type);
+        assertEquals(5, logs.size());
+    }
+
+    @Test
+    public void infoLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.INFO);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(Log.INFO, logs.get(3).type);
+        assertEquals(4, logs.size());
+    }
+
+    @Test
+    public void warnLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.WARN);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(3, logs.size());
+    }
+
+    @Test
+    public void errorLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.ERROR);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(2, logs.size());
+    }
+
+    @Test
+    public void assertLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.ASSERT);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(1, logs.size());
+    }
+
+    @Before
+    public void beforeTest() {
+        PermissiveShadowLog.reset();
+    }
+
     /** Needed to allow debug/verbose logging that is disabled by default. */
     @Implements(android.util.Log.class)
     public static class PermissiveShadowLog extends ShadowLog {
+        private static int sLevel = Log.VERBOSE;
+
+        /** Sets the log level for all tags. */
+        public static void setLevel(int level) {
+            sLevel = level;
+        }
+
         @Implementation
         public static boolean isLoggable(String tag, int level) {
-            return true;
+            return level >= sLevel;
+        }
+
+        public static void reset() {
+            sLevel = Log.VERBOSE;
         }
     }
 }
diff --git a/base/base.gyp b/base/base.gyp
index f724b32..ed8e29e 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -464,6 +464,7 @@
         'containers/linked_list_unittest.cc',
         'containers/mru_cache_unittest.cc',
         'containers/scoped_ptr_hash_map_unittest.cc',
+        'containers/scoped_ptr_map_unittest.cc',
         'containers/small_map_unittest.cc',
         'containers/stack_container_unittest.cc',
         'cpu_unittest.cc',
@@ -905,6 +906,8 @@
         'test/expectations/parser.h',
         'test/gtest_util.cc',
         'test/gtest_util.h',
+        'test/gtest_xml_unittest_result_printer.cc',
+        'test/gtest_xml_unittest_result_printer.h',
         'test/gtest_xml_util.cc',
         'test/gtest_xml_util.h',
         'test/histogram_tester.cc',
@@ -990,6 +993,8 @@
         'test/test_switches.h',
         'test/test_timeouts.cc',
         'test/test_timeouts.h',
+        'test/test_ui_thread_android.cc',
+        'test/test_ui_thread_android.h',
         'test/thread_test_helper.cc',
         'test/thread_test_helper.h',
         'test/trace_event_analyzer.cc',
@@ -1041,6 +1046,22 @@
         ],
       },
     },
+    {
+      'target_name': 'test_launcher_nacl_nonsfi',
+      'conditions': [
+        ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
+          'type': 'static_library',
+          'sources': [
+            'test/launcher/test_launcher_nacl_nonsfi.cc',
+          ],
+          'dependencies': [
+            'test_support_base',
+          ],
+        }, {
+          'type': 'none',
+        }],
+      ],
+    },
   ],
   'conditions': [
     ['OS=="ios" and "<(GENERATOR)"=="ninja"', {
@@ -1391,6 +1412,7 @@
           'type': 'none',
           'sources': [
             'test/android/java/src/org/chromium/base/ContentUriTestUtils.java',
+            'test/android/java/src/org/chromium/base/TestUiThread.java',
           ],
           'variables': {
             'jni_gen_package': 'base',
@@ -1617,13 +1639,6 @@
           'sources': [
             'base_unittests.isolate',
           ],
-          'conditions': [
-            ['use_x11 == 1', {
-              'dependencies': [
-                '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
-              ],
-            }],
-          ],
         },
       ],
     }],
diff --git a/base/base.gypi b/base/base.gypi
index 6e2944a..81a8c99d 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -138,6 +138,7 @@
           'containers/linked_list.h',
           'containers/mru_cache.h',
           'containers/scoped_ptr_hash_map.h',
+          'containers/scoped_ptr_map.h',
           'containers/small_map.h',
           'containers/stack_container.h',
           'cpu.cc',
@@ -436,6 +437,8 @@
           'posix/eintr_wrapper.h',
           'posix/global_descriptors.cc',
           'posix/global_descriptors.h',
+          'posix/safe_strerror.cc',
+          'posix/safe_strerror.h',
           'posix/unix_domain_socket_linux.cc',
           'posix/unix_domain_socket_linux.h',
           'power_monitor/power_monitor.cc',
@@ -522,8 +525,6 @@
           'rand_util_win.cc',
           'run_loop.cc',
           'run_loop.h',
-          'safe_strerror_posix.cc',
-          'safe_strerror_posix.h',
           'scoped_generic.h',
           'scoped_native_library.cc',
           'scoped_native_library.h',
diff --git a/base/base_nacl.gyp b/base/base_nacl.gyp
index 40005d2..7e7d34f 100644
--- a/base/base_nacl.gyp
+++ b/base/base_nacl.gyp
@@ -83,6 +83,7 @@
               'base_switches.h',
 
               # For PathExists and ReadFromFD.
+              'files/file_util.cc',
               'files/file_util_posix.cc',
 
               # For MessageLoopForIO based on libevent.
@@ -112,6 +113,30 @@
             '../third_party/libevent/libevent_nacl_nonsfi.gyp:event_nacl_nonsfi',
           ],
         },
+        {
+          'target_name': 'test_support_base_nacl_nonsfi',
+          'type': 'none',
+          'variables': {
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libtest_support_base_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+
+            'sources': [
+              'test/gtest_util.cc',
+              'test/launcher/unit_test_launcher_nacl_nonsfi.cc',
+              'test/gtest_xml_unittest_result_printer.cc',
+              'test/test_switches.cc',
+            ],
+          },
+          'dependencies': [
+            'base_nacl_nonsfi',
+            '../testing/gtest_nacl.gyp:gtest_nacl',
+          ],
+        },
       ],
     }],
   ],
diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate
index b1c270ca..57fc4d2 100644
--- a/base/base_unittests.isolate
+++ b/base/base_unittests.isolate
@@ -2,38 +2,18 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 {
+  'variables': {
+    'command': [
+      '../testing/test_env.py',
+      '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+      '--brave-new-test-launcher',
+      '--test-launcher-bot-mode',
+      '--asan=<(asan)',
+      '--msan=<(msan)',
+      '--tsan=<(tsan)',
+    ],
+  },
   'conditions': [
-    ['use_x11==0', {
-      'variables': {
-        'command': [
-          '../testing/test_env.py',
-          '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
-          '--brave-new-test-launcher',
-          '--test-launcher-bot-mode',
-          '--asan=<(asan)',
-          '--msan=<(msan)',
-          '--tsan=<(tsan)',
-        ],
-      },
-    }],
-    ['use_x11==1', {
-      'variables': {
-        'command': [
-          '../testing/xvfb.py',
-          '<(PRODUCT_DIR)',
-          '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
-          '--brave-new-test-launcher',
-          '--test-launcher-bot-mode',
-          '--asan=<(asan)',
-          '--msan=<(msan)',
-          '--tsan=<(tsan)',
-        ],
-        'files': [
-          '../testing/xvfb.py',
-          '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
-        ],
-      },
-    }],
     ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', {
       'variables': {
         'files': [
diff --git a/base/basictypes.h b/base/basictypes.h
index bf75e673..d71abd9 100644
--- a/base/basictypes.h
+++ b/base/basictypes.h
@@ -16,7 +16,7 @@
 #include <stdint.h>  // For intptr_t.
 
 #include "base/macros.h"
-#include "base/port.h"  // Types that only need exist on certain systems.
+#include "build/build_config.h"
 
 // DEPRECATED: Please use (u)int{8,16,32,64}_t instead (and include <stdint.h>).
 typedef int8_t int8;
diff --git a/base/containers/scoped_ptr_map.h b/base/containers/scoped_ptr_map.h
new file mode 100644
index 0000000..19a1153
--- /dev/null
+++ b/base/containers/scoped_ptr_map.h
@@ -0,0 +1,137 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_SCOPED_PTR_MAP_H_
+#define BASE_CONTAINERS_SCOPED_PTR_MAP_H_
+
+#include <map>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/move.h"
+#include "base/stl_util.h"
+
+// ScopedPtrMap provides a std::map that supports scoped_ptr values. It ensures
+// that the map's values are properly deleted when removed from the map, or when
+// the map is destroyed.
+//
+// |ScopedPtr| must be a type scoped_ptr<T>. This is for compatibility with
+// std::map in C++11.
+template <class Key, class ScopedPtr>
+class ScopedPtrMap {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedPtrMap)
+
+  using Container = std::map<Key, typename ScopedPtr::element_type*>;
+
+ public:
+  using allocator_type = typename Container::allocator_type;
+  using size_type = typename Container::size_type;
+  using difference_type = typename Container::difference_type;
+  using reference = typename Container::reference;
+  using const_reference = typename Container::const_reference;
+  using key_type = typename Container::key_type;
+  using const_iterator = typename Container::const_iterator;
+  using const_reverse_iterator = typename Container::const_reverse_iterator;
+
+  ScopedPtrMap() {}
+  ~ScopedPtrMap() { clear(); }
+  ScopedPtrMap(ScopedPtrMap<Key, ScopedPtr>&& other) { swap(other); }
+
+  ScopedPtrMap& operator=(ScopedPtrMap<Key, ScopedPtr>&& rhs) {
+    swap(rhs);
+    return *this;
+  }
+
+  const_iterator find(const Key& k) const { return data_.find(k); }
+  size_type count(const Key& k) const { return data_.count(k); }
+
+  bool empty() const { return data_.empty(); }
+  size_t size() const { return data_.size(); }
+
+  const_reverse_iterator rbegin() const { return data_.rbegin(); }
+  const_reverse_iterator rend() const { return data_.rend(); }
+
+  const_iterator begin() const { return data_.begin(); }
+  const_iterator end() const { return data_.end(); }
+
+  void swap(ScopedPtrMap<Key, ScopedPtr>& other) { data_.swap(other.data_); }
+
+  void clear() { STLDeleteValues(&data_); }
+
+  // Inserts |val| into the map, associated with |key|.
+  std::pair<const_iterator, bool> insert(const Key& key, ScopedPtr val) {
+    auto result = data_.insert(std::make_pair(key, val.get()));
+    if (result.second)
+      ignore_result(val.release());
+    return result;
+  }
+
+  // Inserts |val| into the map, associated with |key|. Overwrites any existing
+  // element at |key|.
+  void set(const Key& key, ScopedPtr val) {
+    typename ScopedPtr::element_type*& val_ref = data_[key];
+    delete val_ref;
+    val_ref = val.release();
+  }
+
+  void erase(const_iterator position) {
+    DCHECK(position != end());
+    delete position->second;
+    // Key-based lookup (cannot use const_iterator overload in C++03 library).
+    data_.erase(position->first);
+  }
+
+  size_type erase(const Key& k) {
+    typename Container::iterator it = data_.find(k);
+    if (it == end())
+      return 0;
+
+    delete it->second;
+    data_.erase(it);
+    return 1;
+  }
+
+  void erase(const_iterator first, const_iterator last) {
+    STLDeleteContainerPairSecondPointers(first, last);
+    // Need non-const iterators as required by the C++03 library.
+    data_.erase(ConstIteratorToIterator(first), ConstIteratorToIterator(last));
+  }
+
+  // Like |erase()|, but returns the element instead of deleting it.
+  ScopedPtr take_and_erase(const_iterator position) {
+    DCHECK(position != end());
+    if (position == end())
+      return ScopedPtr();
+
+    ScopedPtr ret(position->second);
+    // Key-based lookup (cannot use const_iterator overload in C++03 library).
+    data_.erase(position->first);
+    return ret.Pass();
+  }
+
+  // Like |erase()|, but returns the element instead of deleting it.
+  ScopedPtr take_and_erase(const Key& k) {
+    typename Container::iterator it = data_.find(k);
+    if (it == end())
+      return ScopedPtr();
+
+    ScopedPtr ret(it->second);
+    data_.erase(it);
+    return ret.Pass();
+  }
+
+ private:
+  Container data_;
+
+  typename Container::iterator ConstIteratorToIterator(const_iterator it) {
+    // This is the only way to convert a const iterator to a non-const iterator
+    // in C++03 (get the key and do the lookup again).
+    if (it == data_.end())
+      return data_.end();
+    return data_.find(it->first);
+  };
+};
+
+#endif  // BASE_CONTAINERS_SCOPED_PTR_MAP_H_
diff --git a/base/containers/scoped_ptr_map_unittest.cc b/base/containers/scoped_ptr_map_unittest.cc
new file mode 100644
index 0000000..ef70440f
--- /dev/null
+++ b/base/containers/scoped_ptr_map_unittest.cc
@@ -0,0 +1,224 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/scoped_ptr_map.h"
+
+#include <map>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// A ScopedDestroyer sets a Boolean to true upon destruction.
+class ScopedDestroyer {
+ public:
+  ScopedDestroyer(bool* destroyed) : destroyed_(destroyed) {
+    *destroyed_ = false;
+  }
+
+  ~ScopedDestroyer() { *destroyed_ = true; }
+
+ private:
+  bool* destroyed_;
+};
+
+TEST(ScopedPtrMapTest, Insert) {
+  bool destroyed1 = false;
+  bool destroyed2 = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+
+    // Insert to new key.
+    ScopedDestroyer* elem1 = new ScopedDestroyer(&destroyed1);
+    EXPECT_FALSE(destroyed1);
+    EXPECT_TRUE(scoped_map.insert(0, make_scoped_ptr(elem1)).second);
+    EXPECT_EQ(elem1, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed1);
+
+    // Insert to existing key.
+    ScopedDestroyer* elem2 = new ScopedDestroyer(&destroyed2);
+    EXPECT_FALSE(destroyed2);
+    EXPECT_FALSE(scoped_map.insert(0, make_scoped_ptr(elem2)).second);
+    EXPECT_EQ(elem1, scoped_map.find(0)->second);
+
+    EXPECT_FALSE(destroyed1);
+    EXPECT_TRUE(destroyed2);
+  }
+  EXPECT_TRUE(destroyed1);
+}
+
+TEST(ScopedPtrMapTest, Set) {
+  bool destroyed1 = false;
+  bool destroyed2 = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+
+    // Set a new key.
+    ScopedDestroyer* elem1 = new ScopedDestroyer(&destroyed1);
+    EXPECT_FALSE(destroyed1);
+    scoped_map.set(0, make_scoped_ptr(elem1));
+    EXPECT_EQ(elem1, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed1);
+
+    // Set to replace an existing key.
+    ScopedDestroyer* elem2 = new ScopedDestroyer(&destroyed2);
+    EXPECT_FALSE(destroyed2);
+    scoped_map.set(0, make_scoped_ptr(elem2));
+    EXPECT_EQ(elem2, scoped_map.find(0)->second);
+
+    EXPECT_TRUE(destroyed1);
+    EXPECT_FALSE(destroyed2);
+  }
+  EXPECT_TRUE(destroyed1);
+  EXPECT_TRUE(destroyed2);
+}
+
+TEST(ScopedPtrMapTest, EraseIterator) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  EXPECT_FALSE(destroyed);
+  scoped_map.erase(scoped_map.find(0));
+  EXPECT_TRUE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+}
+
+TEST(ScopedPtrMapTest, EraseKey) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  EXPECT_FALSE(destroyed);
+  EXPECT_EQ(1u, scoped_map.erase(0));
+  EXPECT_TRUE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+
+  // Test erase of a non-existent key.
+  EXPECT_EQ(0u, scoped_map.erase(7));
+}
+
+TEST(ScopedPtrMapTest, EraseRange) {
+  bool destroyed1 = false;
+  bool destroyed2 = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed1)));
+  EXPECT_FALSE(destroyed1);
+
+  scoped_map.insert(1, make_scoped_ptr(new ScopedDestroyer(&destroyed2)));
+  EXPECT_FALSE(destroyed2);
+
+  scoped_map.erase(scoped_map.find(0), scoped_map.end());
+  EXPECT_TRUE(destroyed1);
+  EXPECT_TRUE(destroyed2);
+  EXPECT_TRUE(scoped_map.empty());
+}
+
+TEST(ScopedPtrMapTest, TakeAndErase) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+  scoped_map.insert(0, make_scoped_ptr(elem));
+  EXPECT_EQ(elem, scoped_map.find(0)->second);
+  EXPECT_FALSE(destroyed);
+  scoped_ptr<ScopedDestroyer> object = scoped_map.take_and_erase(0);
+  EXPECT_EQ(elem, object.get());
+  EXPECT_FALSE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+  object.reset();
+  EXPECT_TRUE(destroyed);
+}
+
+TEST(ScopedPtrMapTest, Clear) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  EXPECT_FALSE(destroyed);
+  scoped_map.clear();
+  EXPECT_TRUE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+}
+
+TEST(ScopedPtrMapTest, Scope) {
+  bool destroyed = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+    scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+    EXPECT_FALSE(destroyed);
+  }
+  EXPECT_TRUE(destroyed);
+}
+
+TEST(ScopedPtrMapTest, MoveConstruct) {
+  bool destroyed = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+    ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+    scoped_map.insert(0, make_scoped_ptr(elem));
+    EXPECT_EQ(elem, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed);
+    EXPECT_FALSE(scoped_map.empty());
+
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map_copy(
+        scoped_map.Pass());
+    EXPECT_TRUE(scoped_map.empty());
+    EXPECT_FALSE(scoped_map_copy.empty());
+    EXPECT_EQ(elem, scoped_map_copy.find(0)->second);
+    EXPECT_FALSE(destroyed);
+  }
+  EXPECT_TRUE(destroyed);
+}
+
+TEST(ScopedPtrMapTest, MoveAssign) {
+  bool destroyed = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+    ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+    scoped_map.insert(0, make_scoped_ptr(elem));
+    EXPECT_EQ(elem, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed);
+    EXPECT_FALSE(scoped_map.empty());
+
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map_assign;
+    scoped_map_assign = scoped_map.Pass();
+    EXPECT_TRUE(scoped_map.empty());
+    EXPECT_FALSE(scoped_map_assign.empty());
+    EXPECT_EQ(elem, scoped_map_assign.find(0)->second);
+    EXPECT_FALSE(destroyed);
+  }
+  EXPECT_TRUE(destroyed);
+}
+
+template <typename Key, typename ScopedPtr>
+ScopedPtrMap<Key, ScopedPtr> PassThru(ScopedPtrMap<Key, ScopedPtr> scoper) {
+  return scoper;
+}
+
+TEST(ScopedPtrMapTest, Passed) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+  scoped_map.insert(0, make_scoped_ptr(elem));
+  EXPECT_EQ(elem, scoped_map.find(0)->second);
+  EXPECT_FALSE(destroyed);
+
+  base::Callback<ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>>(void)>
+      callback = base::Bind(&PassThru<int, scoped_ptr<ScopedDestroyer>>,
+                            base::Passed(&scoped_map));
+  EXPECT_TRUE(scoped_map.empty());
+  EXPECT_FALSE(destroyed);
+
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> result = callback.Run();
+  EXPECT_TRUE(scoped_map.empty());
+  EXPECT_EQ(elem, result.find(0)->second);
+  EXPECT_FALSE(destroyed);
+
+  result.clear();
+  EXPECT_TRUE(destroyed);
+};
+
+}  // namespace
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
index 48393f4..8599571 100644
--- a/base/debug/debugger_posix.cc
+++ b/base/debug/debugger_posix.cc
@@ -38,7 +38,6 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/posix/eintr_wrapper.h"
-#include "base/safe_strerror_posix.h"
 #include "base/strings/string_piece.h"
 
 #if defined(USE_SYMBOLIZE)
diff --git a/base/environment.cc b/base/environment.cc
index 6cf7a18c..245051d 100644
--- a/base/environment.cc
+++ b/base/environment.cc
@@ -20,7 +20,7 @@
 
 namespace {
 
-class EnvironmentImpl : public base::Environment {
+class EnvironmentImpl : public Environment {
  public:
   bool GetVar(const char* variable_name, std::string* result) override {
     if (GetVarImpl(variable_name, result))
@@ -35,7 +35,7 @@
     if (first_char >= 'a' && first_char <= 'z')
       alternate_case_var = StringToUpperASCII(std::string(variable_name));
     else if (first_char >= 'A' && first_char <= 'Z')
-      alternate_case_var = base::StringToLowerASCII(std::string(variable_name));
+      alternate_case_var = StringToLowerASCII(std::string(variable_name));
     else
       return false;
     return GetVarImpl(alternate_case_var.c_str(), result);
diff --git a/base/files/file_tracing.cc b/base/files/file_tracing.cc
index a1919c4..c25772d 100644
--- a/base/files/file_tracing.cc
+++ b/base/files/file_tracing.cc
@@ -27,13 +27,11 @@
     g_provider->FileTracingDisable(this);
 }
 
-FileTracing::ScopedTrace::ScopedTrace() : initialized_(false) {}
+FileTracing::ScopedTrace::ScopedTrace() : id_(nullptr) {}
 
 FileTracing::ScopedTrace::~ScopedTrace() {
-  if (initialized_ && g_provider) {
-    g_provider->FileTracingEventEnd(
-        name_, &file_->trace_enabler_, file_->path_, size_);
-  }
+  if (id_ && g_provider)
+    g_provider->FileTracingEventEnd(name_, id_);
 }
 
 bool FileTracing::ScopedTrace::ShouldInitialize() const {
@@ -42,15 +40,13 @@
 
 void FileTracing::ScopedTrace::Initialize(
     const char* name, File* file, int64 size) {
-  file_ = file;
-  name_ = name;
-  size_ = size;
-  initialized_ = true;
+  if (!g_provider)
+    return;
 
-  if (g_provider) {
-    g_provider->FileTracingEventBegin(
-        name_, &file_->trace_enabler_, file_->path_, size_);
-  }
+  id_ = &file->trace_enabler_;
+  name_ = name;
+
+  g_provider->FileTracingEventBegin(name_, id_, file->path_, size);
 }
 
 }  // namespace base
diff --git a/base/files/file_tracing.h b/base/files/file_tracing.h
index 8452037..149bd78 100644
--- a/base/files/file_tracing.h
+++ b/base/files/file_tracing.h
@@ -37,16 +37,13 @@
     virtual void FileTracingDisable(void* id) = 0;
 
     // Begins an event for |id| with |name|. |path| tells where in the directory
-    // structure the event is happening (and may be blank). |size| is reported
-    // if not 0.
+    // structure the event is happening (and may be blank). |size| is the number
+    // of bytes involved in the event.
     virtual void FileTracingEventBegin(
         const char* name, void* id, const FilePath& path, int64 size) = 0;
 
-    // Ends an event for |id| with |name|. |path| tells where in the directory
-    // structure the event is happening (and may be blank). |size| is reported
-    // if not 0.
-    virtual void FileTracingEventEnd(
-        const char* name, void* id, const FilePath& path, int64 size) = 0;
+    // Ends an event for |id| with |name|.
+    virtual void FileTracingEventEnd(const char* name, void* id) = 0;
   };
 
   // Sets a global file tracing provider to query categories and record events.
@@ -67,23 +64,21 @@
     // Whether this trace should be initialized or not.
     bool ShouldInitialize() const;
 
-    // Called only if the tracing category is enabled.
-    void Initialize(const char* event, File* file, int64 size);
+    // Called only if the tracing category is enabled. |name| is the name of the
+    // event to trace (e.g. "Read", "Write") and must have an application
+    // lifetime (e.g. static or literal). |file| is the file being traced; must
+    // outlive this class. |size| is the size (in bytes) of this event.
+    void Initialize(const char* name, File* file, int64 size);
 
    private:
-    // True if |Initialize()| has been called. Don't touch |path_|, |event_|,
-    // or |bytes_| if |initialized_| is false.
-    bool initialized_;
+    // The ID of this trace. Based on the |file| passed to |Initialize()|. Must
+    // outlive this class.
+    void* id_;
 
-    // The event name to trace (e.g. "Read", "Write"). Prefixed with "File".
+    // The name of the event to trace (e.g. "Read", "Write"). Prefixed with
+    // "File".
     const char* name_;
 
-    // The file being traced. Must outlive this class.
-    File* file_;
-
-    // The size (in bytes) of this trace. Not reported if 0.
-    int64 size_;
-
     DISALLOW_COPY_AND_ASSIGN(ScopedTrace);
   };
 
diff --git a/base/files/file_util.cc b/base/files/file_util.cc
index 32dab6b..4b6b888 100644
--- a/base/files/file_util.cc
+++ b/base/files/file_util.cc
@@ -22,6 +22,7 @@
 
 namespace base {
 
+#if !defined(OS_NACL_NONSFI)
 namespace {
 
 // The maximum number of 'uniquified' files we will try to create.
@@ -120,6 +121,7 @@
 
   return true;
 }
+#endif  // !defined(OS_NACL_NONSFI)
 
 bool ReadFileToString(const FilePath& path,
                       std::string* contents,
@@ -162,6 +164,7 @@
   return ReadFileToString(path, contents, std::numeric_limits<size_t>::max());
 }
 
+#if !defined(OS_NACL_NONSFI)
 bool IsDirectoryEmpty(const FilePath& dir_path) {
   FileEnumerator files(dir_path, false,
       FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
@@ -207,6 +210,7 @@
 
   return file.SetTimes(last_accessed, last_modified);
 }
+#endif  // !defined(OS_NACL_NONSFI)
 
 bool CloseFile(FILE* file) {
   if (file == NULL)
@@ -214,6 +218,7 @@
   return fclose(file) == 0;
 }
 
+#if !defined(OS_NACL_NONSFI)
 bool TruncateFile(FILE* file) {
   if (file == NULL)
     return false;
@@ -251,5 +256,6 @@
 
   return -1;
 }
+#endif  // !defined(OS_NACL_NONSFI)
 
 }  // namespace base
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index b4a64ba..a8c5d44 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -651,6 +651,7 @@
   results->FromStat(file_info);
   return true;
 }
+#endif  // !defined(OS_NACL_NONSFI)
 
 FILE* OpenFile(const FilePath& filename, const char* mode) {
   ThreadRestrictions::AssertIOAllowed();
@@ -710,6 +711,8 @@
   return true;
 }
 
+#if !defined(OS_NACL_NONSFI)
+
 bool AppendToFile(const FilePath& filename, const char* data, int size) {
   ThreadRestrictions::AssertIOAllowed();
   bool ret = true;
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
index b107b0f..52581f8 100644
--- a/base/files/file_util_unittest.cc
+++ b/base/files/file_util_unittest.cc
@@ -331,7 +331,7 @@
   // TEMP can have a lower case drive letter.
   string16 temp_base_a = base_a.value();
   ASSERT_FALSE(temp_base_a.empty());
-  *temp_base_a.begin() = base::ToUpperASCII(*temp_base_a.begin());
+  *temp_base_a.begin() = ToUpperASCII(*temp_base_a.begin());
   base_a = FilePath(temp_base_a);
 #endif
   ASSERT_TRUE(CreateDirectory(base_a));
@@ -537,8 +537,8 @@
   // network file systems. E.g. AFS).
   FilePath access_test_dir = long_test_dir.Append(kTestSubDirName);
   ASSERT_TRUE(CreateDirectory(access_test_dir));
-  base::FilePermissionRestorer long_test_dir_restorer(long_test_dir);
-  ASSERT_TRUE(base::MakeFileUnreadable(long_test_dir));
+  FilePermissionRestorer long_test_dir_restorer(long_test_dir);
+  ASSERT_TRUE(MakeFileUnreadable(long_test_dir));
 
   // Use the short form of the directory to create a temporary filename.
   ASSERT_TRUE(CreateTemporaryFileInDir(
@@ -2101,7 +2101,7 @@
   EXPECT_EQ(0u, data.length());
 
   // Delete test file.
-  EXPECT_TRUE(base::DeleteFile(file_path, false));
+  EXPECT_TRUE(DeleteFile(file_path, false));
 
   data = "temp";
   EXPECT_FALSE(ReadFileToString(file_path, &data));
@@ -2235,24 +2235,17 @@
                                      .AppendASCII("not")
                                      .AppendASCII("exist");
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, does_not_exist, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, does_not_exist, uid_, ok_gids_));
 
   // |base| not a subpath of |path|.
-  EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, base_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(VerifyPathControlledByUser(sub_dir_, base_dir_, uid_, ok_gids_));
 
   // An empty base path will fail to be a prefix for any path.
   FilePath empty;
-  EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          empty, base_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(VerifyPathControlledByUser(empty, base_dir_, uid_, ok_gids_));
 
   // Finding that a bad call fails proves nothing unless a good call succeeds.
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
 }
 
 TEST_F(VerifyPathControlledByUserTest, Symlinks) {
@@ -2264,11 +2257,9 @@
       << "Failed to create symlink.";
 
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, file_link, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, file_link, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          file_link, file_link, uid_, ok_gids_));
+      VerifyPathControlledByUser(file_link, file_link, uid_, ok_gids_));
 
   // Symlink from one directory to another within the path.
   FilePath link_to_sub_dir =  base_dir_.AppendASCII("link_to_sub_dir");
@@ -2278,18 +2269,15 @@
   FilePath file_path_with_link = link_to_sub_dir.AppendASCII("file.txt");
   ASSERT_TRUE(PathExists(file_path_with_link));
 
-  EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, file_path_with_link, uid_, ok_gids_));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, file_path_with_link, uid_,
+                                          ok_gids_));
 
-  EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          link_to_sub_dir, file_path_with_link, uid_, ok_gids_));
+  EXPECT_FALSE(VerifyPathControlledByUser(link_to_sub_dir, file_path_with_link,
+                                          uid_, ok_gids_));
 
   // Symlinks in parents of base path are allowed.
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          file_path_with_link, file_path_with_link, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(file_path_with_link,
+                                         file_path_with_link, uid_, ok_gids_));
 }
 
 TEST_F(VerifyPathControlledByUserTest, OwnershipChecks) {
@@ -2305,37 +2293,26 @@
       ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
 
   // We control these paths.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Another user does not control these paths.
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, bad_uid, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, sub_dir_, bad_uid, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, bad_uid, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, bad_uid, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, bad_uid, ok_gids_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, bad_uid, ok_gids_));
 
   // Another group does not control the paths.
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, bad_gids_));
+      VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, bad_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, bad_gids_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_));
 }
 
 TEST_F(VerifyPathControlledByUserTest, GroupWriteTest) {
@@ -2348,68 +2325,41 @@
       ChangePosixFilePermissions(text_file_, 0u, S_IWOTH|S_IWGRP));
 
   // Any group is okay because the path is not group-writable.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, bad_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, bad_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, bad_gids_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_));
 
   // No group is okay, because we don't check the group
   // if no group can write.
   std::set<gid_t> no_gids;  // Empty set of gids.
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, no_gids));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, no_gids));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, no_gids));
-
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, no_gids));
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, text_file_, uid_, no_gids));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, no_gids));
 
   // Make all files and directories writable by their group.
-  ASSERT_NO_FATAL_FAILURE(
-      ChangePosixFilePermissions(base_dir_, S_IWGRP, 0u));
-  ASSERT_NO_FATAL_FAILURE(
-      ChangePosixFilePermissions(sub_dir_, S_IWGRP, 0u));
-  ASSERT_NO_FATAL_FAILURE(
-      ChangePosixFilePermissions(text_file_, S_IWGRP, 0u));
+  ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(base_dir_, S_IWGRP, 0u));
+  ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(sub_dir_, S_IWGRP, 0u));
+  ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(text_file_, S_IWGRP, 0u));
 
   // Now |ok_gids_| works, but |bad_gids_| fails.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, bad_gids_));
+      VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, bad_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, bad_gids_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_));
 
   // Because any group in the group set is allowed,
   // the union of good and bad gids passes.
@@ -2421,14 +2371,11 @@
       std::inserter(multiple_gids, multiple_gids.begin()));
 
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, multiple_gids));
+      VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, multiple_gids));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, multiple_gids));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, multiple_gids));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, multiple_gids));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, multiple_gids));
 }
 
 TEST_F(VerifyPathControlledByUserTest, WriteBitChecks) {
@@ -2441,94 +2388,63 @@
       ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
 
   // Initialy, we control all parts of the path.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Make base_dir_ world-writable.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(base_dir_, S_IWOTH, 0u));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
-  EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Make sub_dir_ world writable.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(sub_dir_, S_IWOTH, 0u));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
-  EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Make text_file_ world writable.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(text_file_, S_IWOTH, 0u));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
-  EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Make sub_dir_ non-world writable.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
-  EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Make base_dir_ non-world-writable.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
   EXPECT_FALSE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 
   // Back to the initial state: Nothing is writable, so every path
   // should pass.
   ASSERT_NO_FATAL_FAILURE(
       ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
   EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, sub_dir_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          base_dir_, text_file_, uid_, ok_gids_));
-  EXPECT_TRUE(
-      base::VerifyPathControlledByUser(
-          sub_dir_, text_file_, uid_, ok_gids_));
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
 }
 
 #if defined(OS_ANDROID)
@@ -2545,7 +2461,7 @@
 
   // Insert the image into MediaStore. MediaStore will do some conversions, and
   // return the content URI.
-  FilePath path = base::InsertImageIntoMediaStore(image_file);
+  FilePath path = InsertImageIntoMediaStore(image_file);
   EXPECT_TRUE(path.IsContentUri());
   EXPECT_TRUE(PathExists(path));
   // The file size may not equal to the input image as MediaStore may convert
@@ -2581,9 +2497,9 @@
   char c = 0;
   ASSERT_EQ(0, pipe(fds));
   const int write_end = fds[1];
-  base::ScopedFD read_end_closer(fds[0]);
+  ScopedFD read_end_closer(fds[0]);
   {
-    base::ScopedFD write_end_closer(fds[1]);
+    ScopedFD write_end_closer(fds[1]);
   }
   // This is the only thread. This file descriptor should no longer be valid.
   int ret = close(write_end);
@@ -2597,14 +2513,14 @@
 
 #if defined(GTEST_HAS_DEATH_TEST)
 void CloseWithScopedFD(int fd) {
-  base::ScopedFD fd_closer(fd);
+  ScopedFD fd_closer(fd);
 }
 #endif
 
 TEST(ScopedFD, ScopedFDCrashesOnCloseFailure) {
   int fds[2];
   ASSERT_EQ(0, pipe(fds));
-  base::ScopedFD read_end_closer(fds[0]);
+  ScopedFD read_end_closer(fds[0]);
   EXPECT_EQ(0, IGNORE_EINTR(close(fds[1])));
 #if defined(GTEST_HAS_DEATH_TEST)
   // This is the only thread. This file descriptor should no longer be valid.
diff --git a/base/guid_unittest.cc b/base/guid_unittest.cc
index 4eda7f6..1485497 100644
--- a/base/guid_unittest.cc
+++ b/base/guid_unittest.cc
@@ -9,6 +9,8 @@
 #include "base/strings/string_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace base {
+
 #if defined(OS_POSIX)
 
 namespace {
@@ -16,23 +18,22 @@
 bool IsGUIDv4(const std::string& guid) {
   // The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
   // where y is one of [8, 9, A, B].
-  return base::IsValidGUID(guid) && guid[14] == '4' &&
+  return IsValidGUID(guid) && guid[14] == '4' &&
          (guid[19] == '8' || guid[19] == '9' || guid[19] == 'A' ||
           guid[19] == 'a' || guid[19] == 'B' || guid[19] == 'b');
 }
 
 }  // namespace
 
-
 TEST(GUIDTest, GUIDGeneratesAllZeroes) {
   uint64 bytes[] = { 0, 0 };
-  std::string clientid = base::RandomDataToGUIDString(bytes);
+  std::string clientid = RandomDataToGUIDString(bytes);
   EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid);
 }
 
 TEST(GUIDTest, GUIDGeneratesCorrectly) {
   uint64 bytes[] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL };
-  std::string clientid = base::RandomDataToGUIDString(bytes);
+  std::string clientid = RandomDataToGUIDString(bytes);
   EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid);
 }
 #endif
@@ -40,18 +41,18 @@
 TEST(GUIDTest, GUIDCorrectlyFormatted) {
   const int kIterations = 10;
   for (int it = 0; it < kIterations; ++it) {
-    std::string guid = base::GenerateGUID();
-    EXPECT_TRUE(base::IsValidGUID(guid));
-    EXPECT_TRUE(base::IsValidGUID(base::StringToLowerASCII(guid)));
-    EXPECT_TRUE(base::IsValidGUID(StringToUpperASCII(guid)));
+    std::string guid = GenerateGUID();
+    EXPECT_TRUE(IsValidGUID(guid));
+    EXPECT_TRUE(IsValidGUID(StringToLowerASCII(guid)));
+    EXPECT_TRUE(IsValidGUID(StringToUpperASCII(guid)));
   }
 }
 
 TEST(GUIDTest, GUIDBasicUniqueness) {
   const int kIterations = 10;
   for (int it = 0; it < kIterations; ++it) {
-    std::string guid1 = base::GenerateGUID();
-    std::string guid2 = base::GenerateGUID();
+    std::string guid1 = GenerateGUID();
+    std::string guid2 = GenerateGUID();
     EXPECT_EQ(36U, guid1.length());
     EXPECT_EQ(36U, guid2.length());
     EXPECT_NE(guid1, guid2);
@@ -61,3 +62,5 @@
 #endif
   }
 }
+
+}  // namespace base
diff --git a/base/i18n/bidi_line_iterator.cc b/base/i18n/bidi_line_iterator.cc
index e81a36b..216129e 100644
--- a/base/i18n/bidi_line_iterator.cc
+++ b/base/i18n/bidi_line_iterator.cc
@@ -9,6 +9,25 @@
 namespace base {
 namespace i18n {
 
+namespace {
+  UBiDiLevel GetParagraphLevelForDirection(TextDirection direction) {
+    switch (direction) {
+      case UNKNOWN_DIRECTION:
+        return UBIDI_DEFAULT_LTR;
+        break;
+      case RIGHT_TO_LEFT:
+        return 1;  // Highest RTL level.
+        break;
+      case LEFT_TO_RIGHT:
+        return 0;  // Highest LTR level.
+        break;
+      default:
+        NOTREACHED();
+        return 0;
+    }
+  }
+}  // namespace
+
 BiDiLineIterator::BiDiLineIterator() : bidi_(NULL) {
 }
 
@@ -19,19 +38,14 @@
   }
 }
 
-bool BiDiLineIterator::Open(const string16& text,
-                            bool right_to_left,
-                            bool url) {
+bool BiDiLineIterator::Open(const string16& text, TextDirection direction) {
   DCHECK(!bidi_);
   UErrorCode error = U_ZERO_ERROR;
   bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
   if (U_FAILURE(error))
     return false;
-  if (right_to_left && url)
-    ubidi_setReorderingMode(bidi_, UBIDI_REORDER_RUNS_ONLY);
   ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()),
-                right_to_left ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR,
-                NULL, &error);
+                GetParagraphLevelForDirection(direction), NULL, &error);
   return (U_SUCCESS(error) == TRUE);
 }
 
diff --git a/base/i18n/bidi_line_iterator.h b/base/i18n/bidi_line_iterator.h
index d5a2a07..0bf1ec67c 100644
--- a/base/i18n/bidi_line_iterator.h
+++ b/base/i18n/bidi_line_iterator.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/i18n/base_i18n_export.h"
+#include "base/i18n/rtl.h"
 #include "base/strings/string16.h"
 #include "third_party/icu/source/common/unicode/ubidi.h"
 
@@ -23,7 +24,7 @@
 
   // Initializes the bidirectional iterator with the specified text.  Returns
   // whether initialization succeeded.
-  bool Open(const string16& text, bool right_to_left, bool url);
+  bool Open(const string16& text, TextDirection direction);
 
   // Returns the number of visual runs in the text, or zero on error.
   int CountRuns();
diff --git a/base/ios/crb_protocol_observers_unittest.mm b/base/ios/crb_protocol_observers_unittest.mm
index 5f11051..b8cf4231 100644
--- a/base/ios/crb_protocol_observers_unittest.mm
+++ b/base/ios/crb_protocol_observers_unittest.mm
@@ -4,6 +4,7 @@
 
 #import "base/ios/crb_protocol_observers.h"
 #include "base/ios/weak_nsobject.h"
+#include "base/logging.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "base/mac/scoped_nsobject.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -36,10 +37,9 @@
 @end
 
 @interface TestMutateObserver : TestCompleteObserver
-
 - (instancetype)initWithObserver:(CRBProtocolObservers*)observer
     NS_DESIGNATED_INITIALIZER;
-
+- (instancetype)init NS_UNAVAILABLE;
 @end
 
 namespace {
@@ -266,6 +266,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (void)mutateByAddingObserver:(id<TestObserver>)observer {
   [_observers addObserver:observer];
 }
diff --git a/base/json/string_escape.cc b/base/json/string_escape.cc
index a3b0735..469f9f9 100644
--- a/base/json/string_escape.cc
+++ b/base/json/string_escape.cc
@@ -135,7 +135,7 @@
     dest.push_back('"');
 
   for (StringPiece::const_iterator it = str.begin(); it != str.end(); ++it) {
-    ToUnsigned<StringPiece::value_type>::Unsigned c = *it;
+    unsigned char c = *it;
     if (EscapeSpecialCodePoint(c, &dest))
       continue;
 
diff --git a/base/logging.cc b/base/logging.cc
index 2f1d837..71528ad3f 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -59,7 +59,7 @@
 #include "base/threading/platform_thread.h"
 #include "base/vlog.h"
 #if defined(OS_POSIX)
-#include "base/safe_strerror_posix.h"
+#include "base/posix/safe_strerror.h"
 #endif
 
 #if defined(OS_ANDROID)
@@ -719,7 +719,7 @@
 }
 #elif defined(OS_POSIX)
 BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) {
-  return safe_strerror(error_code);
+  return base::safe_strerror(error_code);
 }
 #else
 #error Not implemented
diff --git a/base/mac/OWNERS b/base/mac/OWNERS
index 4aba972a..b092e06 100644
--- a/base/mac/OWNERS
+++ b/base/mac/OWNERS
@@ -11,4 +11,5 @@
 per-file sdk_forward_declarations.*=rohitrao@chromium.org
 per-file sdk_forward_declarations.*=rsesek@chromium.org
 per-file sdk_forward_declarations.*=shess@chromium.org
+per-file sdk_forward_declarations.*=tapted@chromium.org
 per-file sdk_forward_declarations.*=thakis@chromium.org
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
index 1ab05b2f..35d746e 100644
--- a/base/memory/shared_memory_posix.cc
+++ b/base/memory/shared_memory_posix.cc
@@ -16,9 +16,9 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
+#include "base/posix/safe_strerror.h"
 #include "base/process/process_metrics.h"
 #include "base/profiler/scoped_tracker.h"
-#include "base/safe_strerror_posix.h"
 #include "base/scoped_generic.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
@@ -505,7 +505,7 @@
                    << " function:" << function
                    << " fd:" << mapped_file_
                    << " errno:" << errno
-                   << " msg:" << safe_strerror(errno);
+                   << " msg:" << base::safe_strerror(errno);
     }
   }
 }
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index 5e9a461..642222e 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -119,6 +119,11 @@
     ScheduleWork();
 }
 
+TimeTicks IncomingTaskQueue::GetNewlyAddedTaskDelay() {
+  return !incoming_queue_.empty() ? incoming_queue_.front().delayed_run_time :
+      TimeTicks();
+}
+
 IncomingTaskQueue::~IncomingTaskQueue() {
   // Verify that WillDestroyCurrentMessageLoop() has been called.
   DCHECK(!message_loop_);
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
index 7dd1e82..544f3e9 100644
--- a/base/message_loop/incoming_task_queue.h
+++ b/base/message_loop/incoming_task_queue.h
@@ -57,6 +57,9 @@
   // scheduling work.
   void StartScheduling();
 
+  // Returns the delay for the most recently added task.
+  TimeTicks GetNewlyAddedTaskDelay();
+
  private:
   friend class RefCountedThreadSafe<IncomingTaskQueue>;
   virtual ~IncomingTaskQueue();
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 4222c774..b3c895c 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -640,6 +640,10 @@
   return false;
 }
 
+TimeTicks MessageLoop::GetNewlyAddedTaskDelay() {
+  return incoming_task_queue_->GetNewlyAddedTaskDelay();
+}
+
 void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here,
                                      void(*deleter)(const void*),
                                      const void* object) {
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index f2f89d0..2d67fe51 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -475,6 +475,7 @@
   bool DoWork() override;
   bool DoDelayedWork(TimeTicks* next_delayed_work_time) override;
   bool DoIdleWork() override;
+  TimeTicks GetNewlyAddedTaskDelay() override;
 
   const Type type_;
 
diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h
index a2edb45..77a49ce 100644
--- a/base/message_loop/message_pump.h
+++ b/base/message_loop/message_pump.h
@@ -42,6 +42,9 @@
     // Returns true to indicate that idle work was done. Returning false means
     // the pump will now wait.
     virtual bool DoIdleWork() = 0;
+
+    // Returns the delay for the newly added task.
+    virtual TimeTicks GetNewlyAddedTaskDelay() = 0;
   };
 
   MessagePump();
diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc
index 65d7217..7d796dff 100644
--- a/base/message_loop/message_pump_libevent_unittest.cc
+++ b/base/message_loop/message_pump_libevent_unittest.cc
@@ -77,7 +77,13 @@
 
 // Test to make sure that we catch calling WatchFileDescriptor off of the
 // wrong thread.
-TEST_F(MessagePumpLibeventTest, TestWatchingFromBadThread) {
+#if defined(OS_CHROMEOS)
+// Flaky on Chrome OS: crbug.com/138845.
+#define MAYBE_TestWatchingFromBadThread DISABLED_TestWatchingFromBadThread
+#else
+#define MAYBE_TestWatchingFromBadThread TestWatchingFromBadThread
+#endif
+TEST_F(MessagePumpLibeventTest, MAYBE_TestWatchingFromBadThread) {
   MessagePumpLibevent::FileDescriptorWatcher watcher;
   StupidWatcher delegate;
 
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
index cdbf0c26..a84e04e 100644
--- a/base/message_loop/message_pump_win.cc
+++ b/base/message_loop/message_pump_win.cc
@@ -12,6 +12,7 @@
 #include "base/process/memory.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/thread.h"
 #include "base/trace_event/trace_event.h"
 #include "base/win/wrapped_window_proc.h"
 
@@ -34,6 +35,10 @@
 // task (a series of such messages creates a continuous task pump).
 static const int kMsgHaveWork = WM_USER + 1;
 
+// The default delay for the waitable timer used to wake up the UI worker
+// thread.
+static const int64 kDefaultUIWorkerThreadWakeupTimerMs = 3;
+
 //-----------------------------------------------------------------------------
 // MessagePumpWin public:
 
@@ -90,35 +95,39 @@
 MessagePumpForUI::MessagePumpForUI()
     : atom_(0) {
   InitMessageWnd();
+
+  ui_worker_thread_timer_.Set(::CreateWaitableTimer(NULL, FALSE, NULL));
+  ui_worker_thread_.reset(new base::Thread("UI Pump Worker thread"));
+  ui_worker_thread_->Start();
+  ui_worker_thread_->WaitUntilThreadStarted();
+  ui_worker_thread_->task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&MessagePumpForUI::DoWorkerThreadRunLoop,
+                 base::Unretained(this)));
 }
 
 MessagePumpForUI::~MessagePumpForUI() {
   DestroyWindow(message_hwnd_);
   UnregisterClass(MAKEINTATOM(atom_),
                   GetModuleFromAddress(&WndProcThunk));
+
+  ::QueueUserAPC(
+        reinterpret_cast<PAPCFUNC>(&MessagePumpForUI::ShutdownWorkerThread),
+        ui_worker_thread_->thread_handle().platform_handle(), NULL);
+  ui_worker_thread_->Stop();
 }
 
 void MessagePumpForUI::ScheduleWork() {
-  if (InterlockedExchange(&have_work_, 1))
-    return;  // Someone else continued the pumping.
-
-  // Make sure the MessagePump does some work for us.
-  BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork,
-                         reinterpret_cast<WPARAM>(this), 0);
-  if (ret)
-    return;  // There was room in the Window Message queue.
-
-  // We have failed to insert a have-work message, so there is a chance that we
-  // will starve tasks/timers while sitting in a nested message loop.  Nested
-  // loops only look at Windows Message queues, and don't look at *our* task
-  // queues, etc., so we might not get a time slice in such. :-(
-  // We could abort here, but the fear is that this failure mode is plausibly
-  // common (queue is full, of about 2000 messages), so we'll do a near-graceful
-  // recovery.  Nested loops are pretty transient (we think), so this will
-  // probably be recoverable.
-  InterlockedExchange(&have_work_, 0);  // Clarify that we didn't really insert.
-  UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
-                            MESSAGE_LOOP_PROBLEM_MAX);
+  // If we have a regular posted task at the head of queue then we need to
+  // process it quickly.
+  if (state_ && state_->delegate->GetNewlyAddedTaskDelay().is_null()) {
+    // Make sure the MessagePump does some work for us.
+    PostWorkMessage();
+    return;
+  }
+  // Set a one shot timer to fire after 3 milliseconds. The actual resolution
+  // of the timer is dependent on timeBeginPeriod being called.
+  SetWakeupTimer(kDefaultUIWorkerThreadWakeupTimerMs);
 }
 
 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
@@ -409,45 +418,65 @@
 }
 
 bool MessagePumpForUI::ProcessPumpReplacementMessage() {
-  // When we encounter a kMsgHaveWork message, this method is called to peek
-  // and process a replacement message, such as a WM_PAINT or WM_TIMER.  The
-  // goal is to make the kMsgHaveWork as non-intrusive as possible, even though
-  // a continuous stream of such messages are posted.  This method carefully
-  // peeks a message while there is no chance for a kMsgHaveWork to be pending,
-  // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to
-  // possibly be posted), and finally dispatches that peeked replacement.  Note
-  // that the re-post of kMsgHaveWork may be asynchronous to this thread!!
-
-  bool have_message = false;
-  MSG msg;
-  // We should not process all window messages if we are in the context of an
-  // OS modal loop, i.e. in the context of a windows API call like MessageBox.
-  // This is to ensure that these messages are peeked out by the OS modal loop.
-  if (MessageLoop::current()->os_modal_loop()) {
-    // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above.
-    have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
-                   PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
-  } else {
-    have_message = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE;
-  }
-
-  DCHECK(!have_message || kMsgHaveWork != msg.message ||
-         msg.hwnd != message_hwnd_);
-
   // Since we discarded a kMsgHaveWork message, we must update the flag.
-  int old_have_work = InterlockedExchange(&have_work_, 0);
-  DCHECK(old_have_work);
+  InterlockedExchange(&have_work_, 0);
+  return true;
+}
 
-  // We don't need a special time slice if we didn't have_message to process.
-  if (!have_message)
-    return false;
+void MessagePumpForUI::DoWorkerThreadRunLoop() {
+  DCHECK(ui_worker_thread_timer_.Get());
+  while (TRUE) {
+    DWORD ret = WaitForSingleObjectEx(
+        ui_worker_thread_timer_.Get(), INFINITE, TRUE);
+    // The only APC this thread could receive is the Shutdown APC.
+    if (ret == WAIT_IO_COMPLETION)
+      return;
 
-  // Guarantee we'll get another time slice in the case where we go into native
-  // windows code.   This ScheduleWork() may hurt performance a tiny bit when
-  // tasks appear very infrequently, but when the event queue is busy, the
-  // kMsgHaveWork events get (percentage wise) rarer and rarer.
-  ScheduleWork();
-  return ProcessMessageHelper(msg);
+    // Make sure the MessagePump does some work for us.
+    PostWorkMessage();
+
+    // Set a one shot timer to process pending delayed tasks if any in the
+    // queue. The actual resolution of the timer is dependent on the
+    // timeBeginPeriod API being called.
+    SetWakeupTimer(kDefaultUIWorkerThreadWakeupTimerMs);
+  }
+}
+
+// static
+void CALLBACK MessagePumpForUI::ShutdownWorkerThread(ULONG_PTR param) {
+  // This function is empty because we only use the fact that an APC was posted
+  // to the worker thread to shut it down.
+  return;
+}
+
+void MessagePumpForUI::PostWorkMessage() {
+  BOOL posted = PostMessage(message_hwnd_, kMsgHaveWork,
+                            reinterpret_cast<WPARAM>(this),
+                            0);
+  if (!posted) {
+    // We have failed to insert a have-work message, so there is a chance
+    // that we will starve tasks/timers while sitting in a nested message
+    // loop. Nested loops only look at Windows Message queues, and don't
+    // look at *our* task queues, etc., so we might not get a time slice in
+    // such. :-(
+    // We could abort here, but the fear is that this failure mode is
+    // plausibly common (queue is full, of about 2000 messages), so we'll
+    // do a near-graceful recovery. Nested loops are pretty transient
+    // (we think), so this will probably be recoverable.
+    UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem",
+                              MESSAGE_POST_ERROR,
+                              MESSAGE_LOOP_PROBLEM_MAX);
+  }
+}
+
+void MessagePumpForUI::SetWakeupTimer(int64 delay_ms) {
+  // Set the timer for the delay passed in. The actual resolution of the
+  // timer is dependent on whether timeBeginPeriod was called.
+  LARGE_INTEGER due_time = {0};
+  due_time.QuadPart = -delay_ms * 10000;
+  BOOL timer_set = ::SetWaitableTimer(ui_worker_thread_timer_.Get(),
+      &due_time, 0, NULL, NULL, FALSE);
+  CHECK(timer_set);
 }
 
 //-----------------------------------------------------------------------------
diff --git a/base/message_loop/message_pump_win.h b/base/message_loop/message_pump_win.h
index 00a1e77..042efdf 100644
--- a/base/message_loop/message_pump_win.h
+++ b/base/message_loop/message_pump_win.h
@@ -11,6 +11,7 @@
 
 #include "base/base_export.h"
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_pump.h"
 #include "base/message_loop/message_pump_dispatcher.h"
 #include "base/observer_list.h"
@@ -19,6 +20,8 @@
 
 namespace base {
 
+class Thread;
+
 // MessagePumpWin serves as the base for specialized versions of the MessagePump
 // for Windows. It provides basic functionality like handling of observers and
 // controlling the lifetime of the message pump.
@@ -135,11 +138,39 @@
   bool ProcessMessageHelper(const MSG& msg);
   bool ProcessPumpReplacementMessage();
 
+  // We spawn a worker thread to periodically post (3 ms) the kMsgHaveWork
+  // message to the UI message pump. This is to ensure that the main thread
+  // gets to process tasks and delayed tasks when there is no activity in the
+  // Windows message pump or when there is a nested modal loop (sizing/moving/
+  // drag drop/message boxes) etc.
+  void DoWorkerThreadRunLoop();
+
+  // This function is posted as part of a user mode APC to shutdown the worker
+  // thread when the main message pump is shutting down.
+  static void CALLBACK ShutdownWorkerThread(ULONG_PTR param);
+
+  // Helper function for posting the kMsgHaveWork message to wake up the pump
+  // for processing tasks.
+  void PostWorkMessage();
+
+  // Helper function to set the waitable timer used to wake up the UI worker
+  // thread for processing delayed tasks.
+  // |delay_ms| : The delay in milliseconds.
+  void SetWakeupTimer(int64 delay_ms);
+
   // Atom representing the registered window class.
   ATOM atom_;
 
   // A hidden message-only window.
   HWND message_hwnd_;
+
+  // This thread is used to periodically wake up the main thread to process
+  // tasks.
+  scoped_ptr<base::Thread> ui_worker_thread_;
+
+  // The UI worker thread waits on this timer indefinitely. When the main
+  // thread has tasks ready to be processed it sets the timer.
+  base::win::ScopedHandle ui_worker_thread_timer_;
 };
 
 //-----------------------------------------------------------------------------
diff --git a/base/pickle.cc b/base/pickle.cc
index 09d42c9..cf4a865 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -317,13 +317,17 @@
 }
 
 void Pickle::Resize(size_t new_capacity) {
-  new_capacity = AlignInt(new_capacity, kPayloadUnit);
-
   CHECK_NE(capacity_after_header_, kCapacityReadOnly);
-  void* p = realloc(header_, header_size_ + new_capacity);
+  capacity_after_header_ = AlignInt(new_capacity, kPayloadUnit);
+  void* p = realloc(header_, GetTotalAllocatedSize());
   CHECK(p);
   header_ = reinterpret_cast<Header*>(p);
-  capacity_after_header_ = new_capacity;
+}
+
+size_t Pickle::GetTotalAllocatedSize() const {
+  if (capacity_after_header_ == kCapacityReadOnly)
+    return 0;
+  return header_size_ + capacity_after_header_;
 }
 
 // static
diff --git a/base/pickle.h b/base/pickle.h
index 7a6b0c8..c9fef71 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -153,12 +153,18 @@
   // Performs a deep copy.
   Pickle& operator=(const Pickle& other);
 
-  // Returns the size of the Pickle's data.
+  // Returns the number of bytes written in the Pickle, including the header.
   size_t size() const { return header_size_ + header_->payload_size; }
 
   // Returns the data for this Pickle.
   const void* data() const { return header_; }
 
+  // Returns the effective memory capacity of this Pickle, that is, the total
+  // number of bytes currently dynamically allocated or 0 in the case of a
+  // read-only Pickle. This should be used only for diagnostic / profiling
+  // purposes.
+  size_t GetTotalAllocatedSize() const;
+
   // Methods for adding to the payload of the Pickle.  These values are
   // appended to the end of the Pickle's payload.  When reading values from a
   // Pickle, it is important to read them in the order in which they were added
diff --git a/base/port.h b/base/port.h
index 56c4d4e1..ba6171353 100644
--- a/base/port.h
+++ b/base/port.h
@@ -8,24 +8,6 @@
 #include <stdarg.h>
 #include "build/build_config.h"
 
-// DEPRECATED: Use ...LL and ...ULL suffixes.
-// TODO(viettrungluu): Delete these. These are only here until |GG_(U)INT64_C|
-// are deleted (some other header files (re)define |GG_(U)INT64_C|, so our
-// definitions of them must exactly match theirs).
-#ifdef COMPILER_MSVC
-#define GG_LONGLONG(x) x##I64
-#define GG_ULONGLONG(x) x##UI64
-#else
-#define GG_LONGLONG(x) x##LL
-#define GG_ULONGLONG(x) x##ULL
-#endif
-
-// DEPRECATED: In Chromium, we force-define __STDC_CONSTANT_MACROS, so you can
-// just use the regular (U)INTn_C macros from <stdint.h>.
-// TODO(viettrungluu): Remove the remaining GG_(U)INTn_C macros.
-#define GG_INT64_C(x)   GG_LONGLONG(x)
-#define GG_UINT64_C(x)  GG_ULONGLONG(x)
-
 // Define an OS-neutral wrapper for shared library entry points
 #if defined(OS_WIN)
 #define API_CALL __stdcall
diff --git a/base/safe_strerror_posix.cc b/base/posix/safe_strerror.cc
similarity index 97%
rename from base/safe_strerror_posix.cc
rename to base/posix/safe_strerror.cc
index 9da7aee..e80e8f8 100644
--- a/base/safe_strerror_posix.cc
+++ b/base/posix/safe_strerror.cc
@@ -10,13 +10,16 @@
 #undef _GNU_SOURCE
 #endif
 
-#include "build/build_config.h"
-#include "base/safe_strerror_posix.h"
+#include "base/posix/safe_strerror.h"
 
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 
+#include "build/build_config.h"
+
+namespace base {
+
 #define USE_HISTORICAL_STRERRO_R (defined(__GLIBC__) || defined(OS_NACL))
 
 #if USE_HISTORICAL_STRERRO_R && defined(__GNUC__)
@@ -117,3 +120,5 @@
   safe_strerror_r(err, buf, sizeof(buf));
   return std::string(buf);
 }
+
+}  // namespace base
diff --git a/base/safe_strerror_posix.h b/base/posix/safe_strerror.h
similarity index 90%
rename from base/safe_strerror_posix.h
rename to base/posix/safe_strerror.h
index 2f77d84..862a750 100644
--- a/base/safe_strerror_posix.h
+++ b/base/posix/safe_strerror.h
@@ -2,13 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef BASE_SAFE_STRERROR_POSIX_H_
-#define BASE_SAFE_STRERROR_POSIX_H_
+#ifndef BASE_POSIX_SAFE_STRERROR_H_
+#define BASE_POSIX_SAFE_STRERROR_H_
 
 #include <string>
 
 #include "base/base_export.h"
 
+namespace base {
+
 // BEFORE using anything from this file, first look at PLOG and friends in
 // logging.h and use them instead if applicable.
 //
@@ -35,4 +37,6 @@
 // allocate a string.
 BASE_EXPORT std::string safe_strerror(int err);
 
-#endif  // BASE_SAFE_STRERROR_POSIX_H_
+}  // namespace base
+
+#endif  // BASE_POSIX_SAFE_STRERROR_H_
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index 6f6d6e2b..c1fc056 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -420,14 +420,12 @@
   return true;
 }
 
-}  // namespace base
-
 template<typename Iter>
 static inline bool DoLowerCaseEqualsASCII(Iter a_begin,
                                           Iter a_end,
                                           const char* b) {
   for (Iter it = a_begin; it != a_end; ++it, ++b) {
-    if (!*b || base::ToLowerASCII(*it) != *b)
+    if (!*b || ToLowerASCII(*it) != *b)
       return false;
   }
   return *b == 0;
@@ -460,13 +458,25 @@
   return DoLowerCaseEqualsASCII(a_begin, a_end, b);
 }
 
+bool LowerCaseEqualsASCII(const char* a_begin,
+                          const char* a_end,
+                          const char* b_begin,
+                          const char* b_end) {
+  while (a_begin != a_end && b_begin != b_end &&
+         ToLowerASCII(*a_begin) == *b_begin) {
+    a_begin++;
+    b_begin++;
+  }
+  return a_begin == a_end && b_begin == b_end;
+}
+
 bool LowerCaseEqualsASCII(const char16* a_begin,
                           const char16* a_end,
                           const char* b) {
   return DoLowerCaseEqualsASCII(a_begin, a_end, b);
 }
 
-bool EqualsASCII(const string16& a, const base::StringPiece& b) {
+bool EqualsASCII(const string16& a, const StringPiece& b) {
   if (a.length() != b.length())
     return false;
   return std::equal(b.begin(), b.end(), a.begin());
@@ -481,22 +491,19 @@
     return base::strncasecmp(str.c_str(), search.c_str(), search.length()) == 0;
 }
 
-template <typename STR>
-bool StartsWithT(const STR& str, const STR& search, bool case_sensitive) {
+bool StartsWith(const string16& str,
+                const string16& search,
+                bool case_sensitive) {
   if (case_sensitive) {
     return str.compare(0, search.length(), search) == 0;
-  } else {
-    if (search.size() > str.size())
-      return false;
-    return std::equal(search.begin(), search.end(), str.begin(),
-                      base::CaseInsensitiveCompare<typename STR::value_type>());
   }
+  if (search.size() > str.size())
+    return false;
+  return std::equal(search.begin(), search.end(), str.begin(),
+                    CaseInsensitiveCompare<char16>());
 }
 
-bool StartsWith(const string16& str, const string16& search,
-                bool case_sensitive) {
-  return StartsWithT(str, search, case_sensitive);
-}
+}  // namespace base
 
 template <typename STR>
 bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) {
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 5ab2ad5..12915f7 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -272,6 +272,57 @@
   return output;
 }
 
+// Converts the elements of the given string.  This version uses a pointer to
+// clearly differentiate it from the non-pointer variant.
+template <class str> inline void StringToUpperASCII(str* s) {
+  for (typename str::iterator i = s->begin(); i != s->end(); ++i)
+    *i = ToUpperASCII(*i);
+}
+
+template <class str> inline str StringToUpperASCII(const str& s) {
+  // for std::string and std::wstring
+  str output(s);
+  StringToUpperASCII(&output);
+  return output;
+}
+//
+// Compare the lower-case form of the given string against the given ASCII
+// string.  This is useful for doing checking if an input string matches some
+// token, and it is optimized to avoid intermediate string copies.  This API is
+// borrowed from the equivalent APIs in Mozilla.
+BASE_EXPORT bool LowerCaseEqualsASCII(const std::string& a, const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const string16& a, const char* b);
+
+// Same thing, but with string iterators instead.
+BASE_EXPORT bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
+                                      std::string::const_iterator a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
+                                      string16::const_iterator a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
+                                      const char* a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
+                                      const char* a_end,
+                                      const char* b_begin,
+                                      const char* b_end);
+BASE_EXPORT bool LowerCaseEqualsASCII(const char16* a_begin,
+                                      const char16* a_end,
+                                      const char* b);
+
+// Performs a case-sensitive string compare. The behavior is undefined if both
+// strings are not ASCII.
+BASE_EXPORT bool EqualsASCII(const string16& a, const StringPiece& b);
+
+// Returns true if str starts with search, or false otherwise.
+BASE_EXPORT bool StartsWithASCII(const std::string& str,
+                                 const std::string& search,
+                                 bool case_sensitive);
+BASE_EXPORT bool StartsWith(const base::string16& str,
+                            const base::string16& search,
+                            bool case_sensitive);
+
 }  // namespace base
 
 #if defined(OS_WIN)
@@ -282,53 +333,6 @@
 #error Define string operations appropriately for your platform
 #endif
 
-// Converts the elements of the given string.  This version uses a pointer to
-// clearly differentiate it from the non-pointer variant.
-template <class str> inline void StringToUpperASCII(str* s) {
-  for (typename str::iterator i = s->begin(); i != s->end(); ++i)
-    *i = base::ToUpperASCII(*i);
-}
-
-template <class str> inline str StringToUpperASCII(const str& s) {
-  // for std::string and std::wstring
-  str output(s);
-  StringToUpperASCII(&output);
-  return output;
-}
-
-// Compare the lower-case form of the given string against the given ASCII
-// string.  This is useful for doing checking if an input string matches some
-// token, and it is optimized to avoid intermediate string copies.  This API is
-// borrowed from the equivalent APIs in Mozilla.
-BASE_EXPORT bool LowerCaseEqualsASCII(const std::string& a, const char* b);
-BASE_EXPORT bool LowerCaseEqualsASCII(const base::string16& a, const char* b);
-
-// Same thing, but with string iterators instead.
-BASE_EXPORT bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
-                                      std::string::const_iterator a_end,
-                                      const char* b);
-BASE_EXPORT bool LowerCaseEqualsASCII(base::string16::const_iterator a_begin,
-                                      base::string16::const_iterator a_end,
-                                      const char* b);
-BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
-                                      const char* a_end,
-                                      const char* b);
-BASE_EXPORT bool LowerCaseEqualsASCII(const base::char16* a_begin,
-                                      const base::char16* a_end,
-                                      const char* b);
-
-// Performs a case-sensitive string compare. The behavior is undefined if both
-// strings are not ASCII.
-BASE_EXPORT bool EqualsASCII(const base::string16& a, const base::StringPiece& b);
-
-// Returns true if str starts with search, or false otherwise.
-BASE_EXPORT bool StartsWithASCII(const std::string& str,
-                                 const std::string& search,
-                                 bool case_sensitive);
-BASE_EXPORT bool StartsWith(const base::string16& str,
-                            const base::string16& search,
-                            bool case_sensitive);
-
 // Returns true if str ends with search, or false otherwise.
 BASE_EXPORT bool EndsWith(const std::string& str,
                           const std::string& search,
@@ -500,33 +504,4 @@
 BASE_EXPORT bool MatchPattern(const base::string16& string,
                               const base::string16& pattern);
 
-// Hack to convert any char-like type to its unsigned counterpart.
-// For example, it will convert char, signed char and unsigned char to unsigned
-// char.
-template<typename T>
-struct ToUnsigned {
-  typedef T Unsigned;
-};
-
-template<>
-struct ToUnsigned<char> {
-  typedef unsigned char Unsigned;
-};
-template<>
-struct ToUnsigned<signed char> {
-  typedef unsigned char Unsigned;
-};
-template<>
-struct ToUnsigned<wchar_t> {
-#if defined(WCHAR_T_IS_UTF16)
-  typedef unsigned short Unsigned;
-#elif defined(WCHAR_T_IS_UTF32)
-  typedef uint32 Unsigned;
-#endif
-};
-template<>
-struct ToUnsigned<short> {
-  typedef unsigned short Unsigned;
-};
-
 #endif  // BASE_STRINGS_STRING_UTIL_H_
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
index d887c0b3..fb0beada 100644
--- a/base/strings/string_util_unittest.cc
+++ b/base/strings/string_util_unittest.cc
@@ -494,8 +494,8 @@
   const char chars_with_nul[] = "test\0string";
   const int length_with_nul = arraysize(chars_with_nul) - 1;
   std::string string_with_nul(chars_with_nul, length_with_nul);
-  base::string16 string16_with_nul = ASCIIToUTF16(string_with_nul);
-  EXPECT_EQ(static_cast<base::string16::size_type>(length_with_nul),
+  string16 string16_with_nul = ASCIIToUTF16(string_with_nul);
+  EXPECT_EQ(static_cast<string16::size_type>(length_with_nul),
             string16_with_nul.length());
   std::string narrow_with_nul = UTF16ToASCII(string16_with_nul);
   EXPECT_EQ(static_cast<std::string::size_type>(length_with_nul),
@@ -768,7 +768,7 @@
 }
 
 TEST(StringUtilTest, TokenizeStringPiece) {
-  TokenizeTest<base::StringPiece>();
+  TokenizeTest<StringPiece>();
 }
 
 // Test for JoinString
@@ -1038,9 +1038,9 @@
   {
     char dst[10];
     wchar_t wdst[10];
-    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
     EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
-    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8));
   }
 
@@ -1049,10 +1049,10 @@
   {
     char dst[2] = {1, 2};
     wchar_t wdst[2] = {1, 2};
-    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", 0));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", 0));
     EXPECT_EQ(1, dst[0]);
     EXPECT_EQ(2, dst[1]);
-    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", 0));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", 0));
     EXPECT_EQ(static_cast<wchar_t>(1), wdst[0]);
     EXPECT_EQ(static_cast<wchar_t>(2), wdst[1]);
   }
@@ -1061,9 +1061,9 @@
   {
     char dst[8];
     wchar_t wdst[8];
-    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
     EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
-    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8));
   }
 
@@ -1071,9 +1071,9 @@
   {
     char dst[7];
     wchar_t wdst[7];
-    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
     EXPECT_EQ(0, memcmp(dst, "abcdef", 7));
-    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"abcdef", sizeof(wchar_t) * 7));
   }
 
@@ -1081,9 +1081,9 @@
   {
     char dst[3];
     wchar_t wdst[3];
-    EXPECT_EQ(7U, base::strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
     EXPECT_EQ(0, memcmp(dst, "ab", 3));
-    EXPECT_EQ(7U, base::wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
     EXPECT_EQ(0, memcmp(wdst, L"ab", sizeof(wchar_t) * 3));
   }
 }
@@ -1116,7 +1116,7 @@
     { L"% 10ls", true }
   };
   for (size_t i = 0; i < arraysize(cases); ++i)
-    EXPECT_EQ(cases[i].portable, base::IsWprintfFormatPortable(cases[i].input));
+    EXPECT_EQ(cases[i].portable, IsWprintfFormatPortable(cases[i].input));
 }
 
 TEST(StringUtilTest, RemoveChars) {
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index 91456db..a8ae0cf 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -33,6 +33,8 @@
     "expectations/parser.h",
     "gtest_util.cc",
     "gtest_util.h",
+    "gtest_xml_unittest_result_printer.cc",
+    "gtest_xml_unittest_result_printer.h",
     "gtest_xml_util.cc",
     "gtest_xml_util.h",
     "histogram_tester.cc",
@@ -112,6 +114,8 @@
     "test_support_android.h",
     "test_support_ios.h",
     "test_support_ios.mm",
+    "test_ui_thread_android.cc",
+    "test_ui_thread_android.h",
     "thread_test_helper.cc",
     "thread_test_helper.h",
     "trace_event_analyzer.cc",
@@ -203,6 +207,7 @@
   generate_jni("base_unittests_jni_headers") {
     sources = [
       "android/java/src/org/chromium/base/ContentUriTestUtils.java",
+      "android/java/src/org/chromium/base/TestUiThread.java",
     ]
     jni_package = "base"
   }
diff --git a/base/test/android/java/src/org/chromium/base/TestUiThread.java b/base/test/android/java/src/org/chromium/base/TestUiThread.java
new file mode 100644
index 0000000..77f96606a
--- /dev/null
+++ b/base/test/android/java/src/org/chromium/base/TestUiThread.java
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Looper;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * Set up a thread as the Chromium UI Thread, and run its looper. This is is intended for C++ unit
+ * tests (e.g. the net unit tests) that don't run with the UI thread as their main looper, but test
+ * code that, on Android, uses UI thread events, so need a running UI thread.
+ */
+@ThreadSafe
+public class TestUiThread {
+    private static final AtomicBoolean sStarted = new AtomicBoolean(false);
+    private static final String TAG = Log.makeTag("TestUiThread");
+
+    @CalledByNative
+    private static void loop() {
+        // @{link ThreadUtils#setUiThread(Looper)} can only be called once in a test run, so do this
+        // once, and leave it running.
+        if (sStarted.getAndSet(true)) return;
+
+        final CountDownLatch startLatch = new CountDownLatch(1);
+        new Thread(new Runnable() {
+
+            @Override
+            public void run() {
+                Looper.prepare();
+                ThreadUtils.setUiThread(Looper.myLooper());
+                startLatch.countDown();
+                Looper.loop();
+            }
+
+        }).start();
+
+        try {
+            startLatch.await();
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Failed to set UI Thread");
+        }
+    }
+}
diff --git a/base/test/gtest_xml_unittest_result_printer.cc b/base/test/gtest_xml_unittest_result_printer.cc
new file mode 100644
index 0000000..192c228e2
--- /dev/null
+++ b/base/test/gtest_xml_unittest_result_printer.cc
@@ -0,0 +1,77 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/gtest_xml_unittest_result_printer.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+
+namespace base {
+
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter() : output_file_(NULL) {
+}
+
+XmlUnitTestResultPrinter::~XmlUnitTestResultPrinter() {
+  if (output_file_) {
+    fprintf(output_file_, "</testsuites>\n");
+    fflush(output_file_);
+    CloseFile(output_file_);
+  }
+}
+
+bool XmlUnitTestResultPrinter::Initialize(const FilePath& output_file_path) {
+  DCHECK(!output_file_);
+  output_file_ = OpenFile(output_file_path, "w");
+  if (!output_file_)
+    return false;
+
+  fprintf(output_file_,
+          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuites>\n");
+  fflush(output_file_);
+
+  return true;
+}
+
+void XmlUnitTestResultPrinter::OnTestCaseStart(
+    const testing::TestCase& test_case) {
+  fprintf(output_file_, "  <testsuite>\n");
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestStart(
+    const testing::TestInfo& test_info) {
+  // This is our custom extension - it helps to recognize which test was
+  // running when the test binary crashed. Note that we cannot even open the
+  // <testcase> tag here - it requires e.g. run time of the test to be known.
+  fprintf(output_file_,
+          "    <x-teststart name=\"%s\" classname=\"%s\" />\n",
+          test_info.name(),
+          test_info.test_case_name());
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestEnd(const testing::TestInfo& test_info) {
+  fprintf(output_file_,
+          "    <testcase name=\"%s\" status=\"run\" time=\"%.3f\""
+          " classname=\"%s\">\n",
+          test_info.name(),
+          static_cast<double>(test_info.result()->elapsed_time()) /
+              Time::kMillisecondsPerSecond,
+          test_info.test_case_name());
+  if (test_info.result()->Failed()) {
+    fprintf(output_file_,
+            "      <failure message=\"\" type=\"\"></failure>\n");
+  }
+  fprintf(output_file_, "    </testcase>\n");
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestCaseEnd(
+    const testing::TestCase& test_case) {
+  fprintf(output_file_, "  </testsuite>\n");
+  fflush(output_file_);
+}
+
+}  // namespace base
diff --git a/base/test/gtest_xml_unittest_result_printer.h b/base/test/gtest_xml_unittest_result_printer.h
new file mode 100644
index 0000000..3b06b854
--- /dev/null
+++ b/base/test/gtest_xml_unittest_result_printer.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
+#define BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
+
+#include <stdio.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class FilePath;
+
+// Generates an XML output file. Format is very close to GTest, but has
+// extensions needed by the test launcher.
+class XmlUnitTestResultPrinter : public testing::EmptyTestEventListener {
+ public:
+  XmlUnitTestResultPrinter();
+  ~XmlUnitTestResultPrinter() override;
+
+  // Must be called before adding as a listener. Returns true on success.
+  bool Initialize(const FilePath& output_file_path) WARN_UNUSED_RESULT;
+
+ private:
+  // testing::EmptyTestEventListener:
+  void OnTestCaseStart(const testing::TestCase& test_case) override;
+  void OnTestStart(const testing::TestInfo& test_info) override;
+  void OnTestEnd(const testing::TestInfo& test_info) override;
+  void OnTestCaseEnd(const testing::TestCase& test_case) override;
+
+  FILE* output_file_;
+
+  DISALLOW_COPY_AND_ASSIGN(XmlUnitTestResultPrinter);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
diff --git a/base/test/gtest_xml_util.cc b/base/test/gtest_xml_util.cc
index db8cc2d..e24d522 100644
--- a/base/test/gtest_xml_util.cc
+++ b/base/test/gtest_xml_util.cc
@@ -21,73 +21,12 @@
   va_list args;
   va_start(args, message);
   std::string* error = static_cast<std::string*>(context);
-  base::StringAppendV(error, message, args);
+  StringAppendV(error, message, args);
   va_end(args);
 }
 
 }  // namespace
 
-XmlUnitTestResultPrinter::XmlUnitTestResultPrinter() : output_file_(NULL) {
-}
-
-XmlUnitTestResultPrinter::~XmlUnitTestResultPrinter() {
-  if (output_file_) {
-    fprintf(output_file_, "</testsuites>\n");
-    fflush(output_file_);
-    base::CloseFile(output_file_);
-  }
-}
-
-bool XmlUnitTestResultPrinter::Initialize(const FilePath& output_file_path) {
-  DCHECK(!output_file_);
-  output_file_ = OpenFile(output_file_path, "w");
-  if (!output_file_)
-    return false;
-
-  fprintf(output_file_,
-          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuites>\n");
-  fflush(output_file_);
-
-  return true;
-}
-
-void XmlUnitTestResultPrinter::OnTestCaseStart(
-    const testing::TestCase& test_case) {
-  fprintf(output_file_, "  <testsuite>\n");
-  fflush(output_file_);
-}
-
-void XmlUnitTestResultPrinter::OnTestStart(const testing::TestInfo& test_info) {
-  // This is our custom extension - it helps to recognize which test was running
-  // when the test binary crashed. Note that we cannot even open the <testcase>
-  // tag here - it requires e.g. run time of the test to be known.
-  fprintf(output_file_,
-          "    <x-teststart name=\"%s\" classname=\"%s\" />\n",
-          test_info.name(),
-          test_info.test_case_name());
-  fflush(output_file_);
-}
-
-void XmlUnitTestResultPrinter::OnTestEnd(const testing::TestInfo& test_info) {
-  fprintf(output_file_,
-          "    <testcase name=\"%s\" status=\"run\" time=\"%.3f\""
-          " classname=\"%s\">\n",
-          test_info.name(),
-          static_cast<double>(test_info.result()->elapsed_time()) /
-              Time::kMillisecondsPerSecond,
-          test_info.test_case_name());
-  if (test_info.result()->Failed())
-    fprintf(output_file_, "      <failure message=\"\" type=\"\"></failure>\n");
-  fprintf(output_file_, "    </testcase>\n");
-  fflush(output_file_);
-}
-
-void XmlUnitTestResultPrinter::OnTestCaseEnd(
-    const testing::TestCase& test_case) {
-  fprintf(output_file_, "  </testsuite>\n");
-  fflush(output_file_);
-}
-
 bool ProcessGTestOutput(const base::FilePath& output_file,
                         std::vector<TestResult>* results,
                         bool* crashed) {
diff --git a/base/test/gtest_xml_util.h b/base/test/gtest_xml_util.h
index 9ff2406..b023f80 100644
--- a/base/test/gtest_xml_util.h
+++ b/base/test/gtest_xml_util.h
@@ -7,37 +7,13 @@
 
 #include <vector>
 
-#include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
 
 class FilePath;
 struct TestResult;
 
-// Generates an XML output file. Format is very close to GTest, but has
-// extensions needed by the test launcher.
-class XmlUnitTestResultPrinter : public testing::EmptyTestEventListener {
- public:
-  XmlUnitTestResultPrinter();
-  ~XmlUnitTestResultPrinter() override;
-
-  // Must be called before adding as a listener. Returns true on success.
-  bool Initialize(const FilePath& output_file_path) WARN_UNUSED_RESULT;
-
- private:
-  // testing::EmptyTestEventListener:
-  void OnTestCaseStart(const testing::TestCase& test_case) override;
-  void OnTestStart(const testing::TestInfo& test_info) override;
-  void OnTestEnd(const testing::TestInfo& test_info) override;
-  void OnTestCaseEnd(const testing::TestCase& test_case) override;
-
-  FILE* output_file_;
-
-  DISALLOW_COPY_AND_ASSIGN(XmlUnitTestResultPrinter);
-};
-
 // Produces a vector of test results based on GTest output file.
 // Returns true iff the output file exists and has been successfully parsed.
 // On successful return |crashed| is set to true if the test results
diff --git a/base/test/launcher/test_launcher_nacl_nonsfi.cc b/base/test/launcher/test_launcher_nacl_nonsfi.cc
new file mode 100644
index 0000000..fa52604
--- /dev/null
+++ b/base/test/launcher/test_launcher_nacl_nonsfi.cc
@@ -0,0 +1,160 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "base/test/launcher/test_launcher.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+
+namespace base {
+
+namespace {
+
+const char kHelpFlag[] = "help";
+
+void PrintUsage() {
+  fprintf(stdout,
+          "Runs tests using the gtest framework, each batch of tests being\n"
+          "run in their own process. Supported command-line flags:\n"
+          "\n"
+          " Common flags:\n"
+          "  --gtest_filter=...\n"
+          "    Runs a subset of tests (see --gtest_help for more info).\n"
+          "\n"
+          "  --help\n"
+          "    Shows this message.\n"
+          "\n"
+          " Other flags:\n"
+          "  --test-launcher-retry-limit=N\n"
+          "    Sets the limit of test retries on failures to N.\n"
+          "\n"
+          "  --test-launcher-summary-output=PATH\n"
+          "    Saves a JSON machine-readable summary of the run.\n"
+          "\n"
+          "  --test-launcher-print-test-stdio=auto|always|never\n"
+          "    Controls when full test output is printed.\n"
+          "    auto means to print it when the test failed.\n"
+          "\n"
+          "  --test-launcher-total-shards=N\n"
+          "    Sets the total number of shards to N.\n"
+          "\n"
+          "  --test-launcher-shard-index=N\n"
+          "    Sets the shard index to run to N (from 0 to TOTAL - 1).\n");
+  fflush(stdout);
+}
+
+class NonSfiUnitTestPlatformDelegate : public base::UnitTestPlatformDelegate {
+ public:
+  NonSfiUnitTestPlatformDelegate() {
+  }
+
+  bool Init(const std::string& test_binary) {
+    base::FilePath dir_exe;
+    if (!PathService::Get(base::DIR_EXE, &dir_exe)) {
+      LOG(ERROR) << "Failed to get directory of the current executable.";
+      return false;
+    }
+
+    test_path_ = dir_exe.AppendASCII(test_binary);
+    return true;
+  }
+
+ private:
+  bool CreateTemporaryFile(base::FilePath* path) override {
+    if (!base::CreateNewTempDirectory(base::FilePath::StringType(), path))
+      return false;
+    *path = path->AppendASCII("test_results.xml");
+    return true;
+  }
+
+  bool GetTests(std::vector<base::SplitTestName>* output) override {
+    base::FilePath output_file;
+    if (!base::CreateTemporaryFile(&output_file)) {
+      LOG(ERROR) << "Failed to create a temp file.";
+      return false;
+    }
+
+    base::CommandLine cmd_line(test_path_);
+    cmd_line.AppendSwitchPath(switches::kTestLauncherListTests, output_file);
+
+    base::LaunchOptions launch_options;
+    launch_options.wait = true;
+
+    if (!base::LaunchProcess(cmd_line, launch_options).IsValid())
+      return false;
+
+    return base::ReadTestNamesFromFile(output_file, output);
+  }
+
+  std::string GetWrapperForChildGTestProcess() override {
+    return std::string();
+  }
+
+  base::CommandLine GetCommandLineForChildGTestProcess(
+      const std::vector<std::string>& test_names,
+      const base::FilePath& output_file) override {
+    base::CommandLine cmd_line(test_path_);
+    cmd_line.AppendSwitchPath(
+        switches::kTestLauncherOutput, output_file);
+    cmd_line.AppendSwitchASCII(
+        base::kGTestFilterFlag, JoinString(test_names, ":"));
+    return cmd_line;
+  }
+
+  void RelaunchTests(base::TestLauncher* test_launcher,
+                     const std::vector<std::string>& test_names,
+                     int launch_flags) override {
+    RunUnitTestsBatch(test_launcher, this, test_names, launch_flags);
+  }
+
+  base::FilePath test_path_;
+};
+
+}  // namespace
+
+int TestLauncherNonSfiMain(const std::string& test_binary) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) {
+    PrintUsage();
+    return 0;
+  }
+
+  base::TimeTicks start_time(base::TimeTicks::Now());
+
+  TestTimeouts::Initialize();
+
+  base::MessageLoopForIO message_loop;
+
+  NonSfiUnitTestPlatformDelegate platform_delegate;
+  if (!platform_delegate.Init(test_binary)) {
+    fprintf(stderr, "Failed to initialize test launcher.\n");
+    fflush(stderr);
+    return 1;
+  }
+
+  base::UnitTestLauncherDelegate delegate(&platform_delegate, 10, true);
+  base::TestLauncher launcher(&delegate, base::SysInfo::NumberOfProcessors());
+  bool success = launcher.Run();
+
+  fprintf(stdout, "Tests took %" PRId64 " seconds.\n",
+          (base::TimeTicks::Now() - start_time).InSeconds());
+  fflush(stdout);
+  return success ? 0 : 1;
+}
+
+}  // namespace base
diff --git a/base/test/launcher/test_launcher_nacl_nonsfi.h b/base/test/launcher/test_launcher_nacl_nonsfi.h
new file mode 100644
index 0000000..6cb3785
--- /dev/null
+++ b/base/test/launcher/test_launcher_nacl_nonsfi.h
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_LAUNCHER_TEST_LAUNCHER_NACL_NONSFI_H_
+#define BASE_TEST_LAUNCHER_TEST_LAUNCHER_NACL_NONSFI_H_
+
+#include <string>
+
+namespace base {
+
+// Launches the NaCl Non-SFI test binary |test_binary|.
+int TestLauncherNonSfiMain(const std::string& test_binary);
+
+}  // namespace base
+
+#endif  // BASE_TEST_LAUNCHER_TEST_LAUNCHER_NACL_NONSFI_H_
diff --git a/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc b/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc
new file mode 100644
index 0000000..b2cf14a
--- /dev/null
+++ b/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/unit_test_launcher.h"
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/test/gtest_util.h"
+#include "base/test/gtest_xml_unittest_result_printer.h"
+#include "base/test/test_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite) {
+  CHECK(CommandLine::InitializedForCurrentProcess() ||
+        CommandLine::Init(argc, argv));
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kTestLauncherListTests)) {
+    // Dump all test list into a file.
+    FilePath list_path(
+        command_line->GetSwitchValuePath(switches::kTestLauncherListTests));
+    if (!WriteCompiledInTestsToFile(list_path)) {
+      LOG(ERROR) << "Failed to write list of tests.";
+      return 1;
+    }
+
+    // Successfully done.
+    return 0;
+  }
+
+  // Register XML output printer, if --test-launcher-output flag is set.
+  if (command_line->HasSwitch(switches::kTestLauncherOutput)) {
+    FilePath output_path = command_line->GetSwitchValuePath(
+        switches::kTestLauncherOutput);
+    if (PathExists(output_path)) {
+      LOG(WARNING) << "Test launcher output path exists. Do not override";
+    } else {
+      XmlUnitTestResultPrinter* printer = new XmlUnitTestResultPrinter;
+      CHECK(printer->Initialize(output_path));
+      testing::UnitTest::GetInstance()->listeners().Append(printer);
+    }
+  }
+
+  return run_test_suite.Run();
+}
+
+}  // namespace base
diff --git a/base/test/test_pending_task_unittest.cc b/base/test/test_pending_task_unittest.cc
index 32502f2..7623ce4 100644
--- a/base/test/test_pending_task_unittest.cc
+++ b/base/test/test_pending_task_unittest.cc
@@ -10,7 +10,7 @@
 #include "testing/gtest/include/gtest/gtest-spi.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace {
+namespace base {
 
 TEST(TestPendingTaskTest, TraceSupport) {
   base::TestPendingTask task;
@@ -52,4 +52,4 @@
       << task_first << ".ShouldRunBefore(" << task_after << ")\n";
 }
 
-}  // namespace
+}  // namespace base
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index 6c766eb..e281cff 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -18,6 +18,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/process/memory.h"
+#include "base/test/gtest_xml_unittest_result_printer.h"
 #include "base/test/gtest_xml_util.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/multiprocess_test.h"
diff --git a/base/test/test_ui_thread_android.cc b/base/test/test_ui_thread_android.cc
new file mode 100644
index 0000000..6f19974
--- /dev/null
+++ b/base/test/test_ui_thread_android.cc
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "base/test/test_ui_thread_android.h"
+
+#include "jni/TestUiThread_jni.h"
+
+namespace base {
+
+void StartTestUiThreadLooper() {
+  Java_TestUiThread_loop(base::android::AttachCurrentThread());
+}
+
+bool RegisterTestUiThreadAndroid(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/test/test_ui_thread_android.h b/base/test/test_ui_thread_android.h
new file mode 100644
index 0000000..dfecbfe
--- /dev/null
+++ b/base/test/test_ui_thread_android.h
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_UI_THREAD_ANDROID_
+#define BASE_TEST_TEST_UI_THREAD_ANDROID_
+
+#include <jni.h>
+
+namespace base {
+
+// Set up a thread as the Chromium UI Thread, and run its looper. This is is
+// intended for C++ unit tests (e.g. the net unit tests) that don't run with the
+// UI thread as their main looper, but test code that, on Android, uses UI
+// thread events, so need a running UI thread.
+void StartTestUiThreadLooper();
+
+bool RegisterTestUiThreadAndroid(JNIEnv* env);
+}  // namespace base
+
+#endif  //  BASE_TEST_TEST_UI_THREAD_ANDROID_
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
index 923af08b..3468f45 100644
--- a/base/threading/platform_thread.h
+++ b/base/threading/platform_thread.h
@@ -192,6 +192,11 @@
   // |thread_handle|.
   static void Join(PlatformThreadHandle thread_handle);
 
+  // Toggles the target thread's priority at runtime.  Prefer
+  // CreateWithPriority() to set the thread's initial priority.
+  // NOTE: The call may fail if the caller thread is not the same as the
+  // target thread on POSIX.  For example, seccomp-bpf blocks it by default
+  // in the sandbox.
   static void SetThreadPriority(PlatformThreadHandle handle,
                                 ThreadPriority priority);
 
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index 1d11611..0d821a9b 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -13,7 +13,6 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/safe_strerror_posix.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread_internal_posix.h"
 #include "base/threading/thread_id_name_manager.h"
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
index 1bc3113..7059ceab 100644
--- a/base/threading/simple_thread.cc
+++ b/base/threading/simple_thread.cc
@@ -29,7 +29,13 @@
 
 void SimpleThread::Start() {
   DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times.";
-  bool success = PlatformThread::Create(options_.stack_size(), this, &thread_);
+  bool success;
+  if (options_.priority() == ThreadPriority::NORMAL) {
+    success = PlatformThread::Create(options_.stack_size(), this, &thread_);
+  } else {
+    success = PlatformThread::CreateWithPriority(options_.stack_size(), this,
+                                                 &thread_, options_.priority());
+  }
   DCHECK(success);
   base::ThreadRestrictions::ScopedAllowWait allow_wait;
   event_.Wait();  // Wait for the thread to complete initialization.
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
index ecd3604..36548d36 100644
--- a/base/threading/simple_thread.h
+++ b/base/threading/simple_thread.h
@@ -59,7 +59,7 @@
  public:
   class BASE_EXPORT Options {
    public:
-    Options() : stack_size_(0) { }
+    Options() : stack_size_(0), priority_(ThreadPriority::NORMAL) { }
     ~Options() { }
 
     // We use the standard compiler-supplied copy constructor.
@@ -67,8 +67,13 @@
     // A custom stack size, or 0 for the system default.
     void set_stack_size(size_t size) { stack_size_ = size; }
     size_t stack_size() const { return stack_size_; }
+
+    // A custom thread priority.
+    void set_priority(ThreadPriority priority) { priority_ = priority; }
+    ThreadPriority priority() const { return priority_; }
    private:
     size_t stack_size_;
+    ThreadPriority priority_;
   };
 
   // Create a SimpleThread.  |options| should be used to manage any specific
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index 9242c55..63b07cb 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -39,14 +39,16 @@
 Thread::Options::Options()
     : message_loop_type(MessageLoop::TYPE_DEFAULT),
       timer_slack(TIMER_SLACK_NONE),
-      stack_size(0) {
+      stack_size(0),
+      priority(ThreadPriority::NORMAL) {
 }
 
 Thread::Options::Options(MessageLoop::Type type,
                          size_t size)
     : message_loop_type(type),
       timer_slack(TIMER_SLACK_NONE),
-      stack_size(size) {
+      stack_size(size),
+      priority(ThreadPriority::NORMAL) {
 }
 
 Thread::Options::~Options() {
@@ -100,7 +102,14 @@
   // that thread_ is populated before the newly created thread accesses it.
   {
     AutoLock lock(thread_lock_);
-    if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
+    bool created;
+    if (options.priority == ThreadPriority::NORMAL) {
+      created = PlatformThread::Create(options.stack_size, this, &thread_);
+    } else {
+      created = PlatformThread::CreateWithPriority(options.stack_size, this,
+                                                   &thread_, options.priority);
+    }
+    if (!created) {
       DLOG(ERROR) << "failed to create thread";
       delete message_loop_;
       message_loop_ = nullptr;
diff --git a/base/threading/thread.h b/base/threading/thread.h
index 6b2f1c5..6b70058 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -60,6 +60,9 @@
     // This does not necessarily correspond to the thread's initial stack size.
     // A value of 0 indicates that the default maximum should be used.
     size_t stack_size;
+
+    // Specifies the initial thread priority.
+    ThreadPriority priority;
   };
 
   // Constructor.
@@ -170,7 +173,7 @@
   // hold on to this even after the thread is gone; in this situation, attempts
   // to PostTask() will fail.
   scoped_refptr<SingleThreadTaskRunner> task_runner() const {
-    return message_loop_->task_runner();
+    return message_loop_ ? message_loop_->task_runner() : nullptr;
   }
 
   // Returns the name of this thread (for display in debugger too).
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index e86c7582..926d5ddf 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -234,3 +234,9 @@
   EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
   EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
 }
+
+TEST_F(ThreadTest, ThreadNotStarted) {
+  Thread a("Inert");
+  EXPECT_EQ(nullptr, a.message_loop_proxy());
+  EXPECT_EQ(nullptr, a.task_runner());
+}
diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc
index 7826fc6..fc82c62 100644
--- a/base/time/time_posix.cc
+++ b/base/time/time_posix.cc
@@ -17,7 +17,6 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "base/port.h"
 #include "build/build_config.h"
 
 #if defined(OS_ANDROID)
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
index 64c76da..3a8a5bf2 100644
--- a/base/trace_event/BUILD.gn
+++ b/base/trace_event/BUILD.gn
@@ -39,6 +39,8 @@
     "trace_event_impl_constants.cc",
     "trace_event_memory.cc",
     "trace_event_memory.h",
+    "trace_event_memory_overhead.cc",
+    "trace_event_memory_overhead.h",
     "trace_event_synthetic_delay.cc",
     "trace_event_synthetic_delay.h",
     "trace_event_system_stats_monitor.cc",
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
index 5d11bb0..dbd220e3 100644
--- a/base/trace_event/memory_allocator_dump.cc
+++ b/base/trace_event/memory_allocator_dump.cc
@@ -15,23 +15,6 @@
 namespace base {
 namespace trace_event {
 
-namespace {
-// Returns the c-string pointer from a dictionary value without performing extra
-// std::string copies. The ptr will be valid as long as the value exists.
-bool GetDictionaryValueAsCStr(const DictionaryValue* dict_value,
-                              const std::string& key,
-                              const char** out_cstr) {
-  const Value* value = nullptr;
-  const StringValue* str_value = nullptr;
-  if (!dict_value->GetWithoutPathExpansion(key, &value))
-    return false;
-  if (!value->GetAsString(&str_value))
-    return false;
-  *out_cstr = str_value->GetString().c_str();
-  return true;
-}
-}  // namespace
-
 // TODO(primiano): remove kName{Inner,Outer}Size below after all the existing
 // dump providers have been rewritten.
 const char MemoryAllocatorDump::kNameSize[] = "size";
@@ -48,6 +31,7 @@
                                          const MemoryAllocatorDumpGuid& guid)
     : absolute_name_(absolute_name),
       process_memory_dump_(process_memory_dump),
+      attributes_(new TracedValue),
       guid_(guid) {
   // The |absolute_name| cannot be empty.
   DCHECK(!absolute_name.empty());
@@ -78,68 +62,40 @@
 MemoryAllocatorDump::~MemoryAllocatorDump() {
 }
 
-void MemoryAllocatorDump::Add(const std::string& name,
-                              const char* type,
-                              const char* units,
-                              scoped_ptr<Value> value) {
-  scoped_ptr<DictionaryValue> attribute(new DictionaryValue());
-  DCHECK(!attributes_.HasKey(name));
-  attribute->SetStringWithoutPathExpansion("type", type);
-  attribute->SetStringWithoutPathExpansion("units", units);
-  attribute->SetWithoutPathExpansion("value", value.Pass());
-  attributes_.SetWithoutPathExpansion(name, attribute.Pass());
-}
-
-bool MemoryAllocatorDump::Get(const std::string& name,
-                              const char** out_type,
-                              const char** out_units,
-                              const Value** out_value) const {
-  const DictionaryValue* attribute = nullptr;
-  if (!attributes_.GetDictionaryWithoutPathExpansion(name, &attribute))
-    return false;
-
-  if (!GetDictionaryValueAsCStr(attribute, "type", out_type))
-    return false;
-
-  if (!GetDictionaryValueAsCStr(attribute, "units", out_units))
-    return false;
-
-  if (!attribute->GetWithoutPathExpansion("value", out_value))
-    return false;
-
-  return true;
-}
-
-void MemoryAllocatorDump::AddScalar(const std::string& name,
+void MemoryAllocatorDump::AddScalar(const char* name,
                                     const char* units,
                                     uint64 value) {
-  scoped_ptr<Value> hex_value(new StringValue(StringPrintf("%" PRIx64, value)));
-  Add(name, kTypeScalar, units, hex_value.Pass());
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeScalar);
+  attributes_->SetString("units", units);
+  attributes_->SetString("value", StringPrintf("%" PRIx64, value));
+  attributes_->EndDictionary();
 }
 
-void MemoryAllocatorDump::AddScalarF(const std::string& name,
+void MemoryAllocatorDump::AddScalarF(const char* name,
                                      const char* units,
                                      double value) {
-  Add(name, kTypeScalar, units, make_scoped_ptr(new FundamentalValue(value)));
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeScalar);
+  attributes_->SetString("units", units);
+  attributes_->SetDouble("value", value);
+  attributes_->EndDictionary();
 }
 
-void MemoryAllocatorDump::AddString(const std::string& name,
+void MemoryAllocatorDump::AddString(const char* name,
                                     const char* units,
                                     const std::string& value) {
-  scoped_ptr<Value> str_value(new StringValue(value));
-  Add(name, kTypeString, units, str_value.Pass());
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeString);
+  attributes_->SetString("units", units);
+  attributes_->SetString("value", value);
+  attributes_->EndDictionary();
 }
 
 void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
-  value->BeginDictionary(absolute_name_.c_str());
+  value->BeginDictionaryWithCopiedName(absolute_name_);
   value->SetString("guid", guid_.ToString());
-
-  value->BeginDictionary("attrs");
-
-  for (DictionaryValue::Iterator it(attributes_); !it.IsAtEnd(); it.Advance())
-    value->SetValue(it.key().c_str(), it.value().CreateDeepCopy());
-
-  value->EndDictionary();  // "attrs": { ... }
+  value->SetValue("attrs", *attributes_);
   value->EndDictionary();  // "allocator_name/heap_subheap": { ... }
 }
 
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
index 9a151a6..d3b393be 100644
--- a/base/trace_event/memory_allocator_dump.h
+++ b/base/trace_event/memory_allocator_dump.h
@@ -8,6 +8,7 @@
 #include "base/base_export.h"
 #include "base/basictypes.h"
 #include "base/logging.h"
+#include "base/memory/ref_counted.h"
 #include "base/trace_event/memory_allocator_dump_guid.h"
 #include "base/values.h"
 
@@ -51,22 +52,10 @@
   // Absolute name, unique within the scope of an entire ProcessMemoryDump.
   const std::string& absolute_name() const { return absolute_name_; }
 
-  // Generic attribute setter / getter.
-  void Add(const std::string& name,
-           const char* type,
-           const char* units,
-           scoped_ptr<Value> value);
-  bool Get(const std::string& name,
-           const char** out_type,
-           const char** out_units,
-           const Value** out_value) const;
-
   // Helper setter for scalar attributes.
-  void AddScalar(const std::string& name, const char* units, uint64 value);
-  void AddScalarF(const std::string& name, const char* units, double value);
-  void AddString(const std::string& name,
-                 const char* units,
-                 const std::string& value);
+  void AddScalar(const char* name, const char* units, uint64 value);
+  void AddScalarF(const char* name, const char* units, double value);
+  void AddString(const char* name, const char* units, const std::string& value);
 
   // Called at trace generation time to populate the TracedValue.
   void AsValueInto(TracedValue* value) const;
@@ -84,10 +73,12 @@
   // expected to have the same guid.
   const MemoryAllocatorDumpGuid& guid() const { return guid_; }
 
+  TracedValue* attributes_for_testing() const { return attributes_.get(); }
+
  private:
   const std::string absolute_name_;
   ProcessMemoryDump* const process_memory_dump_;  // Not owned (PMD owns this).
-  DictionaryValue attributes_;
+  scoped_refptr<TracedValue> attributes_;
   MemoryAllocatorDumpGuid guid_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
index b9adbae..85b98d655 100644
--- a/base/trace_event/memory_allocator_dump_unittest.cc
+++ b/base/trace_event/memory_allocator_dump_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/trace_event/memory_dump_session_state.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -47,20 +48,23 @@
   }
 };
 
-bool CheckAttribute(const MemoryAllocatorDump* dump,
-                    const std::string& name,
-                    const char* expected_type,
-                    const char* expected_units,
-                    const Value** out_value) {
-  const char* attr_type;
-  const char* attr_units;
-  bool res = dump->Get(name, &attr_type, &attr_units, out_value);
-  EXPECT_TRUE(res);
-  if (!res)
-    return false;
-  EXPECT_EQ(expected_type, std::string(attr_type));
-  EXPECT_EQ(expected_units, std::string(attr_units));
-  return true;
+scoped_ptr<Value> CheckAttribute(const MemoryAllocatorDump* dump,
+                                 const std::string& name,
+                                 const char* expected_type,
+                                 const char* expected_units) {
+  scoped_ptr<Value> raw_attrs = dump->attributes_for_testing()->ToBaseValue();
+  DictionaryValue* args = nullptr;
+  DictionaryValue* arg = nullptr;
+  std::string arg_value;
+  const Value* out_value = nullptr;
+  EXPECT_TRUE(raw_attrs->GetAsDictionary(&args));
+  EXPECT_TRUE(args->GetDictionary(name, &arg));
+  EXPECT_TRUE(arg->GetString("type", &arg_value));
+  EXPECT_EQ(expected_type, arg_value);
+  EXPECT_TRUE(arg->GetString("units", &arg_value));
+  EXPECT_EQ(expected_units, arg_value);
+  EXPECT_TRUE(arg->Get("value", &out_value));
+  return out_value ? out_value->CreateDeepCopy() : scoped_ptr<Value>();
 }
 
 void CheckString(const MemoryAllocatorDump* dump,
@@ -68,12 +72,8 @@
                  const char* expected_type,
                  const char* expected_units,
                  const std::string& expected_value) {
-  const Value* attr_value = nullptr;
   std::string attr_str_value;
-  bool res =
-      CheckAttribute(dump, name, expected_type, expected_units, &attr_value);
-  if (!res)
-    return;
+  auto attr_value = CheckAttribute(dump, name, expected_type, expected_units);
   EXPECT_TRUE(attr_value->GetAsString(&attr_str_value));
   EXPECT_EQ(expected_value, attr_str_value);
 }
@@ -90,12 +90,9 @@
                   const std::string& name,
                   const char* expected_units,
                   double expected_value) {
-  const Value* attr_value = nullptr;
+  auto attr_value = CheckAttribute(dump, name, MemoryAllocatorDump::kTypeScalar,
+                                   expected_units);
   double attr_double_value;
-  bool res = CheckAttribute(dump, name, MemoryAllocatorDump::kTypeScalar,
-                            expected_units, &attr_value);
-  if (!res)
-    return;
   EXPECT_TRUE(attr_value->GetAsDouble(&attr_double_value));
   EXPECT_EQ(expected_value, attr_double_value);
 }
@@ -154,15 +151,15 @@
               MemoryAllocatorDump::kUnitsBytes, 1);
   CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectsCount,
               MemoryAllocatorDump::kUnitsObjects, 3);
-
   const MemoryAllocatorDump* empty_sub_heap =
       pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
   ASSERT_NE(nullptr, empty_sub_heap);
   EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
-  ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameSize, nullptr,
-                                   nullptr, nullptr));
-  ASSERT_FALSE(empty_sub_heap->Get(MemoryAllocatorDump::kNameObjectsCount,
-                                   nullptr, nullptr, nullptr));
+  auto raw_attrs = empty_sub_heap->attributes_for_testing()->ToBaseValue();
+  DictionaryValue* attrs = nullptr;
+  ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs));
+  ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameSize));
+  ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameObjectsCount));
 
   // Check that the AsValueInfo doesn't hit any DCHECK.
   scoped_refptr<TracedValue> traced_value(new TracedValue());
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 1e4d8229a..1771f341 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -64,8 +64,6 @@
 
 // Internal class used to hold details about ProcessMemoryDump requests for the
 // current process.
-// TODO(primiano): In the upcoming CLs, ProcessMemoryDump will become async.
-// and this class will be used to convey more details across PostTask()s.
 class ProcessMemoryDumpHolder
     : public RefCountedThreadSafe<ProcessMemoryDumpHolder> {
  public:
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
index b595004..82a87cc 100644
--- a/base/trace_event/trace_event.gypi
+++ b/base/trace_event/trace_event.gypi
@@ -39,6 +39,8 @@
       'trace_event/trace_event_impl_constants.cc',
       'trace_event/trace_event_memory.cc',
       'trace_event/trace_event_memory.h',
+      'trace_event/trace_event_memory_overhead.cc',
+      'trace_event/trace_event_memory_overhead.h',
       'trace_event/trace_event_synthetic_delay.cc',
       'trace_event/trace_event_synthetic_delay.h',
       'trace_event/trace_event_system_stats_monitor.cc',
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 6fdbf41c..c41ca1e 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -731,16 +731,12 @@
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
         category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
         arg2_name, arg2_val)
-// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 0,
-// 1, or 2 associated arguments. If the category is not enabled, then this does
+// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 0
+// or 2 associated arguments. If the category is not enabled, then this does
 // nothing.
 #define TRACE_EVENT_NESTABLE_ASYNC_END0(category_group, name, id) \
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
         category_group, name, id, TRACE_EVENT_FLAG_NONE)
-#define TRACE_EVENT_NESTABLE_ASYNC_END1(category_group, name, id, arg1_name, \
-        arg1_val) \
-    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
-        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
 #define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
         arg1_val, arg2_name, arg2_val) \
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
@@ -856,6 +852,9 @@
 #define TRACE_EVENT_FLOW_END0(category_group, name, id) \
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
         category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
 #define TRACE_EVENT_FLOW_END1(category_group, name, id, arg1_name, arg1_val) \
     INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
         category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
@@ -1142,6 +1141,7 @@
 #define TRACE_EVENT_FLAG_SCOPE_EXTRA  (static_cast<unsigned char>(1 << 4))
 #define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned char>(1 << 5))
 #define TRACE_EVENT_FLAG_ASYNC_TTS    (static_cast<unsigned char>(1 << 6))
+#define TRACE_EVENT_FLAG_BIND_TO_ENCLOSING (static_cast<unsigned char>(1 << 7))
 
 #define TRACE_EVENT_FLAG_SCOPE_MASK   (static_cast<unsigned char>( \
     TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA))
diff --git a/base/trace_event/trace_event_argument.cc b/base/trace_event/trace_event_argument.cc
index e83aa737..14504ac 100644
--- a/base/trace_event/trace_event_argument.cc
+++ b/base/trace_event/trace_event_argument.cc
@@ -5,112 +5,455 @@
 #include "base/trace_event/trace_event_argument.h"
 
 #include "base/json/json_writer.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
 #include "base/values.h"
 
 namespace base {
 namespace trace_event {
 
-TracedValue::TracedValue() : root_(new DictionaryValue()) {
-  stack_.push_back(root_.get());
+namespace {
+const char kTypeStartDict = '{';
+const char kTypeEndDict = '}';
+const char kTypeStartArray = '[';
+const char kTypeEndArray = ']';
+const char kTypeBool = 'b';
+const char kTypeInt = 'i';
+const char kTypeDouble = 'd';
+const char kTypeString = 's';
+const char kTypeCStr = '*';
+
+#ifndef NDEBUG
+const bool kStackTypeDict = false;
+const bool kStackTypeArray = true;
+#define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back())
+#define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size())
+#define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x)
+#define DEBUG_POP_CONTAINER() nesting_stack_.pop_back()
+#else
+#define DCHECK_CURRENT_CONTAINER_IS(x) do {} while (0)
+#define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) do {} while (0)
+#define DEBUG_PUSH_CONTAINER(x) do {} while (0)
+#define DEBUG_POP_CONTAINER() do {} while (0)
+#endif
+
+inline void WriteKeyNameAsRawPtr(Pickle& pickle, const char* ptr) {
+  pickle.WriteBytes(&kTypeCStr, 1);
+  pickle.WriteUInt64(static_cast<uint64>(reinterpret_cast<uintptr_t>(ptr)));
+}
+
+inline void WriteKeyNameAsStdString(Pickle& pickle, const std::string& str) {
+  pickle.WriteBytes(&kTypeString, 1);
+  pickle.WriteString(str);
+}
+
+std::string ReadKeyName(PickleIterator& pickle_iterator) {
+  const char* type = nullptr;
+  bool res = pickle_iterator.ReadBytes(&type, 1);
+  std::string key_name;
+  if (res && *type == kTypeCStr) {
+    uint64 ptr_value = 0;
+    res = pickle_iterator.ReadUInt64(&ptr_value);
+    key_name = reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value));
+  } else if (res && *type == kTypeString) {
+    res = pickle_iterator.ReadString(&key_name);
+  }
+  DCHECK(res);
+  return key_name;
+}
+}  // namespace
+
+TracedValue::TracedValue() : TracedValue(0) {
+}
+
+TracedValue::TracedValue(size_t capacity) {
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  if (capacity)
+    pickle_.Reserve(capacity);
 }
 
 TracedValue::~TracedValue() {
-  DCHECK_EQ(1u, stack_.size());
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_POP_CONTAINER();
+  DCHECK_CONTAINER_STACK_DEPTH_EQ(0u);
 }
 
 void TracedValue::SetInteger(const char* name, int value) {
-  GetCurrentDictionary()->SetInteger(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetIntegerWithCopiedName(const std::string& name, int value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
+  WriteKeyNameAsStdString(pickle_, name);
 }
 
 void TracedValue::SetDouble(const char* name, double value) {
-  GetCurrentDictionary()->SetDouble(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetDoubleWithCopiedName(const std::string& name,
+                                          double value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
+  WriteKeyNameAsStdString(pickle_, name);
 }
 
 void TracedValue::SetBoolean(const char* name, bool value) {
-  GetCurrentDictionary()->SetBoolean(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetBooleanWithCopiedName(const std::string& name,
+                                           bool value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
+  WriteKeyNameAsStdString(pickle_, name);
 }
 
 void TracedValue::SetString(const char* name, const std::string& value) {
-  GetCurrentDictionary()->SetString(name, value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
 }
 
-void TracedValue::SetValue(const char* name, scoped_ptr<Value> value) {
-  GetCurrentDictionary()->Set(name, value.Pass());
+void TracedValue::SetStringWithCopiedName(const std::string& name,
+                                          const std::string& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+  WriteKeyNameAsStdString(pickle_, name);
+}
+
+void TracedValue::SetValue(const char* name, const TracedValue& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  BeginDictionary(name);
+  pickle_.WriteBytes(value.pickle_.payload(),
+                     static_cast<int>(value.pickle_.payload_size()));
+  EndDictionary();
+}
+
+void TracedValue::SetValueWithCopiedName(const std::string& name,
+                                         const TracedValue& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  BeginDictionaryWithCopiedName(name);
+  pickle_.WriteBytes(value.pickle_.payload(),
+                     static_cast<int>(value.pickle_.payload_size()));
+  EndDictionary();
 }
 
 void TracedValue::BeginDictionary(const char* name) {
-  DictionaryValue* dictionary = new DictionaryValue();
-  GetCurrentDictionary()->Set(name, make_scoped_ptr(dictionary));
-  stack_.push_back(dictionary);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::BeginDictionaryWithCopiedName(const std::string& name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
+  WriteKeyNameAsStdString(pickle_, name);
 }
 
 void TracedValue::BeginArray(const char* name) {
-  ListValue* array = new ListValue();
-  GetCurrentDictionary()->Set(name, make_scoped_ptr(array));
-  stack_.push_back(array);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::BeginArrayWithCopiedName(const std::string& name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
+  WriteKeyNameAsStdString(pickle_, name);
 }
 
 void TracedValue::EndDictionary() {
-  DCHECK_GT(stack_.size(), 1u);
-  DCHECK(GetCurrentDictionary());
-  stack_.pop_back();
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_POP_CONTAINER();
+  pickle_.WriteBytes(&kTypeEndDict, 1);
 }
 
 void TracedValue::AppendInteger(int value) {
-  GetCurrentArray()->AppendInteger(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
 }
 
 void TracedValue::AppendDouble(double value) {
-  GetCurrentArray()->AppendDouble(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
 }
 
 void TracedValue::AppendBoolean(bool value) {
-  GetCurrentArray()->AppendBoolean(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
 }
 
 void TracedValue::AppendString(const std::string& value) {
-  GetCurrentArray()->AppendString(value);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
 }
 
 void TracedValue::BeginArray() {
-  ListValue* array = new ListValue();
-  GetCurrentArray()->Append(array);
-  stack_.push_back(array);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
 }
 
 void TracedValue::BeginDictionary() {
-  DictionaryValue* dictionary = new DictionaryValue();
-  GetCurrentArray()->Append(dictionary);
-  stack_.push_back(dictionary);
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
 }
 
 void TracedValue::EndArray() {
-  DCHECK_GT(stack_.size(), 1u);
-  DCHECK(GetCurrentArray());
-  stack_.pop_back();
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_POP_CONTAINER();
+  pickle_.WriteBytes(&kTypeEndArray, 1);
 }
 
-DictionaryValue* TracedValue::GetCurrentDictionary() {
-  DCHECK(!stack_.empty());
-  DictionaryValue* dictionary = NULL;
-  stack_.back()->GetAsDictionary(&dictionary);
-  DCHECK(dictionary);
-  return dictionary;
+void TracedValue::SetValue(const char* name, scoped_ptr<base::Value> value) {
+  SetBaseValueWithCopiedName(name, *value);
 }
 
-ListValue* TracedValue::GetCurrentArray() {
-  DCHECK(!stack_.empty());
-  ListValue* list = NULL;
-  stack_.back()->GetAsList(&list);
-  DCHECK(list);
-  return list;
+void TracedValue::SetBaseValueWithCopiedName(const std::string& name,
+                                             const base::Value& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  switch (value.GetType()) {
+    case base::Value::TYPE_NULL:
+    case base::Value::TYPE_BINARY:
+      NOTREACHED();
+      break;
+
+    case base::Value::TYPE_BOOLEAN: {
+      bool bool_value;
+      value.GetAsBoolean(&bool_value);
+      SetBooleanWithCopiedName(name, bool_value);
+    } break;
+
+    case base::Value::TYPE_INTEGER: {
+      int int_value;
+      value.GetAsInteger(&int_value);
+      SetIntegerWithCopiedName(name, int_value);
+    } break;
+
+    case base::Value::TYPE_DOUBLE: {
+      double double_value;
+      value.GetAsDouble(&double_value);
+      SetDoubleWithCopiedName(name, double_value);
+    } break;
+
+    case base::Value::TYPE_STRING: {
+      const StringValue* string_value;
+      value.GetAsString(&string_value);
+      SetStringWithCopiedName(name, string_value->GetString());
+    } break;
+
+    case base::Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dict_value;
+      value.GetAsDictionary(&dict_value);
+      BeginDictionaryWithCopiedName(name);
+      for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
+           it.Advance()) {
+        SetBaseValueWithCopiedName(it.key(), it.value());
+      }
+      EndDictionary();
+    } break;
+
+    case base::Value::TYPE_LIST: {
+      const ListValue* list_value;
+      value.GetAsList(&list_value);
+      BeginArrayWithCopiedName(name);
+      for (base::Value* base_value : *list_value)
+        AppendBaseValue(*base_value);
+      EndArray();
+    } break;
+  }
+}
+
+void TracedValue::AppendBaseValue(const base::Value& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  switch (value.GetType()) {
+    case base::Value::TYPE_NULL:
+    case base::Value::TYPE_BINARY:
+      NOTREACHED();
+      break;
+
+    case base::Value::TYPE_BOOLEAN: {
+      bool bool_value;
+      value.GetAsBoolean(&bool_value);
+      AppendBoolean(bool_value);
+    } break;
+
+    case base::Value::TYPE_INTEGER: {
+      int int_value;
+      value.GetAsInteger(&int_value);
+      AppendInteger(int_value);
+    } break;
+
+    case base::Value::TYPE_DOUBLE: {
+      double double_value;
+      value.GetAsDouble(&double_value);
+      AppendDouble(double_value);
+    } break;
+
+    case base::Value::TYPE_STRING: {
+      const StringValue* string_value;
+      value.GetAsString(&string_value);
+      AppendString(string_value->GetString());
+    } break;
+
+    case base::Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dict_value;
+      value.GetAsDictionary(&dict_value);
+      BeginDictionary();
+      for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
+           it.Advance()) {
+        SetBaseValueWithCopiedName(it.key(), it.value());
+      }
+      EndDictionary();
+    } break;
+
+    case base::Value::TYPE_LIST: {
+      const ListValue* list_value;
+      value.GetAsList(&list_value);
+      BeginArray();
+      for (base::Value* base_value : *list_value)
+        AppendBaseValue(*base_value);
+      EndArray();
+    } break;
+  }
+}
+
+scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
+  scoped_ptr<DictionaryValue> root(new DictionaryValue);
+  DictionaryValue* cur_dict = root.get();
+  ListValue* cur_list = nullptr;
+  std::vector<Value*> stack;
+  PickleIterator it(pickle_);
+  const char* type;
+
+  while (it.ReadBytes(&type, 1)) {
+    DCHECK((cur_dict && !cur_list) || (cur_list && !cur_dict));
+    switch (*type) {
+      case kTypeStartDict: {
+        auto new_dict = new DictionaryValue();
+        if (cur_dict) {
+          cur_dict->Set(ReadKeyName(it), make_scoped_ptr(new_dict));
+          stack.push_back(cur_dict);
+          cur_dict = new_dict;
+        } else {
+          cur_list->Append(make_scoped_ptr(new_dict));
+          stack.push_back(cur_list);
+          cur_list = nullptr;
+          cur_dict = new_dict;
+        }
+      } break;
+
+      case kTypeEndArray:
+      case kTypeEndDict: {
+        if (stack.back()->GetAsDictionary(&cur_dict)) {
+          cur_list = nullptr;
+        } else if (stack.back()->GetAsList(&cur_list)) {
+          cur_dict = nullptr;
+        }
+        stack.pop_back();
+      } break;
+
+      case kTypeStartArray: {
+        auto new_list = new ListValue();
+        if (cur_dict) {
+          cur_dict->Set(ReadKeyName(it), make_scoped_ptr(new_list));
+          stack.push_back(cur_dict);
+          cur_dict = nullptr;
+          cur_list = new_list;
+        } else {
+          cur_list->Append(make_scoped_ptr(new_list));
+          stack.push_back(cur_list);
+          cur_list = new_list;
+        }
+      } break;
+
+      case kTypeBool: {
+        bool value;
+        CHECK(it.ReadBool(&value));
+        if (cur_dict) {
+          cur_dict->SetBoolean(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendBoolean(value);
+        }
+      } break;
+
+      case kTypeInt: {
+        int value;
+        CHECK(it.ReadInt(&value));
+        if (cur_dict) {
+          cur_dict->SetInteger(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendInteger(value);
+        }
+      } break;
+
+      case kTypeDouble: {
+        double value;
+        CHECK(it.ReadDouble(&value));
+        if (cur_dict) {
+          cur_dict->SetDouble(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendDouble(value);
+        }
+      } break;
+
+      case kTypeString: {
+        std::string value;
+        CHECK(it.ReadString(&value));
+        if (cur_dict) {
+          cur_dict->SetString(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendString(value);
+        }
+      } break;
+
+      default:
+        NOTREACHED();
+    }
+  }
+  DCHECK(stack.empty());
+  return root.Pass();
 }
 
 void TracedValue::AppendAsTraceFormat(std::string* out) const {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DCHECK_CONTAINER_STACK_DEPTH_EQ(1u);
+
+  // TODO(primiano): this could be smarter, skip the ToBaseValue encoding and
+  // produce the JSON on its own. This will require refactoring JSONWriter
+  // to decouple the base::Value traversal from the JSON writing bits
   std::string tmp;
-  JSONWriter::Write(*stack_.front(), &tmp);
+  JSONWriter::Write(*ToBaseValue(), &tmp);
   *out += tmp;
-  DCHECK_EQ(1u, stack_.size()) << tmp;
+}
+
+void TracedValue::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  overhead->Add("TracedValue", pickle_.GetTotalAllocatedSize());
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/trace_event_argument.h b/base/trace_event/trace_event_argument.h
index 56f7c61..aab58bc 100644
--- a/base/trace_event/trace_event_argument.h
+++ b/base/trace_event/trace_event_argument.h
@@ -9,11 +9,11 @@
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
 #include "base/trace_event/trace_event.h"
 
 namespace base {
-class DictionaryValue;
-class ListValue;
+
 class Value;
 
 namespace trace_event {
@@ -21,18 +21,31 @@
 class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
  public:
   TracedValue();
+  explicit TracedValue(size_t capacity);
 
   void EndDictionary();
   void EndArray();
 
+  // These methods assume that |name| is a long lived "quoted" string.
   void SetInteger(const char* name, int value);
   void SetDouble(const char* name, double value);
   void SetBoolean(const char* name, bool value);
   void SetString(const char* name, const std::string& value);
-  void SetValue(const char* name, scoped_ptr<Value> value);
+  void SetValue(const char* name, const TracedValue& value);
   void BeginDictionary(const char* name);
   void BeginArray(const char* name);
 
+  // These, instead, can be safely passed a temporary string.
+  void SetIntegerWithCopiedName(const std::string& name, int value);
+  void SetDoubleWithCopiedName(const std::string& name, double value);
+  void SetBooleanWithCopiedName(const std::string& name, bool value);
+  void SetStringWithCopiedName(const std::string& name,
+                               const std::string& value);
+  void SetValueWithCopiedName(const std::string& name,
+                              const TracedValue& value);
+  void BeginDictionaryWithCopiedName(const std::string& name);
+  void BeginArrayWithCopiedName(const std::string& name);
+
   void AppendInteger(int);
   void AppendDouble(double);
   void AppendBoolean(bool);
@@ -40,16 +53,33 @@
   void BeginArray();
   void BeginDictionary();
 
+  // ConvertableToTraceFormat implementation.
   void AppendAsTraceFormat(std::string* out) const override;
 
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+  // DEPRECATED: do not use, here only for legacy reasons. These methods causes
+  // a copy-and-translation of the base::Value into the equivalent TracedValue.
+  // TODO(primiano): migrate the (three) existing clients to the cheaper
+  // SetValue(TracedValue) API. crbug.com/495628.
+  void SetValue(const char* name, scoped_ptr<base::Value> value);
+  void SetBaseValueWithCopiedName(const std::string& name,
+                                  const base::Value& value);
+  void AppendBaseValue(const base::Value& value);
+
+  // Public for tests only.
+  scoped_ptr<base::Value> ToBaseValue() const;
+
  private:
   ~TracedValue() override;
 
-  DictionaryValue* GetCurrentDictionary();
-  ListValue* GetCurrentArray();
+  Pickle pickle_;
 
-  scoped_ptr<base::Value> root_;
-  std::vector<Value*> stack_;  // Weak references.
+#ifndef NDEBUG
+  // In debug builds checks the pairings of {Start,End}{Dictionary,Array}
+  std::vector<bool> nesting_stack_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(TracedValue);
 };
 
diff --git a/base/trace_event/trace_event_argument_unittest.cc b/base/trace_event/trace_event_argument_unittest.cc
index c59910e..cb1cf2e 100644
--- a/base/trace_event/trace_event_argument_unittest.cc
+++ b/base/trace_event/trace_event_argument_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -14,10 +15,11 @@
   value->SetDouble("double", 0.0);
   value->SetBoolean("bool", true);
   value->SetString("string", "string");
-  std::string json;
+  std::string json = "PREFIX";
   value->AppendAsTraceFormat(&json);
-  EXPECT_EQ("{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\"}",
-            json);
+  EXPECT_EQ(
+      "PREFIX{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\"}",
+      json);
 }
 
 TEST(TraceEventArgumentTest, Hierarchy) {
@@ -49,5 +51,96 @@
       json);
 }
 
+TEST(TraceEventArgumentTest, LongStrings) {
+  std::string kLongString = "supercalifragilisticexpialidocious";
+  std::string kLongString2 = "0123456789012345678901234567890123456789";
+  char kLongString3[4096];
+  for (size_t i = 0; i < sizeof(kLongString3); ++i)
+    kLongString3[i] = 'a' + (i % 25);
+  kLongString3[sizeof(kLongString3) - 1] = '\0';
+
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->SetString("a", "short");
+  value->SetString("b", kLongString);
+  value->BeginArray("c");
+  value->AppendString(kLongString2);
+  value->AppendString("");
+  value->BeginDictionary();
+  value->SetString("a", kLongString3);
+  value->EndDictionary();
+  value->EndArray();
+
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"a\":\"short\",\"b\":\"" + kLongString + "\",\"c\":[\"" +
+                kLongString2 + "\",\"\",{\"a\":\"" + kLongString3 + "\"}]}",
+            json);
+}
+
+TEST(TraceEventArgumentTest, PassBaseValue) {
+  FundamentalValue int_value(42);
+  FundamentalValue bool_value(true);
+  FundamentalValue double_value(42.0f);
+
+  auto dict_value = make_scoped_ptr(new DictionaryValue);
+  dict_value->SetBoolean("bool", true);
+  dict_value->SetInteger("int", 42);
+  dict_value->SetDouble("double", 42.0f);
+  dict_value->SetString("string", std::string("a") + "b");
+  dict_value->SetString("string", std::string("a") + "b");
+
+  auto list_value = make_scoped_ptr(new ListValue);
+  list_value->AppendBoolean(false);
+  list_value->AppendInteger(1);
+  list_value->AppendString("in_list");
+  list_value->Append(dict_value.Pass());
+
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->BeginDictionary("outer_dict");
+  value->SetValue("inner_list", list_value.Pass());
+  value->EndDictionary();
+
+  dict_value.reset();
+  list_value.reset();
+
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ(
+      "{\"outer_dict\":{\"inner_list\":[false,1,\"in_list\",{\"bool\":true,"
+      "\"double\":42.0,\"int\":42,\"string\":\"ab\"}]}}",
+      json);
+}
+
+TEST(TraceEventArgumentTest, PassTracedValue) {
+  auto dict_value = make_scoped_refptr(new TracedValue);
+  dict_value->SetInteger("a", 1);
+
+  auto nested_dict_value = make_scoped_refptr(new TracedValue);
+  nested_dict_value->SetInteger("b", 2);
+  nested_dict_value->BeginArray("c");
+  nested_dict_value->AppendString("foo");
+  nested_dict_value->EndArray();
+
+  dict_value->SetValue("e", *nested_dict_value);
+
+  // Check the merged result.
+  std::string json;
+  dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"a\":1,\"e\":{\"b\":2,\"c\":[\"foo\"]}}", json);
+
+  // Check that the passed nestd dict was left unouthced.
+  json = "";
+  nested_dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"]}", json);
+
+  // And that it is still usable.
+  nested_dict_value->SetInteger("f", 3);
+  nested_dict_value->BeginDictionary("g");
+  nested_dict_value->EndDictionary();
+  json = "";
+  nested_dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"],\"f\":3,\"g\":{}}", json);
+}
+
 }  // namespace trace_event
 }  // namespace base
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index 3d58d87..b5d4298 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -33,6 +33,9 @@
 #include "base/threading/thread_id_name_manager.h"
 #include "base/threading/worker_pool.h"
 #include "base/time/time.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_synthetic_delay.h"
 
@@ -214,6 +217,18 @@
     return cloned_buffer.Pass();
   }
 
+  void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) override {
+    overhead->Add("TraceBufferRingBuffer", sizeof(*this));
+    for (size_t queue_index = queue_head_; queue_index != queue_tail_;
+         queue_index = NextQueueIndex(queue_index)) {
+      size_t chunk_index = recyclable_chunks_queue_[queue_index];
+      if (chunk_index >= chunks_.size())  // Skip uninitialized chunks.
+        continue;
+      chunks_[chunk_index]->EstimateTraceMemoryOverhead(overhead);
+    }
+  }
+
  private:
   class ClonedTraceBuffer : public TraceBuffer {
    public:
@@ -242,6 +257,10 @@
       NOTIMPLEMENTED();
       return scoped_ptr<TraceBuffer>();
     }
+    void EstimateTraceMemoryOverhead(
+        TraceEventMemoryOverhead* overhead) override {
+      NOTIMPLEMENTED();
+    }
 
     size_t current_iteration_index_;
     ScopedVector<TraceBufferChunk> chunks_;
@@ -350,6 +369,18 @@
     return scoped_ptr<TraceBuffer>();
   }
 
+  void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) override {
+    // Skip the in-flight chunks owned by the threads. They will be accounted
+    // by the per-thread-local dumper, see ThreadLocalEventBuffer::OnMemoryDump.
+    overhead->Add("TraceBufferVector", sizeof(*this));
+    for (size_t i = 0; i < chunks_.size(); ++i) {
+      TraceBufferChunk* chunk = chunks_[i];
+      if (chunk)
+        chunk->EstimateTraceMemoryOverhead(overhead);
+    }
+  }
+
  private:
   size_t in_flight_chunk_count_;
   size_t current_iteration_index_;
@@ -398,11 +429,18 @@
 
 }  // namespace
 
+TraceBufferChunk::TraceBufferChunk(uint32 seq) : next_free_(0), seq_(seq) {
+}
+
+TraceBufferChunk::~TraceBufferChunk() {
+}
+
 void TraceBufferChunk::Reset(uint32 new_seq) {
   for (size_t i = 0; i < next_free_; ++i)
     chunk_[i].Reset();
   next_free_ = 0;
   seq_ = new_seq;
+  cached_overhead_estimate_when_full_.reset();
 }
 
 TraceEvent* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
@@ -419,6 +457,31 @@
   return cloned_chunk.Pass();
 }
 
+void TraceBufferChunk::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  if (cached_overhead_estimate_when_full_) {
+    DCHECK(IsFull());
+    overhead->Update(*cached_overhead_estimate_when_full_);
+    return;
+  }
+
+  // Cache the memory overhead estimate only if the chunk is full.
+  TraceEventMemoryOverhead* estimate = overhead;
+  if (IsFull()) {
+    cached_overhead_estimate_when_full_.reset(new TraceEventMemoryOverhead);
+    estimate = cached_overhead_estimate_when_full_.get();
+  }
+
+  estimate->Add("TraceBufferChunk", sizeof(*this));
+  for (size_t i = 0; i < next_free_; ++i)
+    chunk_[i].EstimateTraceMemoryOverhead(estimate);
+
+  if (IsFull()) {
+    estimate->AddSelf();
+    overhead->Update(*estimate);
+  }
+}
+
 // A helper class that allows the lock to be acquired in the middle of the scope
 // and unlocks at the end of scope if locked.
 class TraceLog::OptionalAutoLock {
@@ -610,6 +673,7 @@
   parameter_copy_storage_ = NULL;
   for (int i = 0; i < kTraceMaxNumArgs; ++i)
     convertable_values_[i] = NULL;
+  cached_memory_overhead_estimate_.reset();
 }
 
 void TraceEvent::UpdateDuration(const TraceTicks& now,
@@ -619,6 +683,29 @@
   thread_duration_ = thread_now - thread_timestamp_;
 }
 
+void TraceEvent::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  if (!cached_memory_overhead_estimate_) {
+    cached_memory_overhead_estimate_.reset(new TraceEventMemoryOverhead);
+    cached_memory_overhead_estimate_->Add("TraceEvent", sizeof(*this));
+    // TODO(primiano): parameter_copy_storage_ is refcounted and, in theory,
+    // could be shared by several events and we might overcount. In practice
+    // this is unlikely but it's worth checking.
+    if (parameter_copy_storage_) {
+      cached_memory_overhead_estimate_->AddRefCountedString(
+          *parameter_copy_storage_.get());
+    }
+    for (size_t i = 0; i < kTraceMaxNumArgs; ++i) {
+      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+        convertable_values_[i]->EstimateTraceMemoryOverhead(
+            cached_memory_overhead_estimate_.get());
+      }
+    }
+    cached_memory_overhead_estimate_->AddSelf();
+  }
+  overhead->Update(*cached_memory_overhead_estimate_);
+}
+
 // static
 void TraceEvent::AppendValueAsJSON(unsigned char type,
                                    TraceEvent::TraceValue value,
@@ -697,34 +784,34 @@
   DCHECK(!strchr(name_, '"'));
   StringAppendF(out, "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64
                      ","
-                     "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":{",
+                     "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":",
                 process_id, thread_id_, time_int64, phase_, category_group_name,
                 name_);
 
   // Output argument names and values, stop at first NULL argument name.
-  if (arg_names_[0]) {
-    bool allow_args = argument_filter_predicate.is_null() ||
-                      argument_filter_predicate.Run(category_group_name, name_);
+  bool strip_args = arg_names_[0] && !argument_filter_predicate.is_null() &&
+                    !argument_filter_predicate.Run(category_group_name, name_);
 
-    if (allow_args) {
-      for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
-        if (i > 0)
-          *out += ",";
-        *out += "\"";
-        *out += arg_names_[i];
-        *out += "\":";
+  if (strip_args) {
+    *out += "\"__stripped__\"";
+  } else {
+    *out += "{";
 
-        if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
-          convertable_values_[i]->AppendAsTraceFormat(out);
-        else
-          AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
-      }
-    } else {
-      *out += "\"stripped\":1";
+    for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+      if (i > 0)
+        *out += ",";
+      *out += "\"";
+      *out += arg_names_[i];
+      *out += "\":";
+
+      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+        convertable_values_[i]->AppendAsTraceFormat(out);
+      else
+        AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
     }
-  }
 
-  *out += "}";
+    *out += "}";
+  }
 
   if (phase_ == TRACE_EVENT_PHASE_COMPLETE) {
     int64 duration = duration_.ToInternalValue();
@@ -753,6 +840,9 @@
   if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
     StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64>(id_));
 
+  if (flags_ & TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
+    StringAppendF(out, ",\"bp\":\"e\"");
+
   // Instant events also output their scope.
   if (phase_ == TRACE_EVENT_PHASE_INSTANT) {
     char scope = '?';
@@ -984,7 +1074,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 class TraceLog::ThreadLocalEventBuffer
-    : public MessageLoop::DestructionObserver {
+    : public MessageLoop::DestructionObserver,
+      public MemoryDumpProvider {
  public:
   ThreadLocalEventBuffer(TraceLog* trace_log);
   ~ThreadLocalEventBuffer() override;
@@ -1008,6 +1099,9 @@
   // MessageLoop::DestructionObserver
   void WillDestroyCurrentMessageLoop() override;
 
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
   void FlushWhileLocked();
 
   void CheckThisIsCurrentBuffer() const {
@@ -1036,6 +1130,10 @@
   MessageLoop* message_loop = MessageLoop::current();
   message_loop->AddDestructionObserver(this);
 
+  // This is to report the local memory usage when memory-infra is enabled.
+  MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+      this, ThreadTaskRunnerHandle::Get());
+
   AutoLock lock(trace_log->lock_);
   trace_log->thread_message_loops_.insert(message_loop);
 }
@@ -1043,6 +1141,7 @@
 TraceLog::ThreadLocalEventBuffer::~ThreadLocalEventBuffer() {
   CheckThisIsCurrentBuffer();
   MessageLoop::current()->RemoveDestructionObserver(this);
+  MemoryDumpManager::GetInstance()->UnregisterDumpProvider(this);
 
   // Zero event_count_ happens in either of the following cases:
   // - no event generated for the thread;
@@ -1119,6 +1218,17 @@
   delete this;
 }
 
+bool TraceLog::ThreadLocalEventBuffer::OnMemoryDump(ProcessMemoryDump* pmd) {
+  if (!chunk_)
+    return true;
+  std::string dump_base_name = StringPrintf(
+      "tracing/thread_%d", static_cast<int>(PlatformThread::CurrentId()));
+  TraceEventMemoryOverhead overhead;
+  chunk_->EstimateTraceMemoryOverhead(&overhead);
+  overhead.DumpInto(dump_base_name.c_str(), pmd);
+  return true;
+}
+
 void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
   if (!chunk_)
     return;
@@ -1195,11 +1305,23 @@
 #endif
 
   logged_events_.reset(CreateTraceBuffer());
+
+  MemoryDumpManager::GetInstance()->RegisterDumpProvider(this);
 }
 
 TraceLog::~TraceLog() {
 }
 
+bool TraceLog::OnMemoryDump(ProcessMemoryDump* pmd) {
+  TraceEventMemoryOverhead overhead;
+  overhead.Add("TraceLog", sizeof(*this));
+  if (logged_events_)
+    logged_events_->EstimateTraceMemoryOverhead(&overhead);
+  overhead.AddSelf();
+  overhead.DumpInto("tracing/main_trace_log", pmd);
+  return true;
+}
+
 const unsigned char* TraceLog::GetCategoryGroupEnabled(
     const char* category_group) {
   TraceLog* tracelog = GetInstance();
@@ -2334,6 +2456,11 @@
   }
 }
 
+void ConvertableToTraceFormat::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  overhead->Add("ConvertableToTraceFormat(Unknown)", sizeof(*this));
+}
+
 }  // namespace trace_event
 }  // namespace base
 
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
index 7fdc5e3..503a69d5 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -24,7 +24,9 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_local.h"
+#include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
 
 // Older style trace macros with explicit id and extra data
 // Only these macros result in publishing data to ETW as currently implemented.
@@ -65,6 +67,8 @@
   // appended.
   virtual void AppendAsTraceFormat(std::string* out) const = 0;
 
+  virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
   std::string ToString() const {
     std::string result;
     AppendAsTraceFormat(&result);
@@ -123,6 +127,8 @@
 
   void UpdateDuration(const TraceTicks& now, const ThreadTicks& thread_now);
 
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead*);
+
   // Serialize event data to JSON
   typedef base::Callback<bool(const char* category_group_name,
                               const char* event_name)> ArgumentFilterPredicate;
@@ -168,6 +174,7 @@
   TimeDelta thread_duration_;
   // id_ can be used to store phase-specific data.
   unsigned long long id_;
+  scoped_ptr<TraceEventMemoryOverhead> cached_memory_overhead_estimate_;
   TraceValue arg_values_[kTraceMaxNumArgs];
   const char* arg_names_[kTraceMaxNumArgs];
   scoped_refptr<ConvertableToTraceFormat> convertable_values_[kTraceMaxNumArgs];
@@ -185,10 +192,8 @@
 // TraceBufferChunk is the basic unit of TraceBuffer.
 class BASE_EXPORT TraceBufferChunk {
  public:
-  explicit TraceBufferChunk(uint32 seq)
-      : next_free_(0),
-        seq_(seq) {
-  }
+  explicit TraceBufferChunk(uint32 seq);
+  ~TraceBufferChunk();
 
   void Reset(uint32 new_seq);
   TraceEvent* AddTraceEvent(size_t* event_index);
@@ -209,10 +214,13 @@
 
   scoped_ptr<TraceBufferChunk> Clone() const;
 
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
   static const size_t kTraceBufferChunkSize = 64;
 
  private:
   size_t next_free_;
+  scoped_ptr<TraceEventMemoryOverhead> cached_overhead_estimate_when_full_;
   TraceEvent chunk_[kTraceBufferChunkSize];
   uint32 seq_;
 };
@@ -235,6 +243,11 @@
   virtual const TraceBufferChunk* NextChunk() = 0;
 
   virtual scoped_ptr<TraceBuffer> CloneForIteration() const = 0;
+
+  // Computes an estimate of the size of the buffer, including all the retained
+  // objects.
+  virtual void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) = 0;
 };
 
 // TraceResultBuffer collects and converts trace fragments returned by TraceLog
@@ -289,7 +302,7 @@
   size_t event_count;
 };
 
-class BASE_EXPORT TraceLog {
+class BASE_EXPORT TraceLog : public MemoryDumpProvider {
  public:
   enum Mode {
     DISABLED = 0,
@@ -365,6 +378,10 @@
   TraceLogStatus GetStatus() const;
   bool BufferIsFull() const;
 
+  // Computes an estimate of the size of the TraceLog including all the retained
+  // objects.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
   // Not using base::Callback because of its limited by 7 parameters.
   // Also, using primitive type allows directly passing callback from WebCore.
   // WARNING: It is possible for the previously set callback to be called
@@ -528,6 +545,9 @@
   // by the Singleton class.
   friend struct DefaultSingletonTraits<TraceLog>;
 
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
   // Enable/disable each category group based on the current mode_,
   // category_filter_, event_callback_ and event_callback_category_filter_.
   // Enable the category group in the enabled mode if category_filter_ matches
@@ -547,7 +567,7 @@
   class OptionalAutoLock;
 
   TraceLog();
-  ~TraceLog();
+  ~TraceLog() override;
   const unsigned char* GetCategoryGroupEnabledInternal(const char* name);
   void AddMetadataEventsWhileLocked();
 
diff --git a/base/trace_event/trace_event_memory_overhead.cc b/base/trace_event/trace_event_memory_overhead.cc
new file mode 100644
index 0000000..a6369fef
--- /dev/null
+++ b/base/trace_event/trace_event_memory_overhead.cc
@@ -0,0 +1,137 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+#include <algorithm>
+
+#include "base/memory/ref_counted_memory.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/values.h"
+
+namespace {
+size_t RoundUp(size_t size, size_t alignment) {
+  return (size + alignment - 1) & ~(alignment - 1);
+}
+}  // namespace
+
+namespace base {
+namespace trace_event {
+
+TraceEventMemoryOverhead::TraceEventMemoryOverhead() {
+}
+
+TraceEventMemoryOverhead::~TraceEventMemoryOverhead() {
+}
+
+void TraceEventMemoryOverhead::AddOrCreateInternal(const char* object_type,
+                                                   size_t count,
+                                                   size_t size_in_bytes) {
+  auto it = allocated_objects_.find(object_type);
+  if (it == allocated_objects_.end()) {
+    allocated_objects_.insert(std::make_pair(
+        object_type, ObjectCountAndSize({count, size_in_bytes})));
+    return;
+  }
+  it->second.count += count;
+  it->second.size_in_bytes += size_in_bytes;
+}
+
+void TraceEventMemoryOverhead::Add(const char* object_type,
+                                   size_t size_in_bytes) {
+  AddOrCreateInternal(object_type, 1 /* count */, size_in_bytes);
+}
+
+void TraceEventMemoryOverhead::AddString(const std::string& str) {
+  // The number below are empirical and mainly based on profiling of real-world
+  // std::string implementations:
+  //  - even short string end up malloc()-inc at least 32 bytes.
+  //  - longer stings seem to malloc() multiples of 16 bytes.
+  Add("std::string",
+      sizeof(std::string) + std::max<size_t>(RoundUp(str.capacity(), 16), 32u));
+}
+
+void TraceEventMemoryOverhead::AddRefCountedString(
+    const RefCountedString& str) {
+  Add("RefCountedString", sizeof(RefCountedString));
+  AddString(str.data());
+}
+
+void TraceEventMemoryOverhead::AddValue(const Value& value) {
+  switch (value.GetType()) {
+    case Value::TYPE_NULL:
+    case Value::TYPE_BOOLEAN:
+    case Value::TYPE_INTEGER:
+    case Value::TYPE_DOUBLE:
+      Add("FundamentalValue", sizeof(Value));
+      break;
+
+    case Value::TYPE_STRING: {
+      const StringValue* string_value = nullptr;
+      value.GetAsString(&string_value);
+      Add("StringValue", sizeof(StringValue));
+      AddString(string_value->GetString());
+    } break;
+
+    case Value::TYPE_BINARY: {
+      const BinaryValue* binary_value = nullptr;
+      value.GetAsBinary(&binary_value);
+      Add("BinaryValue", sizeof(BinaryValue) + binary_value->GetSize());
+    } break;
+
+    case Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dictionary_value = nullptr;
+      value.GetAsDictionary(&dictionary_value);
+      Add("DictionaryValue", sizeof(DictionaryValue));
+      for (DictionaryValue::Iterator it(*dictionary_value); !it.IsAtEnd();
+           it.Advance()) {
+        AddString(it.key());
+        AddValue(it.value());
+      }
+    } break;
+
+    case Value::TYPE_LIST: {
+      const ListValue* list_value = nullptr;
+      value.GetAsList(&list_value);
+      Add("ListValue", sizeof(ListValue));
+      for (const Value* v : *list_value)
+        AddValue(*v);
+    } break;
+
+    default:
+      NOTREACHED();
+  }
+}
+
+void TraceEventMemoryOverhead::AddSelf() {
+  const size_t num_buckets = allocated_objects_.UsingFullMap()
+                                 ? (allocated_objects_.size() + 1)
+                                 : TRACE_EVENT_MEMORY_OVERHEAD_MAP_SIZE;
+  size_t estimated_size = sizeof(*this);
+  estimated_size += sizeof(map_type::value_type) * num_buckets;
+  Add("TraceEventMemoryOverhead", estimated_size);
+}
+
+void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) {
+  for (const auto& it : other.allocated_objects_) {
+    AddOrCreateInternal(it.first, it.second.count, it.second.size_in_bytes);
+  }
+}
+
+void TraceEventMemoryOverhead::DumpInto(const char* base_name,
+                                        ProcessMemoryDump* pmd) const {
+  for (const auto& it : allocated_objects_) {
+    std::string dump_name = StringPrintf("%s/%s", base_name, it.first);
+    MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name);
+    mad->AddScalar(MemoryAllocatorDump::kNameSize,
+                   MemoryAllocatorDump::kUnitsBytes, it.second.size_in_bytes);
+    mad->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                   MemoryAllocatorDump::kUnitsObjects, it.second.count);
+  }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_memory_overhead.h b/base/trace_event/trace_event_memory_overhead.h
new file mode 100644
index 0000000..99a8beb
--- /dev/null
+++ b/base/trace_event/trace_event_memory_overhead.h
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/small_map.h"
+
+namespace base {
+
+class RefCountedString;
+class Value;
+
+namespace trace_event {
+
+class ProcessMemoryDump;
+
+// Used to estimate the memory overhead of the tracing infrastructure.
+class BASE_EXPORT TraceEventMemoryOverhead {
+ public:
+  TraceEventMemoryOverhead();
+  ~TraceEventMemoryOverhead();
+
+  void Add(const char* object_type, size_t size_in_bytes);
+  void AddString(const std::string& str);
+  void AddValue(const Value& value);
+  void AddRefCountedString(const RefCountedString& str);
+
+  // Call this after all the Add* methods above to account the memory used by
+  // this TraceEventMemoryOverhead instance itself.
+  void AddSelf();
+
+  // Adds up and merges all the values from |other| to this instance.
+  void Update(const TraceEventMemoryOverhead& other);
+
+  void DumpInto(const char* base_name, ProcessMemoryDump* pmd) const;
+
+ private:
+  struct ObjectCountAndSize {
+    size_t count;
+    size_t size_in_bytes;
+  };
+#define TRACE_EVENT_MEMORY_OVERHEAD_MAP_SIZE 16
+  using map_type = SmallMap<hash_map<const char*, ObjectCountAndSize>,
+                            TRACE_EVENT_MEMORY_OVERHEAD_MAP_SIZE>;
+  map_type allocated_objects_;
+
+  void AddOrCreateInternal(const char* object_type,
+                           size_t count,
+                           size_t size_in_bytes);
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventMemoryOverhead);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index 2449d54..796c386 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -47,6 +47,8 @@
 const char kAsyncIdStr[] = "0x5";
 const int kAsyncId2 = 6;
 const char kAsyncId2Str[] = "0x6";
+const int kFlowId = 7;
+const char kFlowIdStr[] = "0x7";
 
 const  char kRecordAllCategoryFilter[] = "*";
 
@@ -430,6 +432,12 @@
                            "name1", "value1",
                            "name2", "value2");
 
+    TRACE_EVENT_FLOW_BEGIN0("all", "TRACE_EVENT_FLOW_BEGIN0 call", kFlowId);
+    TRACE_EVENT_FLOW_STEP0("all", "TRACE_EVENT_FLOW_STEP0 call",
+                           kFlowId, "step1");
+    TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0("all",
+        "TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call", kFlowId);
+
     TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW0 call", kAsyncId, NULL);
     TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW1 call", kAsyncId, "value");
     TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW0 call", kAsyncId, NULL);
@@ -613,6 +621,17 @@
   EXPECT_SUB_FIND_("name2");
   EXPECT_SUB_FIND_("value2");
 
+  EXPECT_FIND_("TRACE_EVENT_FLOW_BEGIN0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kFlowIdStr);
+  EXPECT_FIND_("TRACE_EVENT_FLOW_STEP0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kFlowIdStr);
+  EXPECT_SUB_FIND_("step1");
+  EXPECT_FIND_("TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kFlowIdStr);
+
   EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW0 call");
   EXPECT_SUB_FIND_("id");
   EXPECT_SUB_FIND_(kAsyncIdStr);
@@ -2187,7 +2206,10 @@
   dict->GetDictionary("args", &args_dict);
   ASSERT_TRUE(args_dict);
   EXPECT_FALSE(args_dict->GetInteger("int_two", &int_value));
-  EXPECT_TRUE(args_dict->GetInteger("stripped", &int_value));
+
+  std::string args_string;
+  EXPECT_TRUE(dict->GetString("args", &args_string));
+  EXPECT_EQ(args_string, "__stripped__");
 }
 
 class TraceEventCallbackTest : public TraceEventTestFixture {
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index c5b06c4..cf93444 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -32,13 +32,16 @@
 #include "base/win/scoped_propvariant.h"
 #include "base/win/windows_version.h"
 
+namespace base {
+namespace win {
+
 namespace {
 
 // Sets the value of |property_key| to |property_value| in |property_store|.
 bool SetPropVariantValueForPropertyStore(
     IPropertyStore* property_store,
     const PROPERTYKEY& property_key,
-    const base::win::ScopedPropVariant& property_value) {
+    const ScopedPropVariant& property_value) {
   DCHECK(property_store);
 
   HRESULT result = property_store->SetValue(property_key, property_value.get());
@@ -62,7 +65,7 @@
 // are attached to the machine.
 bool IsKeyboardPresentOnSlate() {
   // This function is only supported for Windows 8 and up.
-  DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN8);
+  DCHECK(GetVersion() >= VERSION_WIN8);
 
   // This function should be only invoked for machines with touch screens.
   if ((GetSystemMetrics(SM_DIGITIZER) & NID_INTEGRATED_TOUCH)
@@ -160,9 +163,6 @@
 
 }  // namespace
 
-namespace base {
-namespace win {
-
 static bool g_crash_on_process_detach = false;
 
 void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics) {
@@ -181,7 +181,7 @@
   HANDLE token = NULL;
   if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
     return false;
-  base::win::ScopedHandle token_scoped(token);
+  ScopedHandle token_scoped(token);
 
   DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
   scoped_ptr<BYTE[]> user_bytes(new BYTE[size]);
@@ -226,11 +226,11 @@
   // This can be slow if Windows ends up going to disk.  Should watch this key
   // for changes and only read it once, preferably on the file thread.
   //   http://code.google.com/p/chromium/issues/detail?id=61644
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  ThreadRestrictions::ScopedAllowIO allow_io;
 
-  base::win::RegKey key(HKEY_LOCAL_MACHINE,
-      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
-      KEY_READ);
+  RegKey key(HKEY_LOCAL_MACHINE,
+             L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
+             KEY_READ);
   DWORD uac_enabled;
   if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS)
     return true;
@@ -284,20 +284,20 @@
 
 bool AddCommandToAutoRun(HKEY root_key, const string16& name,
                          const string16& command) {
-  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
   return (autorun_key.WriteValue(name.c_str(), command.c_str()) ==
       ERROR_SUCCESS);
 }
 
 bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) {
-  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
   return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS);
 }
 
 bool ReadCommandFromAutoRun(HKEY root_key,
                             const string16& name,
                             string16* command) {
-  base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
+  RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
   return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS);
 }
 
@@ -326,8 +326,8 @@
   if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0)
     return false;
 
-  base::win::Version version = base::win::GetVersion();
-  if (version == base::win::VERSION_XP)
+  Version version = GetVersion();
+  if (version == VERSION_XP)
     return (GetSystemMetrics(SM_TABLETPC) != 0);
 
   // If the device is docked, the user is treating the device as a PC.
@@ -339,7 +339,7 @@
   POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
   bool mobile_power_profile = (role == PlatformRoleMobile);
   bool slate_power_profile = false;
-  if (version >= base::win::VERSION_WIN8)
+  if (version >= VERSION_WIN8)
     slate_power_profile = (role == PlatformRoleSlate);
 
   if (mobile_power_profile || slate_power_profile)
@@ -349,14 +349,13 @@
 }
 
 bool DisplayVirtualKeyboard() {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+  if (GetVersion() < VERSION_WIN8)
     return false;
 
   if (IsKeyboardPresentOnSlate())
     return false;
 
-  static base::LazyInstance<string16>::Leaky osk_path =
-      LAZY_INSTANCE_INITIALIZER;
+  static LazyInstance<string16>::Leaky osk_path = LAZY_INSTANCE_INITIALIZER;
 
   if (osk_path.Get().empty()) {
     // We need to launch TabTip.exe from the location specified under the
@@ -367,9 +366,8 @@
     // We don't want to launch TabTip.exe from
     // c:\program files (x86)\common files\microsoft shared\ink. This path is
     // normally found on 64 bit Windows.
-    base::win::RegKey key(HKEY_LOCAL_MACHINE,
-                          kWindows8OSKRegPath,
-                          KEY_READ | KEY_WOW64_64KEY);
+    RegKey key(HKEY_LOCAL_MACHINE, kWindows8OSKRegPath,
+               KEY_READ | KEY_WOW64_64KEY);
     DWORD osk_path_length = 1024;
     if (key.ReadValue(NULL,
                       WriteInto(&osk_path.Get(), osk_path_length),
@@ -410,7 +408,7 @@
         common_program_files_path = common_program_files_wow6432.get();
         DCHECK(!common_program_files_path.empty());
       } else {
-        base::win::ScopedCoMem<wchar_t> common_program_files;
+        ScopedCoMem<wchar_t> common_program_files;
         if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL,
                                         &common_program_files))) {
           return false;
@@ -432,7 +430,7 @@
 }
 
 bool DismissVirtualKeyboard() {
-  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+  if (GetVersion() < VERSION_WIN8)
     return false;
 
   // We dismiss the virtual keyboard by generating the ESC keystroke
@@ -474,21 +472,21 @@
 }
 
 bool MaybeHasSHA256Support() {
-  const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
+  const OSInfo* os_info = OSInfo::GetInstance();
 
-  if (os_info->version() == base::win::VERSION_PRE_XP)
+  if (os_info->version() == VERSION_PRE_XP)
     return false;  // Too old to have it and this OS is not supported anyway.
 
-  if (os_info->version() == base::win::VERSION_XP)
+  if (os_info->version() == VERSION_XP)
     return os_info->service_pack().major >= 3;  // Windows XP SP3 has it.
 
   // Assume it is missing in this case, although it may not be. This category
   // includes Windows XP x64, and Windows Server, where a hotfix could be
   // deployed.
-  if (os_info->version() == base::win::VERSION_SERVER_2003)
+  if (os_info->version() == VERSION_SERVER_2003)
     return false;
 
-  DCHECK(os_info->version() >= base::win::VERSION_VISTA);
+  DCHECK(os_info->version() >= VERSION_VISTA);
   return true;  // New enough to have SHA-256 support.
 }
 
diff --git a/build/all.gyp b/build/all.gyp
index 8da4abc3..6b8ad83 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -490,7 +490,7 @@
         }],
         ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
           'dependencies': [
-            '../components/nacl_nonsfi.gyp:nacl_helper_nonsfi_unittests',
+            '../components/nacl.gyp:nacl_helper_nonsfi_unittests',
           ],
         }],
         ['disable_nacl==0 and disable_nacl_untrusted==0', {
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py
index 665c736..8ad42b9 100755
--- a/build/android/buildbot/bb_device_steps.py
+++ b/build/android/buildbot/bb_device_steps.py
@@ -535,7 +535,7 @@
 
   bb_annotations.PrintNamedStep('pixel_tests')
   RunCmd(['content/test/gpu/run_gpu_test.py',
-          'pixel',
+          'pixel', '-v',
           '--browser',
           'android-content-shell',
           '--build-revision',
@@ -549,18 +549,18 @@
           EscapeBuilderName(builder_name)])
 
   bb_annotations.PrintNamedStep('webgl_conformance_tests')
-  RunCmd(['content/test/gpu/run_gpu_test.py',
+  RunCmd(['content/test/gpu/run_gpu_test.py', '-v',
           '--browser=android-content-shell', 'webgl_conformance',
           '--webgl-conformance-version=1.0.1'])
 
   bb_annotations.PrintNamedStep('android_webview_webgl_conformance_tests')
-  RunCmd(['content/test/gpu/run_gpu_test.py',
+  RunCmd(['content/test/gpu/run_gpu_test.py', '-v',
           '--browser=android-webview-shell', 'webgl_conformance',
           '--webgl-conformance-version=1.0.1'])
 
   bb_annotations.PrintNamedStep('gpu_rasterization_tests')
   RunCmd(['content/test/gpu/run_gpu_test.py',
-          'gpu_rasterization',
+          'gpu_rasterization', '-v',
           '--browser',
           'android-content-shell',
           '--build-revision',
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
index b16de84..6921695 100644
--- a/build/android/lint/suppressions.xml
+++ b/build/android/lint/suppressions.xml
@@ -87,10 +87,11 @@
   </issue>
   <issue id="SetJavaScriptEnabled" severity="ignore"/>
   <issue id="UnusedResources">
-    <!-- These files are used by chrome_shell_apk and chrome_apk targets. -->
-    <ignore path="chrome/android/java/res/layout/accessibility_tab_switcher.xml" />
-    <ignore path="chrome/android/java/res/drawable/btn_back.xml" />
-    <ignore path="chrome/android/java/res/drawable/btn_forward.xml" />
+    <!--
+      TODO(pkotwicz): Re-enable after the chrome_java and chrome_staging_java
+      targets have been merged. crbug.com/484934
+    -->
+    <ignore path="chrome/android/java/res" />
   </issue>
   <issue id="SignatureOrSystemPermissions" severity="ignore"/>
   <issue id="UnusedAttribute" severity="ignore"/>
diff --git a/build/android/pylib/device/battery_utils.py b/build/android/pylib/device/battery_utils.py
index ed66591..682238c 100644
--- a/build/android/pylib/device/battery_utils.py
+++ b/build/android/pylib/device/battery_utils.py
@@ -289,12 +289,14 @@
       raise device_errors.DeviceVersionError('Device must be L or higher.')
 
     self._device.RunShellCommand(
-        ['dumpsys', 'battery', 'reset'], check_return=True)
+        ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True)
+    self._device.RunShellCommand(
+        ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True)
     self._device.RunShellCommand(
         ['dumpsys', 'batterystats', '--reset'], check_return=True)
     battery_data = self._device.RunShellCommand(
         ['dumpsys', 'batterystats', '--charged', '--checkin'],
-        check_return=True)
+        check_return=True, large_output=True)
     ROW_TYPE_INDEX = 3
     PWI_POWER_INDEX = 5
     for line in battery_data:
@@ -322,7 +324,9 @@
       device_errors.DeviceVersionError: If device is not L or higher.
     """
     def battery_updates_enabled():
-      return self.GetCharging() is True
+      return (self.GetCharging()
+              or not bool('UPDATES STOPPED' in self._device.RunShellCommand(
+                  ['dumpsys', 'battery'], check_return=True)))
 
     if (self._device.build_version_sdk <
         constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
diff --git a/build/android/pylib/device/battery_utils_test.py b/build/android/pylib/device/battery_utils_test.py
index 72799b8..96e18be 100755
--- a/build/android/pylib/device/battery_utils_test.py
+++ b/build/android/pylib/device/battery_utils_test.py
@@ -104,18 +104,21 @@
 
 class BatteryUtilsSetBatteryMeasurementTest(BatteryUtilsTest):
 
-  def testBatteryMeasurement(self):
+  @mock.patch('time.sleep', mock.Mock())
+  def testBatteryMeasurementWifi(self):
     with self.assertCalls(
         (self.call.device.RunShellCommand(
             mock.ANY, retries=0, single_line=True,
             timeout=10, check_return=True), '22'),
         (self.call.device.RunShellCommand(
-            ['dumpsys', 'battery', 'reset'], check_return=True), []),
+            ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True), []),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True), []),
         (self.call.device.RunShellCommand(
             ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
         (self.call.device.RunShellCommand(
             ['dumpsys', 'batterystats', '--charged', '--checkin'],
-            check_return=True), []),
+            check_return=True, large_output=True), []),
         (self.call.device.RunShellCommand(
             ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []),
         (self.call.device.RunShellCommand(
@@ -123,11 +126,46 @@
         (self.call.battery.GetCharging(), False),
         (self.call.device.RunShellCommand(
             ['dumpsys', 'battery', 'reset'], check_return=True), []),
+        (self.call.battery.GetCharging(), False),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']),
+        (self.call.battery.GetCharging(), False),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery'], check_return=True), [])):
+      with self.battery.BatteryMeasurement():
+        pass
+
+  @mock.patch('time.sleep', mock.Mock())
+  def testBatteryMeasurementUsb(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            mock.ANY, retries=0, single_line=True,
+            timeout=10, check_return=True), '22'),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True), []),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True), []),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'batterystats', '--charged', '--checkin'],
+            check_return=True, large_output=True), []),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True), []),
+        (self.call.battery.GetCharging(), False),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery', 'reset'], check_return=True), []),
+        (self.call.battery.GetCharging(), False),
+        (self.call.device.RunShellCommand(
+            ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']),
         (self.call.battery.GetCharging(), True)):
       with self.battery.BatteryMeasurement():
         pass
 
 
+
 class BatteryUtilsGetPowerData(BatteryUtilsTest):
 
   def testGetPowerData(self):
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index c8b4718..f5f7489 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -364,6 +364,28 @@
     return output[len('package:'):]
 
   @decorators.WithTimeoutAndRetriesFromInstance()
+  def GetApplicationDataDirectory(self, package, timeout=None, retries=None):
+    """Get the data directory on the device for the given package.
+
+    Args:
+      package: Name of the package.
+
+    Returns:
+      The package's data directory, or None if the package doesn't exist on the
+      device.
+    """
+    try:
+      output = self._RunPipedShellCommand(
+          'pm dump %s | grep dataDir=' % cmd_helper.SingleQuote(package))
+      for line in output:
+        _, _, dataDir = line.partition('dataDir=')
+        if dataDir:
+          return dataDir
+    except device_errors.CommandFailedError:
+      logging.exception('Could not find data directory for %s', package)
+    return None
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
   def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None):
     """Wait for the device to fully boot.
 
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index 317e81e..ca097b7 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -336,6 +336,25 @@
         self.device.GetApplicationPath('android')
 
 
+class DeviceUtilsGetApplicationDataDirectoryTest(DeviceUtilsTest):
+
+  def testGetApplicationDataDirectory_exists(self):
+    with self.assertCall(
+        self.call.device._RunPipedShellCommand(
+            'pm dump foo.bar.baz | grep dataDir='),
+        ['dataDir=/data/data/foo.bar.baz']):
+      self.assertEquals(
+          '/data/data/foo.bar.baz',
+          self.device.GetApplicationDataDirectory('foo.bar.baz'))
+
+  def testGetApplicationDataDirectory_notExists(self):
+    with self.assertCall(
+        self.call.device._RunPipedShellCommand(
+            'pm dump foo.bar.baz | grep dataDir='),
+        self.ShellError()):
+      self.assertIsNone(self.device.GetApplicationDataDirectory('foo.bar.baz'))
+
+
 @mock.patch('time.sleep', mock.Mock())
 class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest):
 
diff --git a/build/android/pylib/forwarder.py b/build/android/pylib/forwarder.py
index d16b9b1..c8c47d6 100644
--- a/build/android/pylib/forwarder.py
+++ b/build/android/pylib/forwarder.py
@@ -289,7 +289,8 @@
         Forwarder._DEVICE_FORWARDER_FOLDER)])
     cmd = '%s %s' % (tool.GetUtilWrapper(), Forwarder._DEVICE_FORWARDER_PATH)
     device.RunShellCommand(
-        cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER})
+        cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER},
+        check_return=True)
     self._initialized_devices.add(device_serial)
 
   def _KillHostLocked(self):
@@ -326,4 +327,5 @@
     cmd = '%s %s --kill-server' % (tool.GetUtilWrapper(),
                                    Forwarder._DEVICE_FORWARDER_PATH)
     device.RunShellCommand(
-        cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER})
+        cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER},
+        check_return=True)
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py
index cea50160..ed1190fc 100644
--- a/build/android/pylib/gtest/gtest_test_instance.py
+++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -7,6 +7,7 @@
 import re
 import shutil
 import sys
+import tempfile
 
 from pylib import constants
 from pylib.base import base_test_result
@@ -127,6 +128,17 @@
       logging.warning('No isolate file provided. No data deps will be pushed.');
       self._isolate_delegate = None
 
+    if args.app_data_files:
+      self._app_data_files = args.app_data_files
+      if args.app_data_file_dir:
+        self._app_data_file_dir = args.app_data_file_dir
+      else:
+        self._app_data_file_dir = tempfile.mkdtemp()
+        logging.critical('Saving app files to %s', self._app_data_file_dir)
+    else:
+      self._app_data_files = None
+      self._app_data_file_dir = None
+
   #override
   def TestType(self):
     return 'gtest'
@@ -232,6 +244,14 @@
     return self._apk_path
 
   @property
+  def app_file_dir(self):
+    return self._app_data_file_dir
+
+  @property
+  def app_files(self):
+    return self._app_data_files
+
+  @property
   def exe(self):
     return self._exe_path
 
diff --git a/build/android/pylib/gtest/local_device_gtest_run.py b/build/android/pylib/gtest/local_device_gtest_run.py
index 15a58a4..c375b97 100644
--- a/build/android/pylib/gtest/local_device_gtest_run.py
+++ b/build/android/pylib/gtest/local_device_gtest_run.py
@@ -2,9 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-
+import itertools
 import logging
 import os
+import posixpath
 
 from pylib import constants
 from pylib import ports
@@ -37,6 +38,20 @@
   'net_unittests', 'unit_tests'
 ]
 
+# TODO(jbudorick): Move this inside _ApkDelegate once TestPackageApk is gone.
+def PullAppFilesImpl(device, package, files, directory):
+  device_dir = device.GetApplicationDataDirectory(package)
+  host_dir = os.path.join(directory, str(device))
+  for f in files:
+    device_file = posixpath.join(device_dir, f)
+    host_file = os.path.join(host_dir, *f.split(posixpath.sep))
+    host_file_base, ext = os.path.splitext(host_file)
+    for i in itertools.count():
+      host_file = '%s_%d%s' % (host_file_base, i, ext)
+      if not os.path.exists(host_file):
+        break
+    device.PullFile(device_file, host_file)
+
 class _ApkDelegate(object):
   def __init__(self, apk):
     self._apk = apk
@@ -63,6 +78,9 @@
       return device.StartInstrumentation(
           self._component, extras=extras, raw=False, **kwargs)
 
+  def PullAppFiles(self, device, files, directory):
+    PullAppFilesImpl(device, self._package, files, directory)
+
   def Clear(self, device):
     device.ClearApplicationState(self._package)
 
@@ -119,6 +137,9 @@
                                       env=env, **kwargs)
     return output
 
+  def PullAppFiles(self, device, files, directory):
+    pass
+
   def Clear(self, device):
     device.KillAll(self._exe_file_name, blocking=True, timeout=30, quiet=True)
 
@@ -199,6 +220,9 @@
         device, '--gtest_filter=%s' % test, timeout=900, retries=0)
     for s in self._servers[str(device)]:
       s.Reset()
+    if self._test_instance.app_files:
+      self._delegate.PullAppFiles(device, self._test_instance.app_files,
+                                  self._test_instance.app_file_dir)
     self._delegate.Clear(device)
 
     # Parse the output.
diff --git a/build/android/pylib/gtest/test_options.py b/build/android/pylib/gtest/test_options.py
index 58cd82b..a8d5e97 100644
--- a/build/android/pylib/gtest/test_options.py
+++ b/build/android/pylib/gtest/test_options.py
@@ -13,4 +13,6 @@
     'test_arguments',
     'timeout',
     'isolate_file_path',
-    'suite_name'])
+    'suite_name',
+    'app_data_files',
+    'app_data_file_dir'])
diff --git a/build/android/pylib/gtest/test_package.py b/build/android/pylib/gtest/test_package.py
index dbd47bfe..4042a98 100644
--- a/build/android/pylib/gtest/test_package.py
+++ b/build/android/pylib/gtest/test_package.py
@@ -22,7 +22,7 @@
     Args:
       device: Instance of DeviceUtils.
     """
-    raise NotImplementedError('Method must be overriden.')
+    raise NotImplementedError('Method must be overridden.')
 
   def CreateCommandLineFileOnDevice(self, device, test_filter, test_arguments):
     """Creates a test runner script and pushes to the device.
@@ -32,7 +32,7 @@
       test_filter: A test_filter flag.
       test_arguments: Additional arguments to pass to the test binary.
     """
-    raise NotImplementedError('Method must be overriden.')
+    raise NotImplementedError('Method must be overridden.')
 
   def GetAllTests(self, device):
     """Returns a list of all tests available in the test suite.
@@ -40,7 +40,7 @@
     Args:
       device: Instance of DeviceUtils.
     """
-    raise NotImplementedError('Method must be overriden.')
+    raise NotImplementedError('Method must be overridden.')
 
   def GetGTestReturnCode(self, _device):
     return None
@@ -54,7 +54,7 @@
     Returns:
       An instance of pexpect spawn class.
     """
-    raise NotImplementedError('Method must be overriden.')
+    raise NotImplementedError('Method must be overridden.')
 
   def Install(self, device):
     """Install the test package to the device.
@@ -62,5 +62,15 @@
     Args:
       device: Instance of DeviceUtils.
     """
-    raise NotImplementedError('Method must be overriden.')
+    raise NotImplementedError('Method must be overridden.')
 
+  def PullAppFiles(self, device, files, directory):
+    """Pull application data from the device.
+
+    Args:
+      device: Instance of DeviceUtils.
+      files: A list of paths relative to the application data directory to
+        retrieve from the device.
+      directory: The host directory to which files should be pulled.
+    """
+    raise NotImplementedError('Method must be overridden.')
diff --git a/build/android/pylib/gtest/test_package_apk.py b/build/android/pylib/gtest/test_package_apk.py
index 64478209..16ef21c6 100644
--- a/build/android/pylib/gtest/test_package_apk.py
+++ b/build/android/pylib/gtest/test_package_apk.py
@@ -5,8 +5,10 @@
 """Defines TestPackageApk to help run APK-based native tests."""
 # pylint: disable=W0212
 
+import itertools
 import logging
 import os
+import posixpath
 import shlex
 import sys
 import tempfile
@@ -18,6 +20,7 @@
 from pylib.device import device_errors
 from pylib.device import intent
 from pylib.gtest import gtest_test_instance
+from pylib.gtest import local_device_gtest_run
 from pylib.gtest.test_package import TestPackage
 
 
@@ -141,3 +144,8 @@
   def Install(self, device):
     self.tool.CopyFiles(device)
     device.Install(self.suite_path)
+
+  #override
+  def PullAppFiles(self, device, files, directory):
+    local_device_gtest_run.PullAppFilesImpl(
+        device, self._package_info.package, files, directory)
diff --git a/build/android/pylib/gtest/test_package_exe.py b/build/android/pylib/gtest/test_package_exe.py
index 7cdcb99e..87071b5 100644
--- a/build/android/pylib/gtest/test_package_exe.py
+++ b/build/android/pylib/gtest/test_package_exe.py
@@ -157,3 +157,7 @@
     deps_path = self.suite_path + '_deps'
     if os.path.isdir(deps_path):
       device.PushChangedFiles([(deps_path, test_binary_path + '_deps')])
+
+  #override
+  def PullAppFiles(self, device, files, directory):
+    pass
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py
index 6d01990c..a48f18a 100644
--- a/build/android/pylib/gtest/test_runner.py
+++ b/build/android/pylib/gtest/test_runner.py
@@ -5,6 +5,7 @@
 import logging
 import os
 import re
+import tempfile
 
 from pylib import pexpect
 from pylib import ports
@@ -80,6 +81,17 @@
     else:
       self._servers = []
 
+    if test_options.app_data_files:
+      self._app_data_files = test_options.app_data_files
+      if test_options.app_data_file_dir:
+        self._app_data_file_dir = test_options.app_data_file_dir
+      else:
+        self._app_data_file_dir = tempfile.mkdtemp()
+        logging.critical('Saving app files to %s', self._app_data_file_dir)
+    else:
+      self._app_data_files = None
+      self._app_data_file_dir = None
+
   #override
   def InstallTestPackage(self):
     self.test_package.Install(self.device)
@@ -167,6 +179,9 @@
           self.device, test, self._test_arguments)
       test_results = self._ParseTestOutput(
           self.test_package.SpawnTestProcess(self.device))
+      if self._app_data_files:
+        self.test_package.PullAppFiles(self.device, self._app_data_files,
+                                       self._app_data_file_dir)
     finally:
       for s in self._servers:
         s.Reset()
diff --git a/build/android/pylib/perf/test_runner.py b/build/android/pylib/perf/test_runner.py
index 991fc00..0f464c3 100644
--- a/build/android/pylib/perf/test_runner.py
+++ b/build/android/pylib/perf/test_runner.py
@@ -233,8 +233,15 @@
       return ''
 
     json_output_path = os.path.join(self._output_dir, 'results-chart.json')
-    with open(json_output_path) as f:
-      return f.read()
+    try:
+      with open(json_output_path) as f:
+        return f.read()
+    except IOError:
+      logging.exception('Exception when reading chartjson.')
+      logging.error('This usually means that telemetry did not run, so it could'
+                    ' not generate the file. Please check the device running'
+                    ' the test.')
+      return ''
 
   def _LaunchPerfTest(self, test_name):
     """Runs a perf test.
diff --git a/build/android/pylib/utils/md5sum.py b/build/android/pylib/utils/md5sum.py
index ed2e6bc8..3e61c8fa 100644
--- a/build/android/pylib/utils/md5sum.py
+++ b/build/android/pylib/utils/md5sum.py
@@ -20,16 +20,19 @@
     'test -f {path} -o -d {path} '
     '&& LD_LIBRARY_PATH={md5sum_lib} {md5sum_bin} {path}')
 
-_STARTS_WITH_CHECKSUM_RE = re.compile(r'^\s*[0-9a-fA-f]{32}\s+')
+_STARTS_WITH_CHECKSUM_RE = re.compile(r'^\s*[0-9a-fA-F]{32}\s+')
 
 
 def CalculateHostMd5Sums(paths):
   """Calculates the MD5 sum value for all items in |paths|.
 
+  Directories are traversed recursively and the MD5 sum of each file found is
+  reported in the result.
+
   Args:
     paths: A list of host paths to md5sum.
   Returns:
-    A dict mapping paths to their respective md5sum checksums.
+    A dict mapping file paths to their respective md5sum checksums.
   """
   if isinstance(paths, basestring):
     paths = [paths]
@@ -46,10 +49,13 @@
 def CalculateDeviceMd5Sums(paths, device):
   """Calculates the MD5 sum value for all items in |paths|.
 
+  Directories are traversed recursively and the MD5 sum of each file found is
+  reported in the result.
+
   Args:
     paths: A list of device paths to md5sum.
   Returns:
-    A dict mapping paths to their respective md5sum checksums.
+    A dict mapping file paths to their respective md5sum checksums.
   """
   if isinstance(paths, basestring):
     paths = [paths]
diff --git a/build/android/pylib/utils/md5sum_test.py b/build/android/pylib/utils/md5sum_test.py
index 5bdee32b..c94c19d 100755
--- a/build/android/pylib/utils/md5sum_test.py
+++ b/build/android/pylib/utils/md5sum_test.py
@@ -199,6 +199,7 @@
     device_md5sum_output = [
         'WARNING: linker: /data/local/tmp/md5sum/md5sum_bin: '
             'unused DT entry: type 0x1d arg 0x15db',
+        'THIS_IS_NOT_A_VALID_CHECKSUM_ZZZ some random text',
         '0123456789abcdeffedcba9876543210 '
             '/storage/emulated/legacy/test/file.dat',
     ]
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 52de8fd..2cff5f2 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -215,6 +215,12 @@
                      dest='isolate_file_path',
                      help='.isolate file path to override the default '
                           'path')
+  group.add_argument('--app-data-file', action='append', dest='app_data_files',
+                     help='A file path relative to the app data directory '
+                          'that should be saved to the host.')
+  group.add_argument('--app-data-file-dir',
+                     help='Host directory to which app data files will be'
+                          ' saved. Used with --app-data-file.')
 
   filter_group = group.add_mutually_exclusive_group()
   filter_group.add_argument('-f', '--gtest_filter', '--gtest-filter',
@@ -640,7 +646,9 @@
         args.test_arguments,
         args.timeout,
         args.isolate_file_path,
-        suite_name)
+        suite_name,
+        args.app_data_files,
+        args.app_data_file_dir)
     runner_factory, tests = gtest_setup.Setup(gtest_options, devices)
 
     results, test_exit_code = test_dispatcher.RunTests(
diff --git a/build/common.gypi b/build/common.gypi
index 0b32d449..99426eb 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -416,6 +416,9 @@
       # Web speech is enabled by default. Set to 0 to disable.
       'enable_web_speech%': 1,
 
+      # 'Ok Google' hotwording is enabled by default. Set to 0 to disable.
+      'enable_hotwording%': 1,
+
       # Notifications are compiled in by default. Set to 0 to disable.
       'notifications%' : 1,
 
@@ -638,9 +641,6 @@
       # with one of those tools.
       'build_for_tool%': '',
 
-      # If no directory is specified then a temporary directory will be used.
-      'test_isolation_outdir%': '',
-
       'wix_path%': '<(DEPTH)/third_party/wix',
 
       # Supervised users are enabled by default.
@@ -649,8 +649,6 @@
       # Platform sends memory pressure signals natively.
       'native_memory_pressure_signals%': 0,
 
-      'spdy_proxy_auth_property%' : '',
-      'spdy_proxy_auth_value%' : '',
       'enable_mdns%' : 0,
       'enable_service_discovery%': 0,
       'enable_wifi_bootstrapping%': 0,
@@ -1146,6 +1144,7 @@
     'configuration_policy%': '<(configuration_policy)',
     'safe_browsing%': '<(safe_browsing)',
     'enable_web_speech%': '<(enable_web_speech)',
+    'enable_hotwording%': '<(enable_hotwording)',
     'notifications%': '<(notifications)',
     'clang_use_chrome_plugins%': '<(clang_use_chrome_plugins)',
     'mac_want_real_dsym%': '<(mac_want_real_dsym)',
@@ -1189,7 +1188,6 @@
     'linux_use_debug_fission%': '<(linux_use_debug_fission)',
     'use_canvas_skia%': '<(use_canvas_skia)',
     'test_isolation_mode%': '<(test_isolation_mode)',
-    'test_isolation_outdir%': '<(test_isolation_outdir)',
     'enable_basic_printing%': '<(enable_basic_printing)',
     'enable_print_preview%': '<(enable_print_preview)',
     'enable_spellcheck%': '<(enable_spellcheck)',
@@ -1217,8 +1215,6 @@
     'google_default_client_secret%': '<(google_default_client_secret)',
     'enable_supervised_users%': '<(enable_supervised_users)',
     'native_memory_pressure_signals%': '<(native_memory_pressure_signals)',
-    'spdy_proxy_auth_property%': '<(spdy_proxy_auth_property)',
-    'spdy_proxy_auth_value%': '<(spdy_proxy_auth_value)',
     'enable_mdns%' : '<(enable_mdns)',
     'enable_service_discovery%' : '<(enable_service_discovery)',
     'enable_wifi_bootstrapping%': '<(enable_wifi_bootstrapping)',
@@ -3012,12 +3008,6 @@
       ['enable_supervised_users==1', {
         'defines': ['ENABLE_SUPERVISED_USERS=1'],
       }],
-      ['spdy_proxy_auth_property != ""', {
-        'defines': ['SPDY_PROXY_AUTH_PROPERTY="<(spdy_proxy_auth_property)"'],
-      }],
-      ['spdy_proxy_auth_value != ""', {
-        'defines': ['SPDY_PROXY_AUTH_VALUE="<(spdy_proxy_auth_value)"'],
-      }],
       ['enable_mdns==1', {
         'defines': ['ENABLE_MDNS=1'],
       }],
@@ -5706,8 +5696,6 @@
             ['clang==1', {
               'VCCLCompilerTool': {
                 'AdditionalOptions': [
-                  '-fmsc-version=1800',
-
                   # Many files use intrinsics without including this header.
                   # TODO(hans): Fix those files, or move this to sub-GYPs.
                   '/FIIntrin.h',
@@ -5764,6 +5752,20 @@
                 ],
               },
             }],
+            ['clang==1 and MSVS_VERSION == "2013"', {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  '-fmsc-version=1800',
+                ],
+              },
+            }],
+            ['clang==1 and MSVS_VERSION == "2015"', {
+              'VCCLCompilerTool': {
+                'AdditionalOptions': [
+                  '-fmsc-version=1900',
+                ],
+              },
+            }],
           ],
         },
       },
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 606a229..10d9d3f 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -361,7 +361,6 @@
   "//build/config/compiler:compiler_arm_fpu",
   "//build/config/compiler:chromium_code",
   "//build/config/compiler:default_include_dirs",
-  "//build/config/compiler:default_warnings",
   "//build/config/compiler:no_rtti",
   "//build/config/compiler:runtime_library",
 ]
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 76d8ea1b..fbf6db6e 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -13,6 +13,9 @@
 if (is_posix) {
   import("//build/config/gcc/gcc_version.gni")
 }
+if (is_win) {
+  import("//build/config/win/visual_studio_version.gni")
+}
 
 import("//build/toolchain/ccache.gni")
 import("//build/config/sanitizers/sanitizers.gni")
@@ -108,12 +111,17 @@
     # Keep this in sync with the similar block in build/common.gypi
     if (is_clang) {
       cflags += [
-        "-fmsc-version=1800",
-
         # Many files use intrinsics without including this header.
         # TODO(hans): Fix those files, or move this to sub-GYPs.
         "/FIIntrin.h",
       ]
+
+      if (visual_studio_version == "2013") {
+        cflags += [ "-fmsc-version=1800" ]
+      } else if (visual_studio_version == "2015") {
+        cflags += [ "-fmsc-version=1900" ]
+      }
+
       if (current_cpu == "x86") {
         cflags += [
           "/fallback",
@@ -704,6 +712,246 @@
   }
 }
 
+# default_warning_flags collects all warning flags that are used by default.
+# This is in a variable instead of a config so that it can be used in
+# both chromium_code and no_chromium_code.  This way these flags are guaranteed
+# to appear on the compile command line after -Wall.
+
+default_warning_flags = []
+default_warning_flags_cc = []
+if (is_win) {
+  if (!is_clang || current_cpu != "x86") {
+    default_warning_flags += [ "/WX" ]  # Treat warnings as errors.
+  }
+
+  default_warning_flags += [
+    # Warnings permanently disabled:
+
+    # TODO(GYP) The GYP build doesn't have this globally enabled but disabled
+    # for a bunch of individual targets. Re-enable this globally when those
+    # targets are fixed.
+    "/wd4018",  # Comparing signed and unsigned values.
+
+    # C4127: conditional expression is constant
+    # This warning can in theory catch dead code and other problems, but
+    # triggers in far too many desirable cases where the conditional
+    # expression is either set by macros or corresponds some legitimate
+    # compile-time constant expression (due to constant template args,
+    # conditionals comparing the sizes of different types, etc.).  Some of
+    # these can be worked around, but it's not worth it.
+    "/wd4127",
+
+    # C4251: 'identifier' : class 'type' needs to have dll-interface to be
+    #        used by clients of class 'type2'
+    # This is necessary for the shared library build.
+    "/wd4251",
+
+    # C4351: new behavior: elements of array 'array' will be default
+    #        initialized
+    # This is a silly "warning" that basically just alerts you that the
+    # compiler is going to actually follow the language spec like it's
+    # supposed to, instead of not following it like old buggy versions did.
+    # There's absolutely no reason to turn this on.
+    "/wd4351",
+
+    # C4355: 'this': used in base member initializer list
+    # It's commonly useful to pass |this| to objects in a class' initializer
+    # list.  While this warning can catch real bugs, most of the time the
+    # constructors in question don't attempt to call methods on the passed-in
+    # pointer (until later), and annotating every legit usage of this is
+    # simply more hassle than the warning is worth.
+    "/wd4355",
+
+    # C4503: 'identifier': decorated name length exceeded, name was
+    #        truncated
+    # This only means that some long error messages might have truncated
+    # identifiers in the presence of lots of templates.  It has no effect on
+    # program correctness and there's no real reason to waste time trying to
+    # prevent it.
+    "/wd4503",
+
+    # C4611: interaction between 'function' and C++ object destruction is
+    #        non-portable
+    # This warning is unavoidable when using e.g. setjmp/longjmp.  MSDN
+    # suggests using exceptions instead of setjmp/longjmp for C++, but
+    # Chromium code compiles without exception support.  We therefore have to
+    # use setjmp/longjmp for e.g. JPEG decode error handling, which means we
+    # have to turn off this warning (and be careful about how object
+    # destruction happens in such cases).
+    "/wd4611",
+
+    # Warnings to evaluate and possibly fix/reenable later:
+
+    "/wd4100",  # Unreferenced formal function parameter.
+    "/wd4121",  # Alignment of a member was sensitive to packing.
+    "/wd4244",  # Conversion: possible loss of data.
+    "/wd4481",  # Nonstandard extension: override specifier.
+    "/wd4505",  # Unreferenced local function has been removed.
+    "/wd4510",  # Default constructor could not be generated.
+    "/wd4512",  # Assignment operator could not be generated.
+    "/wd4610",  # Class can never be instantiated, constructor required.
+    "/wd4996",  # Deprecated function warning.
+  ]
+
+  # VS xtree header file needs to be patched or 4702 (unreachable code
+  # warning) is reported if _HAS_EXCEPTIONS=0. Disable the warning if xtree is
+  # not patched.
+  if (!msvs_xtree_patched &&
+      exec_script("../../win_is_xtree_patched.py", [], "value") == 0) {
+    default_warning_flags += [ "/wd4702" ]  # Unreachable code.
+  }
+
+  # Building with Clang on Windows is a work in progress and very
+  # experimental. See crbug.com/82385.
+  # Keep this in sync with the similar block in build/common.gypi
+  if (is_clang) {
+    default_warning_flags += [
+      # TODO(hans): Make this list shorter eventually.
+      "-Qunused-arguments",
+      "-Wno-c++11-compat-deprecated-writable-strings",
+      "-Wno-deprecated-declarations",
+      "-Wno-empty-body",
+      "-Wno-enum-conversion",
+      "-Wno-extra-tokens",
+      "-Wno-ignored-attributes",
+      "-Wno-incompatible-pointer-types",
+      "-Wno-int-to-void-pointer-cast",
+      "-Wno-invalid-noreturn",
+      "-Wno-logical-op-parentheses",
+      "-Wno-microsoft",
+      "-Wno-missing-braces",
+      "-Wno-missing-declarations",
+      "-Wno-msvc-include",
+      "-Wno-null-dereference",
+      "-Wno-overloaded-virtual",
+      "-Wno-parentheses",
+      "-Wno-pointer-sign",
+      "-Wno-reorder",
+      "-Wno-return-type-c-linkage",
+      "-Wno-self-assign",
+      "-Wno-sometimes-uninitialized",
+      "-Wno-switch",
+      "-Wno-tautological-compare",
+      "-Wno-unknown-pragmas",
+      "-Wno-unsequenced",
+      "-Wno-unused-function",
+      "-Wno-unused-private-field",
+      "-Wno-unused-value",
+      "-Wno-unused-variable",
+      "-Wno-unused-local-typedef",  # http://crbug.com/411648
+      "-Wno-inconsistent-missing-override",  #http://crbug.com/428099
+    ]
+  }
+} else {
+  # Common GCC warning setup.
+  default_warning_flags += [
+    # Enables.
+    "-Wendif-labels",  # Weird old-style text after an #endif.
+    "-Werror",  # Warnings as errors.
+
+    # Disables.
+    "-Wno-missing-field-initializers",  # "struct foo f = {0};"
+    "-Wno-unused-parameter",  # Unused function parameters.
+  ]
+
+  if (is_mac) {
+    default_warning_flags += [ "-Wnewline-eof" ]
+    if (!is_nacl) {
+      # When compiling Objective-C, warns if a method is used whose
+      # availability is newer than the deployment target. This is not
+      # required when compiling Chrome for iOS.
+      default_warning_flags += [ "-Wpartial-availability" ]
+    }
+  }
+
+  if (gcc_version >= 48) {
+    default_warning_flags_cc += [
+      # See comment for -Wno-c++11-narrowing.
+      "-Wno-narrowing",
+
+      # TODO(thakis): Remove, http://crbug.com/263960
+      "-Wno-literal-suffix",
+    ]
+  }
+
+  # Suppress warnings about ABI changes on ARM (Clang doesn't give this
+  # warning).
+  if (current_cpu == "arm" && !is_clang) {
+    default_warning_flags += [ "-Wno-psabi" ]
+  }
+
+  if (is_android) {
+    # Disable any additional warnings enabled by the Android build system but
+    # which chromium does not build cleanly with (when treating warning as
+    # errors).
+    default_warning_flags += [
+      "-Wno-extra",
+      "-Wno-ignored-qualifiers",
+      "-Wno-type-limits",
+    ]
+    default_warning_flags_cc += [
+      # Disabling c++0x-compat should be handled in WebKit, but
+      # this currently doesn't work because gcc_version is not set
+      # correctly when building with the Android build system.
+      # TODO(torne): Fix this in WebKit.
+      "-Wno-error=c++0x-compat",
+
+      # Other things unrelated to -Wextra:
+      "-Wno-non-virtual-dtor",
+      "-Wno-sign-promo",
+    ]
+  }
+
+  if (gcc_version >= 48) {
+    # Don't warn about the "typedef 'foo' locally defined but not used"
+    # for gcc 4.8.
+    # TODO: remove this flag once all builds work. See crbug.com/227506
+    default_warning_flags += [ "-Wno-unused-local-typedefs" ]
+  }
+}
+if (is_clang) {
+  default_warning_flags += [
+    # This warns on using ints as initializers for floats in
+    # initializer lists (e.g. |int a = f(); CGSize s = { a, a };|),
+    # which happens in several places in chrome code. Not sure if
+    # this is worth fixing.
+    "-Wno-c++11-narrowing",
+
+    # Don't die on dtoa code that uses a char as an array index.
+    # This is required solely for base/third_party/dmg_fp/dtoa.cc.
+    # TODO(brettw) move this to that project then!
+    "-Wno-char-subscripts",
+
+    # Warns on switches on enums that cover all enum values but
+    # also contain a default: branch. Chrome is full of that.
+    "-Wno-covered-switch-default",
+
+    # Clang considers the `register` keyword as deprecated, but e.g.
+    # code generated by flex (used in angle) contains that keyword.
+    # http://crbug.com/255186
+    "-Wno-deprecated-register",
+
+    # TODO(thakis): This used to be implied by -Wno-unused-function,
+    # which we no longer use. Check if it makes sense to remove
+    # this as well. http://crbug.com/316352
+    "-Wno-unneeded-internal-declaration",
+
+    # TODO(thakis): Remove, http://crbug.com/263960
+    "-Wno-reserved-user-defined-literal",
+  ]
+
+  # NaCl's Clang compiler and Chrome's hermetic Clang compiler will almost
+  # always have different versions. Certain flags may not be recognized by
+  # one version or the other.
+  if (!is_nacl) {
+    # Flags NaCl does not recognize.
+    default_warning_flags += [
+      # TODO(hans): Get this cleaned up.
+      "-Wno-inconsistent-missing-override",
+    ]
+  }
+}
+
 # chromium_code ---------------------------------------------------------------
 #
 # Toggles between higher and lower warnings for code that is (or isn't)
@@ -742,6 +990,8 @@
       defines += [ "_FORTIFY_SOURCE=2" ]
     }
   }
+  cflags += default_warning_flags
+  cflags_cc = default_warning_flags_cc
 }
 config("no_chromium_code") {
   cflags = []
@@ -780,6 +1030,8 @@
       "-Wno-deprecated",
     ]
   }
+  cflags += default_warning_flags
+  cflags_cc += default_warning_flags_cc
 }
 
 # rtti ------------------------------------------------------------------------
@@ -800,248 +1052,6 @@
 }
 
 # Warnings ---------------------------------------------------------------------
-#
-# This is where we disable various warnings that we've decided aren't
-# worthwhile, and enable special warnings.
-
-config("default_warnings") {
-  if (is_win) {
-    cflags = []
-
-    if (!is_clang || current_cpu != "x86") {
-      cflags += [ "/WX" ]  # Treat warnings as errors.
-    }
-
-    cflags += [
-      # Warnings permanently disabled:
-
-      # TODO(GYP) The GYP build doesn't have this globally enabled but disabled
-      # for a bunch of individual targets. Re-enable this globally when those
-      # targets are fixed.
-      "/wd4018",  # Comparing signed and unsigned values.
-
-      # C4127: conditional expression is constant
-      # This warning can in theory catch dead code and other problems, but
-      # triggers in far too many desirable cases where the conditional
-      # expression is either set by macros or corresponds some legitimate
-      # compile-time constant expression (due to constant template args,
-      # conditionals comparing the sizes of different types, etc.).  Some of
-      # these can be worked around, but it's not worth it.
-      "/wd4127",
-
-      # C4251: 'identifier' : class 'type' needs to have dll-interface to be
-      #        used by clients of class 'type2'
-      # This is necessary for the shared library build.
-      "/wd4251",
-
-      # C4351: new behavior: elements of array 'array' will be default
-      #        initialized
-      # This is a silly "warning" that basically just alerts you that the
-      # compiler is going to actually follow the language spec like it's
-      # supposed to, instead of not following it like old buggy versions did.
-      # There's absolutely no reason to turn this on.
-      "/wd4351",
-
-      # C4355: 'this': used in base member initializer list
-      # It's commonly useful to pass |this| to objects in a class' initializer
-      # list.  While this warning can catch real bugs, most of the time the
-      # constructors in question don't attempt to call methods on the passed-in
-      # pointer (until later), and annotating every legit usage of this is
-      # simply more hassle than the warning is worth.
-      "/wd4355",
-
-      # C4503: 'identifier': decorated name length exceeded, name was
-      #        truncated
-      # This only means that some long error messages might have truncated
-      # identifiers in the presence of lots of templates.  It has no effect on
-      # program correctness and there's no real reason to waste time trying to
-      # prevent it.
-      "/wd4503",
-
-      # C4611: interaction between 'function' and C++ object destruction is
-      #        non-portable
-      # This warning is unavoidable when using e.g. setjmp/longjmp.  MSDN
-      # suggests using exceptions instead of setjmp/longjmp for C++, but
-      # Chromium code compiles without exception support.  We therefore have to
-      # use setjmp/longjmp for e.g. JPEG decode error handling, which means we
-      # have to turn off this warning (and be careful about how object
-      # destruction happens in such cases).
-      "/wd4611",
-
-      # Warnings to evaluate and possibly fix/reenable later:
-
-      "/wd4100",  # Unreferenced formal function parameter.
-      "/wd4121",  # Alignment of a member was sensitive to packing.
-      "/wd4244",  # Conversion: possible loss of data.
-      "/wd4481",  # Nonstandard extension: override specifier.
-      "/wd4505",  # Unreferenced local function has been removed.
-      "/wd4510",  # Default constructor could not be generated.
-      "/wd4512",  # Assignment operator could not be generated.
-      "/wd4610",  # Class can never be instantiated, constructor required.
-      "/wd4996",  # Deprecated function warning.
-    ]
-
-    # VS xtree header file needs to be patched or 4702 (unreachable code
-    # warning) is reported if _HAS_EXCEPTIONS=0. Disable the warning if xtree is
-    # not patched.
-    if (!msvs_xtree_patched &&
-        exec_script("../../win_is_xtree_patched.py", [], "value") == 0) {
-      cflags += [ "/wd4702" ]  # Unreachable code.
-    }
-
-    # Building with Clang on Windows is a work in progress and very
-    # experimental. See crbug.com/82385.
-    # Keep this in sync with the similar block in build/common.gypi
-    if (is_clang) {
-      cflags += [
-        # TODO(hans): Make this list shorter eventually.
-        "-Qunused-arguments",
-        "-Wno-c++11-compat-deprecated-writable-strings",
-        "-Wno-deprecated-declarations",
-        "-Wno-empty-body",
-        "-Wno-enum-conversion",
-        "-Wno-extra-tokens",
-        "-Wno-ignored-attributes",
-        "-Wno-incompatible-pointer-types",
-        "-Wno-int-to-void-pointer-cast",
-        "-Wno-invalid-noreturn",
-        "-Wno-logical-op-parentheses",
-        "-Wno-microsoft",
-        "-Wno-missing-braces",
-        "-Wno-missing-declarations",
-        "-Wno-msvc-include",
-        "-Wno-null-dereference",
-        "-Wno-overloaded-virtual",
-        "-Wno-parentheses",
-        "-Wno-pointer-sign",
-        "-Wno-reorder",
-        "-Wno-return-type-c-linkage",
-        "-Wno-self-assign",
-        "-Wno-sometimes-uninitialized",
-        "-Wno-switch",
-        "-Wno-tautological-compare",
-        "-Wno-unknown-pragmas",
-        "-Wno-unsequenced",
-        "-Wno-unused-function",
-        "-Wno-unused-private-field",
-        "-Wno-unused-value",
-        "-Wno-unused-variable",
-        "-Wno-unused-local-typedef",  # http://crbug.com/411648
-        "-Wno-inconsistent-missing-override",  #http://crbug.com/428099
-      ]
-    }
-  } else {
-    # Common GCC warning setup.
-    cflags = [
-      # Enables.
-      "-Wendif-labels",  # Weird old-style text after an #endif.
-      "-Werror",  # Warnings as errors.
-
-      # Disables.
-      "-Wno-missing-field-initializers",  # "struct foo f = {0};"
-      "-Wno-unused-parameter",  # Unused function parameters.
-    ]
-    cflags_cc = []
-
-    if (is_mac) {
-      cflags += [ "-Wnewline-eof" ]
-      if (!is_nacl) {
-        # When compiling Objective-C, warns if a method is used whose
-        # availability is newer than the deployment target. This is not
-        # required when compiling Chrome for iOS.
-        cflags += [ "-Wpartial-availability" ]
-      }
-    }
-
-    if (gcc_version >= 48) {
-      cflags_cc += [
-        # See comment for -Wno-c++11-narrowing.
-        "-Wno-narrowing",
-
-        # TODO(thakis): Remove, http://crbug.com/263960
-        "-Wno-literal-suffix",
-      ]
-    }
-
-    # Suppress warnings about ABI changes on ARM (Clang doesn't give this
-    # warning).
-    if (current_cpu == "arm" && !is_clang) {
-      cflags += [ "-Wno-psabi" ]
-    }
-
-    if (is_android) {
-      # Disable any additional warnings enabled by the Android build system but
-      # which chromium does not build cleanly with (when treating warning as
-      # errors).
-      cflags += [
-        "-Wno-extra",
-        "-Wno-ignored-qualifiers",
-        "-Wno-type-limits",
-      ]
-      cflags_cc += [
-        # Disabling c++0x-compat should be handled in WebKit, but
-        # this currently doesn't work because gcc_version is not set
-        # correctly when building with the Android build system.
-        # TODO(torne): Fix this in WebKit.
-        "-Wno-error=c++0x-compat",
-
-        # Other things unrelated to -Wextra:
-        "-Wno-non-virtual-dtor",
-        "-Wno-sign-promo",
-      ]
-    }
-
-    if (gcc_version >= 48) {
-      # Don't warn about the "typedef 'foo' locally defined but not used"
-      # for gcc 4.8.
-      # TODO: remove this flag once all builds work. See crbug.com/227506
-      cflags += [ "-Wno-unused-local-typedefs" ]
-    }
-  }
-
-  if (is_clang) {
-    cflags += [
-      # This warns on using ints as initializers for floats in
-      # initializer lists (e.g. |int a = f(); CGSize s = { a, a };|),
-      # which happens in several places in chrome code. Not sure if
-      # this is worth fixing.
-      "-Wno-c++11-narrowing",
-
-      # Don't die on dtoa code that uses a char as an array index.
-      # This is required solely for base/third_party/dmg_fp/dtoa.cc.
-      # TODO(brettw) move this to that project then!
-      "-Wno-char-subscripts",
-
-      # Warns on switches on enums that cover all enum values but
-      # also contain a default: branch. Chrome is full of that.
-      "-Wno-covered-switch-default",
-
-      # Clang considers the `register` keyword as deprecated, but e.g.
-      # code generated by flex (used in angle) contains that keyword.
-      # http://crbug.com/255186
-      "-Wno-deprecated-register",
-
-      # TODO(thakis): This used to be implied by -Wno-unused-function,
-      # which we no longer use. Check if it makes sense to remove
-      # this as well. http://crbug.com/316352
-      "-Wno-unneeded-internal-declaration",
-
-      # TODO(thakis): Remove, http://crbug.com/263960
-      "-Wno-reserved-user-defined-literal",
-    ]
-
-    # NaCl's Clang compiler and Chrome's hermetic Clang compiler will almost
-    # always have different versions. Certain flags may not be recognized by
-    # one version or the other.
-    if (!is_nacl) {
-      # Flags NaCl does not recognize.
-      cflags += [
-        # TODO(hans): Get this cleaned up.
-        "-Wno-inconsistent-missing-override",
-      ]
-    }
-  }
-}
 
 # This will generate warnings when using Clang if code generates exit-time
 # destructors, which will slow down closing the program.
diff --git a/build/config/ui.gni b/build/config/ui.gni
index bee5f48..7d3c1693 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -35,23 +35,12 @@
 
   # Whether the entire browser uses toolkit-views on Mac instead of Cocoa.
   mac_views_browser = false
-
-  # Whether we should use glib, a low level C utility library.
-  use_glib = is_linux && !use_ozone
 }
 
 # Additional dependent variables -----------------------------------------------
 #
 # These variables depend on other variables and can't be set externally.
 
-if (is_linux && use_glib) {
-  use_cairo = true
-  use_pango = true
-} else {
-  use_cairo = false
-  use_pango = false
-}
-
 # Use GPU accelerated cross process image transport by default on linux builds
 # with the Aura window manager.
 ui_compositor_image_transport = use_aura && is_linux
@@ -61,6 +50,17 @@
 # Indicates if the UI toolkit depends on X11.
 use_x11 = is_linux && !use_ozone
 
+# Whether we should use glib, a low level C utility library.
+use_glib = is_linux && !use_ozone
+
+if (is_linux && use_glib) {
+  use_cairo = true
+  use_pango = true
+} else {
+  use_cairo = false
+  use_pango = false
+}
+
 use_ozone_evdev = use_ozone
 
 use_clipboard_aurax11 = is_linux && use_aura && use_x11
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index 0ce7b2eb..8108100 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -606,7 +606,7 @@
           'dependencies': [
             # TODO(GYP): Figure out which of these run on android/mac/win/ios/etc.
             '../net/net.gyp:net_docs',
-            '../remoting/app_remoting_test.gyp:ar_sample_test_driver',
+            '../remoting/remoting.gyp:ar_sample_test_driver',
 
             # TODO(GYP): in progress - see tfarina.
             '../third_party/webrtc/tools/tools.gyp:frame_analyzer',
@@ -640,7 +640,7 @@
             '../gpu/gpu.gyp:angle_perftests',
             '../net/net.gyp:net_docs',
             '../ppapi/ppapi_internal.gyp:ppapi_perftests',
-            '../remoting/app_remoting_test.gyp:ar_sample_test_driver',
+            '../remoting/remoting.gyp:ar_sample_test_driver',
             '../remoting/remoting.gyp:remoting_breakpad_tester',
             '../remoting/remoting.gyp:remoting_console',
             '../remoting/remoting.gyp:remoting_desktop',
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
index 8fb4f0ec..ba06159 100644
--- a/build/ios/grit_whitelist.txt
+++ b/build/ios/grit_whitelist.txt
@@ -21,6 +21,7 @@
 IDR_DIR_HEADER_HTML
 IDR_DISTILLABLE_PAGE_SERIALIZED_MODEL
 IDR_DISTILLER_CSS
+IDR_DISTILLER_IOS_CSS
 IDR_DISTILLER_JS
 IDR_DOM_DISTILLER_VIEWER_HTML
 IDR_DOM_DISTILLER_VIEWER_JS
@@ -326,6 +327,7 @@
 IDS_DOM_DISTILLER_QUALITY_ANSWER_NO
 IDS_DOM_DISTILLER_QUALITY_ANSWER_YES
 IDS_DOM_DISTILLER_QUALITY_QUESTION
+IDS_DOM_DISTILLER_VIEWER_CLOSE_READER_VIEW
 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_CONTENT
 IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE
 IDS_DOM_DISTILLER_VIEWER_LOADING_STRING
@@ -540,8 +542,6 @@
 IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_NAME
 IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH
 IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH_DESCRIPTION
-IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_DESCRIPTION
-IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_NAME
 IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_DESCRIPTION
 IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_NAME
 IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_DESCRIPTION
diff --git a/build/isolate.gypi b/build/isolate.gypi
index 092a4e4..69af5b05 100644
--- a/build/isolate.gypi
+++ b/build/isolate.gypi
@@ -110,9 +110,6 @@
             '--extra-variable', 'mac_product_name=<(mac_product_name)',
           ],
         }],
-        ["test_isolation_outdir!=''", {
-          'action': [ '--isolate-server', '<(test_isolation_outdir)' ],
-        }],
         ["test_isolation_mode == 'prepare'", {
           'outputs': [
             '<(PRODUCT_DIR)/<(RULE_INPUT_ROOT).isolated.gen.json',
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 22df7d0f..cd86520 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -122,8 +122,6 @@
     "layers/heads_up_display_layer.h",
     "layers/heads_up_display_layer_impl.cc",
     "layers/heads_up_display_layer_impl.h",
-    "layers/image_layer.cc",
-    "layers/image_layer.h",
     "layers/io_surface_layer.cc",
     "layers/io_surface_layer.h",
     "layers/io_surface_layer_impl.cc",
@@ -388,8 +386,6 @@
     "resources/bitmap_skpicture_content_layer_updater.h",
     "resources/content_layer_updater.cc",
     "resources/content_layer_updater.h",
-    "resources/image_layer_updater.cc",
-    "resources/image_layer_updater.h",
     "resources/layer_painter.h",
     "resources/layer_updater.cc",
     "resources/layer_updater.h",
@@ -538,9 +534,6 @@
     ]
   }
 
-  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
   public_deps = [
     "//cc/base",
     "//skia",
@@ -574,12 +567,8 @@
     "test/begin_frame_args_test.h",
     "test/failure_output_surface.cc",
     "test/failure_output_surface.h",
-    "test/fake_content_layer.cc",
-    "test/fake_content_layer.h",
     "test/fake_content_layer_client.cc",
     "test/fake_content_layer_client.h",
-    "test/fake_content_layer_impl.cc",
-    "test/fake_content_layer_impl.h",
     "test/fake_delegated_renderer_layer.cc",
     "test/fake_delegated_renderer_layer.h",
     "test/fake_delegated_renderer_layer_impl.cc",
@@ -701,8 +690,6 @@
     "test/tiled_layer_test_common.h",
   ]
 
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
   include_dirs = [
     ".",
     "test",
@@ -791,6 +778,7 @@
     "layers/tiled_layer_unittest.cc",
     "layers/ui_resource_layer_impl_unittest.cc",
     "layers/ui_resource_layer_unittest.cc",
+    "layers/video_frame_provider_client_impl_unittest.cc",
     "layers/video_layer_impl_unittest.cc",
     "output/begin_frame_args_unittest.cc",
     "output/delegating_renderer_unittest.cc",
@@ -875,8 +863,6 @@
     "test/run_all_unittests.cc",
   ]
 
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
   deps = [
     ":cc",
     ":test_support",
@@ -917,8 +903,6 @@
     "trees/occlusion_tracker_perftest.cc",
   ]
 
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
   deps = [
     ":cc",
     ":test_support",
diff --git a/cc/base/list_container_unittest.cc b/cc/base/list_container_unittest.cc
index cfe593b..51c119c 100644
--- a/cc/base/list_container_unittest.cc
+++ b/cc/base/list_container_unittest.cc
@@ -513,16 +513,16 @@
 TEST(ListContainerTest, SimpleDeletion) {
   ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
   std::vector<SimpleDerivedElement*> sde_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
+  int size = 10;
+  for (int i = 0; i < size; ++i) {
     sde_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
     sde_list.back()->set_value(i);
   }
-  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(static_cast<size_t>(size), list.size());
 
   list.EraseAndInvalidateAllPointers(list.begin());
   --size;
-  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(static_cast<size_t>(size), list.size());
   int i = 1;
   for (ListContainer<DerivedElement>::Iterator iter = list.begin();
        iter != list.end(); ++iter) {
@@ -643,13 +643,13 @@
 TEST(ListContainerTest, SimpleManipulationWithIndexSimpleDerivedElement) {
   ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
   std::vector<SimpleDerivedElement*> de_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
+  int size = 10;
+  for (int i = 0; i < size; ++i) {
     de_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
   }
-  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(static_cast<size_t>(size), list.size());
 
-  for (size_t i = 0; i < size; ++i) {
+  for (int i = 0; i < size; ++i) {
     static_cast<SimpleDerivedElement*>(list.ElementAt(i))->set_value(i);
   }
 
@@ -665,13 +665,13 @@
      SimpleManipulationWithIndexMoreThanOneAllocationSimpleDerivedElement) {
   ListContainer<DerivedElement> list(LargestDerivedElementSize(), 2);
   std::vector<SimpleDerivedElement*> de_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
+  int size = 10;
+  for (int i = 0; i < size; ++i) {
     de_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
   }
-  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(static_cast<size_t>(size), list.size());
 
-  for (size_t i = 0; i < size; ++i) {
+  for (int i = 0; i < size; ++i) {
     static_cast<SimpleDerivedElement*>(list.ElementAt(i))->set_value(i);
   }
 
diff --git a/cc/blink/web_content_layer_impl.cc b/cc/blink/web_content_layer_impl.cc
index 98ff60b9..dcdba6b1 100644
--- a/cc/blink/web_content_layer_impl.cc
+++ b/cc/blink/web_content_layer_impl.cc
@@ -39,20 +39,13 @@
 
 WebContentLayerImpl::WebContentLayerImpl(blink::WebContentLayerClient* client)
     : client_(client) {
-  if (WebLayerImpl::UsingPictureLayer())
-    layer_ = make_scoped_ptr(new WebLayerImpl(
-        PictureLayer::Create(WebLayerImpl::LayerSettings(), this)));
-  else
-    layer_ = make_scoped_ptr(new WebLayerImpl(
-        ContentLayer::Create(WebLayerImpl::LayerSettings(), this)));
+  layer_ = make_scoped_ptr(new WebLayerImpl(
+      PictureLayer::Create(WebLayerImpl::LayerSettings(), this)));
   layer_->layer()->SetIsDrawable(true);
 }
 
 WebContentLayerImpl::~WebContentLayerImpl() {
-  if (WebLayerImpl::UsingPictureLayer())
-    static_cast<PictureLayer*>(layer_->layer())->ClearClient();
-  else
-    static_cast<ContentLayer*>(layer_->layer())->ClearClient();
+  static_cast<PictureLayer*>(layer_->layer())->ClearClient();
 }
 
 blink::WebLayer* WebContentLayerImpl::layer() {
diff --git a/cc/blink/web_external_texture_layer_impl.cc b/cc/blink/web_external_texture_layer_impl.cc
index 0b6bbdb..a9c132b 100644
--- a/cc/blink/web_external_texture_layer_impl.cc
+++ b/cc/blink/web_external_texture_layer_impl.cc
@@ -87,10 +87,10 @@
   if (bitmap) {
     *mailbox = cc::TextureMailbox(bitmap->shared_bitmap(), bitmap->size());
   } else {
-    *mailbox =
-        cc::TextureMailbox(name, GL_TEXTURE_2D, client_mailbox.syncPoint);
+    // TODO(achaulk): pass a valid size here if allowOverlay is set.
+    *mailbox = cc::TextureMailbox(name, GL_TEXTURE_2D, client_mailbox.syncPoint,
+                                  gfx::Size(), client_mailbox.allowOverlay);
   }
-  mailbox->set_allow_overlay(client_mailbox.allowOverlay);
   mailbox->set_nearest_neighbor(client_mailbox.nearestNeighbor);
 
   if (mailbox->IsValid()) {
diff --git a/cc/blink/web_image_layer_impl.cc b/cc/blink/web_image_layer_impl.cc
index 1cc6e80d..55e28ef8 100644
--- a/cc/blink/web_image_layer_impl.cc
+++ b/cc/blink/web_image_layer_impl.cc
@@ -6,18 +6,13 @@
 
 #include "cc/blink/web_layer_impl.h"
 #include "cc/blink/web_layer_impl_fixed_bounds.h"
-#include "cc/layers/image_layer.h"
 #include "cc/layers/picture_image_layer.h"
 
 namespace cc_blink {
 
 WebImageLayerImpl::WebImageLayerImpl() {
-  if (WebLayerImpl::UsingPictureLayer())
-    layer_.reset(new WebLayerImplFixedBounds(
-        cc::PictureImageLayer::Create(WebLayerImpl::LayerSettings())));
-  else
-    layer_.reset(new WebLayerImpl(
-        cc::ImageLayer::Create(WebLayerImpl::LayerSettings())));
+  layer_.reset(new WebLayerImplFixedBounds(
+      cc::PictureImageLayer::Create(WebLayerImpl::LayerSettings())));
 }
 
 WebImageLayerImpl::~WebImageLayerImpl() {
@@ -28,20 +23,14 @@
 }
 
 void WebImageLayerImpl::setImageBitmap(const SkBitmap& bitmap) {
-  if (WebLayerImpl::UsingPictureLayer()) {
-    static_cast<cc::PictureImageLayer*>(layer_->layer())->SetBitmap(bitmap);
-    static_cast<WebLayerImplFixedBounds*>(layer_.get())
-        ->SetFixedBounds(gfx::Size(bitmap.width(), bitmap.height()));
-  } else {
-    static_cast<cc::ImageLayer*>(layer_->layer())->SetBitmap(bitmap);
-  }
+  static_cast<cc::PictureImageLayer*>(layer_->layer())->SetBitmap(bitmap);
+  static_cast<WebLayerImplFixedBounds*>(layer_.get())
+      ->SetFixedBounds(gfx::Size(bitmap.width(), bitmap.height()));
 }
 
 void WebImageLayerImpl::setNearestNeighbor(bool nearest_neighbor) {
-  if (WebLayerImpl::UsingPictureLayer()) {
-    static_cast<cc::PictureImageLayer*>(layer_->layer())
-        ->SetNearestNeighbor(nearest_neighbor);
-  }
+  static_cast<cc::PictureImageLayer*>(layer_->layer())
+      ->SetNearestNeighbor(nearest_neighbor);
 }
 
 }  // namespace cc_blink
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index f0fd873..3ba9431 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -46,8 +46,6 @@
 namespace cc_blink {
 namespace {
 
-bool g_impl_side_painting_enabled = false;
-
 base::LazyInstance<cc::LayerSettings> g_layer_settings =
     LAZY_INSTANCE_INITIALIZER;
 
@@ -71,16 +69,6 @@
 }
 
 // static
-bool WebLayerImpl::UsingPictureLayer() {
-  return g_impl_side_painting_enabled;
-}
-
-// static
-void WebLayerImpl::SetImplSidePaintingEnabled(bool enabled) {
-  g_impl_side_painting_enabled = enabled;
-}
-
-// static
 void WebLayerImpl::SetLayerSettings(const cc::LayerSettings& settings) {
   g_layer_settings.Get() = settings;
 }
diff --git a/cc/blink/web_layer_impl.h b/cc/blink/web_layer_impl.h
index cf4eaae7..eb049b8 100644
--- a/cc/blink/web_layer_impl.h
+++ b/cc/blink/web_layer_impl.h
@@ -52,9 +52,6 @@
   CC_BLINK_EXPORT explicit WebLayerImpl(scoped_refptr<cc::Layer>);
   virtual ~WebLayerImpl();
 
-  static bool UsingPictureLayer();
-  CC_BLINK_EXPORT static void SetImplSidePaintingEnabled(bool enabled);
-
   CC_BLINK_EXPORT static void SetLayerSettings(
       const cc::LayerSettings& settings);
   CC_BLINK_EXPORT static const cc::LayerSettings& LayerSettings();
diff --git a/cc/cc.gyp b/cc/cc.gyp
index bd2ae27..8245f97 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -178,8 +178,6 @@
         'layers/heads_up_display_layer.h',
         'layers/heads_up_display_layer_impl.cc',
         'layers/heads_up_display_layer_impl.h',
-        'layers/image_layer.cc',
-        'layers/image_layer.h',
         'layers/io_surface_layer.cc',
         'layers/io_surface_layer.h',
         'layers/io_surface_layer_impl.cc',
@@ -445,8 +443,6 @@
         'resources/bitmap_skpicture_content_layer_updater.h',
         'resources/content_layer_updater.cc',
         'resources/content_layer_updater.h',
-        'resources/image_layer_updater.cc',
-        'resources/image_layer_updater.h',
         'resources/layer_painter.h',
         'resources/layer_updater.cc',
         'resources/layer_updater.h',
@@ -590,8 +586,6 @@
       'includes': [
         '../build/android/increase_size_for_speed.gypi',
       ],
-      # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-      'msvs_disabled_warnings': [ 4267, ],
       'conditions': [
         ['target_arch == "ia32" or target_arch == "x64"', {
           'sources': [
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index c1e456a7..994d6102 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -62,6 +62,7 @@
       'layers/tiled_layer_unittest.cc',
       'layers/ui_resource_layer_impl_unittest.cc',
       'layers/ui_resource_layer_unittest.cc',
+      'layers/video_frame_provider_client_impl_unittest.cc',
       'layers/video_layer_impl_unittest.cc',
       'output/begin_frame_args_unittest.cc',
       'output/bsp_tree_unittest.cc',
@@ -155,12 +156,8 @@
       'test/begin_frame_args_test.h',
       'test/failure_output_surface.cc',
       'test/failure_output_surface.h',
-      'test/fake_content_layer.cc',
-      'test/fake_content_layer.h',
       'test/fake_content_layer_client.cc',
       'test/fake_content_layer_client.h',
-      'test/fake_content_layer_impl.cc',
-      'test/fake_content_layer_impl.h',
       'test/fake_delegated_renderer_layer.cc',
       'test/fake_delegated_renderer_layer.h',
       'test/fake_delegated_renderer_layer_impl.cc',
@@ -334,8 +331,6 @@
           }
         ],
       ],
-      # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-      'msvs_disabled_warnings': [ 4267, ],
     },
     {
       # GN version: //cc/cc_perftests
@@ -396,8 +391,6 @@
           }
         ],
       ],
-      # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-      'msvs_disabled_warnings': [ 4267, ],
     },
     {
       'target_name': 'cc_test_support',
@@ -429,8 +422,6 @@
       'sources': [
         '<@(cc_tests_support_files)',
       ],
-      # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-      'msvs_disabled_warnings': [ 4267, ],
     },
   ],
   'conditions': [
diff --git a/cc/cc_unittests.isolate b/cc/cc_unittests.isolate
index 7c359d0..6a16fcd 100644
--- a/cc/cc_unittests.isolate
+++ b/cc/cc_unittests.isolate
@@ -46,7 +46,6 @@
     ['OS=="linux"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
         ],
       },
@@ -54,7 +53,6 @@
     ['OS=="mac"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
           '<(PRODUCT_DIR)/osmesa.so',
         ],
       },
@@ -62,7 +60,6 @@
     ['OS=="win"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/osmesa.dll',
         ],
       },
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index 81d91b87..5e5f166 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -136,7 +136,7 @@
   virtual void PinchGestureEnd() = 0;
 
   // Request another callback to InputHandlerClient::Animate().
-  virtual void SetNeedsAnimate() = 0;
+  virtual void SetNeedsAnimateInput() = 0;
 
   // Whether the layer under |viewport_point| is the currently scrolling layer.
   virtual bool IsCurrentlyScrollingLayerAt(const gfx::Point& viewport_point,
diff --git a/cc/input/layer_scroll_offset_delegate.h b/cc/input/layer_scroll_offset_delegate.h
index 02ba011..0afc4db 100644
--- a/cc/input/layer_scroll_offset_delegate.h
+++ b/cc/input/layer_scroll_offset_delegate.h
@@ -6,6 +6,8 @@
 #define CC_INPUT_LAYER_SCROLL_OFFSET_DELEGATE_H_
 
 #include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/time/time.h"
 #include "ui/gfx/geometry/scroll_offset.h"
 #include "ui/gfx/geometry/size_f.h"
 
@@ -44,7 +46,14 @@
 
   // This is called by the compositor to check whether a delegate-managed fling
   // is active or not.
-  virtual bool IsExternalFlingActive() const = 0;
+  // TODO(hush): Remove after WebView's smooth scrolling path is unified with
+  // Chrome's.
+  virtual bool IsExternalScrollActive() const = 0;
+
+  // This is called by the compositor when a fling hitting the root layer
+  // requires a scheduled animation update.
+  typedef base::Callback<void(base::TimeTicks)> AnimationCallback;
+  virtual void SetNeedsAnimate(const AnimationCallback& animation) = 0;
 
  protected:
   LayerScrollOffsetDelegate() {}
diff --git a/cc/layers/delegated_renderer_layer_impl.cc b/cc/layers/delegated_renderer_layer_impl.cc
index 4532312..e48cab7 100644
--- a/cc/layers/delegated_renderer_layer_impl.cc
+++ b/cc/layers/delegated_renderer_layer_impl.cc
@@ -180,7 +180,7 @@
     RenderPassList::iterator to_take =
         render_passes_in_draw_order->begin() + i;
     render_passes_index_by_id_.insert(
-        std::pair<RenderPassId, int>((*to_take)->id, i));
+        RenderPassToIndexMap::value_type((*to_take)->id, i));
     scoped_ptr<RenderPass> taken_render_pass =
         render_passes_in_draw_order->take(to_take);
     render_passes_in_draw_order_.push_back(taken_render_pass.Pass());
@@ -210,8 +210,13 @@
   have_render_passes_to_push_ = false;
 }
 
-static inline int IndexToId(int index) { return index + 1; }
-static inline int IdToIndex(int id) { return id - 1; }
+static inline size_t IndexToId(size_t index) {
+  return index + 1;
+}
+static inline size_t IdToIndex(size_t id) {
+  DCHECK_GT(id, 0u);
+  return id - 1;
+}
 
 RenderPassId DelegatedRendererLayerImpl::FirstContributingRenderPassId() const {
   return RenderPassId(id(), IndexToId(0));
@@ -225,13 +230,13 @@
 bool DelegatedRendererLayerImpl::ConvertDelegatedRenderPassId(
     RenderPassId delegated_render_pass_id,
     RenderPassId* output_render_pass_id) const {
-  base::hash_map<RenderPassId, int>::const_iterator found =
+  RenderPassToIndexMap::const_iterator found =
       render_passes_index_by_id_.find(delegated_render_pass_id);
   if (found == render_passes_index_by_id_.end()) {
     // Be robust against a RenderPass id that isn't part of the frame.
     return false;
   }
-  unsigned delegated_render_pass_index = found->second;
+  size_t delegated_render_pass_index = found->second;
   *output_render_pass_id =
       RenderPassId(id(), IndexToId(delegated_render_pass_index));
   return true;
@@ -249,7 +254,7 @@
                                           inverse_device_scale_factor_);
 
   for (size_t i = 0; i < render_passes_in_draw_order_.size() - 1; ++i) {
-    RenderPassId output_render_pass_id(-1, -1);
+    RenderPassId output_render_pass_id;
     bool present =
         ConvertDelegatedRenderPassId(render_passes_in_draw_order_[i]->id,
                                      &output_render_pass_id);
@@ -257,7 +262,7 @@
     // Don't clash with the RenderPass we generate if we own a RenderSurface.
     DCHECK(present) << render_passes_in_draw_order_[i]->id.layer_id << ", "
                     << render_passes_in_draw_order_[i]->id.index;
-    DCHECK_GT(output_render_pass_id.index, 0);
+    DCHECK_GT(output_render_pass_id.index, 0u);
 
     scoped_ptr<RenderPass> copy_pass =
         render_passes_in_draw_order_[i]->Copy(output_render_pass_id);
@@ -308,7 +313,7 @@
     // Verify that the RenderPass we are appending to was created by us.
     DCHECK(target_render_pass_id.layer_id == id());
 
-    int render_pass_index = IdToIndex(target_render_pass_id.index);
+    size_t render_pass_index = IdToIndex(target_render_pass_id.index);
     const RenderPass* delegated_render_pass =
         render_passes_in_draw_order_[render_pass_index];
     AppendRenderPassQuads(render_pass,
@@ -343,7 +348,7 @@
   const int kStripeWidth = 300;
   const int kStripeHeight = 300;
 
-  for (size_t i = 0; ; ++i) {
+  for (int i = 0;; ++i) {
     // For horizontal lines.
     int x =  kStripeWidth * i;
     int width = std::min(kStripeWidth, content_bounds().width() - x - 1);
@@ -436,7 +441,7 @@
         if (render_target() == this) {
           DCHECK(!is_clipped());
           DCHECK(render_surface());
-          DCHECK_EQ(0, num_unclipped_descendants());
+          DCHECK_EQ(0u, num_unclipped_descendants());
           output_shared_quad_state->clip_rect =
               MathUtil::MapEnclosingClippedRect(
                   delegated_frame_to_target_transform,
@@ -486,7 +491,7 @@
     } else {
       RenderPassId delegated_contributing_render_pass_id =
           RenderPassDrawQuad::MaterialCast(delegated_quad)->render_pass_id;
-      RenderPassId output_contributing_render_pass_id(-1, -1);
+      RenderPassId output_contributing_render_pass_id;
 
       bool present =
           ConvertDelegatedRenderPassId(delegated_contributing_render_pass_id,
diff --git a/cc/layers/delegated_renderer_layer_impl.h b/cc/layers/delegated_renderer_layer_impl.h
index 617d76f..2543894 100644
--- a/cc/layers/delegated_renderer_layer_impl.h
+++ b/cc/layers/delegated_renderer_layer_impl.h
@@ -87,7 +87,9 @@
   bool have_render_passes_to_push_;
   float inverse_device_scale_factor_;
   RenderPassList render_passes_in_draw_order_;
-  base::hash_map<RenderPassId, int> render_passes_index_by_id_;
+
+  using RenderPassToIndexMap = base::hash_map<RenderPassId, size_t>;
+  RenderPassToIndexMap render_passes_index_by_id_;
   ResourceProvider::ResourceIdSet resources_;
 
   int child_id_;
diff --git a/cc/layers/delegated_renderer_layer_impl_unittest.cc b/cc/layers/delegated_renderer_layer_impl_unittest.cc
index cc5f03d..8976cc5 100644
--- a/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -307,16 +307,16 @@
   // The DelegatedRendererLayer should have added its contributing RenderPasses
   // to the frame.
   EXPECT_EQ(4, frame.render_passes[1]->id.layer_id);
-  EXPECT_EQ(1, frame.render_passes[1]->id.index);
+  EXPECT_EQ(1u, frame.render_passes[1]->id.index);
   EXPECT_EQ(4, frame.render_passes[2]->id.layer_id);
-  EXPECT_EQ(2, frame.render_passes[2]->id.index);
+  EXPECT_EQ(2u, frame.render_passes[2]->id.index);
   // And all other RenderPasses should be non-delegated.
   EXPECT_NE(4, frame.render_passes[0]->id.layer_id);
-  EXPECT_EQ(0, frame.render_passes[0]->id.index);
+  EXPECT_EQ(0u, frame.render_passes[0]->id.index);
   EXPECT_NE(4, frame.render_passes[3]->id.layer_id);
-  EXPECT_EQ(0, frame.render_passes[3]->id.index);
+  EXPECT_EQ(0u, frame.render_passes[3]->id.index);
   EXPECT_NE(4, frame.render_passes[4]->id.layer_id);
-  EXPECT_EQ(0, frame.render_passes[4]->id.index);
+  EXPECT_EQ(0u, frame.render_passes[4]->id.index);
 
   // The DelegatedRendererLayer should have added its RenderPasses to the frame
   // in order.
@@ -341,9 +341,9 @@
   // The DelegatedRendererLayer should have added its contributing RenderPasses
   // to the frame.
   EXPECT_EQ(4, frame.render_passes[1]->id.layer_id);
-  EXPECT_EQ(1, frame.render_passes[1]->id.index);
+  EXPECT_EQ(1u, frame.render_passes[1]->id.index);
   EXPECT_EQ(4, frame.render_passes[2]->id.layer_id);
-  EXPECT_EQ(2, frame.render_passes[2]->id.index);
+  EXPECT_EQ(2u, frame.render_passes[2]->id.index);
 
   // The DelegatedRendererLayer should have added copies of its quads to
   // contributing RenderPasses.
@@ -485,20 +485,20 @@
   // The DelegatedRendererLayer should have added its contributing RenderPasses
   // to the frame.
   EXPECT_EQ(4, frame.render_passes[1]->id.layer_id);
-  EXPECT_EQ(1, frame.render_passes[1]->id.index);
+  EXPECT_EQ(1u, frame.render_passes[1]->id.index);
   EXPECT_EQ(4, frame.render_passes[2]->id.layer_id);
-  EXPECT_EQ(2, frame.render_passes[2]->id.index);
+  EXPECT_EQ(2u, frame.render_passes[2]->id.index);
   // The DelegatedRendererLayer should have added a RenderPass for its surface
   // to the frame.
   EXPECT_EQ(4, frame.render_passes[1]->id.layer_id);
-  EXPECT_EQ(0, frame.render_passes[3]->id.index);
+  EXPECT_EQ(0u, frame.render_passes[3]->id.index);
   // And all other RenderPasses should be non-delegated.
   EXPECT_NE(4, frame.render_passes[0]->id.layer_id);
-  EXPECT_EQ(0, frame.render_passes[0]->id.index);
+  EXPECT_EQ(0u, frame.render_passes[0]->id.index);
   EXPECT_NE(4, frame.render_passes[4]->id.layer_id);
-  EXPECT_EQ(0, frame.render_passes[4]->id.index);
+  EXPECT_EQ(0u, frame.render_passes[4]->id.index);
   EXPECT_NE(4, frame.render_passes[5]->id.layer_id);
-  EXPECT_EQ(0, frame.render_passes[5]->id.index);
+  EXPECT_EQ(0u, frame.render_passes[5]->id.index);
 
   // The DelegatedRendererLayer should have added its RenderPasses to the frame
   // in order.
@@ -524,9 +524,9 @@
   // The DelegatedRendererLayer should have added its contributing RenderPasses
   // to the frame.
   EXPECT_EQ(4, frame.render_passes[1]->id.layer_id);
-  EXPECT_EQ(1, frame.render_passes[1]->id.index);
+  EXPECT_EQ(1u, frame.render_passes[1]->id.index);
   EXPECT_EQ(4, frame.render_passes[2]->id.layer_id);
-  EXPECT_EQ(2, frame.render_passes[2]->id.index);
+  EXPECT_EQ(2u, frame.render_passes[2]->id.index);
 
   // The DelegatedRendererLayer should have added copies of its quads to
   // contributing RenderPasses.
@@ -764,10 +764,10 @@
     ASSERT_EQ(num_render_passes, frame.render_passes.size());
     // The contributing render pass in the DelegatedRendererLayer.
     EXPECT_EQ(2, frame.render_passes[0]->id.layer_id);
-    EXPECT_EQ(1, frame.render_passes[0]->id.index);
+    EXPECT_EQ(1u, frame.render_passes[0]->id.index);
     // The root render pass.
     EXPECT_EQ(1, frame.render_passes.back()->id.layer_id);
-    EXPECT_EQ(0, frame.render_passes.back()->id.index);
+    EXPECT_EQ(0u, frame.render_passes.back()->id.index);
 
     const QuadList& contrib_delegated_quad_list =
         frame.render_passes[0]->quad_list;
diff --git a/cc/layers/draw_properties.h b/cc/layers/draw_properties.h
index 6126489..ecb2b669 100644
--- a/cc/layers/draw_properties.h
+++ b/cc/layers/draw_properties.h
@@ -104,7 +104,7 @@
 
   // Number of descendants with a clip parent that is our ancestor. NB - this
   // does not include our clip children because they are clipped by us.
-  int num_unclipped_descendants;
+  size_t num_unclipped_descendants;
 
   // If true, the layer or some layer in its sub-tree has a CopyOutputRequest
   // present on it.
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 986c332..fad85a09 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <vector>
 
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
@@ -383,7 +384,8 @@
 
   const int kFontHeight = 15;
 
-  const int kGraphWidth = fps_counter->time_stamp_history_size() - 2;
+  const int kGraphWidth =
+      base::saturated_cast<int>(fps_counter->time_stamp_history_size()) - 2;
   const int kGraphHeight = 40;
 
   const int kHistogramWidth = 37;
@@ -625,7 +627,8 @@
   const int kPadding = 4;
   const int kFontHeight = 14;
 
-  const int kGraphWidth = paint_time_counter->HistorySize();
+  const int kGraphWidth =
+      base::saturated_cast<int>(paint_time_counter->HistorySize());
   const int kGraphHeight = 40;
 
   SkPaint paint = CreatePaint();
diff --git a/cc/layers/image_layer.cc b/cc/layers/image_layer.cc
deleted file mode 100644
index 19173b00..0000000
--- a/cc/layers/image_layer.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/layers/image_layer.h"
-
-#include "base/compiler_specific.h"
-#include "cc/resources/image_layer_updater.h"
-#include "cc/resources/layer_updater.h"
-#include "cc/resources/prioritized_resource.h"
-#include "cc/resources/resource_update_queue.h"
-#include "cc/trees/layer_tree_host.h"
-
-namespace cc {
-
-scoped_refptr<ImageLayer> ImageLayer::Create(const LayerSettings& settings) {
-  return make_scoped_refptr(new ImageLayer(settings));
-}
-
-ImageLayer::ImageLayer(const LayerSettings& settings) : TiledLayer(settings) {
-}
-
-ImageLayer::~ImageLayer() {}
-
-void ImageLayer::SetBitmap(const SkBitmap& bitmap) {
-  // SetBitmap() currently gets called whenever there is any
-  // style change that affects the layer even if that change doesn't
-  // affect the actual contents of the image (e.g. a CSS animation).
-  // With this check in place we avoid unecessary texture uploads.
-  if (bitmap.pixelRef() && bitmap.pixelRef() == bitmap_.pixelRef())
-    return;
-
-  bitmap_ = bitmap;
-  UpdateDrawsContent(HasDrawableContent());
-  SetNeedsDisplay();
-}
-
-bool ImageLayer::HasDrawableContent() const {
-  return !bitmap_.isNull() && TiledLayer::HasDrawableContent();
-}
-
-void ImageLayer::SetTexturePriorities(const PriorityCalculator& priority_calc) {
-  // Update the tile data before creating all the layer's tiles.
-  UpdateTileSizeAndTilingOption();
-
-  TiledLayer::SetTexturePriorities(priority_calc);
-}
-
-bool ImageLayer::Update(ResourceUpdateQueue* queue,
-                        const OcclusionTracker<Layer>* occlusion) {
-  CreateUpdaterIfNeeded();
-  if (!updater_->UsingBitmap(bitmap_)) {
-    updater_->SetBitmap(bitmap_);
-    UpdateTileSizeAndTilingOption();
-    InvalidateContentRect(gfx::Rect(content_bounds()));
-  }
-  return TiledLayer::Update(queue, occlusion);
-}
-
-void ImageLayer::CreateUpdaterIfNeeded() {
-  if (updater_.get())
-    return;
-
-  updater_ = ImageLayerUpdater::Create();
-  SetTextureFormat(
-      layer_tree_host()->GetRendererCapabilities().best_texture_format);
-}
-
-LayerUpdater* ImageLayer::Updater() const {
-  return updater_.get();
-}
-
-void ImageLayer::CalculateContentsScale(float ideal_contents_scale,
-                                        float* contents_scale_x,
-                                        float* contents_scale_y,
-                                        gfx::Size* content_bounds) {
-  *contents_scale_x = ImageContentsScaleX();
-  *contents_scale_y = ImageContentsScaleY();
-  *content_bounds = gfx::Size(bitmap_.width(), bitmap_.height());
-}
-
-void ImageLayer::OnOutputSurfaceCreated() {
-  SetTextureFormat(
-      layer_tree_host()->GetRendererCapabilities().best_texture_format);
-  TiledLayer::OnOutputSurfaceCreated();
-}
-
-float ImageLayer::ImageContentsScaleX() const {
-  if (bounds().IsEmpty() || bitmap_.width() == 0)
-    return 1;
-  return static_cast<float>(bitmap_.width()) / bounds().width();
-}
-
-float ImageLayer::ImageContentsScaleY() const {
-  if (bounds().IsEmpty() || bitmap_.height() == 0)
-    return 1;
-  return static_cast<float>(bitmap_.height()) / bounds().height();
-}
-
-}  // namespace cc
diff --git a/cc/layers/image_layer.h b/cc/layers/image_layer.h
deleted file mode 100644
index a81b599..0000000
--- a/cc/layers/image_layer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_LAYERS_IMAGE_LAYER_H_
-#define CC_LAYERS_IMAGE_LAYER_H_
-
-#include "cc/base/cc_export.h"
-#include "cc/layers/content_layer.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace cc {
-
-class ImageLayerUpdater;
-
-// A Layer that contains only an Image element.
-class CC_EXPORT ImageLayer : public TiledLayer {
- public:
-  static scoped_refptr<ImageLayer> Create(const LayerSettings& settings);
-
-  // Layer implementation.
-  void SetTexturePriorities(const PriorityCalculator& priority_calc) override;
-  bool Update(ResourceUpdateQueue* queue,
-              const OcclusionTracker<Layer>* occlusion) override;
-  void CalculateContentsScale(float ideal_contents_scale,
-                              float* contents_scale_x,
-                              float* contents_scale_y,
-                              gfx::Size* content_bounds) override;
-  void OnOutputSurfaceCreated() override;
-
-  void SetBitmap(const SkBitmap& image);
-
- protected:
-  bool HasDrawableContent() const override;
-
- private:
-  explicit ImageLayer(const LayerSettings& settings);
-  ~ImageLayer() override;
-
-  // TiledLayer Implementation.
-  LayerUpdater* Updater() const override;
-  void CreateUpdaterIfNeeded() override;
-
-  float ImageContentsScaleX() const;
-  float ImageContentsScaleY() const;
-
-  SkBitmap bitmap_;
-
-  scoped_refptr<ImageLayerUpdater> updater_;
-
-  DISALLOW_COPY_AND_ASSIGN(ImageLayer);
-};
-
-}  // namespace cc
-
-#endif  // CC_LAYERS_IMAGE_LAYER_H_
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index af3fc674..706fc0a 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -40,7 +40,7 @@
 
 Layer::Layer(const LayerSettings& settings)
     : needs_push_properties_(false),
-      num_dependents_need_push_properties_(false),
+      num_dependents_need_push_properties_(0),
       stacking_order_changed_(false),
       // Layer IDs start from 1.
       layer_id_(g_next_layer_id.GetNext() + 1),
@@ -132,6 +132,11 @@
   if (layer_tree_host_)
     layer_tree_host_->property_trees()->needs_rebuild = true;
 
+  if (host)
+    host->property_trees()->needs_rebuild = true;
+
+  InvalidatePropertyTreesIndices();
+
   layer_tree_host_ = host;
 
   // When changing hosts, the layer needs to commit its properties to the impl
@@ -337,12 +342,14 @@
   if (reference == new_layer.get())
     return;
 
-  int reference_index = IndexOfChild(reference);
-  if (reference_index == -1) {
-    NOTREACHED();
-    return;
-  }
-
+  // Find the index of |reference| in |children_|.
+  auto reference_it =
+      std::find_if(children_.begin(), children_.end(),
+                   [reference](const scoped_refptr<Layer>& layer) {
+                     return layer.get() == reference;
+                   });
+  DCHECK(reference_it != children_.end());
+  size_t reference_index = reference_it - children_.begin();
   reference->RemoveFromParent();
 
   if (new_layer.get()) {
@@ -351,14 +358,6 @@
   }
 }
 
-int Layer::IndexOfChild(const Layer* reference) {
-  for (size_t i = 0; i < children_.size(); ++i) {
-    if (children_[i].get() == reference)
-      return i;
-  }
-  return -1;
-}
-
 void Layer::SetBounds(const gfx::Size& size) {
   DCHECK(IsPropertyChangeAllowed());
   if (bounds() == size)
@@ -416,7 +415,7 @@
 void Layer::RequestCopyOfOutput(
     scoped_ptr<CopyOutputRequest> request) {
   DCHECK(IsPropertyChangeAllowed());
-  int size = copy_requests_.size();
+  bool had_no_copy_requests = copy_requests_.empty();
   if (void* source = request->source()) {
     auto it = std::find_if(
         copy_requests_.begin(), copy_requests_.end(),
@@ -427,7 +426,7 @@
   if (request->IsEmpty())
     return;
   copy_requests_.push_back(request.Pass());
-  if (size == 0) {
+  if (had_no_copy_requests) {
     bool copy_request_added = true;
     UpdateNumCopyRequestsForSubtree(copy_request_added);
   }
@@ -1053,6 +1052,13 @@
   return opacity_tree_index_;
 }
 
+void Layer::InvalidatePropertyTreesIndices() {
+  int invalid_property_tree_index = -1;
+  SetTransformTreeIndex(invalid_property_tree_index);
+  SetClipTreeIndex(invalid_property_tree_index);
+  SetOpacityTreeIndex(invalid_property_tree_index);
+}
+
 void Layer::SetShouldFlattenTransform(bool should_flatten) {
   DCHECK(IsPropertyChangeAllowed());
   if (should_flatten_transform_ == should_flatten)
@@ -1274,7 +1280,7 @@
   layer->SetScrollCompensationAdjustment(ScrollCompensationAdjustment());
 
   // Wrap the copy_requests_ in a PostTask to the main thread.
-  int size = copy_requests_.size();
+  bool had_copy_requests = !copy_requests_.empty();
   ScopedPtrVector<CopyOutputRequest> main_thread_copy_requests;
   for (ScopedPtrVector<CopyOutputRequest>::iterator it = copy_requests_.begin();
        it != copy_requests_.end();
@@ -1293,7 +1299,7 @@
   }
   if (!copy_requests_.empty() && layer_tree_host_)
     layer_tree_host_->property_trees()->needs_rebuild = true;
-  if (size != 0)
+  if (had_copy_requests)
     UpdateNumCopyRequestsForSubtree(false);
   copy_requests_.clear();
   layer->PassCopyRequests(&main_thread_copy_requests);
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 84e9c0f8..2ae79a0 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -269,7 +269,7 @@
            draw_properties_.render_target->render_surface());
     return draw_properties_.render_target;
   }
-  int num_unclipped_descendants() const {
+  size_t num_unclipped_descendants() const {
     return draw_properties_.num_unclipped_descendants;
   }
 
@@ -671,9 +671,6 @@
   // trigger a Commit.
   void SetHasRenderSurface(bool has_render_surface);
 
-  // Returns the index of the child or -1 if not found.
-  int IndexOfChild(const Layer* reference);
-
   // This should only be called from RemoveFromParent().
   void RemoveChildOrDependent(Layer* child);
 
@@ -696,6 +693,10 @@
   // children.
   void RemoveFromClipTree();
 
+  // When we detach or attach layer to new LayerTreeHost, all property trees'
+  // indices becomes invalid.
+  void InvalidatePropertyTreesIndices();
+
   void UpdateNumCopyRequestsForSubtree(bool add);
   void UpdateNumInputHandlersForSubtree(bool add);
 
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index e6d9700..7e3a2c72 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -5,6 +5,7 @@
 #include "cc/layers/layer_impl.h"
 
 #include "base/json/json_reader.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
@@ -1150,8 +1151,8 @@
   NoteLayerPropertyChanged();
 }
 
-bool LayerImpl::IsExternalFlingActive() const {
-  return layer_tree_impl_->IsExternalFlingActive();
+bool LayerImpl::IsExternalScrollActive() const {
+  return layer_tree_impl_->IsExternalScrollActive();
 }
 
 void LayerImpl::SetCurrentScrollOffset(const gfx::ScrollOffset& scroll_offset) {
@@ -1515,7 +1516,8 @@
   MathUtil::AddToTracedValue("position", position_, state);
 
   state->SetInteger("draws_content", DrawsContent());
-  state->SetInteger("gpu_memory_usage", GPUMemoryUsageInBytes());
+  state->SetInteger("gpu_memory_usage",
+                    base::saturated_cast<int>(GPUMemoryUsageInBytes()));
 
   MathUtil::AddToTracedValue(
       "scroll_offset", scroll_offset_ ? scroll_offset_->Current(IsActive())
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 9803902..ae7c7a5 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -407,7 +407,7 @@
     return draw_properties_.render_target;
   }
 
-  int num_unclipped_descendants() const {
+  size_t num_unclipped_descendants() const {
     return draw_properties_.num_unclipped_descendants;
   }
 
@@ -430,7 +430,7 @@
   float contents_scale_y() const { return draw_properties_.contents_scale_y; }
   void SetContentsScale(float contents_scale_x, float contents_scale_y);
 
-  bool IsExternalFlingActive() const;
+  bool IsExternalScrollActive() const;
 
   void SetCurrentScrollOffset(const gfx::ScrollOffset& scroll_offset);
   void SetCurrentScrollOffsetFromDelegate(
diff --git a/cc/layers/layer_iterator.h b/cc/layers/layer_iterator.h
index ba5c6aa..cd8da68 100644
--- a/cc/layers/layer_iterator.h
+++ b/cc/layers/layer_iterator.h
@@ -82,10 +82,11 @@
 // Non-templated constants
 struct LayerIteratorValue {
   static const int kInvalidTargetRenderSurfaceLayerIndex = -1;
-  // This must be -1 since the iterator action code assumes that this value can
-  // be reached by subtracting one from the position of the first layer in the
-  // current target surface's child layer list, which is 0.
-  static const int kLayerIndexRepresentingTargetRenderSurface = -1;
+  // This must be (size_t)-1 since the iterator action code assumes that this
+  // value can be reached by subtracting one from the position of the first
+  // layer in the current target surface's child layer list, which is 0.
+  static const size_t kLayerIndexRepresentingTargetRenderSurface =
+      static_cast<size_t>(-1);
 };
 
 // The position of a layer iterator that is independent
@@ -286,9 +287,10 @@
   // current target surface. When pointing to one of these layers,
   // this is a value from 0 to n-1 (n = number of children).
   // Since the iterator must also stop at the layers representing
-  // the target surface, this is done by setting the current_layerIndex
-  // to a value of LayerIteratorValue::LayerRepresentingTargetRenderSurface.
-  int current_layer_index_;
+  // the target surface, this is done by setting the current_layer_index
+  // to a value of
+  // LayerIteratorValue::kLayerIndexRepresentingTargetRenderSurface.
+  size_t current_layer_index_;
 };
 
 }  // namespace cc
diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc
index 100ada6..5ed8fc60 100644
--- a/cc/layers/painted_scrollbar_layer.cc
+++ b/cc/layers/painted_scrollbar_layer.cc
@@ -46,7 +46,7 @@
       scrollbar_(scrollbar.Pass()),
       scroll_layer_id_(scroll_layer_id),
       clip_layer_id_(Layer::INVALID_ID),
-      internal_contents_scale_(0.f),
+      internal_contents_scale_(1.f),
       thumb_thickness_(scrollbar_->ThumbThickness()),
       thumb_length_(scrollbar_->ThumbLength()),
       is_overlay_(scrollbar_->IsOverlay()),
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
index 87c4bd7..2b4da20 100644
--- a/cc/layers/picture_layer_unittest.cc
+++ b/cc/layers/picture_layer_unittest.cc
@@ -150,16 +150,16 @@
   // The PictureLayer is put in one LayerTreeHost.
   host1->SetRootLayer(layer);
   // Do a main frame, record the picture layers.
-  EXPECT_EQ(0u, layer->update_count());
+  EXPECT_EQ(0, layer->update_count());
   layer->SetNeedsDisplay();
   host1->Composite(base::TimeTicks::Now());
-  EXPECT_EQ(1u, layer->update_count());
+  EXPECT_EQ(1, layer->update_count());
   EXPECT_EQ(1, host1->source_frame_number());
 
   // The source frame number in |host1| is now higher than host2.
   layer->SetNeedsDisplay();
   host1->Composite(base::TimeTicks::Now());
-  EXPECT_EQ(2u, layer->update_count());
+  EXPECT_EQ(2, layer->update_count());
   EXPECT_EQ(2, host1->source_frame_number());
 
   // Then moved to another LayerTreeHost.
@@ -170,7 +170,7 @@
   // non-monotonically.
   layer->SetNeedsDisplay();
   host2->Composite(base::TimeTicks::Now());
-  EXPECT_EQ(3u, layer->update_count());
+  EXPECT_EQ(3, layer->update_count());
   EXPECT_EQ(1, host2->source_frame_number());
 }
 
diff --git a/cc/layers/render_surface.h b/cc/layers/render_surface.h
index 1e3719d..ac58903 100644
--- a/cc/layers/render_surface.h
+++ b/cc/layers/render_surface.h
@@ -146,7 +146,7 @@
 
   // For LayerIteratorActions
   int target_render_surface_layer_index_history_;
-  int current_layer_index_history_;
+  size_t current_layer_index_history_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderSurface);
 };
diff --git a/cc/layers/render_surface_impl.h b/cc/layers/render_surface_impl.h
index 2035e28..84a574e 100644
--- a/cc/layers/render_surface_impl.h
+++ b/cc/layers/render_surface_impl.h
@@ -192,7 +192,7 @@
 
   // For LayerIteratorActions
   int target_render_surface_layer_index_history_;
-  int current_layer_index_history_;
+  size_t current_layer_index_history_;
 
   friend class LayerIterator<LayerImpl>;
 
diff --git a/cc/layers/texture_layer_impl.cc b/cc/layers/texture_layer_impl.cc
index 63d0549..d0e6b19 100644
--- a/cc/layers/texture_layer_impl.cc
+++ b/cc/layers/texture_layer_impl.cc
@@ -99,12 +99,12 @@
     // hardware draw.
     if (!texture_copy_)
       texture_copy_ = ScopedResource::Create(resource_provider);
-    if (texture_copy_->size() != texture_mailbox_.shared_memory_size() ||
+    if (texture_copy_->size() != texture_mailbox_.size_in_pixels() ||
         resource_provider->InUseByConsumer(texture_copy_->id()))
       texture_copy_->Free();
 
     if (!texture_copy_->id()) {
-      texture_copy_->Allocate(texture_mailbox_.shared_memory_size(),
+      texture_copy_->Allocate(texture_mailbox_.size_in_pixels(),
                               ResourceProvider::TEXTURE_HINT_IMMUTABLE,
                               resource_provider->best_texture_format());
     }
@@ -126,12 +126,10 @@
         pixels = &swizzled[0];
       }
 
-      resource_provider->SetPixels(
-          texture_copy_->id(),
-          pixels,
-          gfx::Rect(texture_mailbox_.shared_memory_size()),
-          gfx::Rect(texture_mailbox_.shared_memory_size()),
-          gfx::Vector2d());
+      resource_provider->SetPixels(texture_copy_->id(), pixels,
+                                   gfx::Rect(texture_mailbox_.size_in_pixels()),
+                                   gfx::Rect(texture_mailbox_.size_in_pixels()),
+                                   gfx::Vector2d());
 
       valid_texture_copy_ = true;
     }
@@ -179,6 +177,10 @@
                vertex_opacity_,
                flipped_,
                nearest_neighbor_);
+  if (!valid_texture_copy_) {
+    quad->set_resource_size_in_pixels(texture_mailbox_.size_in_pixels());
+    quad->set_allow_overlay(texture_mailbox_.allow_overlay());
+  }
   ValidateQuadResources(quad);
 }
 
diff --git a/cc/layers/video_frame_provider_client_impl.h b/cc/layers/video_frame_provider_client_impl.h
index 5429228b4..e626b54 100644
--- a/cc/layers/video_frame_provider_client_impl.h
+++ b/cc/layers/video_frame_provider_client_impl.h
@@ -59,6 +59,10 @@
   void DidReceiveFrame() override;
   void DidUpdateMatrix(const float* matrix) override;
 
+  const VideoFrameProvider* get_provider_for_testing() const {
+    return provider_;
+  }
+
  private:
   friend class base::RefCounted<VideoFrameProviderClientImpl>;
 
diff --git a/cc/layers/video_frame_provider_client_impl_unittest.cc b/cc/layers/video_frame_provider_client_impl_unittest.cc
new file mode 100644
index 0000000..f2f2c0d
--- /dev/null
+++ b/cc/layers/video_frame_provider_client_impl_unittest.cc
@@ -0,0 +1,167 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/video_frame_provider_client_impl.h"
+#include "cc/layers/video_layer_impl.h"
+#include "cc/output/begin_frame_args.h"
+#include "cc/test/fake_video_frame_provider.h"
+#include "cc/test/layer_test_common.h"
+#include "media/base/video_frame.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+
+namespace cc {
+
+// NOTE: We cannot use DebugScopedSetImplThreadAndMainThreadBlocked in these
+// tests because it gets destroyed before the VideoLayerImpl is destroyed. This
+// causes a DCHECK in VideoLayerImpl's destructor to fail.
+static void DebugSetImplThreadAndMainThreadBlocked(Proxy* proxy) {
+#if DCHECK_IS_ON()
+  proxy->SetCurrentThreadIsImplThread(true);
+  proxy->SetMainThreadBlocked(true);
+#endif
+}
+
+class VideoFrameProviderClientImplTest : public testing::Test,
+                                         public VideoFrameControllerClient {
+ public:
+  VideoFrameProviderClientImplTest()
+      : client_impl_(VideoFrameProviderClientImpl::Create(&provider_, this)),
+        video_layer_impl_(nullptr),
+        test_frame_(media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
+                                                   gfx::Size(10, 10),
+                                                   gfx::Rect(10, 10),
+                                                   gfx::Size(10, 10),
+                                                   base::TimeDelta())) {
+    DebugSetImplThreadAndMainThreadBlocked(impl_.proxy());
+  }
+
+  ~VideoFrameProviderClientImplTest() {
+    if (!client_impl_->Stopped()) {
+      client_impl_->Stop();
+      DCHECK(client_impl_->Stopped());
+      DCHECK(!client_impl_->ActiveVideoLayer());
+    }
+
+    provider_.SetVideoFrameProviderClient(nullptr);
+  }
+
+  void StartRendering() {
+    EXPECT_CALL(*this, AddVideoFrameController(_));
+    client_impl_->StartRendering();
+  }
+
+  void StopRendering() {
+    EXPECT_CALL(*this, RemoveVideoFrameController(_));
+    client_impl_->StopRendering();
+  }
+
+  void StartRenderingAndRenderFrame() {
+    EXPECT_FALSE(client_impl_->HasCurrentFrame());
+    provider_.set_frame(test_frame_);
+    EXPECT_TRUE(client_impl_->HasCurrentFrame());
+
+    // Start rendering and verify SetNeedsRedraw() was called for the new frame.
+    StartRendering();
+    EXPECT_EQ(gfx::Rect(), video_layer_impl_->update_rect());
+    client_impl_->OnBeginFrame(BeginFrameArgs());
+    EXPECT_NE(gfx::Rect(), video_layer_impl_->update_rect());
+  }
+
+  void CreateActiveVideoLayer() {
+    gfx::Size layer_size(100, 100);
+    video_layer_impl_ = impl_.AddChildToRoot<VideoLayerImpl>(
+        &provider_, media::VIDEO_ROTATION_0);
+    video_layer_impl_->SetBounds(layer_size);
+    video_layer_impl_->SetContentBounds(layer_size);
+    video_layer_impl_->SetDrawsContent(true);
+    client_impl_->SetActiveVideoLayer(video_layer_impl_);
+    ASSERT_TRUE(client_impl_->ActiveVideoLayer());
+  }
+
+  MOCK_METHOD1(AddVideoFrameController, void(VideoFrameController*));
+  MOCK_METHOD1(RemoveVideoFrameController, void(VideoFrameController*));
+
+ protected:
+  FakeVideoFrameProvider provider_;
+  LayerTestCommon::LayerImplTest impl_;
+  scoped_refptr<VideoFrameProviderClientImpl> client_impl_;
+  VideoLayerImpl* video_layer_impl_;
+  scoped_refptr<media::VideoFrame> test_frame_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VideoFrameProviderClientImplTest);
+};
+
+TEST_F(VideoFrameProviderClientImplTest, StartStopRendering) {
+  StartRendering();
+  StopRendering();
+}
+
+TEST_F(VideoFrameProviderClientImplTest, StopUsingProvider) {
+  ASSERT_TRUE(client_impl_->get_provider_for_testing());
+  StartRendering();
+  EXPECT_CALL(*this, RemoveVideoFrameController(_));
+  client_impl_->StopUsingProvider();
+  ASSERT_FALSE(client_impl_->get_provider_for_testing());
+}
+
+TEST_F(VideoFrameProviderClientImplTest, FrameAcquisition) {
+  CreateActiveVideoLayer();
+  StartRenderingAndRenderFrame();
+
+  // Verify GetCurrentFrame() and PutCurrentFrame() work correctly.
+  EXPECT_EQ(test_frame_, client_impl_->AcquireLockAndCurrentFrame());
+  EXPECT_EQ(0, provider_.put_current_frame_count());
+  client_impl_->PutCurrentFrame();
+  EXPECT_EQ(1, provider_.put_current_frame_count());
+
+  client_impl_->ReleaseLock();
+  StopRendering();
+}
+
+TEST_F(VideoFrameProviderClientImplTest, DidReceiveFrame) {
+  CreateActiveVideoLayer();
+  EXPECT_EQ(gfx::Rect(), video_layer_impl_->update_rect());
+  client_impl_->DidReceiveFrame();
+  EXPECT_NE(gfx::Rect(), video_layer_impl_->update_rect());
+}
+
+TEST_F(VideoFrameProviderClientImplTest, DidDrawFrameIssuesPutCurrentFrame) {
+  CreateActiveVideoLayer();
+  StartRenderingAndRenderFrame();
+  EXPECT_EQ(0, provider_.put_current_frame_count());
+  client_impl_->DidDrawFrame();
+  EXPECT_EQ(1, provider_.put_current_frame_count());
+  StopRendering();
+}
+
+TEST_F(VideoFrameProviderClientImplTest, StreamTextureMatrix) {
+  const float kIdentityMatrix[] = {
+      1.0,
+      0.0,
+      0.0,
+      0.0,
+      0.0,
+      1.0,
+      0.0,
+      0.0,
+      0.0,
+      0.0,
+      1.0,
+      0.0,
+      0.0,
+      0.0,
+      0.0,
+      1.0,
+  };
+
+  EXPECT_FALSE(client_impl_->StreamTextureMatrix().IsIdentity());
+  client_impl_->DidUpdateMatrix(kIdentityMatrix);
+  EXPECT_TRUE(client_impl_->StreamTextureMatrix().IsIdentity());
+}
+
+}  // namespace cc
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc
index 754a2f2..eb9eaca 100644
--- a/cc/layers/video_layer_impl.cc
+++ b/cc/layers/video_layer_impl.cc
@@ -125,7 +125,9 @@
         external_resources.mailboxes[i],
         SingleReleaseCallbackImpl::Create(
             external_resources.release_callbacks[i]));
-    frame_resources_.push_back(resource_id);
+    frame_resources_.push_back(FrameResource(
+        resource_id, external_resources.mailboxes[i].size_in_pixels(),
+        external_resources.mailboxes[i].allow_overlay()));
   }
 
   return true;
@@ -271,8 +273,10 @@
       yuv_video_quad->SetNew(
           shared_quad_state, quad_rect, opaque_rect, visible_quad_rect,
           ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size, uv_tex_size,
-          frame_resources_[0], frame_resources_[1], frame_resources_[2],
-          frame_resources_.size() > 3 ? frame_resources_[3] : 0, color_space);
+          frame_resources_[0].id, frame_resources_[1].id,
+          frame_resources_[2].id,
+          frame_resources_.size() > 3 ? frame_resources_[3].id : 0,
+          color_space);
       ValidateQuadResources(yuv_video_quad);
       break;
     }
@@ -290,17 +294,10 @@
       bool nearest_neighbor = false;
       TextureDrawQuad* texture_quad =
           render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
-      texture_quad->SetNew(shared_quad_state,
-                           quad_rect,
-                           opaque_rect,
-                           visible_quad_rect,
-                           frame_resources_[0],
-                           premultiplied_alpha,
-                           uv_top_left,
-                           uv_bottom_right,
-                           SK_ColorTRANSPARENT,
-                           opacity,
-                           flipped,
+      texture_quad->SetNew(shared_quad_state, quad_rect, opaque_rect,
+                           visible_quad_rect, frame_resources_[0].id,
+                           premultiplied_alpha, uv_top_left, uv_bottom_right,
+                           SK_ColorTRANSPARENT, opacity, flipped,
                            nearest_neighbor);
       ValidateQuadResources(texture_quad);
       break;
@@ -315,7 +312,8 @@
           render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
       stream_video_quad->SetNew(
           shared_quad_state, quad_rect, opaque_rect, visible_quad_rect,
-          frame_resources_[0],
+          frame_resources_[0].id, frame_resources_[0].size_in_pixels,
+          frame_resources_[0].allow_overlay,
           scale * provider_client_impl_->StreamTextureMatrix());
       ValidateQuadResources(stream_video_quad);
       break;
@@ -326,12 +324,9 @@
         break;
       IOSurfaceDrawQuad* io_surface_quad =
           render_pass->CreateAndAppendDrawQuad<IOSurfaceDrawQuad>();
-      io_surface_quad->SetNew(shared_quad_state,
-                              quad_rect,
-                              opaque_rect,
-                              visible_quad_rect,
-                              visible_rect.size(),
-                              frame_resources_[0],
+      io_surface_quad->SetNew(shared_quad_state, quad_rect, opaque_rect,
+                              visible_quad_rect, visible_rect.size(),
+                              frame_resources_[0].id,
                               IOSurfaceDrawQuad::UNFLIPPED);
       ValidateQuadResources(io_surface_quad);
       break;
@@ -383,7 +378,7 @@
     software_release_callback_.Reset();
   } else {
     for (size_t i = 0; i < frame_resources_.size(); ++i)
-      resource_provider->DeleteResource(frame_resources_[i]);
+      resource_provider->DeleteResource(frame_resources_[i].id);
     frame_resources_.clear();
   }
 
diff --git a/cc/layers/video_layer_impl.h b/cc/layers/video_layer_impl.h
index 5b3d9550..58c0e12 100644
--- a/cc/layers/video_layer_impl.h
+++ b/cc/layers/video_layer_impl.h
@@ -62,7 +62,16 @@
 
   scoped_ptr<VideoResourceUpdater> updater_;
   VideoFrameExternalResources::ResourceType frame_resource_type_;
-  std::vector<ResourceId> frame_resources_;
+  struct FrameResource {
+    FrameResource(ResourceId id, gfx::Size size_in_pixels, bool allow_overlay)
+        : id(id),
+          size_in_pixels(size_in_pixels),
+          allow_overlay(allow_overlay) {}
+    ResourceId id;
+    gfx::Size size_in_pixels;
+    bool allow_overlay;
+  };
+  std::vector<FrameResource> frame_resources_;
 
   // TODO(danakj): Remove these, hide software path inside ResourceProvider and
   // ExternalResource (aka TextureMailbox) classes.
diff --git a/cc/layers/video_layer_impl_unittest.cc b/cc/layers/video_layer_impl_unittest.cc
index 56d43a7..35a07df 100644
--- a/cc/layers/video_layer_impl_unittest.cc
+++ b/cc/layers/video_layer_impl_unittest.cc
@@ -363,7 +363,9 @@
       media::VideoFrame::WrapYUV420NativeTextures(
           mailbox_holder, mailbox_holder, mailbox_holder,
           base::Bind(EmptyCallback), gfx::Size(10, 10), gfx::Rect(10, 10),
-          gfx::Size(10, 10), base::TimeDelta(), true);
+          gfx::Size(10, 10), base::TimeDelta());
+  video_frame->metadata()->SetBoolean(media::VideoFrameMetadata::ALLOW_OVERLAY,
+                                      true);
   FakeVideoFrameProvider provider;
   provider.set_frame(video_frame);
 
diff --git a/cc/layers/viewport.cc b/cc/layers/viewport.cc
index 944f1bbd..35db561e 100644
--- a/cc/layers/viewport.cc
+++ b/cc/layers/viewport.cc
@@ -24,13 +24,23 @@
   DCHECK(host_impl_);
 }
 
+void Viewport::Pan(const gfx::Vector2dF& delta) {
+  gfx::Vector2dF pending_delta = delta;
+
+  pending_delta -= host_impl_->ScrollLayer(InnerScrollLayer(),
+                                           pending_delta,
+                                           gfx::Point(),
+                                           false);
+}
+
 Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta,
                                           const gfx::Point& viewport_point,
-                                          bool is_wheel_scroll) {
+                                          bool is_wheel_scroll,
+                                          bool affect_top_controls) {
   gfx::Vector2dF content_delta = delta;
   ScrollResult result;
 
-  if (ShouldTopControlsConsumeScroll(delta)) {
+  if (affect_top_controls && ShouldTopControlsConsumeScroll(delta)) {
     result.top_controls_applied_delta = ScrollTopControls(delta);
     content_delta -= result.top_controls_applied_delta;
   }
diff --git a/cc/layers/viewport.h b/cc/layers/viewport.h
index 25528af0..794df21 100644
--- a/cc/layers/viewport.h
+++ b/cc/layers/viewport.h
@@ -28,11 +28,16 @@
 
   static scoped_ptr<Viewport> Create(LayerTreeHostImpl* host_impl);
 
+  // Differs from scrolling in that only the visual viewport is moved, without
+  // affecting the top controls or outer viewport.
+  void Pan(const gfx::Vector2dF& delta);
+
   // Scrolls the viewport, applying the unique bubbling between the inner and
   // outer viewport. Scrolls can be consumed by top controls.
   ScrollResult ScrollBy(const gfx::Vector2dF& delta,
                         const gfx::Point& viewport_point,
-                        bool is_wheel_scroll);
+                        bool is_wheel_scroll,
+                        bool affect_top_controls);
 
  private:
   explicit Viewport(LayerTreeHostImpl* host_impl);
diff --git a/cc/output/begin_frame_args.cc b/cc/output/begin_frame_args.cc
index 4b43d94a..216eb52 100644
--- a/cc/output/begin_frame_args.cc
+++ b/cc/output/begin_frame_args.cc
@@ -27,7 +27,8 @@
     : frame_time(base::TimeTicks()),
       deadline(base::TimeTicks()),
       interval(base::TimeDelta::FromMicroseconds(-1)),
-      type(BeginFrameArgs::INVALID) {
+      type(BeginFrameArgs::INVALID),
+      on_critical_path(true) {
 }
 
 BeginFrameArgs::BeginFrameArgs(base::TimeTicks frame_time,
@@ -37,7 +38,8 @@
     : frame_time(frame_time),
       deadline(deadline),
       interval(interval),
-      type(type) {
+      type(type),
+      on_critical_path(true) {
 }
 
 BeginFrameArgs BeginFrameArgs::Create(BeginFrameArgs::CreationLocation location,
@@ -73,6 +75,7 @@
 #ifndef NDEBUG
   state->SetString("created_from", created_from.ToString());
 #endif
+  state->SetBoolean("on_critical_path", on_critical_path);
 }
 
 // This is a hard-coded deadline adjustment that assumes 60Hz, to be used in
diff --git a/cc/output/begin_frame_args.h b/cc/output/begin_frame_args.h
index c22f7fdd..1a7ae5f9 100644
--- a/cc/output/begin_frame_args.h
+++ b/cc/output/begin_frame_args.h
@@ -83,6 +83,7 @@
   base::TimeTicks deadline;
   base::TimeDelta interval;
   BeginFrameArgsType type;
+  bool on_critical_path;
 
  private:
   BeginFrameArgs(base::TimeTicks frame_time,
diff --git a/cc/output/begin_frame_args_unittest.cc b/cc/output/begin_frame_args_unittest.cc
index 4521c1b7..c6f5a42 100644
--- a/cc/output/begin_frame_args_unittest.cc
+++ b/cc/output/begin_frame_args_unittest.cc
@@ -77,6 +77,7 @@
   // BeginFrames are not valid by default
   BeginFrameArgs args1;
   EXPECT_FALSE(args1.IsValid()) << args1;
+  EXPECT_TRUE(args1.on_critical_path);
 
   BeginFrameArgs args2 = BeginFrameArgs::Create(
       BEGINFRAME_FROM_HERE, base::TimeTicks::FromInternalValue(1),
diff --git a/cc/output/context_provider.h b/cc/output/context_provider.h
index dfaab4a1..aa4367d 100644
--- a/cc/output/context_provider.h
+++ b/cc/output/context_provider.h
@@ -58,9 +58,6 @@
   // Returns the capabilities of the currently bound 3d context.
   virtual Capabilities ContextCapabilities() = 0;
 
-  // Checks if the context is currently known to be lost.
-  virtual bool IsContextLost() = 0;
-
   // Ask the provider to check if the contexts are valid or lost. If they are,
   // this should invalidate the provider so that it can be replaced with a new
   // one.
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 39158169..058c53b 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -10,6 +10,7 @@
 #include "base/containers/hash_tables.h"
 #include "base/containers/scoped_ptr_hash_map.h"
 #include "base/metrics/histogram.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/base/math_util.h"
 #include "cc/output/bsp_tree.h"
@@ -132,8 +133,7 @@
     : Renderer(client, settings),
       output_surface_(output_surface),
       resource_provider_(resource_provider),
-      overlay_processor_(
-          new OverlayProcessor(output_surface, resource_provider)) {
+      overlay_processor_(new OverlayProcessor(output_surface)) {
   overlay_processor_->Initialize();
 }
 
@@ -193,8 +193,9 @@
                                const gfx::Rect& device_clip_rect,
                                bool disable_picture_quad_image_filtering) {
   TRACE_EVENT0("cc", "DirectRenderer::DrawFrame");
-  UMA_HISTOGRAM_COUNTS("Renderer4.renderPassCount",
-                       render_passes_in_draw_order->size());
+  UMA_HISTOGRAM_COUNTS(
+      "Renderer4.renderPassCount",
+      base::saturated_cast<int>(render_passes_in_draw_order->size()));
 
   const RenderPass* root_render_pass = render_passes_in_draw_order->back();
   DCHECK(root_render_pass);
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index faf6bbb..c37991d 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -2239,8 +2239,11 @@
       static_cast<int>(draw_cache_.vertex_opacity_data.size()),
       static_cast<float*>(&draw_cache_.vertex_opacity_data.front()));
 
+  DCHECK_LE(draw_cache_.matrix_data.size(),
+            static_cast<size_t>(std::numeric_limits<int>::max()) / 6u);
   // Draw the quads!
-  gl_->DrawElements(GL_TRIANGLES, 6 * draw_cache_.matrix_data.size(),
+  gl_->DrawElements(GL_TRIANGLES,
+                    6 * static_cast<int>(draw_cache_.matrix_data.size()),
                     GL_UNSIGNED_SHORT, 0);
 
   // Clear the cache.
@@ -3499,7 +3502,7 @@
 }
 
 bool GLRenderer::IsContextLost() {
-  return output_surface_->context_provider()->IsContextLost();
+  return gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
 }
 
 void GLRenderer::ScheduleOverlays(DrawingFrame* frame) {
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index 62c5e74..4b133c930 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -2029,9 +2029,8 @@
                       OverlayCandidateList* candidates));
   };
 
-  TestOverlayProcessor(OutputSurface* surface,
-                       ResourceProvider* resource_provider)
-      : OverlayProcessor(surface, resource_provider) {}
+  explicit TestOverlayProcessor(OutputSurface* surface)
+      : OverlayProcessor(surface) {}
   ~TestOverlayProcessor() override {}
   void Initialize() override {
     strategy_ = new Strategy();
@@ -2069,7 +2068,7 @@
                           resource_provider.get(), mailbox_deleter.get());
 
   TestOverlayProcessor* processor =
-      new TestOverlayProcessor(output_surface.get(), resource_provider.get());
+      new TestOverlayProcessor(output_surface.get());
   processor->Initialize();
   renderer.SetOverlayProcessor(processor);
 
@@ -2084,7 +2083,6 @@
   unsigned sync_point = 0;
   TextureMailbox mailbox =
       TextureMailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point);
-  mailbox.set_allow_overlay(true);
   scoped_ptr<SingleReleaseCallbackImpl> release_callback =
       SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased));
   ResourceId resource_id = resource_provider->CreateResourceFromTextureMailbox(
@@ -2101,6 +2099,7 @@
                        premultiplied_alpha, gfx::PointF(0, 0),
                        gfx::PointF(1, 1), SK_ColorTRANSPARENT, vertex_opacity,
                        flipped, nearest_neighbor);
+  overlay_quad->set_allow_overlay(true);
 
   // DirectRenderer::DrawFrame calls into OverlayProcessor::ProcessForOverlays.
   // Attempt will be called for each strategy in OverlayProcessor. We have
@@ -2140,13 +2139,12 @@
     }
   };
 
-  SingleOverlayOnTopProcessor(OutputSurface* surface,
-                              ResourceProvider* resource_provider)
-      : OverlayProcessor(surface, resource_provider) {}
+  explicit SingleOverlayOnTopProcessor(OutputSurface* surface)
+      : OverlayProcessor(surface) {}
 
   void Initialize() override {
-    strategies_.push_back(scoped_ptr<Strategy>(
-        new OverlayStrategySingleOnTop(&validator_, resource_provider_)));
+    strategies_.push_back(
+        scoped_ptr<Strategy>(new OverlayStrategySingleOnTop(&validator_)));
   }
 
   SingleOverlayValidator validator_;
@@ -2195,8 +2193,8 @@
   FakeRendererGL renderer(&renderer_client, &settings, output_surface.get(),
                           resource_provider.get(), mailbox_deleter.get());
 
-  SingleOverlayOnTopProcessor* processor = new SingleOverlayOnTopProcessor(
-      output_surface.get(), resource_provider.get());
+  SingleOverlayOnTopProcessor* processor =
+      new SingleOverlayOnTopProcessor(output_surface.get());
   processor->Initialize();
   renderer.SetOverlayProcessor(processor);
 
@@ -2209,7 +2207,6 @@
   unsigned sync_point = TestRenderPass::kSyncPointForMailboxTextureQuad;
   TextureMailbox mailbox =
       TextureMailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point);
-  mailbox.set_allow_overlay(true);
   scoped_ptr<SingleReleaseCallbackImpl> release_callback =
       SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased));
   ResourceId resource_id = resource_provider->CreateResourceFromTextureMailbox(
@@ -2230,6 +2227,7 @@
                        viewport_rect, resource_id, premultiplied_alpha,
                        uv_top_left, uv_bottom_right, SK_ColorTRANSPARENT,
                        vertex_opacity, flipped, nearest_neighbor);
+  overlay_quad->set_allow_overlay(true);
 
   // Verify that overlay_quad actually gets turned into an overlay, and even
   // though it's not drawn, that its sync point is waited on.
diff --git a/cc/output/overlay_candidate.h b/cc/output/overlay_candidate.h
index 36396358e..b3e7fb3 100644
--- a/cc/output/overlay_candidate.h
+++ b/cc/output/overlay_candidate.h
@@ -34,6 +34,8 @@
   gfx::OverlayTransform transform;
   // Format of the buffer to composite.
   ResourceFormat format;
+  // Size of the resource, in pixels.
+  gfx::Size resource_size_in_pixels;
   // Rect on the display to position the overlay to. Implementer must convert
   // to integer coordinates if setting |overlay_handled| to true.
   gfx::RectF display_rect;
diff --git a/cc/output/overlay_processor.cc b/cc/output/overlay_processor.cc
index 0f5ec56..baae69d 100644
--- a/cc/output/overlay_processor.cc
+++ b/cc/output/overlay_processor.cc
@@ -12,22 +12,19 @@
 
 namespace cc {
 
-OverlayProcessor::OverlayProcessor(OutputSurface* surface,
-                                   ResourceProvider* resource_provider)
-    : surface_(surface), resource_provider_(resource_provider) {}
+OverlayProcessor::OverlayProcessor(OutputSurface* surface) : surface_(surface) {
+}
 
 void OverlayProcessor::Initialize() {
   DCHECK(surface_);
-  if (!resource_provider_)
-    return;
 
   OverlayCandidateValidator* candidates =
       surface_->GetOverlayCandidateValidator();
   if (candidates) {
-    strategies_.push_back(scoped_ptr<Strategy>(
-        new OverlayStrategySingleOnTop(candidates, resource_provider_)));
-    strategies_.push_back(scoped_ptr<Strategy>(
-        new OverlayStrategyUnderlay(candidates, resource_provider_)));
+    strategies_.push_back(
+        scoped_ptr<Strategy>(new OverlayStrategySingleOnTop(candidates)));
+    strategies_.push_back(
+        scoped_ptr<Strategy>(new OverlayStrategyUnderlay(candidates)));
   }
 }
 
diff --git a/cc/output/overlay_processor.h b/cc/output/overlay_processor.h
index e50972e..e37816c 100644
--- a/cc/output/overlay_processor.h
+++ b/cc/output/overlay_processor.h
@@ -29,7 +29,7 @@
   };
   typedef ScopedPtrVector<Strategy> StrategyList;
 
-  OverlayProcessor(OutputSurface* surface, ResourceProvider* resource_provider);
+  explicit OverlayProcessor(OutputSurface* surface);
   virtual ~OverlayProcessor();
   // Virtual to allow testing different strategies.
   virtual void Initialize();
@@ -40,7 +40,6 @@
  protected:
   StrategyList strategies_;
   OutputSurface* surface_;
-  ResourceProvider* resource_provider_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(OverlayProcessor);
diff --git a/cc/output/overlay_strategy_common.cc b/cc/output/overlay_strategy_common.cc
index 6fa778a..f95b373 100644
--- a/cc/output/overlay_strategy_common.cc
+++ b/cc/output/overlay_strategy_common.cc
@@ -16,29 +16,21 @@
 
 namespace cc {
 
-OverlayStrategyCommon::OverlayStrategyCommon(
-    OverlayCandidateValidator* capability_checker,
-    ResourceProvider* resource_provider)
-    : capability_checker_(capability_checker),
-      resource_provider_(resource_provider) {
+OverlayStrategyCommon::OverlayStrategyCommon() {
 }
 
 OverlayStrategyCommon::~OverlayStrategyCommon() {
 }
 
 bool OverlayStrategyCommon::IsOverlayQuad(const DrawQuad* draw_quad) {
-  unsigned int resource_id;
   switch (draw_quad->material) {
     case DrawQuad::TEXTURE_CONTENT:
-      resource_id = TextureDrawQuad::MaterialCast(draw_quad)->resource_id();
-      break;
+      return TextureDrawQuad::MaterialCast(draw_quad)->allow_overlay();
     case DrawQuad::STREAM_VIDEO_CONTENT:
-      resource_id = StreamVideoDrawQuad::MaterialCast(draw_quad)->resource_id();
-      break;
+      return StreamVideoDrawQuad::MaterialCast(draw_quad)->allow_overlay();
     default:
       return false;
   }
-  return resource_provider_->AllowOverlay(resource_id);
 }
 
 bool OverlayStrategyCommon::IsInvisibleQuad(const DrawQuad* draw_quad) {
@@ -64,6 +56,7 @@
       overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
     return false;
   quad_info->resource_id = quad.resource_id();
+  quad_info->resource_size_in_pixels = quad.resource_size_in_pixels();
   quad_info->transform = overlay_transform;
   quad_info->uv_rect = BoundingRect(quad.uv_top_left, quad.uv_bottom_right);
   return true;
@@ -82,6 +75,7 @@
     return false;
   }
   quad_info->resource_id = quad.resource_id();
+  quad_info->resource_size_in_pixels = quad.resource_size_in_pixels();
   quad_info->transform = overlay_transform;
 
   gfx::Point3F uv0 = gfx::Point3F(0, 0, 0);
diff --git a/cc/output/overlay_strategy_common.h b/cc/output/overlay_strategy_common.h
index 515a106..2dc6075 100644
--- a/cc/output/overlay_strategy_common.h
+++ b/cc/output/overlay_strategy_common.h
@@ -17,8 +17,7 @@
 
 class CC_EXPORT OverlayStrategyCommon : public OverlayProcessor::Strategy {
  public:
-  OverlayStrategyCommon(OverlayCandidateValidator* capability_checker,
-                        ResourceProvider* resource_provider);
+  OverlayStrategyCommon();
   ~OverlayStrategyCommon() override;
 
  protected:
@@ -38,9 +37,6 @@
   bool GetVideoQuadInfo(const StreamVideoDrawQuad& quad,
                         OverlayCandidate* quad_info);
 
-  OverlayCandidateValidator* capability_checker_;
-  ResourceProvider* resource_provider_;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(OverlayStrategyCommon);
 };
diff --git a/cc/output/overlay_strategy_single_on_top.cc b/cc/output/overlay_strategy_single_on_top.cc
index 921dba7a..e188916 100644
--- a/cc/output/overlay_strategy_single_on_top.cc
+++ b/cc/output/overlay_strategy_single_on_top.cc
@@ -12,9 +12,8 @@
 namespace cc {
 
 OverlayStrategySingleOnTop::OverlayStrategySingleOnTop(
-    OverlayCandidateValidator* capability_checker,
-    ResourceProvider* resource_provider)
-    : OverlayStrategyCommon(capability_checker, resource_provider) {
+    OverlayCandidateValidator* capability_checker)
+    : capability_checker_(capability_checker) {
 }
 
 bool OverlayStrategySingleOnTop::Attempt(
diff --git a/cc/output/overlay_strategy_single_on_top.h b/cc/output/overlay_strategy_single_on_top.h
index eeecd32..cacc0234 100644
--- a/cc/output/overlay_strategy_single_on_top.h
+++ b/cc/output/overlay_strategy_single_on_top.h
@@ -19,12 +19,14 @@
 
 class CC_EXPORT OverlayStrategySingleOnTop : public OverlayStrategyCommon {
  public:
-  OverlayStrategySingleOnTop(OverlayCandidateValidator* capability_checker,
-                             ResourceProvider* resource_provider);
+  explicit OverlayStrategySingleOnTop(
+      OverlayCandidateValidator* capability_checker);
   bool Attempt(RenderPassList* render_passes_in_draw_order,
                OverlayCandidateList* candidate_list) override;
 
  private:
+  OverlayCandidateValidator* capability_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(OverlayStrategySingleOnTop);
 };
 
diff --git a/cc/output/overlay_strategy_underlay.cc b/cc/output/overlay_strategy_underlay.cc
index a88997a..2e794d6 100644
--- a/cc/output/overlay_strategy_underlay.cc
+++ b/cc/output/overlay_strategy_underlay.cc
@@ -11,9 +11,8 @@
 namespace cc {
 
 OverlayStrategyUnderlay::OverlayStrategyUnderlay(
-    OverlayCandidateValidator* capability_checker,
-    ResourceProvider* resource_provider)
-    : OverlayStrategyCommon(capability_checker, resource_provider) {
+    OverlayCandidateValidator* capability_checker)
+    : capability_checker_(capability_checker) {
 }
 
 bool OverlayStrategyUnderlay::Attempt(
diff --git a/cc/output/overlay_strategy_underlay.h b/cc/output/overlay_strategy_underlay.h
index 881e170..d8351ef 100644
--- a/cc/output/overlay_strategy_underlay.h
+++ b/cc/output/overlay_strategy_underlay.h
@@ -18,12 +18,14 @@
 // are fully opaque.
 class CC_EXPORT OverlayStrategyUnderlay : public OverlayStrategyCommon {
  public:
-  OverlayStrategyUnderlay(OverlayCandidateValidator* capability_checker,
-                          ResourceProvider* resource_provider);
+  explicit OverlayStrategyUnderlay(
+      OverlayCandidateValidator* capability_checker);
   bool Attempt(RenderPassList* render_passes_in_draw_order,
                OverlayCandidateList* candidate_list) override;
 
  private:
+  OverlayCandidateValidator* capability_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(OverlayStrategyUnderlay);
 };
 
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index a0c1643..448d04d 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -78,11 +78,9 @@
 template <typename OverlayStrategyType>
 class SingleOverlayProcessor : public OverlayProcessor {
  public:
-  SingleOverlayProcessor(OutputSurface* surface,
-                         ResourceProvider* resource_provider)
-      : OverlayProcessor(surface, resource_provider) {
+  explicit SingleOverlayProcessor(OutputSurface* surface)
+      : OverlayProcessor(surface) {
     EXPECT_EQ(surface, surface_);
-    EXPECT_EQ(resource_provider, resource_provider_);
   }
 
   // Virtual to allow testing different strategies.
@@ -90,22 +88,20 @@
     OverlayCandidateValidator* candidates =
         surface_->GetOverlayCandidateValidator();
     ASSERT_TRUE(candidates != NULL);
-    strategies_.push_back(scoped_ptr<Strategy>(
-        new OverlayStrategyType(candidates, resource_provider_)));
+    strategies_.push_back(
+        scoped_ptr<Strategy>(new OverlayStrategyType(candidates)));
   }
 };
 
 class DefaultOverlayProcessor : public OverlayProcessor {
  public:
-  DefaultOverlayProcessor(OutputSurface* surface,
-                          ResourceProvider* resource_provider);
+  explicit DefaultOverlayProcessor(OutputSurface* surface);
   size_t GetStrategyCount();
 };
 
-DefaultOverlayProcessor::DefaultOverlayProcessor(
-    OutputSurface* surface,
-    ResourceProvider* resource_provider)
-    : OverlayProcessor(surface, resource_provider) {}
+DefaultOverlayProcessor::DefaultOverlayProcessor(OutputSurface* surface)
+    : OverlayProcessor(surface) {
+}
 
 size_t DefaultOverlayProcessor::GetStrategyCount() {
   return strategies_.size();
@@ -157,7 +153,6 @@
   unsigned sync_point = 0;
   TextureMailbox mailbox =
       TextureMailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point);
-  mailbox.set_allow_overlay(true);
   scoped_ptr<SingleReleaseCallbackImpl> release_callback =
       SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased));
 
@@ -185,6 +180,8 @@
   bool flipped = false;
   bool nearest_neighbor = false;
   float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+  gfx::Size resource_size_in_pixels = gfx::Size(64, 64);
+  bool allow_overlay = true;
 
   TextureDrawQuad* overlay_quad =
       render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -200,6 +197,8 @@
                        vertex_opacity,
                        flipped,
                        nearest_neighbor);
+  overlay_quad->set_allow_overlay(allow_overlay);
+  overlay_quad->set_resource_size_in_pixels(resource_size_in_pixels);
 
   return overlay_quad;
 }
@@ -211,11 +210,13 @@
     const gfx::Rect& rect,
     const gfx::Transform& transform) {
   ResourceId resource_id = CreateResource(resource_provider);
+  gfx::Size resource_size_in_pixels = gfx::Size(64, 64);
+  bool allow_overlay = true;
 
   StreamVideoDrawQuad* overlay_quad =
       render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
   overlay_quad->SetNew(shared_quad_state, rect, rect, rect, resource_id,
-                       transform);
+                       resource_size_in_pixels, allow_overlay, transform);
 
   return overlay_quad;
 }
@@ -306,7 +307,7 @@
       &output_surface, shared_bitmap_manager.get());
 
   scoped_ptr<DefaultOverlayProcessor> overlay_processor(
-      new DefaultOverlayProcessor(&output_surface, resource_provider.get()));
+      new DefaultOverlayProcessor(&output_surface));
   overlay_processor->Initialize();
   EXPECT_GE(2U, overlay_processor->GetStrategyCount());
 }
@@ -325,8 +326,8 @@
     resource_provider_ = FakeResourceProvider::Create(
         output_surface_.get(), shared_bitmap_manager_.get());
 
-    overlay_processor_.reset(new SingleOverlayProcessor<OverlayStrategyType>(
-        output_surface_.get(), resource_provider_.get()));
+    overlay_processor_.reset(
+        new SingleOverlayProcessor<OverlayStrategyType>(output_surface_.get()));
     overlay_processor_->Initialize();
   }
 
diff --git a/cc/output/program_binding.cc b/cc/output/program_binding.cc
index 7809e108..c05447c7 100644
--- a/cc/output/program_binding.cc
+++ b/cc/output/program_binding.cc
@@ -6,6 +6,7 @@
 
 #include "base/trace_event/trace_event.h"
 #include "cc/output/geometry_binding.h"
+#include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 
 using gpu::gles2::GLES2Interface;
@@ -129,4 +130,8 @@
   }
 }
 
+bool ProgramBindingBase::IsContextLost(GLES2Interface* context) {
+  return context->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
+}
+
 }  // namespace cc
diff --git a/cc/output/program_binding.h b/cc/output/program_binding.h
index 1d5132b..8018cad 100644
--- a/cc/output/program_binding.h
+++ b/cc/output/program_binding.h
@@ -42,6 +42,8 @@
                                unsigned fragment_shader);
   void CleanupShaders(gpu::gles2::GLES2Interface* context);
 
+  bool IsContextLost(gpu::gles2::GLES2Interface* context);
+
   unsigned program_;
   unsigned vertex_shader_id_;
   unsigned fragment_shader_id_;
@@ -79,7 +81,7 @@
     DCHECK(context_provider);
     DCHECK(!initialized_);
 
-    if (context_provider->IsContextLost())
+    if (IsContextLost(context_provider->ContextGL()))
       return;
 
     fragment_shader_.set_blend_mode(blend_mode);
@@ -89,7 +91,7 @@
             context_provider->ContextGL(),
             vertex_shader_.GetShaderString(),
             fragment_shader_.GetShaderString(precision, sampler))) {
-      DCHECK(context_provider->IsContextLost());
+      DCHECK(IsContextLost(context_provider->ContextGL()));
       return;
     }
 
@@ -101,7 +103,7 @@
 
     // Link after binding uniforms
     if (!Link(context_provider->ContextGL())) {
-      DCHECK(context_provider->IsContextLost());
+      DCHECK(IsContextLost(context_provider->ContextGL()));
       return;
     }
 
diff --git a/cc/playback/display_item_list.cc b/cc/playback/display_item_list.cc
index abd40db..cb3cde8 100644
--- a/cc/playback/display_item_list.cc
+++ b/cc/playback/display_item_list.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "cc/base/math_util.h"
@@ -214,7 +215,7 @@
   scoped_refptr<base::trace_event::TracedValue> state =
       new base::trace_event::TracedValue();
 
-  state->SetInteger("length", items_.size());
+  state->SetInteger("length", base::saturated_cast<int>(items_.size()));
   state->BeginArray("params.items");
   for (const DisplayItem* item : items_) {
     item->AsValueInto(state.get());
diff --git a/cc/playback/display_list_raster_source_unittest.cc b/cc/playback/display_list_raster_source_unittest.cc
index e41bc64..1827d71 100644
--- a/cc/playback/display_list_raster_source_unittest.cc
+++ b/cc/playback/display_list_raster_source_unittest.cc
@@ -395,8 +395,9 @@
   raster = DisplayListRasterSource::CreateFromDisplayListRecordingSource(
       recording_source.get(), false);
 
-  // We're going to playback from "everything is black" into a smaller area.
-  playback_rect.Inset(1, 2);
+  // We're going to playback from "everything is black" into a smaller area,
+  // that touches the edge pixels of the recording.
+  playback_rect.Inset(1, 2, 0, 1);
   raster->PlaybackToCanvas(&canvas, raster_full_rect, playback_rect,
                            contents_scale);
 
@@ -405,8 +406,8 @@
   int num_white = 0;
   for (int i = 0; i < bitmap.width(); ++i) {
     for (int j = 0; j < bitmap.height(); ++j) {
-      SCOPED_TRACE(i);
       SCOPED_TRACE(j);
+      SCOPED_TRACE(i);
       bool expect_black = playback_rect.Contains(i, j);
       if (expect_black) {
         EXPECT_EQ(255u, SkColorGetA(pixels[i + j * bitmap.width()]));
diff --git a/cc/playback/raster_source_helper.cc b/cc/playback/raster_source_helper.cc
index 6d00f5f2..9636575 100644
--- a/cc/playback/raster_source_helper.cc
+++ b/cc/playback/raster_source_helper.cc
@@ -67,6 +67,7 @@
     // covered by content.
     gfx::Rect deflated_content_rect = content_rect;
     deflated_content_rect.Inset(0, 0, 1, 1);
+    deflated_content_rect.Intersect(canvas_playback_rect);
     if (!deflated_content_rect.Contains(canvas_playback_rect)) {
       if (clear_canvas_with_debug_color) {
         // Any non-painted areas outside of the content bounds are left in
@@ -87,7 +88,10 @@
       canvas->save();
       canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y());
       gfx::Rect inflated_content_rect = content_rect;
+      // Only clear edges that will be inside the canvas_playback_rect, else we
+      // clear things that are still valid from a previous raster.
       inflated_content_rect.Inset(0, 0, -1, -1);
+      inflated_content_rect.Intersect(canvas_playback_rect);
       canvas->clipRect(gfx::RectToSkRect(inflated_content_rect),
                        SkRegion::kReplace_Op);
       canvas->clipRect(gfx::RectToSkRect(deflated_content_rect),
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc
index 055b7d9..5bce42e 100644
--- a/cc/quads/draw_quad_unittest.cc
+++ b/cc/quads/draw_quad_unittest.cc
@@ -330,6 +330,15 @@
   }                                                              \
   SETUP_AND_COPY_QUAD_NEW(Type, quad_new);
 
+#define CREATE_QUAD_10_ALL(Type, a, b, c, d, e, f, g, h, i, j)                \
+  Type* quad_all = render_pass->CreateAndAppendDrawQuad<Type>();              \
+  {                                                                           \
+    QUAD_DATA quad_all->SetAll(shared_state, quad_rect, quad_opaque_rect,     \
+                               quad_visible_rect, needs_blending, a, b, c, d, \
+                               e, f, g, h, i, j);                             \
+  }                                                                           \
+  SETUP_AND_COPY_QUAD_ALL(Type, quad_all);
+
 #define CREATE_QUAD_11_NEW(Type, a, b, c, d, e, f, g, h, i, j, k)            \
   Type* quad_new = render_pass->CreateAndAppendDrawQuad<Type>();             \
   {                                                                          \
@@ -508,20 +517,27 @@
   gfx::Rect opaque_rect(33, 47, 10, 12);
   gfx::Rect visible_rect(40, 50, 30, 20);
   ResourceId resource_id = 64;
+  gfx::Size resource_size_in_pixels = gfx::Size(40, 41);
+  bool allow_overlay = true;
   gfx::Transform matrix = gfx::Transform(0.5, 0.25, 1, 0.75, 0, 1);
   CREATE_SHARED_STATE();
 
-  CREATE_QUAD_4_NEW(
-      StreamVideoDrawQuad, opaque_rect, visible_rect, resource_id, matrix);
+  CREATE_QUAD_6_NEW(StreamVideoDrawQuad, opaque_rect, visible_rect, resource_id,
+                    resource_size_in_pixels, allow_overlay, matrix);
   EXPECT_EQ(DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
+  EXPECT_EQ(allow_overlay, copy_quad->allow_overlay());
+  EXPECT_EQ(resource_size_in_pixels, copy_quad->resource_size_in_pixels());
   EXPECT_EQ(matrix, copy_quad->matrix);
 
-  CREATE_QUAD_2_ALL(StreamVideoDrawQuad, resource_id, matrix);
+  CREATE_QUAD_4_ALL(StreamVideoDrawQuad, resource_id, resource_size_in_pixels,
+                    allow_overlay, matrix);
   EXPECT_EQ(DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
+  EXPECT_EQ(allow_overlay, copy_quad->allow_overlay());
+  EXPECT_EQ(resource_size_in_pixels, copy_quad->resource_size_in_pixels());
   EXPECT_EQ(matrix, copy_quad->matrix);
 }
 
@@ -545,6 +561,8 @@
   gfx::Rect opaque_rect(33, 47, 10, 12);
   gfx::Rect visible_rect(40, 50, 30, 20);
   unsigned resource_id = 82;
+  gfx::Size resource_size_in_pixels = gfx::Size(40, 41);
+  bool allow_overlay = true;
   bool premultiplied_alpha = true;
   gfx::PointF uv_top_left(0.5f, 224.f);
   gfx::PointF uv_bottom_right(51.5f, 260.f);
@@ -575,17 +593,14 @@
   EXPECT_EQ(y_flipped, copy_quad->y_flipped);
   EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
 
-  CREATE_QUAD_8_ALL(TextureDrawQuad,
-                    resource_id,
-                    premultiplied_alpha,
-                    uv_top_left,
-                    uv_bottom_right,
-                    SK_ColorTRANSPARENT,
-                    vertex_opacity,
-                    y_flipped,
-                    nearest_neighbor);
+  CREATE_QUAD_10_ALL(TextureDrawQuad, resource_id, resource_size_in_pixels,
+                     allow_overlay, premultiplied_alpha, uv_top_left,
+                     uv_bottom_right, SK_ColorTRANSPARENT, vertex_opacity,
+                     y_flipped, nearest_neighbor);
   EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, copy_quad->material);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
+  EXPECT_EQ(allow_overlay, copy_quad->allow_overlay());
+  EXPECT_EQ(resource_size_in_pixels, copy_quad->resource_size_in_pixels());
   EXPECT_EQ(premultiplied_alpha, copy_quad->premultiplied_alpha);
   EXPECT_EQ(uv_top_left, copy_quad->uv_top_left);
   EXPECT_EQ(uv_bottom_right, copy_quad->uv_bottom_right);
@@ -831,12 +846,16 @@
   gfx::Rect opaque_rect(33, 47, 10, 12);
   gfx::Rect visible_rect(40, 50, 30, 20);
   ResourceId resource_id = 64;
+  gfx::Size resource_size_in_pixels = gfx::Size(40, 41);
+  bool allow_overlay = true;
   gfx::Transform matrix = gfx::Transform(0.5, 0.25, 1, 0.75, 0, 1);
 
   CREATE_SHARED_STATE();
-  CREATE_QUAD_4_NEW(
-      StreamVideoDrawQuad, opaque_rect, visible_rect, resource_id, matrix);
+  CREATE_QUAD_6_NEW(StreamVideoDrawQuad, opaque_rect, visible_rect, resource_id,
+                    resource_size_in_pixels, allow_overlay, matrix);
   EXPECT_EQ(resource_id, quad_new->resource_id());
+  EXPECT_EQ(allow_overlay, quad_new->allow_overlay());
+  EXPECT_EQ(resource_size_in_pixels, quad_new->resource_size_in_pixels());
   EXPECT_EQ(1, IterateAndCount(quad_new));
   EXPECT_EQ(resource_id + 1, quad_new->resource_id());
 }
diff --git a/cc/quads/render_pass.cc b/cc/quads/render_pass.cc
index 567145a8..5c4d98a 100644
--- a/cc/quads/render_pass.cc
+++ b/cc/quads/render_pass.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
@@ -52,8 +53,7 @@
 }
 
 RenderPass::RenderPass()
-    : id(RenderPassId(-1, -1)),
-      has_transparent_background(true),
+    : has_transparent_background(true),
       quad_list(kDefaultNumQuadsToReserve),
       shared_quad_state_list(sizeof(SharedQuadState),
                              kDefaultNumSharedQuadStatesToReserve) {
@@ -62,16 +62,14 @@
 // Each layer usually produces one shared quad state, so the number of layers
 // is a good hint for what to reserve here.
 RenderPass::RenderPass(size_t num_layers)
-    : id(RenderPassId(-1, -1)),
-      has_transparent_background(true),
+    : has_transparent_background(true),
       quad_list(kDefaultNumQuadsToReserve),
       shared_quad_state_list(sizeof(SharedQuadState), num_layers) {
 }
 
 RenderPass::RenderPass(size_t shared_quad_state_list_size,
                        size_t quad_list_size)
-    : id(RenderPassId(-1, -1)),
-      has_transparent_background(true),
+    : has_transparent_background(true),
       quad_list(quad_list_size),
       shared_quad_state_list(sizeof(SharedQuadState),
                              shared_quad_state_list_size) {
@@ -148,7 +146,6 @@
                         const gfx::Rect& damage_rect,
                         const gfx::Transform& transform_to_root_target) {
   DCHECK_GT(id.layer_id, 0);
-  DCHECK_GE(id.index, 0);
   DCHECK(damage_rect.IsEmpty() || output_rect.Contains(damage_rect))
       << "damage_rect: " << damage_rect.ToString()
       << " output_rect: " << output_rect.ToString();
@@ -168,7 +165,6 @@
                         const gfx::Transform& transform_to_root_target,
                         bool has_transparent_background) {
   DCHECK_GT(id.layer_id, 0);
-  DCHECK_GE(id.index, 0);
 
   this->id = id;
   this->output_rect = output_rect;
@@ -185,7 +181,8 @@
   MathUtil::AddToTracedValue("damage_rect", damage_rect, value);
 
   value->SetBoolean("has_transparent_background", has_transparent_background);
-  value->SetInteger("copy_requests", copy_requests.size());
+  value->SetInteger("copy_requests",
+                    base::saturated_cast<int>(copy_requests.size()));
 
   value->BeginArray("shared_quad_state_list");
   for (const auto& shared_quad_state : shared_quad_state_list) {
diff --git a/cc/quads/render_pass.h b/cc/quads/render_pass.h
index 0f57fae..8c31d823 100644
--- a/cc/quads/render_pass.h
+++ b/cc/quads/render_pass.h
@@ -136,7 +136,7 @@
 template <>
 struct hash<cc::RenderPassId> {
   size_t operator()(cc::RenderPassId key) const {
-    return base::HashPair(key.layer_id, key.index);
+    return base::HashPair(key.layer_id, static_cast<int>(key.index));
   }
 };
 }  // namespace BASE_HASH_NAMESPACE
diff --git a/cc/quads/render_pass_draw_quad.cc b/cc/quads/render_pass_draw_quad.cc
index fc2c3339..1b03ec8 100644
--- a/cc/quads/render_pass_draw_quad.cc
+++ b/cc/quads/render_pass_draw_quad.cc
@@ -12,8 +12,7 @@
 
 namespace cc {
 
-RenderPassDrawQuad::RenderPassDrawQuad()
-    : render_pass_id(RenderPassId(-1, -1)) {
+RenderPassDrawQuad::RenderPassDrawQuad() {
 }
 
 RenderPassDrawQuad::~RenderPassDrawQuad() {
@@ -30,7 +29,6 @@
                                 const gfx::Vector2dF& filters_scale,
                                 const FilterOperations& background_filters) {
   DCHECK_GT(render_pass_id.layer_id, 0);
-  DCHECK_GE(render_pass_id.index, 0);
 
   gfx::Rect opaque_rect;
   bool needs_blending = false;
@@ -61,7 +59,6 @@
                                 const gfx::Vector2dF& filters_scale,
                                 const FilterOperations& background_filters) {
   DCHECK_GT(render_pass_id.layer_id, 0);
-  DCHECK_GE(render_pass_id.index, 0);
 
   DrawQuad::SetAll(shared_quad_state, DrawQuad::RENDER_PASS, rect, opaque_rect,
                    visible_rect, needs_blending);
diff --git a/cc/quads/render_pass_id.cc b/cc/quads/render_pass_id.cc
index a84582c..5fea6dc8 100644
--- a/cc/quads/render_pass_id.cc
+++ b/cc/quads/render_pass_id.cc
@@ -9,7 +9,8 @@
 void* RenderPassId::AsTracingId() const {
   static_assert(sizeof(size_t) <= sizeof(void*),  // NOLINT
                 "size of size_t should not be greater than that of a pointer");
-  return reinterpret_cast<void*>(base::HashPair(layer_id, index));
+  return reinterpret_cast<void*>(
+      base::HashPair(layer_id, static_cast<int>(index)));
 }
 
 }  // namespace cc
diff --git a/cc/quads/render_pass_id.h b/cc/quads/render_pass_id.h
index 0554130..ebf6387e 100644
--- a/cc/quads/render_pass_id.h
+++ b/cc/quads/render_pass_id.h
@@ -14,9 +14,10 @@
 class CC_EXPORT RenderPassId {
  public:
   int layer_id;
-  int index;
+  size_t index;
 
-  RenderPassId(int layer_id, int index) : layer_id(layer_id), index(index) {}
+  RenderPassId() : layer_id(-1), index(0) {}
+  RenderPassId(int layer_id, size_t index) : layer_id(layer_id), index(index) {}
   void* AsTracingId() const;
 
   bool operator==(const RenderPassId& other) const {
diff --git a/cc/quads/stream_video_draw_quad.cc b/cc/quads/stream_video_draw_quad.cc
index 3ab9928..c25e5d5 100644
--- a/cc/quads/stream_video_draw_quad.cc
+++ b/cc/quads/stream_video_draw_quad.cc
@@ -19,11 +19,15 @@
                                  const gfx::Rect& opaque_rect,
                                  const gfx::Rect& visible_rect,
                                  unsigned resource_id,
+                                 gfx::Size resource_size_in_pixels,
+                                 bool allow_overlay,
                                  const gfx::Transform& matrix) {
   bool needs_blending = false;
   DrawQuad::SetAll(shared_quad_state, DrawQuad::STREAM_VIDEO_CONTENT, rect,
                    opaque_rect, visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
+  overlay_resources.size_in_pixels[kResourceIdIndex] = resource_size_in_pixels;
+  overlay_resources.allow_overlay[kResourceIdIndex] = allow_overlay;
   resources.count = 1;
   this->matrix = matrix;
 }
@@ -34,10 +38,14 @@
                                  const gfx::Rect& visible_rect,
                                  bool needs_blending,
                                  unsigned resource_id,
+                                 gfx::Size resource_size_in_pixels,
+                                 bool allow_overlay,
                                  const gfx::Transform& matrix) {
   DrawQuad::SetAll(shared_quad_state, DrawQuad::STREAM_VIDEO_CONTENT, rect,
                    opaque_rect, visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
+  overlay_resources.size_in_pixels[kResourceIdIndex] = resource_size_in_pixels;
+  overlay_resources.allow_overlay[kResourceIdIndex] = allow_overlay;
   resources.count = 1;
   this->matrix = matrix;
 }
@@ -54,4 +62,9 @@
   MathUtil::AddToTracedValue("matrix", matrix, value);
 }
 
+StreamVideoDrawQuad::OverlayResources::OverlayResources() {
+  for (size_t i = 0; i < Resources::kMaxResourceIdCount; ++i)
+    allow_overlay[i] = false;
+}
+
 }  // namespace cc
diff --git a/cc/quads/stream_video_draw_quad.h b/cc/quads/stream_video_draw_quad.h
index faffd20..519c353 100644
--- a/cc/quads/stream_video_draw_quad.h
+++ b/cc/quads/stream_video_draw_quad.h
@@ -21,6 +21,8 @@
               const gfx::Rect& opaque_rect,
               const gfx::Rect& visible_rect,
               unsigned resource_id,
+              gfx::Size resource_size_in_pixels,
+              bool allow_overlay,
               const gfx::Transform& matrix);
 
   void SetAll(const SharedQuadState* shared_quad_state,
@@ -29,13 +31,29 @@
               const gfx::Rect& visible_rect,
               bool needs_blending,
               unsigned resource_id,
+              gfx::Size resource_size_in_pixels,
+              bool allow_overlay,
               const gfx::Transform& matrix);
 
   gfx::Transform matrix;
 
+  struct OverlayResources {
+    OverlayResources();
+
+    gfx::Size size_in_pixels[Resources::kMaxResourceIdCount];
+    bool allow_overlay[Resources::kMaxResourceIdCount];
+  };
+  OverlayResources overlay_resources;
+
   static const StreamVideoDrawQuad* MaterialCast(const DrawQuad*);
 
   ResourceId resource_id() const { return resources.ids[kResourceIdIndex]; }
+  const gfx::Size& resource_size_in_pixels() const {
+    return overlay_resources.size_in_pixels[kResourceIdIndex];
+  }
+  bool allow_overlay() const {
+    return overlay_resources.allow_overlay[kResourceIdIndex];
+  }
 
  private:
   static const size_t kResourceIdIndex = 0;
diff --git a/cc/quads/texture_draw_quad.cc b/cc/quads/texture_draw_quad.cc
index 7106af5e..c469c875 100644
--- a/cc/quads/texture_draw_quad.cc
+++ b/cc/quads/texture_draw_quad.cc
@@ -59,6 +59,8 @@
                              const gfx::Rect& visible_rect,
                              bool needs_blending,
                              unsigned resource_id,
+                             gfx::Size resource_size_in_pixels,
+                             bool allow_overlay,
                              bool premultiplied_alpha,
                              const gfx::PointF& uv_top_left,
                              const gfx::PointF& uv_bottom_right,
@@ -69,6 +71,8 @@
   DrawQuad::SetAll(shared_quad_state, DrawQuad::TEXTURE_CONTENT, rect,
                    opaque_rect, visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
+  overlay_resources.size_in_pixels[kResourceIdIndex] = resource_size_in_pixels;
+  overlay_resources.allow_overlay[kResourceIdIndex] = allow_overlay;
   resources.count = 1;
   this->premultiplied_alpha = premultiplied_alpha;
   this->uv_top_left = uv_top_left;
@@ -105,4 +109,9 @@
   value->SetBoolean("nearest_neighbor", nearest_neighbor);
 }
 
+TextureDrawQuad::OverlayResources::OverlayResources() {
+  for (size_t i = 0; i < Resources::kMaxResourceIdCount; ++i)
+    allow_overlay[i] = false;
+}
+
 }  // namespace cc
diff --git a/cc/quads/texture_draw_quad.h b/cc/quads/texture_draw_quad.h
index 3f85920..40c7623c 100644
--- a/cc/quads/texture_draw_quad.h
+++ b/cc/quads/texture_draw_quad.h
@@ -35,6 +35,8 @@
               const gfx::Rect& visible_rect,
               bool needs_blending,
               unsigned resource_id,
+              gfx::Size resource_size_in_pixels,
+              bool allow_overlay,
               bool premultiplied_alpha,
               const gfx::PointF& uv_top_left,
               const gfx::PointF& uv_bottom_right,
@@ -51,7 +53,27 @@
   bool y_flipped;
   bool nearest_neighbor;
 
+  struct OverlayResources {
+    OverlayResources();
+
+    gfx::Size size_in_pixels[Resources::kMaxResourceIdCount];
+    bool allow_overlay[Resources::kMaxResourceIdCount];
+  };
+  OverlayResources overlay_resources;
+
   ResourceId resource_id() const { return resources.ids[kResourceIdIndex]; }
+  const gfx::Size& resource_size_in_pixels() const {
+    return overlay_resources.size_in_pixels[kResourceIdIndex];
+  }
+  void set_resource_size_in_pixels(const gfx::Size& size_in_pixels) {
+    overlay_resources.size_in_pixels[kResourceIdIndex] = size_in_pixels;
+  }
+  bool allow_overlay() const {
+    return overlay_resources.allow_overlay[kResourceIdIndex];
+  }
+  void set_allow_overlay(bool allow_overlay) {
+    overlay_resources.allow_overlay[kResourceIdIndex] = allow_overlay;
+  }
 
   static const TextureDrawQuad* MaterialCast(const DrawQuad*);
 
diff --git a/cc/raster/bitmap_tile_task_worker_pool.cc b/cc/raster/bitmap_tile_task_worker_pool.cc
index f77fdbb..586b9a9 100644
--- a/cc/raster/bitmap_tile_task_worker_pool.cc
+++ b/cc/raster/bitmap_tile_task_worker_pool.cc
@@ -106,7 +106,7 @@
   // Mark all task sets as pending.
   tasks_pending_.set();
 
-  unsigned priority = kTileTaskPriorityBase;
+  size_t priority = kTileTaskPriorityBase;
 
   graph_.Reset();
 
diff --git a/cc/raster/gpu_tile_task_worker_pool.cc b/cc/raster/gpu_tile_task_worker_pool.cc
index 3de7118..a79b880b 100644
--- a/cc/raster/gpu_tile_task_worker_pool.cc
+++ b/cc/raster/gpu_tile_task_worker_pool.cc
@@ -139,7 +139,7 @@
   // Mark all task sets as pending.
   tasks_pending_.set();
 
-  unsigned priority = kTileTaskPriorityBase;
+  size_t priority = kTileTaskPriorityBase;
 
   graph_.Reset();
 
diff --git a/cc/raster/one_copy_tile_task_worker_pool.cc b/cc/raster/one_copy_tile_task_worker_pool.cc
index dd8937c..e3d1df5 100644
--- a/cc/raster/one_copy_tile_task_worker_pool.cc
+++ b/cc/raster/one_copy_tile_task_worker_pool.cc
@@ -109,6 +109,10 @@
 // wait for copy operations to complete if needed.
 const int kFailedAttemptsBeforeWaitIfNeeded = 256;
 
+// 4MiB is the size of 4 512x512 tiles, which has proven to be a good
+// default batch size for copy operations.
+const int kMaxBytesPerCopyOperation = 1024 * 1024 * 4;
+
 }  // namespace
 
 OneCopyTileTaskWorkerPool::CopyOperation::CopyOperation(
@@ -129,11 +133,11 @@
     ContextProvider* context_provider,
     ResourceProvider* resource_provider,
     ResourcePool* resource_pool,
-    int max_bytes_per_copy_operation,
+    int max_copy_texture_chromium_size,
     bool have_persistent_gpu_memory_buffers) {
   return make_scoped_ptr<TileTaskWorkerPool>(new OneCopyTileTaskWorkerPool(
       task_runner, task_graph_runner, context_provider, resource_provider,
-      resource_pool, max_bytes_per_copy_operation,
+      resource_pool, max_copy_texture_chromium_size,
       have_persistent_gpu_memory_buffers));
 }
 
@@ -143,7 +147,7 @@
     ContextProvider* context_provider,
     ResourceProvider* resource_provider,
     ResourcePool* resource_pool,
-    int max_bytes_per_copy_operation,
+    int max_copy_texture_chromium_size,
     bool have_persistent_gpu_memory_buffers)
     : task_runner_(task_runner),
       task_graph_runner_(task_graph_runner),
@@ -151,7 +155,11 @@
       context_provider_(context_provider),
       resource_provider_(resource_provider),
       resource_pool_(resource_pool),
-      max_bytes_per_copy_operation_(max_bytes_per_copy_operation),
+      max_bytes_per_copy_operation_(
+          max_copy_texture_chromium_size
+              ? std::min(kMaxBytesPerCopyOperation,
+                         max_copy_texture_chromium_size)
+              : kMaxBytesPerCopyOperation),
       have_persistent_gpu_memory_buffers_(have_persistent_gpu_memory_buffers),
       last_issued_copy_operation_(0),
       last_flushed_copy_operation_(0),
@@ -210,7 +218,7 @@
   // Mark all task sets as pending.
   tasks_pending_.set();
 
-  unsigned priority = kTileTaskPriorityBase;
+  size_t priority = kTileTaskPriorityBase;
 
   graph_.Reset();
 
diff --git a/cc/raster/one_copy_tile_task_worker_pool.h b/cc/raster/one_copy_tile_task_worker_pool.h
index a808fc8..f627193f 100644
--- a/cc/raster/one_copy_tile_task_worker_pool.h
+++ b/cc/raster/one_copy_tile_task_worker_pool.h
@@ -39,7 +39,7 @@
       ContextProvider* context_provider,
       ResourceProvider* resource_provider,
       ResourcePool* resource_pool,
-      int max_bytes_per_copy_operation,
+      int max_copy_texture_chromium_size,
       bool have_persistent_gpu_memory_buffers);
 
   // Overridden from TileTaskWorkerPool:
@@ -87,7 +87,7 @@
                             ContextProvider* context_provider,
                             ResourceProvider* resource_provider,
                             ResourcePool* resource_pool,
-                            int max_bytes_per_copy_operation,
+                            int max_copy_texture_chromium_size,
                             bool have_persistent_gpu_memory_buffers);
 
  private:
diff --git a/cc/raster/pixel_buffer_tile_task_worker_pool.cc b/cc/raster/pixel_buffer_tile_task_worker_pool.cc
index 0132fe0..14b6ee2 100644
--- a/cc/raster/pixel_buffer_tile_task_worker_pool.cc
+++ b/cc/raster/pixel_buffer_tile_task_worker_pool.cc
@@ -503,7 +503,7 @@
 
   RasterTaskVector tasks[kNumberOfTaskSets];
 
-  unsigned priority = kTileTaskPriorityBase;
+  size_t priority = kTileTaskPriorityBase;
 
   graph_.Reset();
 
diff --git a/cc/raster/task_graph_runner.h b/cc/raster/task_graph_runner.h
index a5498435..bb55afc1 100644
--- a/cc/raster/task_graph_runner.h
+++ b/cc/raster/task_graph_runner.h
@@ -53,11 +53,11 @@
 
     typedef std::vector<Node> Vector;
 
-    Node(Task* task, unsigned priority, size_t dependencies)
+    Node(Task* task, size_t priority, size_t dependencies)
         : task(task), priority(priority), dependencies(dependencies) {}
 
     Task* task;
-    unsigned priority;
+    size_t priority;
     size_t dependencies;
   };
 
@@ -141,11 +141,11 @@
   struct PrioritizedTask {
     typedef std::vector<PrioritizedTask> Vector;
 
-    PrioritizedTask(Task* task, unsigned priority)
+    PrioritizedTask(Task* task, size_t priority)
         : task(task), priority(priority) {}
 
     Task* task;
-    unsigned priority;
+    size_t priority;
   };
 
   typedef std::vector<const Task*> TaskVector;
diff --git a/cc/raster/tile_task_worker_pool.cc b/cc/raster/tile_task_worker_pool.cc
index 70dfb924..d349514 100644
--- a/cc/raster/tile_task_worker_pool.cc
+++ b/cc/raster/tile_task_worker_pool.cc
@@ -109,7 +109,7 @@
     TaskGraph* graph,
     RasterTask* raster_task,
     const ImageDecodeTask::Vector& decode_tasks,
-    unsigned priority) {
+    size_t priority) {
   size_t dependencies = 0u;
 
   // Insert image decode tasks.
diff --git a/cc/raster/tile_task_worker_pool.h b/cc/raster/tile_task_worker_pool.h
index cd7ad2c3..ff001890 100644
--- a/cc/raster/tile_task_worker_pool.h
+++ b/cc/raster/tile_task_worker_pool.h
@@ -51,7 +51,7 @@
       TaskGraph* graph,
       RasterTask* task,
       const ImageDecodeTask::Vector& decode_tasks,
-      unsigned priority);
+      size_t priority);
 
   // Utility function that will create a temporary bitmap and copy pixels to
   // |memory| when necessary. The |canvas_bitmap_rect| is the rect of the bitmap
diff --git a/cc/raster/tile_task_worker_pool_perftest.cc b/cc/raster/tile_task_worker_pool_perftest.cc
index 53cabf4..b49c498 100644
--- a/cc/raster/tile_task_worker_pool_perftest.cc
+++ b/cc/raster/tile_task_worker_pool_perftest.cc
@@ -97,7 +97,6 @@
   }
   void SetupLock() override {}
   base::Lock* GetLock() override { return &context_lock_; }
-  bool IsContextLost() override { return false; }
   void VerifyContexts() override {}
   void DeleteCachedResources() override {}
   bool DestroyedOnMainThread() override { return false; }
diff --git a/cc/raster/zero_copy_tile_task_worker_pool.cc b/cc/raster/zero_copy_tile_task_worker_pool.cc
index 2da2888..d42570a 100644
--- a/cc/raster/zero_copy_tile_task_worker_pool.cc
+++ b/cc/raster/zero_copy_tile_task_worker_pool.cc
@@ -104,7 +104,7 @@
   // Mark all task sets as pending.
   tasks_pending_.set();
 
-  unsigned priority = kTileTaskPriorityBase;
+  size_t priority = kTileTaskPriorityBase;
 
   graph_.Reset();
 
diff --git a/cc/resources/image_layer_updater.cc b/cc/resources/image_layer_updater.cc
deleted file mode 100644
index 0538d96..0000000
--- a/cc/resources/image_layer_updater.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/image_layer_updater.h"
-#include "cc/resources/prioritized_resource.h"
-#include "cc/resources/resource_update_queue.h"
-
-namespace cc {
-
-ImageLayerUpdater::Resource::Resource(ImageLayerUpdater* updater,
-                                      scoped_ptr<PrioritizedResource> texture)
-    : LayerUpdater::Resource(texture.Pass()), updater_(updater) {}
-
-ImageLayerUpdater::Resource::~Resource() {}
-
-void ImageLayerUpdater::Resource::Update(ResourceUpdateQueue* queue,
-                                         const gfx::Rect& source_rect,
-                                         const gfx::Vector2d& dest_offset,
-                                         bool partial_update) {
-  updater_->UpdateTexture(
-      queue, texture(), source_rect, dest_offset, partial_update);
-}
-
-// static
-scoped_refptr<ImageLayerUpdater> ImageLayerUpdater::Create() {
-  return make_scoped_refptr(new ImageLayerUpdater());
-}
-
-scoped_ptr<LayerUpdater::Resource> ImageLayerUpdater::CreateResource(
-    PrioritizedResourceManager* manager) {
-  return make_scoped_ptr(
-      new Resource(this, PrioritizedResource::Create(manager)));
-}
-
-void ImageLayerUpdater::UpdateTexture(ResourceUpdateQueue* queue,
-                                      PrioritizedResource* texture,
-                                      const gfx::Rect& source_rect,
-                                      const gfx::Vector2d& dest_offset,
-                                      bool partial_update) {
-  // Source rect should never go outside the image pixels, even if this
-  // is requested because the texture extends outside the image.
-  gfx::Rect clipped_source_rect = source_rect;
-  gfx::Rect image_rect = gfx::Rect(0, 0, bitmap_.width(), bitmap_.height());
-  clipped_source_rect.Intersect(image_rect);
-
-  gfx::Vector2d clipped_dest_offset =
-      dest_offset +
-      gfx::Vector2d(clipped_source_rect.origin() - source_rect.origin());
-
-  ResourceUpdate upload = ResourceUpdate::Create(
-      texture, &bitmap_, image_rect, clipped_source_rect, clipped_dest_offset);
-  if (partial_update)
-    queue->AppendPartialUpload(upload);
-  else
-    queue->AppendFullUpload(upload);
-}
-
-void ImageLayerUpdater::SetBitmap(const SkBitmap& bitmap) {
-  DCHECK(bitmap.pixelRef());
-  bitmap_ = bitmap;
-}
-
-bool ImageLayerUpdater::UsingBitmap(const SkBitmap& bitmap) const {
-  return bitmap.pixelRef() == bitmap_.pixelRef();
-}
-
-}  // namespace cc
diff --git a/cc/resources/image_layer_updater.h b/cc/resources/image_layer_updater.h
deleted file mode 100644
index 81225ba7..0000000
--- a/cc/resources/image_layer_updater.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RESOURCES_IMAGE_LAYER_UPDATER_H_
-#define CC_RESOURCES_IMAGE_LAYER_UPDATER_H_
-
-#include "cc/base/cc_export.h"
-#include "cc/resources/layer_updater.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace cc {
-
-class ResourceUpdateQueue;
-
-class CC_EXPORT ImageLayerUpdater : public LayerUpdater {
- public:
-  class Resource : public LayerUpdater::Resource {
-   public:
-    Resource(ImageLayerUpdater* updater,
-             scoped_ptr<PrioritizedResource> texture);
-    ~Resource() override;
-
-    void Update(ResourceUpdateQueue* queue,
-                const gfx::Rect& source_rect,
-                const gfx::Vector2d& dest_offset,
-                bool partial_update) override;
-
-   private:
-    ImageLayerUpdater* updater_;
-
-    DISALLOW_COPY_AND_ASSIGN(Resource);
-  };
-
-  static scoped_refptr<ImageLayerUpdater> Create();
-
-  scoped_ptr<LayerUpdater::Resource> CreateResource(
-      PrioritizedResourceManager*) override;
-
-  void UpdateTexture(ResourceUpdateQueue* queue,
-                     PrioritizedResource* texture,
-                     const gfx::Rect& source_rect,
-                     const gfx::Vector2d& dest_offset,
-                     bool partial_update);
-
-  void SetBitmap(const SkBitmap& bitmap);
-  bool UsingBitmap(const SkBitmap& bitmap) const;
-
- private:
-  ImageLayerUpdater() {}
-  ~ImageLayerUpdater() override {}
-
-  SkBitmap bitmap_;
-
-  DISALLOW_COPY_AND_ASSIGN(ImageLayerUpdater);
-};
-
-}  // namespace cc
-
-#endif  // CC_RESOURCES_IMAGE_LAYER_UPDATER_H_
diff --git a/cc/resources/memory_history.cc b/cc/resources/memory_history.cc
index 4dc49c88..29bad2a 100644
--- a/cc/resources/memory_history.cc
+++ b/cc/resources/memory_history.cc
@@ -19,21 +19,4 @@
   ring_buffer_.SaveToBuffer(entry);
 }
 
-void MemoryHistory::GetMinAndMax(size_t* min, size_t* max) const {
-  *min = std::numeric_limits<size_t>::max();
-  *max = 0;
-
-  for (RingBufferType::Iterator it = ring_buffer_.Begin(); it; ++it) {
-    size_t bytes_total = it->total_bytes_used;
-
-    if (bytes_total < *min)
-      *min = bytes_total;
-    if (bytes_total > *max)
-      *max = bytes_total;
-  }
-
-  if (*min > *max)
-    *min = *max;
-}
-
 }  // namespace cc
diff --git a/cc/resources/memory_history.h b/cc/resources/memory_history.h
index 570a3d0..15ddc75a 100644
--- a/cc/resources/memory_history.h
+++ b/cc/resources/memory_history.h
@@ -26,12 +26,11 @@
           had_enough_memory(false) {}
 
     size_t total_budget_in_bytes;
-    size_t total_bytes_used;
+    int64 total_bytes_used;
     bool had_enough_memory;
   };
 
   void SaveEntry(const Entry& entry);
-  void GetMinAndMax(size_t* min, size_t* max) const;
 
   typedef RingBuffer<Entry, 80> RingBufferType;
   RingBufferType::Iterator Begin() const { return ring_buffer_.Begin(); }
diff --git a/cc/resources/prioritized_resource_unittest.cc b/cc/resources/prioritized_resource_unittest.cc
index 0e0f32b..99329d5 100644
--- a/cc/resources/prioritized_resource_unittest.cc
+++ b/cc/resources/prioritized_resource_unittest.cc
@@ -132,7 +132,7 @@
 
   // Set decreasing priorities
   for (size_t i = 0; i < kMaxTextures * 2; ++i)
-    textures[i]->set_request_priority(100 + i);
+    textures[i]->set_request_priority(base::checked_cast<int>(100 + i));
 
   // Only lower half should be available.
   PrioritizeTexturesAndBackings(resource_manager.get());
@@ -143,7 +143,7 @@
 
   // Set increasing priorities
   for (size_t i = 0; i < kMaxTextures * 2; ++i)
-    textures[i]->set_request_priority(100 - i);
+    textures[i]->set_request_priority(base::checked_cast<int>(100 - i));
 
   // Only upper half should be available.
   PrioritizeTexturesAndBackings(resource_manager.get());
@@ -175,7 +175,7 @@
         resource_manager->CreateTexture(texture_size_, texture_format_);
   }
   for (size_t i = 0; i < kMaxTextures; ++i)
-    textures[i]->set_request_priority(100 + i);
+    textures[i]->set_request_priority(base::checked_cast<int>(100 + i));
 
   // Set max limit to 8 textures
   resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(8));
@@ -242,7 +242,7 @@
         resource_manager->CreateTexture(texture_size_, texture_format_);
   }
   for (size_t i = 0; i < kMaxTextures; ++i)
-    textures[i]->set_request_priority(100 + i);
+    textures[i]->set_request_priority(base::checked_cast<int>(100 + i));
 
   // Set the memory limit to the max number of textures.
   resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures));
@@ -312,7 +312,7 @@
         resource_manager->CreateTexture(texture_size_, texture_format_);
   }
   for (size_t i = 0; i < kMaxTextures; ++i)
-    textures[i]->set_request_priority(100 + i);
+    textures[i]->set_request_priority(base::checked_cast<int>(100 + i));
 
   // Set the memory limit to the max number of textures.
   resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures));
@@ -392,7 +392,7 @@
         resource_manager->CreateTexture(texture_size_, texture_format_);
   }
   for (size_t i = 0; i < kMaxTextures; ++i)
-    textures[i]->set_request_priority(100 + i);
+    textures[i]->set_request_priority(base::checked_cast<int>(100 + i));
 
   // Set the cutoff to drop two textures. Try to request_late on all textures,
   // and make sure that request_late doesn't work on a texture with equal
@@ -464,7 +464,7 @@
   for (size_t i = 0; i < kMaxTextures; ++i) {
     textures[i] =
         resource_manager->CreateTexture(texture_size_, texture_format_);
-    textures[i]->set_request_priority(100 + i);
+    textures[i]->set_request_priority(base::checked_cast<int>(100 + i));
   }
 
   PrioritizeTexturesAndBackings(resource_manager.get());
@@ -613,7 +613,7 @@
   }
 
   for (size_t i = 0; i < kNumTextures; ++i)
-    textures[i]->set_request_priority(200 + i);
+    textures[i]->set_request_priority(base::checked_cast<int>(200 + i));
   PrioritizeTexturesAndBackings(resource_manager.get());
 
   // Allocate textures which are currently high priority.
@@ -628,7 +628,7 @@
   EXPECT_TRUE(textures[3]->have_backing_texture());
 
   for (size_t i = 0; i < kNumTextures; ++i)
-    more_textures[i]->set_request_priority(100 + i);
+    more_textures[i]->set_request_priority(base::checked_cast<int>(100 + i));
   PrioritizeTexturesAndBackings(resource_manager.get());
 
   // Textures are now below cutoff.
@@ -796,7 +796,7 @@
 
   // Set decreasing non-visible priorities outside root surface.
   for (size_t i = 0; i < kMaxTextures; ++i)
-    textures[i]->set_request_priority(100 + i);
+    textures[i]->set_request_priority(base::checked_cast<int>(100 + i));
 
   // Only lower half should be available.
   PrioritizeTexturesAndBackings(resource_manager.get());
@@ -807,7 +807,7 @@
 
   // Set increasing non-visible priorities outside root surface.
   for (size_t i = 0; i < kMaxTextures; ++i)
-    textures[i]->set_request_priority(100 - i);
+    textures[i]->set_request_priority(base::checked_cast<int>(100 - i));
 
   // Only upper half should be available.
   PrioritizeTexturesAndBackings(resource_manager.get());
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 449e04b..079d034 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -278,7 +278,6 @@
       allocated(false),
       read_lock_fences_enabled(false),
       has_shared_bitmap_id(false),
-      allow_overlay(false),
       read_lock_fence(NULL),
       size(size),
       origin(origin),
@@ -322,7 +321,6 @@
       allocated(false),
       read_lock_fences_enabled(false),
       has_shared_bitmap_id(!!bitmap),
-      allow_overlay(false),
       read_lock_fence(NULL),
       size(size),
       origin(origin),
@@ -367,7 +365,6 @@
       allocated(false),
       read_lock_fences_enabled(false),
       has_shared_bitmap_id(true),
-      allow_overlay(false),
       read_lock_fence(NULL),
       size(size),
       origin(origin),
@@ -451,11 +448,6 @@
   return resource->lost;
 }
 
-bool ResourceProvider::AllowOverlay(ResourceId id) {
-  Resource* resource = GetResource(id);
-  return resource->allow_overlay;
-}
-
 ResourceId ResourceProvider::CreateResource(const gfx::Size& size,
                                             GLint wrap_mode,
                                             TextureHint hint,
@@ -575,7 +567,7 @@
     uint8_t* pixels = shared_bitmap->pixels();
     DCHECK(pixels);
     resource = InsertResource(
-        id, Resource(pixels, shared_bitmap, mailbox.shared_memory_size(),
+        id, Resource(pixels, shared_bitmap, mailbox.size_in_pixels(),
                      Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE));
   }
   resource->allocated = true;
@@ -583,7 +575,6 @@
   resource->release_callback_impl =
       base::Bind(&SingleReleaseCallbackImpl::Run,
                  base::Owned(release_callback_impl.release()));
-  resource->allow_overlay = mailbox.allow_overlay();
   return id;
 }
 
@@ -1060,6 +1051,8 @@
   if (!gpu_memory_buffer_)
     return;
 
+  resource_provider_->LazyCreate(resource_);
+
   if (!resource_->image_id) {
     GLES2Interface* gl = resource_provider_->ContextGL();
     DCHECK(gl);
@@ -1389,7 +1382,6 @@
     // Don't allocate a texture for a child.
     resource->allocated = true;
     resource->imported_count = 1;
-    resource->allow_overlay = it->allow_overlay;
     child_info.parent_to_child_map[local_id] = it->id;
     child_info.child_to_parent_map[it->id] = local_id;
   }
@@ -1493,7 +1485,6 @@
   resource->filter = source->filter;
   resource->size = source->size;
   resource->is_repeated = (source->wrap_mode == GL_REPEAT);
-  resource->allow_overlay = source->allow_overlay;
 
   if (source->type == RESOURCE_TYPE_BITMAP) {
     resource->mailbox_holder.mailbox = source->shared_bitmap_id;
@@ -1911,21 +1902,20 @@
   resource->allocated = true;
   GLES2Interface* gl = ContextGL();
   gfx::Size& size = resource->size;
-  DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
   ResourceFormat format = resource->format;
-  gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
+  gl->BindTexture(resource->target, resource->gl_id);
   if (use_texture_storage_ext_ &&
       IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
       (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
     GLenum storage_format = TextureToStorageFormat(format);
-    gl->TexStorage2DEXT(GL_TEXTURE_2D, 1, storage_format, size.width(),
+    gl->TexStorage2DEXT(resource->target, 1, storage_format, size.width(),
                         size.height());
   } else {
     // ETC1 does not support preallocation.
     if (format != ETC1) {
-      gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(format), size.width(),
-                     size.height(), 0, GLDataFormat(format), GLDataType(format),
-                     NULL);
+      gl->TexImage2D(resource->target, 0, GLInternalFormat(format),
+                     size.width(), size.height(), 0, GLDataFormat(format),
+                     GLDataType(format), NULL);
     }
   }
 }
@@ -1953,8 +1943,7 @@
   DCHECK(source_resource->origin == Resource::INTERNAL);
   DCHECK_EQ(source_resource->exported_count, 0);
   DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type);
-  DCHECK(source_resource->allocated);
-  LazyCreate(source_resource);
+  LazyAllocate(source_resource);
 
   Resource* dest_resource = GetResource(dest_id);
   DCHECK(!dest_resource->locked_for_write);
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 2130bb7b1..efcb632a 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -107,7 +107,6 @@
   bool InUseByConsumer(ResourceId id);
 
   bool IsLost(ResourceId id);
-  bool AllowOverlay(ResourceId id);
 
   // Producer interface.
 
@@ -503,7 +502,6 @@
     bool allocated : 1;
     bool read_lock_fences_enabled : 1;
     bool has_shared_bitmap_id : 1;
-    bool allow_overlay : 1;
     scoped_refptr<Fence> read_lock_fence;
     gfx::Size size;
     Origin origin;
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index 7ad0e867..0b27a832 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -1045,55 +1045,6 @@
   resource_provider_->DestroyChild(child_id);
 }
 
-TEST_P(ResourceProviderTest, AllowOverlayTransfersToParent) {
-  // Overlays only supported on the GL path.
-  if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
-    return;
-
-  uint32 sync_point = 0;
-  TextureMailbox mailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point);
-  mailbox.set_allow_overlay(true);
-  scoped_ptr<SingleReleaseCallbackImpl> release_callback =
-      SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback));
-  ResourceId id1 = child_resource_provider_->CreateResourceFromTextureMailbox(
-      mailbox, release_callback.Pass());
-
-  TextureMailbox mailbox2(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point);
-  mailbox2.set_allow_overlay(false);
-  scoped_ptr<SingleReleaseCallbackImpl> release_callback2 =
-      SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback));
-  ResourceId id2 = child_resource_provider_->CreateResourceFromTextureMailbox(
-      mailbox2, release_callback2.Pass());
-
-  ReturnedResourceArray returned_to_child;
-  int child_id =
-      resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
-
-  // Transfer some resources to the parent.
-  ResourceProvider::ResourceIdArray resource_ids_to_transfer;
-  resource_ids_to_transfer.push_back(id1);
-  resource_ids_to_transfer.push_back(id2);
-  TransferableResourceArray list;
-  child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
-                                                &list);
-  ASSERT_EQ(2u, list.size());
-  resource_provider_->ReceiveFromChild(child_id, list);
-  EXPECT_TRUE(resource_provider_->AllowOverlay(list[0].id));
-  EXPECT_FALSE(resource_provider_->AllowOverlay(list[1].id));
-
-  resource_provider_->DeclareUsedResourcesFromChild(
-      child_id, ResourceProvider::ResourceIdSet());
-
-  EXPECT_EQ(2u, returned_to_child.size());
-  child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
-
-  child_resource_provider_->DeleteResource(id1);
-  child_resource_provider_->DeleteResource(id2);
-  EXPECT_EQ(0u, child_resource_provider_->num_resources());
-
-  resource_provider_->DestroyChild(child_id);
-}
-
 TEST_P(ResourceProviderTest, TransferSoftwareResources) {
   if (GetParam() != ResourceProvider::RESOURCE_TYPE_BITMAP)
     return;
@@ -3419,6 +3370,12 @@
   id = resource_provider->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
 
+  EXPECT_CALL(*context, NextTextureId())
+      .WillOnce(Return(kTextureId))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId))
+      .Times(1)
+      .RetiresOnSaturation();
   EXPECT_CALL(*context, createImageCHROMIUM(_, kWidth, kHeight, GL_RGBA))
       .WillOnce(Return(kImageId))
       .RetiresOnSaturation();
@@ -3428,11 +3385,8 @@
     EXPECT_TRUE(lock.GetGpuMemoryBuffer());
   }
 
-  EXPECT_CALL(*context, NextTextureId())
-      .WillOnce(Return(kTextureId))
-      .RetiresOnSaturation();
-  // Once in CreateTextureId and once in BindForSampling
-  EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(2)
+  EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId))
+      .Times(1)
       .RetiresOnSaturation();
   EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId))
       .Times(1)
@@ -3501,6 +3455,12 @@
   source_id = resource_provider->CreateResource(
       size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
 
+  EXPECT_CALL(*context, NextTextureId())
+      .WillOnce(Return(kSourceTextureId))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kSourceTextureId))
+      .Times(1)
+      .RetiresOnSaturation();
   EXPECT_CALL(*context, createImageCHROMIUM(_, kWidth, kHeight, GL_RGBA))
       .WillOnce(Return(kImageId))
       .RetiresOnSaturation();
@@ -3524,11 +3484,8 @@
                                    GL_UNSIGNED_BYTE, nullptr))
       .Times(1)
       .RetiresOnSaturation();
-  EXPECT_CALL(*context, NextTextureId())
-      .WillOnce(Return(kSourceTextureId))
-      .RetiresOnSaturation();
   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kSourceTextureId))
-      .Times(2)
+      .Times(1)
       .RetiresOnSaturation();
   EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId))
       .Times(1)
diff --git a/cc/resources/texture_mailbox.cc b/cc/resources/texture_mailbox.cc
index 9bf242e..7e4dd297 100644
--- a/cc/resources/texture_mailbox.cc
+++ b/cc/resources/texture_mailbox.cc
@@ -28,15 +28,28 @@
       nearest_neighbor_(false) {
 }
 
+TextureMailbox::TextureMailbox(const gpu::Mailbox& mailbox,
+                               uint32 target,
+                               uint32 sync_point,
+                               const gfx::Size& size_in_pixels,
+                               bool allow_overlay)
+    : mailbox_holder_(mailbox, target, sync_point),
+      shared_bitmap_(nullptr),
+      size_in_pixels_(size_in_pixels),
+      allow_overlay_(allow_overlay),
+      nearest_neighbor_(false) {
+  DCHECK_IMPLIES(allow_overlay, !size_in_pixels.IsEmpty());
+}
+
 TextureMailbox::TextureMailbox(SharedBitmap* shared_bitmap,
-                               const gfx::Size& size)
+                               const gfx::Size& size_in_pixels)
     : shared_bitmap_(shared_bitmap),
-      shared_memory_size_(size),
+      size_in_pixels_(size_in_pixels),
       allow_overlay_(false),
       nearest_neighbor_(false) {
   // If an embedder of cc gives an invalid TextureMailbox, we should crash
   // here to identify the offender.
-  CHECK(SharedBitmap::VerifySizeInBytes(shared_memory_size_));
+  CHECK(SharedBitmap::VerifySizeInBytes(size_in_pixels_));
 }
 
 TextureMailbox::~TextureMailbox() {}
@@ -57,7 +70,7 @@
 size_t TextureMailbox::SharedMemorySizeInBytes() const {
   // UncheckedSizeInBytes is okay because we VerifySizeInBytes in the
   // constructor and the field is immutable.
-  return SharedBitmap::UncheckedSizeInBytes(shared_memory_size_);
+  return SharedBitmap::UncheckedSizeInBytes(size_in_pixels_);
 }
 
 }  // namespace cc
diff --git a/cc/resources/texture_mailbox.h b/cc/resources/texture_mailbox.h
index cec60ce..47e71ac 100644
--- a/cc/resources/texture_mailbox.h
+++ b/cc/resources/texture_mailbox.h
@@ -22,7 +22,12 @@
   TextureMailbox();
   explicit TextureMailbox(const gpu::MailboxHolder& mailbox_holder);
   TextureMailbox(const gpu::Mailbox& mailbox, uint32 target, uint32 sync_point);
-  TextureMailbox(SharedBitmap* shared_bitmap, const gfx::Size& size);
+  TextureMailbox(const gpu::Mailbox& mailbox,
+                 uint32 target,
+                 uint32 sync_point,
+                 const gfx::Size& size_in_pixels,
+                 bool allow_overlay);
+  TextureMailbox(SharedBitmap* shared_bitmap, const gfx::Size& size_in_pixels);
 
   ~TextureMailbox();
 
@@ -41,20 +46,21 @@
   }
 
   bool allow_overlay() const { return allow_overlay_; }
-  void set_allow_overlay(bool allow_overlay) { allow_overlay_ = allow_overlay; }
   bool nearest_neighbor() const { return nearest_neighbor_; }
   void set_nearest_neighbor(bool nearest_neighbor) {
     nearest_neighbor_ = nearest_neighbor;
   }
 
+  // This is valid if allow_overlau() or IsSharedMemory() is true.
+  gfx::Size size_in_pixels() const { return size_in_pixels_; }
+
   SharedBitmap* shared_bitmap() const { return shared_bitmap_; }
-  gfx::Size shared_memory_size() const { return shared_memory_size_; }
   size_t SharedMemorySizeInBytes() const;
 
  private:
   gpu::MailboxHolder mailbox_holder_;
   SharedBitmap* shared_bitmap_;
-  gfx::Size shared_memory_size_;
+  gfx::Size size_in_pixels_;
   bool allow_overlay_;
   bool nearest_neighbor_;
 };
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index d681b39..ba63431 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -417,9 +417,9 @@
     const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i);
     external_resources.mailboxes.push_back(
         TextureMailbox(mailbox_holder.mailbox, mailbox_holder.texture_target,
-                       mailbox_holder.sync_point));
-    external_resources.mailboxes.back().set_allow_overlay(
-        video_frame->allow_overlay());
+                       mailbox_holder.sync_point, video_frame->coded_size(),
+                       video_frame->metadata()->IsTrue(
+                           media::VideoFrameMetadata::ALLOW_OVERLAY)));
     external_resources.release_callbacks.push_back(
         base::Bind(&ReturnTexture, AsWeakPtr(), video_frame));
   }
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index 17095e6..094116e 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -112,14 +112,13 @@
     const unsigned sync_point = 7;
     const unsigned target = GL_TEXTURE_2D;
     return media::VideoFrame::WrapNativeTexture(
+        media::VideoFrame::ARGB,
         gpu::MailboxHolder(mailbox, target, sync_point),
         base::Bind(&ReleaseMailboxCB),
-        size,               // coded_size
-        gfx::Rect(size),    // visible_rect
-        size,               // natural_size
-        base::TimeDelta(),  // timestamp
-        false,              // allow_overlay
-        true);              // has_alpha
+        size,                // coded_size
+        gfx::Rect(size),     // visible_rect
+        size,                // natural_size
+        base::TimeDelta());  // timestamp
   }
 
   scoped_refptr<media::VideoFrame> CreateTestYUVHardareVideoFrame() {
@@ -141,11 +140,10 @@
         gpu::MailboxHolder(mailbox[media::VideoFrame::kVPlane], target,
                            sync_point),
         base::Bind(&ReleaseMailboxCB),
-        size,               // coded_size
-        gfx::Rect(size),    // visible_rect
-        size,               // natural_size
-        base::TimeDelta(),  // timestamp
-        false);             // allow_overlay
+        size,                // coded_size
+        gfx::Rect(size),     // visible_rect
+        size,                // natural_size
+        base::TimeDelta());  // timestamp
   }
 
   WebGraphicsContext3DUploadCounter* context3d_;
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 0d90c68214..b3fbc086 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "base/auto_reset.h"
+#include "base/debug/stack_trace.h"
 #include "base/logging.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/single_thread_task_runner.h"
@@ -226,7 +227,8 @@
 }
 
 void Scheduler::DidSwapBuffersComplete() {
-  DCHECK_GT(state_machine_.pending_swaps(), 0) << AsValue()->ToString();
+  DCHECK_GT(state_machine_.pending_swaps(), 0)
+      << AsValue()->ToString() << base::debug::StackTrace().ToString();
   state_machine_.DidSwapBuffersComplete();
   ProcessScheduledActions();
 }
@@ -354,6 +356,7 @@
   // TODO(brianderson): Adjust deadline in the DisplayScheduler.
   BeginFrameArgs adjusted_args(args);
   adjusted_args.deadline -= EstimatedParentDrawTime();
+  adjusted_args.on_critical_path = !ImplLatencyTakesPriority();
 
   // Deliver BeginFrames to children.
   // TODO(brianderson): Move this responsibility to the DisplayScheduler.
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 98e92c0d..3a290fb3 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -152,6 +152,9 @@
   bool BeginImplFrameDeadlinePending() const {
     return !begin_impl_frame_deadline_task_.IsCancelled();
   }
+  bool ImplLatencyTakesPriority() const {
+    return state_machine_.impl_latency_takes_priority();
+  }
 
   base::TimeTicks AnticipatedDrawTime() const;
 
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 3fc5c06..080d290c 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop/message_loop.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/run_loop.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
@@ -84,7 +85,7 @@
   int ActionIndex(const char* action) const {
     for (size_t i = 0; i < actions_.size(); i++)
       if (!strcmp(actions_[i], action))
-        return i;
+        return base::checked_cast<int>(i);
     return -1;
   }
 
@@ -3003,5 +3004,38 @@
   EXPECT_EQ(authoritative_interval, scheduler_->BeginImplFrameInterval());
 }
 
+TEST_F(SchedulerTest, ImplLatencyTakesPriority) {
+  SetUpScheduler(true);
+  scheduler_->SetImplLatencyTakesPriority(true);
+  EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
+
+  scheduler_->SetImplLatencyTakesPriority(false);
+  EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
+}
+
+TEST_F(SchedulerTest, BeginFrameArgs_OnCriticalPath) {
+  scheduler_settings_.use_external_begin_frame_source = true;
+  SetUpScheduler(true);
+
+  scheduler_->SetImplLatencyTakesPriority(false);
+  scheduler_->SetChildrenNeedBeginFrames(true);
+
+  EXPECT_SCOPED(AdvanceFrame());
+  EXPECT_TRUE(client_->begin_frame_is_sent_to_children());
+  EXPECT_TRUE(client_->begin_frame_args_sent_to_children().on_critical_path);
+}
+
+TEST_F(SchedulerTest, BeginFrameArgs_NotOnCriticalPath) {
+  scheduler_settings_.use_external_begin_frame_source = true;
+  SetUpScheduler(true);
+
+  scheduler_->SetImplLatencyTakesPriority(true);
+  scheduler_->SetChildrenNeedBeginFrames(true);
+
+  EXPECT_SCOPED(AdvanceFrame());
+  EXPECT_TRUE(client_->begin_frame_is_sent_to_children());
+  EXPECT_FALSE(client_->begin_frame_args_sent_to_children().on_critical_path);
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/surfaces/surface_aggregator_perftest.cc b/cc/surfaces/surface_aggregator_perftest.cc
index 104a55c..b5fddf5 100644
--- a/cc/surfaces/surface_aggregator_perftest.cc
+++ b/cc/surfaces/surface_aggregator_perftest.cc
@@ -70,8 +70,8 @@
         bool flipped = false;
         bool nearest_neighbor = false;
         quad->SetAll(sqs, rect, opaque_rect, visible_rect, needs_blending, j,
-                     premultiplied_alpha, uv_top_left, uv_bottom_right,
-                     background_color, vertex_opacity, flipped,
+                     gfx::Size(), false, premultiplied_alpha, uv_top_left,
+                     uv_bottom_right, background_color, vertex_opacity, flipped,
                      nearest_neighbor);
       }
       sqs = pass->CreateAndAppendSharedQuadState();
diff --git a/cc/surfaces/surface_aggregator_test_helpers.h b/cc/surfaces/surface_aggregator_test_helpers.h
index 05c8344..6d00c4f 100644
--- a/cc/surfaces/surface_aggregator_test_helpers.h
+++ b/cc/surfaces/surface_aggregator_test_helpers.h
@@ -55,11 +55,7 @@
   RenderPassId render_pass_id;
 
  private:
-  Quad()
-      : material(DrawQuad::INVALID),
-        opacity(1.f),
-        color(SK_ColorWHITE),
-        render_pass_id(-1, -1) {}
+  Quad() : material(DrawQuad::INVALID), opacity(1.f), color(SK_ColorWHITE) {}
 };
 
 struct Pass {
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index ac81b3b6..981a573 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -1352,19 +1352,10 @@
     const float vertex_opacity[4] = {0.f, 0.f, 1.f, 1.f};
     bool flipped = false;
     bool nearest_neighbor = false;
-    quad->SetAll(sqs,
-                 rect,
-                 opaque_rect,
-                 visible_rect,
-                 needs_blending,
-                 resource_ids[i],
-                 premultiplied_alpha,
-                 uv_top_left,
-                 uv_bottom_right,
-                 background_color,
-                 vertex_opacity,
-                 flipped,
-                 nearest_neighbor);
+    quad->SetAll(sqs, rect, opaque_rect, visible_rect, needs_blending,
+                 resource_ids[i], gfx::Size(), false, premultiplied_alpha,
+                 uv_top_left, uv_bottom_right, background_color, vertex_opacity,
+                 flipped, nearest_neighbor);
   }
   frame_data->render_pass_list.push_back(pass.Pass());
   scoped_ptr<CompositorFrame> frame(new CompositorFrame);
diff --git a/cc/surfaces/surface_display_output_surface.cc b/cc/surfaces/surface_display_output_surface.cc
index e1f90da..9bd3e717 100644
--- a/cc/surfaces/surface_display_output_surface.cc
+++ b/cc/surfaces/surface_display_output_surface.cc
@@ -5,6 +5,7 @@
 #include "cc/surfaces/surface_display_output_surface.h"
 
 #include "base/bind.h"
+#include "base/debug/stack_trace.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/output/compositor_frame_ack.h"
 #include "cc/surfaces/display.h"
@@ -21,7 +22,8 @@
     : OutputSurface(context_provider),
       display_client_(NULL),
       factory_(surface_manager, this),
-      allocator_(allocator) {
+      allocator_(allocator),
+      inside_swap_buffers_(0) {
   factory_.set_needs_sync_points(false);
   capabilities_.delegated_rendering = true;
   capabilities_.max_frames_pending = 1;
@@ -46,27 +48,38 @@
 }
 
 void SurfaceDisplayOutputSurface::SwapBuffers(CompositorFrame* frame) {
+  inside_swap_buffers_ = 1;
+
   gfx::Size frame_size =
       frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
   if (frame_size.IsEmpty() || frame_size != display_size_) {
+    inside_swap_buffers_ = 2;
     if (!surface_id_.is_null()) {
       factory_.Destroy(surface_id_);
     }
+    inside_swap_buffers_ = 3;
     surface_id_ = allocator_->GenerateId();
     factory_.Create(surface_id_);
     display_size_ = frame_size;
   }
+  inside_swap_buffers_ = 4;
   display_client_->display()->SetSurfaceId(surface_id_,
                                            frame->metadata.device_scale_factor);
 
+  client_->DidSwapBuffers();
+
+  inside_swap_buffers_ = 5;
+
   scoped_ptr<CompositorFrame> frame_copy(new CompositorFrame());
+  inside_swap_buffers_ = 6;
   frame->AssignTo(frame_copy.get());
+  inside_swap_buffers_ = 7;
   factory_.SubmitFrame(
       surface_id_, frame_copy.Pass(),
       base::Bind(&SurfaceDisplayOutputSurface::SwapBuffersComplete,
                  base::Unretained(this)));
 
-  client_->DidSwapBuffers();
+  inside_swap_buffers_ = 0;
 }
 
 bool SurfaceDisplayOutputSurface::BindToClient(OutputSurfaceClient* client) {
@@ -92,6 +105,7 @@
 }
 
 void SurfaceDisplayOutputSurface::SwapBuffersComplete(SurfaceDrawStatus drawn) {
+  DCHECK_EQ(0, inside_swap_buffers_) << base::debug::StackTrace().ToString();
   if (client_ && !display_client_->output_surface_lost())
     client_->DidSwapBuffersComplete();
 }
diff --git a/cc/surfaces/surface_display_output_surface.h b/cc/surfaces/surface_display_output_surface.h
index c11bb86..f332967 100644
--- a/cc/surfaces/surface_display_output_surface.h
+++ b/cc/surfaces/surface_display_output_surface.h
@@ -54,6 +54,9 @@
   SurfaceId surface_id_;
   SurfaceIdAllocator* allocator_;
 
+  // TODO(brianderson): Remove this after solving crbug.com/495650
+  int inside_swap_buffers_;
+
   DISALLOW_COPY_AND_ASSIGN(SurfaceDisplayOutputSurface);
 };
 
diff --git a/cc/test/fake_content_layer.cc b/cc/test/fake_content_layer.cc
deleted file mode 100644
index 52a2662..0000000
--- a/cc/test/fake_content_layer.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/test/fake_content_layer.h"
-
-#include "cc/resources/content_layer_updater.h"
-#include "cc/resources/prioritized_resource.h"
-#include "cc/test/fake_content_layer_impl.h"
-
-namespace cc {
-
-class FakeContentLayerUpdater : public ContentLayerUpdater {
- public:
-  using ContentLayerUpdater::paint_rect;
-
- private:
-  ~FakeContentLayerUpdater() override {}
-};
-
-FakeContentLayer::FakeContentLayer(const LayerSettings& settings,
-                                   ContentLayerClient* client)
-    : ContentLayer(settings, client),
-      update_count_(0),
-      push_properties_count_(0),
-      output_surface_created_count_(0),
-      always_update_resources_(false) {
-  SetBounds(gfx::Size(1, 1));
-  SetIsDrawable(true);
-}
-
-FakeContentLayer::~FakeContentLayer() {}
-
-scoped_ptr<LayerImpl> FakeContentLayer::CreateLayerImpl(
-    LayerTreeImpl* tree_impl) {
-  return FakeContentLayerImpl::Create(tree_impl, layer_id_);
-}
-
-bool FakeContentLayer::Update(ResourceUpdateQueue* queue,
-                              const OcclusionTracker<Layer>* occlusion) {
-  bool updated = ContentLayer::Update(queue, occlusion);
-  update_count_++;
-  return updated || always_update_resources_;
-}
-
-gfx::Rect FakeContentLayer::LastPaintRect() const {
-  return (static_cast<FakeContentLayerUpdater*>(Updater()))->paint_rect();
-}
-
-void FakeContentLayer::PushPropertiesTo(LayerImpl* layer) {
-  ContentLayer::PushPropertiesTo(layer);
-  push_properties_count_++;
-}
-
-void FakeContentLayer::OnOutputSurfaceCreated() {
-  ContentLayer::OnOutputSurfaceCreated();
-  output_surface_created_count_++;
-}
-
-bool FakeContentLayer::HaveBackingAt(int i, int j) {
-  const PrioritizedResource* resource = ResourceAtForTesting(i, j);
-  return resource && resource->have_backing_texture();
-}
-
-}  // namespace cc
diff --git a/cc/test/fake_content_layer.h b/cc/test/fake_content_layer.h
deleted file mode 100644
index 1fe156f8..0000000
--- a/cc/test/fake_content_layer.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_TEST_FAKE_CONTENT_LAYER_H_
-#define CC_TEST_FAKE_CONTENT_LAYER_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "cc/layers/content_layer.h"
-
-namespace cc {
-
-class FakeContentLayer : public ContentLayer {
- public:
-  static scoped_refptr<FakeContentLayer> Create(const LayerSettings& settings,
-                                                ContentLayerClient* client) {
-    return make_scoped_refptr(new FakeContentLayer(settings, client));
-  }
-
-  scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
-
-  size_t update_count() const { return update_count_; }
-  void reset_update_count() { update_count_ = 0; }
-
-  size_t push_properties_count() const { return push_properties_count_; }
-  void reset_push_properties_count() { push_properties_count_ = 0; }
-
-  bool Update(ResourceUpdateQueue* queue,
-              const OcclusionTracker<Layer>* occlusion) override;
-
-  gfx::Rect LastPaintRect() const;
-
-  void set_always_update_resources(bool always_update_resources) {
-    always_update_resources_ = always_update_resources;
-  }
-
-  void PushPropertiesTo(LayerImpl* layer) override;
-
-  void OnOutputSurfaceCreated() override;
-  size_t output_surface_created_count() const {
-    return output_surface_created_count_;
-  }
-
-  bool HaveBackingAt(int i, int j);
-
- private:
-  explicit FakeContentLayer(const LayerSettings& settings,
-                            ContentLayerClient* client);
-  ~FakeContentLayer() override;
-
-  size_t update_count_;
-  size_t push_properties_count_;
-  size_t output_surface_created_count_;
-  bool always_update_resources_;
-};
-
-}  // namespace cc
-
-#endif  // CC_TEST_FAKE_CONTENT_LAYER_H_
diff --git a/cc/test/fake_content_layer_impl.cc b/cc/test/fake_content_layer_impl.cc
deleted file mode 100644
index 54c62d0..0000000
--- a/cc/test/fake_content_layer_impl.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/test/fake_content_layer_impl.h"
-
-namespace cc {
-
-FakeContentLayerImpl::FakeContentLayerImpl(
-    LayerTreeImpl* tree_impl,
-    int id,
-    scoped_refptr<LayerImpl::SyncedScrollOffset> synced_scroll_offset)
-    : TiledLayerImpl(tree_impl, id, synced_scroll_offset),
-      lost_output_surface_count_(0) {
-}
-
-FakeContentLayerImpl::~FakeContentLayerImpl() {}
-
-scoped_ptr<LayerImpl> FakeContentLayerImpl::CreateLayerImpl(
-    LayerTreeImpl* tree_impl) {
-  return FakeContentLayerImpl::Create(tree_impl, id(), synced_scroll_offset());
-}
-
-bool FakeContentLayerImpl::HaveResourceForTileAt(int i, int j) {
-  return HasResourceIdForTileAt(i, j);
-}
-
-void FakeContentLayerImpl::ReleaseResources() {
-  TiledLayerImpl::ReleaseResources();
-  ++lost_output_surface_count_;
-}
-
-}  // namespace cc
diff --git a/cc/test/fake_content_layer_impl.h b/cc/test/fake_content_layer_impl.h
deleted file mode 100644
index d199fad..0000000
--- a/cc/test/fake_content_layer_impl.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_TEST_FAKE_CONTENT_LAYER_IMPL_H_
-#define CC_TEST_FAKE_CONTENT_LAYER_IMPL_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "cc/layers/tiled_layer_impl.h"
-
-namespace cc {
-
-class FakeContentLayerImpl : public TiledLayerImpl {
- public:
-  static scoped_ptr<FakeContentLayerImpl> Create(
-      LayerTreeImpl* tree_impl, int id) {
-    return make_scoped_ptr(new FakeContentLayerImpl(
-        tree_impl, id, new LayerImpl::SyncedScrollOffset));
-  }
-  static scoped_ptr<FakeContentLayerImpl> Create(
-      LayerTreeImpl* tree_impl,
-      int id,
-      scoped_refptr<LayerImpl::SyncedScrollOffset> synced_scroll_offset) {
-    return make_scoped_ptr(
-        new FakeContentLayerImpl(tree_impl, id, synced_scroll_offset));
-  }
-  ~FakeContentLayerImpl() override;
-
-  scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
-
-  bool HaveResourceForTileAt(int i, int j);
-
-  size_t lost_output_surface_count() const {
-    return lost_output_surface_count_;
-  }
-  void reset_lost_output_surface_count() { lost_output_surface_count_ = 0; }
-
-  void ReleaseResources() override;
-
- private:
-  explicit FakeContentLayerImpl(
-      LayerTreeImpl* tree_impl,
-      int id,
-      scoped_refptr<LayerImpl::SyncedScrollOffset> synced_scroll_offset);
-
-  size_t lost_output_surface_count_;
-};
-
-}  // namespace cc
-
-#endif  // CC_TEST_FAKE_CONTENT_LAYER_IMPL_H_
diff --git a/cc/test/fake_picture_layer.h b/cc/test/fake_picture_layer.h
index 19e365d..3801ec00 100644
--- a/cc/test/fake_picture_layer.h
+++ b/cc/test/fake_picture_layer.h
@@ -28,7 +28,7 @@
 
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
 
-  size_t update_count() const { return update_count_; }
+  int update_count() const { return update_count_; }
   void reset_update_count() { update_count_ = 0; }
 
   size_t push_properties_count() const { return push_properties_count_; }
@@ -57,7 +57,7 @@
                    scoped_ptr<RecordingSource> source);
   ~FakePictureLayer() override;
 
-  size_t update_count_;
+  int update_count_;
   size_t push_properties_count_;
   size_t output_surface_created_count_;
   bool always_update_resources_;
diff --git a/cc/test/fake_video_frame_provider.cc b/cc/test/fake_video_frame_provider.cc
index b979b0c..01455446 100644
--- a/cc/test/fake_video_frame_provider.cc
+++ b/cc/test/fake_video_frame_provider.cc
@@ -7,7 +7,8 @@
 namespace cc {
 
 FakeVideoFrameProvider::FakeVideoFrameProvider()
-    : frame_(NULL), client_(NULL) {}
+    : frame_(NULL), client_(NULL), put_current_frame_count_(0) {
+}
 
 FakeVideoFrameProvider::~FakeVideoFrameProvider() {
   if (client_)
@@ -16,7 +17,7 @@
 
 bool FakeVideoFrameProvider::UpdateCurrentFrame(base::TimeTicks deadline_min,
                                                 base::TimeTicks deadline_max) {
-  return false;
+  return HasCurrentFrame();
 }
 
 void FakeVideoFrameProvider::SetVideoFrameProviderClient(Client* client) {
@@ -31,4 +32,8 @@
   return frame_;
 }
 
+void FakeVideoFrameProvider::PutCurrentFrame() {
+  ++put_current_frame_count_;
+}
+
 }  // namespace cc
diff --git a/cc/test/fake_video_frame_provider.h b/cc/test/fake_video_frame_provider.h
index da68d5ba..4cbd80a2 100644
--- a/cc/test/fake_video_frame_provider.h
+++ b/cc/test/fake_video_frame_provider.h
@@ -21,7 +21,7 @@
                           base::TimeTicks deadline_max) override;
   bool HasCurrentFrame() override;
   scoped_refptr<media::VideoFrame> GetCurrentFrame() override;
-  void PutCurrentFrame() override {}
+  void PutCurrentFrame() override;
 
   Client* client() { return client_; }
 
@@ -29,9 +29,12 @@
     frame_ = frame;
   }
 
+  int put_current_frame_count() const { return put_current_frame_count_; }
+
  private:
   scoped_refptr<media::VideoFrame> frame_;
   Client* client_;
+  int put_current_frame_count_;
 };
 
 }  // namespace cc
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index 4d122e951..93ee1ac 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -139,7 +139,7 @@
       host_impl->output_surface()->context_provider();
   ResourceProvider* resource_provider = host_impl->resource_provider();
   size_t max_transfer_buffer_usage_bytes = 1024u * 1024u * 60u;
-  size_t max_bytes_per_copy_operation = 1024u * 1024u;
+  int max_bytes_per_copy_operation = 1024 * 1024;
 
   switch (resource_pool_option_) {
     case BITMAP_TILE_TASK_WORKER_POOL:
diff --git a/cc/test/ordered_simple_task_runner.cc b/cc/test/ordered_simple_task_runner.cc
index 4bf9783..4853c47 100644
--- a/cc/test/ordered_simple_task_runner.cc
+++ b/cc/test/ordered_simple_task_runner.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/auto_reset.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
@@ -70,7 +71,7 @@
 
 void TestOrderablePendingTask::AsValueInto(
     base::trace_event::TracedValue* state) const {
-  state->SetInteger("id", task_id_);
+  state->SetInteger("id", base::saturated_cast<int>(task_id_));
   state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
   state->SetString("posted_from", location.ToString());
 }
@@ -271,7 +272,8 @@
 
 void OrderedSimpleTaskRunner::AsValueInto(
     base::trace_event::TracedValue* state) const {
-  state->SetInteger("pending_tasks", pending_tasks_.size());
+  state->SetInteger("pending_tasks",
+                    base::saturated_cast<int>(pending_tasks_.size()));
 
   state->BeginArray("tasks");
   for (std::set<TestOrderablePendingTask>::const_iterator it =
diff --git a/cc/test/render_pass_test_common.cc b/cc/test/render_pass_test_common.cc
index 3789efc..b2242f7e 100644
--- a/cc/test/render_pass_test_common.cc
+++ b/cc/test/render_pass_test_common.cc
@@ -144,12 +144,8 @@
 
   StreamVideoDrawQuad* stream_video_quad =
       this->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
-  stream_video_quad->SetNew(shared_state,
-                            rect,
-                            opaque_rect,
-                            visible_rect,
-                            resource6,
-                            gfx::Transform());
+  stream_video_quad->SetNew(shared_state, rect, opaque_rect, visible_rect,
+                            resource6, gfx::Size(), false, gfx::Transform());
 
   TextureDrawQuad* texture_quad =
       this->CreateAndAppendDrawQuad<TextureDrawQuad>();
diff --git a/cc/test/test_context_provider.cc b/cc/test/test_context_provider.cc
index 2bf803c..ca7714d3 100644
--- a/cc/test/test_context_provider.cc
+++ b/cc/test/test_context_provider.cc
@@ -55,7 +55,7 @@
   if (bound_)
     return true;
 
-  if (context3d_->isContextLost()) {
+  if (context_gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR) {
     base::AutoLock lock(destroyed_lock_);
     destroyed_ = true;
     return false;
@@ -106,7 +106,7 @@
       kOpenGL_GrBackend, reinterpret_cast<GrBackendContext>(gl_context->gl())));
 
   // If GlContext is already lost, also abandon the new GrContext.
-  if (IsContextLost())
+  if (ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR)
     gr_context_->abandonContext();
 
   return gr_context_.get();
@@ -127,18 +127,11 @@
   return &context_lock_;
 }
 
-bool TestContextProvider::IsContextLost() {
-  DCHECK(bound_);
-  DCHECK(context_thread_checker_.CalledOnValidThread());
-
-  return context3d_->isContextLost();
-}
-
 void TestContextProvider::VerifyContexts() {
   DCHECK(bound_);
   DCHECK(context_thread_checker_.CalledOnValidThread());
 
-  if (context3d_->isContextLost()) {
+  if (ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR) {
     base::AutoLock lock(destroyed_lock_);
     destroyed_ = true;
   }
diff --git a/cc/test/test_context_provider.h b/cc/test/test_context_provider.h
index 54b2ed5..82b3e61 100644
--- a/cc/test/test_context_provider.h
+++ b/cc/test/test_context_provider.h
@@ -37,7 +37,6 @@
   void InvalidateGrContext(uint32_t state) override;
   void SetupLock() override;
   base::Lock* GetLock() override;
-  bool IsContextLost() override;
   void VerifyContexts() override;
   void DeleteCachedResources() override;
   bool DestroyedOnMainThread() override;
diff --git a/cc/test/test_gles2_interface.cc b/cc/test/test_gles2_interface.cc
index 6ce087f..38b1d201 100644
--- a/cc/test/test_gles2_interface.cc
+++ b/cc/test/test_gles2_interface.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "cc/test/test_web_graphics_context_3d.h"
+#include "gpu/GLES2/gl2extchromium.h"
 
 namespace cc {
 
@@ -423,4 +424,10 @@
   test_context_->loseContextCHROMIUM(current, other);
 }
 
+GLenum TestGLES2Interface::GetGraphicsResetStatusKHR() {
+  if (test_context_->isContextLost())
+    return GL_UNKNOWN_CONTEXT_RESET_KHR;
+  return GL_NO_ERROR;
+}
+
 }  // namespace cc
diff --git a/cc/test/test_gles2_interface.h b/cc/test/test_gles2_interface.h
index 0d9c10a..6f501bf 100644
--- a/cc/test/test_gles2_interface.h
+++ b/cc/test/test_gles2_interface.h
@@ -177,6 +177,7 @@
 
   void ResizeCHROMIUM(GLuint width, GLuint height, float device_scale) override;
   void LoseContextCHROMIUM(GLenum current, GLenum other) override;
+  GLenum GetGraphicsResetStatusKHR() override;
 
  private:
   TestWebGraphicsContext3D* test_context_;
diff --git a/cc/test/test_gpu_memory_buffer_manager.cc b/cc/test/test_gpu_memory_buffer_manager.cc
index cda1d611..154ead3 100644
--- a/cc/test/test_gpu_memory_buffer_manager.cc
+++ b/cc/test/test_gpu_memory_buffer_manager.cc
@@ -5,12 +5,13 @@
 #include "cc/test/test_gpu_memory_buffer_manager.h"
 
 #include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
 namespace cc {
 namespace {
 
-size_t NumberOfPlanesForGpuMemoryBufferFormat(
+int NumberOfPlanesForGpuMemoryBufferFormat(
     gfx::GpuMemoryBuffer::Format format) {
   switch (format) {
     case gfx::GpuMemoryBuffer::ATC:
@@ -88,8 +89,8 @@
 size_t BufferSizeInBytes(const gfx::Size& size,
                          gfx::GpuMemoryBuffer::Format format) {
   size_t size_in_bytes = 0;
-  size_t num_planes = NumberOfPlanesForGpuMemoryBufferFormat(format);
-  for (size_t i = 0; i < num_planes; ++i) {
+  int num_planes = NumberOfPlanesForGpuMemoryBufferFormat(format);
+  for (int i = 0; i < num_planes; ++i) {
     size_in_bytes += StrideInBytes(size.width(), format, i) *
                      (size.height() / SubsamplingFactor(format, i));
   }
@@ -113,8 +114,8 @@
       return false;
     mapped_ = true;
     size_t offset = 0;
-    size_t num_planes = NumberOfPlanesForGpuMemoryBufferFormat(format_);
-    for (size_t i = 0; i < num_planes; ++i) {
+    int num_planes = NumberOfPlanesForGpuMemoryBufferFormat(format_);
+    for (int i = 0; i < num_planes; ++i) {
       data[i] = reinterpret_cast<uint8*>(shared_memory_->memory()) + offset;
       offset += StrideInBytes(size_.width(), format_, i) *
                 (size_.height() / SubsamplingFactor(format_, i));
@@ -129,9 +130,10 @@
   bool IsMapped() const override { return mapped_; }
   Format GetFormat() const override { return format_; }
   void GetStride(int* stride) const override {
-    size_t num_planes = NumberOfPlanesForGpuMemoryBufferFormat(format_);
-    for (size_t i = 0; i < num_planes; ++i)
-      stride[i] = StrideInBytes(size_.width(), format_, i);
+    int num_planes = NumberOfPlanesForGpuMemoryBufferFormat(format_);
+    for (int i = 0; i < num_planes; ++i)
+      stride[i] =
+          base::checked_cast<int>(StrideInBytes(size_.width(), format_, i));
   }
   gfx::GpuMemoryBufferHandle GetHandle() const override {
     gfx::GpuMemoryBufferHandle handle;
diff --git a/cc/test/test_in_process_context_provider.cc b/cc/test/test_in_process_context_provider.cc
index 42c8a833..efbbeec 100644
--- a/cc/test/test_in_process_context_provider.cc
+++ b/cc/test/test_in_process_context_provider.cc
@@ -155,8 +155,6 @@
   return capabilities;
 }
 
-bool TestInProcessContextProvider::IsContextLost() { return false; }
-
 void TestInProcessContextProvider::VerifyContexts() {}
 
 void TestInProcessContextProvider::DeleteCachedResources() {
diff --git a/cc/test/test_in_process_context_provider.h b/cc/test/test_in_process_context_provider.h
index bb56e57..efea7120 100644
--- a/cc/test/test_in_process_context_provider.h
+++ b/cc/test/test_in_process_context_provider.h
@@ -36,7 +36,6 @@
   void SetupLock() override;
   base::Lock* GetLock() override;
   Capabilities ContextCapabilities() override;
-  bool IsContextLost() override;
   void VerifyContexts() override;
   void DeleteCachedResources() override;
   bool DestroyedOnMainThread() override;
diff --git a/cc/test/test_web_graphics_context_3d.cc b/cc/test/test_web_graphics_context_3d.cc
index f675d7e..1e69bcb 100644
--- a/cc/test/test_web_graphics_context_3d.cc
+++ b/cc/test/test_web_graphics_context_3d.cc
@@ -11,6 +11,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
+#include "base/numerics/safe_conversions.h"
 #include "cc/test/test_context_support.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -553,7 +554,9 @@
   if (data != NULL)
     memcpy(buffer->pixels.get(), data, size);
   if (buffer->target == GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM)
-    current_used_transfer_buffer_usage_bytes_ += buffer->size - old_size;
+    current_used_transfer_buffer_usage_bytes_ +=
+        base::checked_cast<int>(buffer->size) -
+        base::checked_cast<int>(old_size);
   max_used_transfer_buffer_usage_bytes_ =
       std::max(max_used_transfer_buffer_usage_bytes_,
                current_used_transfer_buffer_usage_bytes_);
diff --git a/cc/test/tiled_layer_test_common.cc b/cc/test/tiled_layer_test_common.cc
index ea45f48a..a396ff94 100644
--- a/cc/test/tiled_layer_test_common.cc
+++ b/cc/test/tiled_layer_test_common.cc
@@ -127,7 +127,7 @@
 }
 
 void FakeTiledLayer::ResetNumDependentsNeedPushProperties() {
-  size_t num = 0;
+  int num = 0;
   if (mask_layer()) {
     if (mask_layer()->needs_push_properties() ||
         mask_layer()->descendant_needs_push_properties())
diff --git a/cc/tiles/picture_layer_tiling.cc b/cc/tiles/picture_layer_tiling.cc
index 3c22a4f..a500e80 100644
--- a/cc/tiles/picture_layer_tiling.cc
+++ b/cc/tiles/picture_layer_tiling.cc
@@ -12,6 +12,7 @@
 #include "base/containers/hash_tables.h"
 #include "base/containers/small_map.h"
 #include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "cc/base/math_util.h"
@@ -940,7 +941,7 @@
 
 void PictureLayerTiling::AsValueInto(
     base::trace_event::TracedValue* state) const {
-  state->SetInteger("num_tiles", tiles_.size());
+  state->SetInteger("num_tiles", base::saturated_cast<int>(tiles_.size()));
   state->SetDouble("content_scale", contents_scale_);
   MathUtil::AddToTracedValue("visible_rect", current_visible_rect_, state);
   MathUtil::AddToTracedValue("skewport_rect", current_skewport_rect_, state);
diff --git a/cc/tiles/picture_layer_tiling_set.cc b/cc/tiles/picture_layer_tiling_set.cc
index 416eefc5..c61b58c 100644
--- a/cc/tiles/picture_layer_tiling_set.cc
+++ b/cc/tiles/picture_layer_tiling_set.cc
@@ -385,12 +385,11 @@
     : set_(set),
       contents_scale_(contents_scale),
       ideal_contents_scale_(ideal_contents_scale),
-      current_tiling_(-1) {
+      current_tiling_(std::numeric_limits<size_t>::max()) {
   missing_region_.Union(content_rect);
 
-  for (ideal_tiling_ = 0;
-       static_cast<size_t>(ideal_tiling_) < set_->tilings_.size();
-       ++ideal_tiling_) {
+  size_t tilings_size = set_->tilings_.size();
+  for (ideal_tiling_ = 0; ideal_tiling_ < tilings_size; ++ideal_tiling_) {
     PictureLayerTiling* tiling = set_->tilings_[ideal_tiling_];
     if (tiling->contents_scale() < ideal_contents_scale_) {
       if (ideal_tiling_ > 0)
@@ -399,11 +398,7 @@
     }
   }
 
-  DCHECK_LE(set_->tilings_.size(),
-            static_cast<size_t>(std::numeric_limits<int>::max()));
-
-  int num_tilings = set_->tilings_.size();
-  if (ideal_tiling_ == num_tilings && ideal_tiling_ > 0)
+  if (ideal_tiling_ == tilings_size && ideal_tiling_ > 0)
     ideal_tiling_--;
 
   ++(*this);
@@ -447,20 +442,20 @@
 
 PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling()
     const {
-  if (current_tiling_ < 0)
+  if (current_tiling_ == std::numeric_limits<size_t>::max())
     return NULL;
-  if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size())
+  if (current_tiling_ >= set_->tilings_.size())
     return NULL;
   return set_->tilings_[current_tiling_];
 }
 
-int PictureLayerTilingSet::CoverageIterator::NextTiling() const {
+size_t PictureLayerTilingSet::CoverageIterator::NextTiling() const {
   // Order returned by this method is:
   // 1. Ideal tiling index
   // 2. Tiling index < Ideal in decreasing order (higher res than ideal)
   // 3. Tiling index > Ideal in increasing order (lower res than ideal)
   // 4. Tiling index > tilings.size() (invalid index)
-  if (current_tiling_ < 0)
+  if (current_tiling_ == std::numeric_limits<size_t>::max())
     return ideal_tiling_;
   else if (current_tiling_ > ideal_tiling_)
     return current_tiling_ + 1;
@@ -472,7 +467,7 @@
 
 PictureLayerTilingSet::CoverageIterator&
 PictureLayerTilingSet::CoverageIterator::operator++() {
-  bool first_time = current_tiling_ < 0;
+  bool first_time = current_tiling_ == std::numeric_limits<size_t>::max();
 
   if (!*this && !first_time)
     return *this;
@@ -506,7 +501,7 @@
       }
 
       // No more valid tiles, return this checkerboard rect.
-      if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
+      if (current_tiling_ >= set_->tilings_.size())
         return *this;
     }
 
@@ -516,7 +511,7 @@
     region_iter_.next();
 
     // Done, found next checkerboard rect to return.
-    if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
+    if (current_tiling_ >= set_->tilings_.size())
       return *this;
 
     // Construct a new iterator for the next tiling, but we need to loop
@@ -531,8 +526,7 @@
 }
 
 PictureLayerTilingSet::CoverageIterator::operator bool() const {
-  return current_tiling_ < static_cast<int>(set_->tilings_.size()) ||
-      region_iter_.has_rect();
+  return current_tiling_ < set_->tilings_.size() || region_iter_.has_rect();
 }
 
 void PictureLayerTilingSet::AsValueInto(
@@ -556,9 +550,10 @@
   // Doesn't seem to be the case right now but if it ever becomes a performance
   // problem to compute these ranges each time this function is called, we can
   // compute them only when the tiling set has changed instead.
+  size_t tilings_size = tilings_.size();
   TilingRange high_res_range(0, 0);
   TilingRange low_res_range(tilings_.size(), tilings_.size());
-  for (size_t i = 0; i < tilings_.size(); ++i) {
+  for (size_t i = 0; i < tilings_size; ++i) {
     const PictureLayerTiling* tiling = tilings_[i];
     if (tiling->resolution() == HIGH_RESOLUTION)
       high_res_range = TilingRange(i, i + 1);
@@ -590,7 +585,7 @@
       range = low_res_range;
       break;
     case LOWER_THAN_LOW_RES:
-      range = TilingRange(low_res_range.end, tilings_.size());
+      range = TilingRange(low_res_range.end, tilings_size);
       break;
   }
 
diff --git a/cc/tiles/picture_layer_tiling_set.h b/cc/tiles/picture_layer_tiling_set.h
index 7e54411..46af6c4b 100644
--- a/cc/tiles/picture_layer_tiling_set.h
+++ b/cc/tiles/picture_layer_tiling_set.h
@@ -31,10 +31,10 @@
     LOWER_THAN_LOW_RES
   };
   struct TilingRange {
-    TilingRange(int start, int end) : start(start), end(end) {}
+    TilingRange(size_t start, size_t end) : start(start), end(end) {}
 
-    int start;
-    int end;
+    size_t start;
+    size_t end;
   };
 
   static scoped_ptr<PictureLayerTilingSet> Create(
@@ -152,14 +152,14 @@
     PictureLayerTiling* CurrentTiling() const;
 
    private:
-    int NextTiling() const;
+    size_t NextTiling() const;
 
     const PictureLayerTilingSet* set_;
     float contents_scale_;
     float ideal_contents_scale_;
     PictureLayerTiling::CoverageIterator tiling_iter_;
-    int current_tiling_;
-    int ideal_tiling_;
+    size_t current_tiling_;
+    size_t ideal_tiling_;
 
     Region current_region_;
     Region missing_region_;
diff --git a/cc/tiles/picture_layer_tiling_set_unittest.cc b/cc/tiles/picture_layer_tiling_set_unittest.cc
index dd37570..16f8a9e 100644
--- a/cc/tiles/picture_layer_tiling_set_unittest.cc
+++ b/cc/tiles/picture_layer_tiling_set_unittest.cc
@@ -87,26 +87,26 @@
 
   higher_than_high_res_range =
       set->GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
-  EXPECT_EQ(0, higher_than_high_res_range.start);
-  EXPECT_EQ(1, higher_than_high_res_range.end);
+  EXPECT_EQ(0u, higher_than_high_res_range.start);
+  EXPECT_EQ(1u, higher_than_high_res_range.end);
 
   high_res_range = set->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
-  EXPECT_EQ(1, high_res_range.start);
-  EXPECT_EQ(2, high_res_range.end);
+  EXPECT_EQ(1u, high_res_range.start);
+  EXPECT_EQ(2u, high_res_range.end);
 
   between_high_and_low_res_range =
       set->GetTilingRange(PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
-  EXPECT_EQ(2, between_high_and_low_res_range.start);
-  EXPECT_EQ(3, between_high_and_low_res_range.end);
+  EXPECT_EQ(2u, between_high_and_low_res_range.start);
+  EXPECT_EQ(3u, between_high_and_low_res_range.end);
 
   low_res_range = set->GetTilingRange(PictureLayerTilingSet::LOW_RES);
-  EXPECT_EQ(3, low_res_range.start);
-  EXPECT_EQ(4, low_res_range.end);
+  EXPECT_EQ(3u, low_res_range.start);
+  EXPECT_EQ(4u, low_res_range.end);
 
   lower_than_low_res_range =
       set->GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES);
-  EXPECT_EQ(4, lower_than_low_res_range.start);
-  EXPECT_EQ(5, lower_than_low_res_range.end);
+  EXPECT_EQ(4u, lower_than_low_res_range.start);
+  EXPECT_EQ(5u, lower_than_low_res_range.end);
 
   scoped_ptr<PictureLayerTilingSet> set_without_low_res =
       CreateTilingSet(&client);
@@ -118,26 +118,26 @@
 
   higher_than_high_res_range = set_without_low_res->GetTilingRange(
       PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
-  EXPECT_EQ(0, higher_than_high_res_range.start);
-  EXPECT_EQ(1, higher_than_high_res_range.end);
+  EXPECT_EQ(0u, higher_than_high_res_range.start);
+  EXPECT_EQ(1u, higher_than_high_res_range.end);
 
   high_res_range =
       set_without_low_res->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
-  EXPECT_EQ(1, high_res_range.start);
-  EXPECT_EQ(2, high_res_range.end);
+  EXPECT_EQ(1u, high_res_range.start);
+  EXPECT_EQ(2u, high_res_range.end);
 
   between_high_and_low_res_range = set_without_low_res->GetTilingRange(
       PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
-  EXPECT_EQ(2, between_high_and_low_res_range.start);
-  EXPECT_EQ(4, between_high_and_low_res_range.end);
+  EXPECT_EQ(2u, between_high_and_low_res_range.start);
+  EXPECT_EQ(4u, between_high_and_low_res_range.end);
 
   low_res_range =
       set_without_low_res->GetTilingRange(PictureLayerTilingSet::LOW_RES);
-  EXPECT_EQ(0, low_res_range.end - low_res_range.start);
+  EXPECT_EQ(0u, low_res_range.end - low_res_range.start);
 
   lower_than_low_res_range = set_without_low_res->GetTilingRange(
       PictureLayerTilingSet::LOWER_THAN_LOW_RES);
-  EXPECT_EQ(0, lower_than_low_res_range.end - lower_than_low_res_range.start);
+  EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
 
   scoped_ptr<PictureLayerTilingSet> set_with_only_high_and_low_res =
       CreateTilingSet(&client);
@@ -148,28 +148,28 @@
 
   higher_than_high_res_range = set_with_only_high_and_low_res->GetTilingRange(
       PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
-  EXPECT_EQ(0,
+  EXPECT_EQ(0u,
             higher_than_high_res_range.end - higher_than_high_res_range.start);
 
   high_res_range = set_with_only_high_and_low_res->GetTilingRange(
       PictureLayerTilingSet::HIGH_RES);
-  EXPECT_EQ(0, high_res_range.start);
-  EXPECT_EQ(1, high_res_range.end);
+  EXPECT_EQ(0u, high_res_range.start);
+  EXPECT_EQ(1u, high_res_range.end);
 
   between_high_and_low_res_range =
       set_with_only_high_and_low_res->GetTilingRange(
           PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
-  EXPECT_EQ(0, between_high_and_low_res_range.end -
-                   between_high_and_low_res_range.start);
+  EXPECT_EQ(0u, between_high_and_low_res_range.end -
+                    between_high_and_low_res_range.start);
 
   low_res_range = set_with_only_high_and_low_res->GetTilingRange(
       PictureLayerTilingSet::LOW_RES);
-  EXPECT_EQ(1, low_res_range.start);
-  EXPECT_EQ(2, low_res_range.end);
+  EXPECT_EQ(1u, low_res_range.start);
+  EXPECT_EQ(2u, low_res_range.end);
 
   lower_than_low_res_range = set_with_only_high_and_low_res->GetTilingRange(
       PictureLayerTilingSet::LOWER_THAN_LOW_RES);
-  EXPECT_EQ(0, lower_than_low_res_range.end - lower_than_low_res_range.start);
+  EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
 
   scoped_ptr<PictureLayerTilingSet> set_with_only_high_res =
       CreateTilingSet(&client);
@@ -178,26 +178,26 @@
 
   higher_than_high_res_range = set_with_only_high_res->GetTilingRange(
       PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
-  EXPECT_EQ(0,
+  EXPECT_EQ(0u,
             higher_than_high_res_range.end - higher_than_high_res_range.start);
 
   high_res_range =
       set_with_only_high_res->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
-  EXPECT_EQ(0, high_res_range.start);
-  EXPECT_EQ(1, high_res_range.end);
+  EXPECT_EQ(0u, high_res_range.start);
+  EXPECT_EQ(1u, high_res_range.end);
 
   between_high_and_low_res_range = set_with_only_high_res->GetTilingRange(
       PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
-  EXPECT_EQ(0, between_high_and_low_res_range.end -
-                   between_high_and_low_res_range.start);
+  EXPECT_EQ(0u, between_high_and_low_res_range.end -
+                    between_high_and_low_res_range.start);
 
   low_res_range =
       set_with_only_high_res->GetTilingRange(PictureLayerTilingSet::LOW_RES);
-  EXPECT_EQ(0, low_res_range.end - low_res_range.start);
+  EXPECT_EQ(0u, low_res_range.end - low_res_range.start);
 
   lower_than_low_res_range = set_with_only_high_res->GetTilingRange(
       PictureLayerTilingSet::LOWER_THAN_LOW_RES);
-  EXPECT_EQ(0, lower_than_low_res_range.end - lower_than_low_res_range.start);
+  EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
 }
 
 class PictureLayerTilingSetTestWithResources : public testing::Test {
diff --git a/cc/tiles/tile.cc b/cc/tiles/tile.cc
index a596194..6052e5e0 100644
--- a/cc/tiles/tile.cc
+++ b/cc/tiles/tile.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "cc/base/math_util.h"
 #include "cc/debug/traced_value.h"
@@ -62,7 +63,8 @@
                     draw_info().has_resource() || HasRasterTask());
   value->SetInteger("scheduled_priority", scheduled_priority_);
   value->SetBoolean("use_picture_analysis", use_picture_analysis());
-  value->SetInteger("gpu_memory_usage", GPUMemoryUsageInBytes());
+  value->SetInteger("gpu_memory_usage",
+                    base::saturated_cast<int>(GPUMemoryUsageInBytes()));
 }
 
 size_t Tile::GPUMemoryUsageInBytes() const {
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index e110fc2..77622c2 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -12,6 +12,7 @@
 #include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "cc/base/histograms.h"
 #include "cc/debug/devtools_instrumentation.h"
@@ -208,8 +209,10 @@
 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
   scoped_refptr<base::trace_event::TracedValue> state =
       new base::trace_event::TracedValue();
-  state->SetInteger("completed_count", stats.completed_count);
-  state->SetInteger("canceled_count", stats.canceled_count);
+  state->SetInteger("completed_count",
+                    base::saturated_cast<int>(stats.completed_count));
+  state->SetInteger("canceled_count",
+                    base::saturated_cast<int>(stats.canceled_count));
   return state;
 }
 
@@ -413,7 +416,7 @@
 
 void TileManager::BasicStateAsValueInto(
     base::trace_event::TracedValue* state) const {
-  state->SetInteger("tile_count", tiles_.size());
+  state->SetInteger("tile_count", base::saturated_cast<int>(tiles_.size()));
   state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
   state->BeginDictionary("global_state");
   global_state_.AsValueInto(state);
@@ -586,6 +589,7 @@
   memory_stats_from_last_assign_.total_budget_in_bytes =
       global_state_.hard_memory_limit_in_bytes;
   memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
+  DCHECK_GE(memory_stats_from_last_assign_.total_bytes_used, 0);
   memory_stats_from_last_assign_.had_enough_memory =
       had_enough_memory_to_schedule_tiles_needed_now;
 
@@ -966,8 +970,18 @@
 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
 }
 
-TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes, int resource_count)
-    : memory_bytes_(memory_bytes), resource_count_(resource_count) {
+TileManager::MemoryUsage::MemoryUsage(size_t memory_bytes,
+                                      size_t resource_count)
+    : memory_bytes_(static_cast<int64>(memory_bytes)),
+      resource_count_(static_cast<int>(resource_count)) {
+  // MemoryUsage is constructed using size_ts, since it deals with memory and
+  // the inputs are typically size_t. However, during the course of usage (in
+  // particular operator-=) can cause internal values to become negative. Thus,
+  // member variables are signed.
+  DCHECK_LE(memory_bytes,
+            static_cast<size_t>(std::numeric_limits<int64>::max()));
+  DCHECK_LE(resource_count,
+            static_cast<size_t>(std::numeric_limits<int>::max()));
 }
 
 // static
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index 8611b3a..bc20f29 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -213,7 +213,7 @@
   class MemoryUsage {
    public:
     MemoryUsage();
-    MemoryUsage(int64 memory_bytes, int resource_count);
+    MemoryUsage(size_t memory_bytes, size_t resource_count);
 
     static MemoryUsage FromConfig(const gfx::Size& size, ResourceFormat format);
     static MemoryUsage FromTile(const Tile* tile);
diff --git a/cc/tiles/tile_priority.cc b/cc/tiles/tile_priority.cc
index cf9872e..0efe51e 100644
--- a/cc/tiles/tile_priority.cc
+++ b/cc/tiles/tile_priority.cc
@@ -4,6 +4,7 @@
 
 #include "cc/tiles/tile_priority.h"
 
+#include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
@@ -89,9 +90,12 @@
     base::trace_event::TracedValue* state) const {
   state->SetString("memory_limit_policy",
                    TileMemoryLimitPolicyToString(memory_limit_policy));
-  state->SetInteger("soft_memory_limit_in_bytes", soft_memory_limit_in_bytes);
-  state->SetInteger("hard_memory_limit_in_bytes", hard_memory_limit_in_bytes);
-  state->SetInteger("num_resources_limit", num_resources_limit);
+  state->SetInteger("soft_memory_limit_in_bytes",
+                    base::saturated_cast<int>(soft_memory_limit_in_bytes));
+  state->SetInteger("hard_memory_limit_in_bytes",
+                    base::saturated_cast<int>(hard_memory_limit_in_bytes));
+  state->SetInteger("num_resources_limit",
+                    base::saturated_cast<int>(num_resources_limit));
   state->SetString("tree_priority", TreePriorityToString(tree_priority));
 }
 
diff --git a/cc/tiles/tiling_set_eviction_queue.cc b/cc/tiles/tiling_set_eviction_queue.cc
index 9329d0d..65bfdb2 100644
--- a/cc/tiles/tiling_set_eviction_queue.cc
+++ b/cc/tiles/tiling_set_eviction_queue.cc
@@ -33,37 +33,39 @@
   // for this class.
   PictureLayerTilingSet::TilingRange range =
       tiling_set->GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
-  for (int i = range.start; i < range.end; ++i) {
-    PictureLayerTiling* tiling = tiling_set->tiling_at(i);
+  for (size_t index = range.start; index < range.end; ++index) {
+    PictureLayerTiling* tiling = tiling_set->tiling_at(index);
     if (tiling->has_tiles())
       tilings_.push_back(tiling);
   }
 
   range = tiling_set->GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES);
-  for (int i = range.end - 1; i >= range.start; --i) {
-    PictureLayerTiling* tiling = tiling_set->tiling_at(i);
+  for (size_t i = range.start; i < range.end; ++i) {
+    size_t index = range.start + (range.end - 1 - i);
+    PictureLayerTiling* tiling = tiling_set->tiling_at(index);
     if (tiling->has_tiles())
       tilings_.push_back(tiling);
   }
 
   range = tiling_set->GetTilingRange(
       PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
-  for (int i = range.end - 1; i >= range.start; --i) {
-    PictureLayerTiling* tiling = tiling_set->tiling_at(i);
+  for (size_t i = range.start; i < range.end; ++i) {
+    size_t index = range.start + (range.end - 1 - i);
+    PictureLayerTiling* tiling = tiling_set->tiling_at(index);
     if (tiling->has_tiles())
       tilings_.push_back(tiling);
   }
 
   range = tiling_set->GetTilingRange(PictureLayerTilingSet::LOW_RES);
-  for (int i = range.start; i < range.end; ++i) {
-    PictureLayerTiling* tiling = tiling_set->tiling_at(i);
+  for (size_t index = range.start; index < range.end; ++index) {
+    PictureLayerTiling* tiling = tiling_set->tiling_at(index);
     if (tiling->has_tiles())
       tilings_.push_back(tiling);
   }
 
   range = tiling_set->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
-  for (int i = range.start; i < range.end; ++i) {
-    PictureLayerTiling* tiling = tiling_set->tiling_at(i);
+  for (size_t index = range.start; index < range.end; ++index) {
+    PictureLayerTiling* tiling = tiling_set->tiling_at(index);
     if (tiling->has_tiles())
       tilings_.push_back(tiling);
   }
diff --git a/cc/trees/damage_tracker_unittest.cc b/cc/trees/damage_tracker_unittest.cc
index 2df71ddf..9727759 100644
--- a/cc/trees/damage_tracker_unittest.cc
+++ b/cc/trees/damage_tracker_unittest.cc
@@ -14,6 +14,7 @@
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_host_common.h"
+#include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/effects/SkBlurImageFilter.h"
@@ -47,6 +48,7 @@
 }
 
 void EmulateDrawingOneFrame(LayerImpl* root) {
+  root->layer_tree_impl()->property_trees()->needs_rebuild = true;
   // This emulates only steps that are relevant to testing the damage tracker:
   //   1. computing the render passes and layerlists
   //   2. updating all damage trackers in the correct order
@@ -58,16 +60,17 @@
 
   // Iterate back-to-front, so that damage correctly propagates from descendant
   // surfaces to ancestors.
-  for (int i = render_surface_layer_list.size() - 1; i >= 0; --i) {
+  size_t render_surface_layer_list_size = render_surface_layer_list.size();
+  for (size_t i = 0; i < render_surface_layer_list_size; ++i) {
+    size_t index = render_surface_layer_list_size - 1 - i;
     RenderSurfaceImpl* target_surface =
-            render_surface_layer_list[i]->render_surface();
+        render_surface_layer_list[index]->render_surface();
     target_surface->damage_tracker()->UpdateDamageTrackingState(
-        target_surface->layer_list(),
-        target_surface->OwningLayerId(),
+        target_surface->layer_list(), target_surface->OwningLayerId(),
         target_surface->SurfacePropertyChangedOnlyFromDescendant(),
         target_surface->content_rect(),
-        render_surface_layer_list[i]->mask_layer(),
-        render_surface_layer_list[i]->filters());
+        render_surface_layer_list[index]->mask_layer(),
+        render_surface_layer_list[index]->filters());
   }
 
   root->ResetAllChangeTrackingForSubtree();
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index e94d301..5f081b4 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -302,8 +302,8 @@
          current_target->render_surface()->draw_transform();
 
     // If we have unclipped descendants, the draw transform is a translation.
-    DCHECK(current_target->num_unclipped_descendants() == 0 ||
-           current_draw_transform.IsIdentityOrTranslation());
+    DCHECK_IMPLIES(current_target->num_unclipped_descendants(),
+                   current_draw_transform.IsIdentityOrTranslation());
 
     target_rect = gfx::ToEnclosingRect(
         MathUtil::MapClippedRect(current_draw_transform, target_rect));
@@ -1184,7 +1184,7 @@
 }
 
 struct PreCalculateMetaInformationRecursiveData {
-  int num_unclipped_descendants;
+  size_t num_unclipped_descendants;
   int num_layer_or_descendants_with_copy_request;
   int num_layer_or_descendants_with_input_handler;
 
@@ -1273,7 +1273,7 @@
   }
 
   if (layer->clip_children()) {
-    int num_clip_children = layer->clip_children()->size();
+    size_t num_clip_children = layer->clip_children()->size();
     DCHECK_GE(recursive_data->num_unclipped_descendants, num_clip_children);
     recursive_data->num_unclipped_descendants -= num_clip_children;
   }
@@ -1331,7 +1331,7 @@
   }
 
   if (layer->clip_children()) {
-    int num_clip_children = layer->clip_children()->size();
+    size_t num_clip_children = layer->clip_children()->size();
     DCHECK_GE(recursive_data->num_unclipped_descendants, num_clip_children);
     recursive_data->num_unclipped_descendants -= num_clip_children;
   }
@@ -2078,7 +2078,7 @@
       gfx::Rect projected_surface_rect = MathUtil::ProjectEnclosingClippedRect(
           inverse_surface_draw_transform, surface_clip_rect_in_target_space);
 
-      if (layer_draw_properties.num_unclipped_descendants > 0) {
+      if (layer_draw_properties.num_unclipped_descendants > 0u) {
         // If we have unclipped descendants, we cannot count on the render
         // surface's bounds clipping our subtree: the unclipped descendants
         // could cause us to expand our bounds. In this case, we must rely on
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 3db11585..fa9563f 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -7108,8 +7108,8 @@
             render_surface2->render_surface()->content_rect().ToString());
 
   // Sanity check our num_unclipped_descendants values.
-  EXPECT_EQ(1, render_surface1->num_unclipped_descendants());
-  EXPECT_EQ(0, render_surface2->num_unclipped_descendants());
+  EXPECT_EQ(1u, render_surface1->num_unclipped_descendants());
+  EXPECT_EQ(0u, render_surface2->num_unclipped_descendants());
 }
 
 TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
@@ -8227,6 +8227,7 @@
   scale_matrix.Scale(1.f, 2.f);
   grand_parent->SetTransform(scale_matrix);
   parent_raw->SetTransform(scale_matrix);
+  grand_parent->layer_tree_impl()->property_trees()->needs_rebuild = true;
   AddAnimatedTransformToLayer(parent_raw, 1.0, TransformOperations(), scale);
   ExecuteCalculateDrawProperties(grand_parent.get());
 
@@ -8245,6 +8246,7 @@
   gfx::Transform perspective_matrix;
   perspective_matrix.ApplyPerspectiveDepth(2.f);
   child_raw->SetTransform(perspective_matrix);
+  grand_parent->layer_tree_impl()->property_trees()->needs_rebuild = true;
   ExecuteCalculateDrawProperties(grand_parent.get());
 
   // |child| has a transform that's neither a translation nor a scale.
@@ -8257,6 +8259,7 @@
       0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
 
   parent_raw->SetTransform(perspective_matrix);
+  grand_parent->layer_tree_impl()->property_trees()->needs_rebuild = true;
   ExecuteCalculateDrawProperties(grand_parent.get());
 
   // |parent| and |child| have transforms that are neither translations nor
@@ -8272,6 +8275,7 @@
   parent_raw->SetTransform(identity_matrix);
   child_raw->SetTransform(identity_matrix);
   grand_parent->SetTransform(perspective_matrix);
+  grand_parent->layer_tree_impl()->property_trees()->needs_rebuild = true;
 
   ExecuteCalculateDrawProperties(grand_parent.get());
 
@@ -9599,7 +9603,7 @@
   host->SetRootLayer(root);
 
   ExecuteCalculateDrawProperties(root.get());
-  EXPECT_EQ(parent->draw_properties().num_unclipped_descendants, 1);
+  EXPECT_EQ(parent->draw_properties().num_unclipped_descendants, 1u);
 
   // Ensure the dynamic update to input handlers happens.
   child->SetHaveWheelEventHandlers(true);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 6dc90435..2ef7beff 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -14,6 +14,7 @@
 #include "base/containers/small_map.h"
 #include "base/json/json_writer.h"
 #include "base/metrics/histogram.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event_argument.h"
@@ -402,8 +403,11 @@
   // DCHECK(!current_begin_frame_tracker_.HasFinished());
   // DCHECK(monotonic_time == current_begin_frame_tracker_.Current().frame_time)
   //  << "Called animate with unknown frame time!?";
-  if (input_handler_client_)
-    input_handler_client_->Animate(monotonic_time);
+  if (!root_layer_scroll_offset_delegate_ ||
+      (CurrentlyScrollingLayer() != InnerViewportScrollLayer() &&
+       CurrentlyScrollingLayer() != OuterViewportScrollLayer())) {
+    AnimateInput(monotonic_time);
+  }
   AnimatePageScale(monotonic_time);
   AnimateLayers(monotonic_time);
   AnimateScrollbars(monotonic_time);
@@ -462,6 +466,22 @@
   client_->RenewTreePriority();
 }
 
+void LayerTreeHostImpl::SetNeedsAnimateInput() {
+  if (root_layer_scroll_offset_delegate_ &&
+      (CurrentlyScrollingLayer() == InnerViewportScrollLayer() ||
+       CurrentlyScrollingLayer() == OuterViewportScrollLayer())) {
+    if (root_layer_animation_callback_.is_null()) {
+      root_layer_animation_callback_ =
+          base::Bind(&LayerTreeHostImpl::AnimateInput, AsWeakPtr());
+    }
+    root_layer_scroll_offset_delegate_->SetNeedsAnimate(
+        root_layer_animation_callback_);
+    return;
+  }
+
+  SetNeedsAnimate();
+}
+
 bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt(
     const gfx::Point& viewport_point,
     InputHandler::ScrollInputType type) {
@@ -571,10 +591,9 @@
   // must compute all damage tracking before drawing anything, so that we know
   // the root damage rect. The root damage rect is then used to scissor each
   // surface.
-
-  for (int surface_index = render_surface_layer_list.size() - 1;
-       surface_index >= 0;
-       --surface_index) {
+  size_t render_surface_layer_list_size = render_surface_layer_list.size();
+  for (size_t i = 0; i < render_surface_layer_list_size; ++i) {
+    size_t surface_index = render_surface_layer_list_size - 1 - i;
     LayerImpl* render_surface_layer = render_surface_layer_list[surface_index];
     RenderSurfaceImpl* render_surface = render_surface_layer->render_surface();
     DCHECK(render_surface);
@@ -750,9 +769,10 @@
       "RequiresHighResToDraw", RequiresHighResToDraw());
 
   // Create the render passes in dependency order.
-  for (int surface_index = frame->render_surface_layer_list->size() - 1;
-       surface_index >= 0;
-       --surface_index) {
+  size_t render_surface_layer_list_size =
+      frame->render_surface_layer_list->size();
+  for (size_t i = 0; i < render_surface_layer_list_size; ++i) {
+    size_t surface_index = render_surface_layer_list_size - 1 - i;
     LayerImpl* render_surface_layer =
         (*frame->render_surface_layer_list)[surface_index];
     RenderSurfaceImpl* render_surface = render_surface_layer->render_surface();
@@ -996,14 +1016,16 @@
     input_handler_client_->ReconcileElasticOverscrollAndRootScroll();
 
   UMA_HISTOGRAM_CUSTOM_COUNTS(
-      "Compositing.NumActiveLayers", active_tree_->NumLayers(), 1, 400, 20);
+      "Compositing.NumActiveLayers",
+      base::saturated_cast<int>(active_tree_->NumLayers()), 1, 400, 20);
 
   size_t total_picture_memory = 0;
   for (const PictureLayerImpl* layer : active_tree()->picture_layers())
     total_picture_memory += layer->GetRasterSource()->GetPictureMemoryUsage();
   if (total_picture_memory != 0) {
-    UMA_HISTOGRAM_COUNTS("Compositing.PictureMemoryUsageKb",
-                         total_picture_memory / 1024);
+    UMA_HISTOGRAM_COUNTS(
+        "Compositing.PictureMemoryUsageKb",
+        base::saturated_cast<int>(total_picture_memory / 1024));
   }
 
   bool update_lcd_text = false;
@@ -1305,6 +1327,20 @@
 
 void LayerTreeHostImpl::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
   SetManagedMemoryPolicy(policy);
+
+  // This is short term solution to synchronously drop tile resources when
+  // using synchronous compositing to avoid memory usage regression.
+  // TODO(boliu): crbug.com/499004 to track removing this.
+  if (!policy.bytes_limit_when_visible && tile_manager_ &&
+      settings_.using_synchronous_renderer_compositor) {
+    ReleaseTreeResources();
+    // TileManager destruction will synchronoulsy wait for all tile workers to
+    // be cancelled or completed. This allows all resources to be freed
+    // synchronously.
+    DestroyTileManager();
+    CreateAndSetTileManager();
+    RecreateTreeResources();
+  }
 }
 
 void LayerTreeHostImpl::SetTreeActivationCallback(
@@ -1824,9 +1860,9 @@
 bool LayerTreeHostImpl::IsActivelyScrolling() const {
   return (did_lock_scrolling_layer_ && CurrentlyScrollingLayer()) ||
          (InnerViewportScrollLayer() &&
-          InnerViewportScrollLayer()->IsExternalFlingActive()) ||
+          InnerViewportScrollLayer()->IsExternalScrollActive()) ||
          (OuterViewportScrollLayer() &&
-          OuterViewportScrollLayer()->IsExternalFlingActive());
+          OuterViewportScrollLayer()->IsExternalScrollActive());
 }
 
 // Content layers can be either directly scrollable or contained in an outer
@@ -1948,10 +1984,11 @@
   else
     EvictAllUIResources();
 
-  // Evict tiles immediately if invisible since this tab may never get another
-  // draw or timer tick.
-  if (!visible_)
-    PrepareTiles();
+  // Call PrepareTiles unconditionally on visibility change since this tab may
+  // never get another draw or timer tick. When becoming visible we care about
+  // unblocking the scheduler which might be waiting for activation / ready to
+  // draw. When becoming invisible we care about evicting tiles immediately.
+  PrepareTiles();
 
   if (!renderer_)
     return;
@@ -2137,10 +2174,14 @@
     *resource_pool =
         ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D);
 
+    int max_copy_texture_chromium_size =
+        context_provider->ContextCapabilities()
+            .gpu.max_copy_texture_chromium_size;
+
     *tile_task_worker_pool = OneCopyTileTaskWorkerPool::Create(
         task_runner, task_graph_runner, context_provider,
         resource_provider_.get(), staging_resource_pool_.get(),
-        settings_.max_bytes_per_copy_operation,
+        max_copy_texture_chromium_size,
         settings_.use_persistent_map_for_gpu_memory_buffers);
     return;
   }
@@ -2626,6 +2667,13 @@
                                            delta);
 }
 
+static LayerImpl* nextLayerInScrollOrder(LayerImpl* layer) {
+  if (layer->scroll_parent())
+    return layer->scroll_parent();
+
+  return layer->parent();
+}
+
 InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
     const gfx::Point& viewport_point,
     const gfx::Vector2dF& scroll_delta) {
@@ -2639,9 +2687,16 @@
   bool did_scroll_y = false;
   bool did_scroll_top_controls = false;
 
+  if (pinch_gesture_active_ && settings().invert_viewport_scroll_order) {
+    // Scrolls during a pinch gesture should pan the visual viewport, rather
+    // than a typical bubbling scroll.
+    viewport()->Pan(pending_delta);
+    return InputHandlerScrollResult();
+  }
+
   for (LayerImpl* layer_impl = CurrentlyScrollingLayer();
        layer_impl;
-       layer_impl = layer_impl->parent()) {
+       layer_impl = nextLayerInScrollOrder(layer_impl)) {
     // Skip the outer viewport scroll layer so that we try to scroll the
     // viewport only once. i.e. The inner viewport layer represents the
     // viewport.
@@ -2650,9 +2705,11 @@
 
     gfx::Vector2dF applied_delta;
     if (layer_impl == InnerViewportScrollLayer()) {
+      bool affect_top_controls = true;
       Viewport::ScrollResult result = viewport()->ScrollBy(pending_delta,
                                                            viewport_point,
-                                                           wheel_scrolling_);
+                                                           wheel_scrolling_,
+                                                           affect_top_controls);
       applied_delta = result.applied_delta;
       unused_root_delta = result.unused_scroll_delta;
       did_scroll_top_controls = result.top_controls_applied_delta.y() != 0;
@@ -2804,13 +2861,6 @@
   if (!active_tree_->CurrentlyScrollingLayer())
     return SCROLL_IGNORED;
 
-  if (settings_.ignore_root_layer_flings &&
-      (active_tree_->CurrentlyScrollingLayer() == InnerViewportScrollLayer() ||
-       active_tree_->CurrentlyScrollingLayer() == OuterViewportScrollLayer())) {
-    ClearCurrentlyScrollingLayer();
-    return SCROLL_IGNORED;
-  }
-
   if (!wheel_scrolling_) {
     // Allow the fling to lock to the first layer that moves after the initial
     // fling |ScrollBy()| event.
@@ -2941,25 +2991,26 @@
   gfx::PointF new_scale_anchor = gfx::ScalePoint(anchor, 1.f / page_scale);
   gfx::Vector2dF move = previous_scale_anchor - new_scale_anchor;
 
+  // Scale back to viewport space since that's the coordinate space ScrollBy
+  // uses.
+  move.Scale(page_scale);
+
   previous_pinch_anchor_ = anchor;
 
   // If clamping the inner viewport scroll offset causes a change, it should
   // be accounted for from the intended move.
   move -= InnerViewportScrollLayer()->ClampScrollToMaxScrollOffset();
 
-  // We manually manage the bubbling behaviour here as it is different to that
-  // implemented in LayerTreeHostImpl::ScrollBy(). Specifically:
-  // 1) we want to explicit limit the bubbling to the outer/inner viewports,
-  // 2) we don't want the directional limitations on the unused parts that
-  //    ScrollBy() implements, and
-  // 3) pinching should not engage the top controls manager.
-  gfx::Vector2dF unused = OuterViewportScrollLayer()
-                              ? OuterViewportScrollLayer()->ScrollBy(move)
-                              : move;
-
-  if (!unused.IsZero()) {
-    InnerViewportScrollLayer()->ScrollBy(unused);
-    InnerViewportScrollLayer()->ClampScrollToMaxScrollOffset();
+  if (settings().invert_viewport_scroll_order) {
+    viewport()->Pan(move);
+  } else {
+    gfx::Point viewport_point;
+    bool is_wheel_event = false;
+    bool affect_top_controls = false;
+    viewport()->ScrollBy(move,
+                         viewport_point,
+                         is_wheel_event,
+                         affect_top_controls);
   }
 
   active_tree_->SetRootLayerScrollOffsetDelegate(
@@ -3043,6 +3094,12 @@
     InnerViewportScrollLayer()->ScrollBy(unused_delta);
 }
 
+void LayerTreeHostImpl::AnimateInput(base::TimeTicks monotonic_time) {
+  DCHECK(proxy_->IsImplThread());
+  if (input_handler_client_)
+    input_handler_client_->Animate(monotonic_time);
+}
+
 void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks monotonic_time) {
   if (!page_scale_animation_)
     return;
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index dddf231..6551255 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -185,7 +185,7 @@
                                bool anchor_point,
                                float page_scale,
                                base::TimeDelta duration);
-  void SetNeedsAnimate() override;
+  void SetNeedsAnimateInput() override;
   bool IsCurrentlyScrollingLayerAt(const gfx::Point& viewport_point,
                                    InputHandler::ScrollInputType type) override;
   bool HaveWheelEventHandlersAt(const gfx::Point& viewport_point) override;
@@ -394,6 +394,7 @@
   bool AnimationsAreVisible() { return visible() && CanDraw(); }
 
   void SetNeedsCommit() { client_->SetNeedsCommitOnImplThread(); }
+  void SetNeedsAnimate();
   void SetNeedsRedraw();
 
   ManagedMemoryPolicy ActualManagedMemoryPolicy() const;
@@ -599,6 +600,7 @@
   // outer if the inner is at its scroll extents.
   void ScrollViewportInnerFirst(gfx::Vector2dF scroll_delta);
 
+  void AnimateInput(base::TimeTicks monotonic_time);
   void AnimatePageScale(base::TimeTicks monotonic_time);
   void AnimateScrollbars(base::TimeTicks monotonic_time);
   void AnimateTopControls(base::TimeTicks monotonic_time);
@@ -698,6 +700,8 @@
 
   // The optional delegate for the root layer scroll offset.
   LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate_;
+  LayerScrollOffsetDelegate::AnimationCallback root_layer_animation_callback_;
+
   const LayerTreeSettings settings_;
   LayerTreeDebugState debug_state_;
   bool visible_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 5e9fcce8..2a7cbe3 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -100,7 +100,7 @@
         reduce_memory_result_(true),
         current_limit_bytes_(0),
         current_priority_cutoff_value_(0) {
-    media::InitializeMediaLibraryForTesting();
+    media::InitializeMediaLibrary();
   }
 
   LayerTreeSettings DefaultSettings() {
@@ -1136,6 +1136,50 @@
   }
 }
 
+TEST_F(LayerTreeHostImplTest, ScrollDuringPinchScrollsInnerViewport) {
+  LayerTreeSettings settings = DefaultSettings();
+  settings.invert_viewport_scroll_order = true;
+  CreateHostImpl(settings,
+                 CreateOutputSurface());
+
+  LayerImpl* inner_scroll_layer =
+      SetupScrollAndContentsLayers(gfx::Size(100, 100));
+
+  // Adjust the content layer to be larger than the outer viewport container so
+  // that we get scrolling in both viewports.
+  LayerImpl* content_layer =
+      host_impl_->OuterViewportScrollLayer()->children().back();
+  LayerImpl* outer_scroll_layer = host_impl_->OuterViewportScrollLayer();
+  LayerImpl* inner_clip_layer =
+      host_impl_->InnerViewportScrollLayer()->parent()->parent();
+  inner_clip_layer->SetBounds(gfx::Size(100, 100));
+  inner_clip_layer->SetContentBounds(gfx::Size(100, 100));
+  outer_scroll_layer->SetBounds(gfx::Size(200, 200));
+  outer_scroll_layer->SetContentBounds(gfx::Size(200, 200));
+  content_layer->SetBounds(gfx::Size(200, 200));
+  content_layer->SetContentBounds(gfx::Size(200, 200));
+
+  host_impl_->SetViewportSize(gfx::Size(100, 100));
+
+  EXPECT_VECTOR_EQ(
+      gfx::Vector2dF(100, 100),
+      outer_scroll_layer->MaxScrollOffset());
+
+  host_impl_->ScrollBegin(gfx::Point(99, 99), InputHandler::GESTURE);
+  host_impl_->PinchGestureBegin();
+  host_impl_->PinchGestureUpdate(2, gfx::Point(99, 99));
+  host_impl_->ScrollBy(gfx::Point(99, 99), gfx::Vector2dF(10.f, 10.f));
+  host_impl_->PinchGestureEnd();
+  host_impl_->ScrollEnd();
+
+  EXPECT_VECTOR_EQ(
+      gfx::Vector2dF(0, 0),
+      outer_scroll_layer->CurrentScrollOffset());
+  EXPECT_VECTOR_EQ(
+      gfx::Vector2dF(50, 50),
+      inner_scroll_layer->CurrentScrollOffset());
+}
+
 TEST_F(LayerTreeHostImplTest, ImplPinchZoomWheelBubbleBetweenViewports) {
   LayerImpl* inner_scroll_layer =
       SetupScrollAndContentsLayers(gfx::Size(100, 100));
@@ -1223,6 +1267,85 @@
   EXPECT_EQ(latency_info.trace_id, scroll_info->swap_promises[0]->TraceId());
 }
 
+// Test that scrolls targeting a layer with a non-null scroll_parent() bubble
+// up to the scroll_parent, rather than the stacking parent.
+TEST_F(LayerTreeHostImplTest, ScrollBubblesToScrollParent) {
+  LayerImpl* viewport_scroll =
+      SetupScrollAndContentsLayers(gfx::Size(100, 100));
+  host_impl_->SetViewportSize(gfx::Size(50, 50));
+
+  // Set up two scrolling children of the root, one of which is a scroll parent
+  // to the other. Scrolls bubbling from the child should bubble to the parent,
+  // not the viewport.
+  LayerImpl *parent;
+  LayerImpl *child;
+  LayerImpl *child_clip;
+
+  scoped_ptr<LayerImpl> scroll_parent_clip =
+      LayerImpl::Create(host_impl_->active_tree(), 6);
+  scoped_ptr<LayerImpl> scroll_parent = CreateScrollableLayer(
+      7, gfx::Size(10, 10), scroll_parent_clip.get());
+  parent = scroll_parent.get();
+  scroll_parent_clip->AddChild(scroll_parent.Pass());
+
+  viewport_scroll->AddChild(scroll_parent_clip.Pass());
+
+  scoped_ptr<LayerImpl> scroll_child_clip =
+      LayerImpl::Create(host_impl_->active_tree(), 8);
+  scoped_ptr<LayerImpl> scroll_child = CreateScrollableLayer(
+      9, gfx::Size(10, 10), scroll_child_clip.get());
+  child = scroll_child.get();
+  scroll_child->SetPosition(gfx::Point(20, 20));
+  scroll_child_clip->AddChild(scroll_child.Pass());
+
+  child_clip = scroll_child_clip.get();
+  viewport_scroll->AddChild(scroll_child_clip.Pass());
+
+  child_clip->SetScrollParent(parent);
+
+  DrawFrame();
+
+  {
+    host_impl_->ScrollBegin(gfx::Point(21, 21), InputHandler::GESTURE);
+    host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(5, 5));
+    host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(2, 1));
+    host_impl_->ScrollEnd();
+
+    // The child should be fully scrolled by the first ScrollBy.
+    EXPECT_VECTOR_EQ(gfx::Vector2dF(5, 5), child->CurrentScrollOffset());
+
+    // The scroll_parent should receive the bubbled up second ScrollBy.
+    EXPECT_VECTOR_EQ(gfx::Vector2dF(2, 1), parent->CurrentScrollOffset());
+
+    // The viewport shouldn't have been scrolled at all.
+    EXPECT_VECTOR_EQ(
+        gfx::Vector2dF(0, 0),
+        host_impl_->InnerViewportScrollLayer()->CurrentScrollOffset());
+    EXPECT_VECTOR_EQ(
+        gfx::Vector2dF(0, 0),
+        host_impl_->OuterViewportScrollLayer()->CurrentScrollOffset());
+  }
+
+  {
+    host_impl_->ScrollBegin(gfx::Point(21, 21), InputHandler::GESTURE);
+    host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(3, 4));
+    host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(2, 1));
+    host_impl_->ScrollEnd();
+
+    // The first ScrollBy should scroll the parent to its extent.
+    EXPECT_VECTOR_EQ(gfx::Vector2dF(5, 5), parent->CurrentScrollOffset());
+
+    // The viewport should now be next in bubbling order.
+    EXPECT_VECTOR_EQ(
+        gfx::Vector2dF(2, 1),
+        host_impl_->InnerViewportScrollLayer()->CurrentScrollOffset());
+    EXPECT_VECTOR_EQ(
+        gfx::Vector2dF(0, 0),
+        host_impl_->OuterViewportScrollLayer()->CurrentScrollOffset());
+  }
+}
+
+
 TEST_F(LayerTreeHostImplTest, PinchGesture) {
   SetupScrollAndContentsLayers(gfx::Size(100, 100));
   host_impl_->SetViewportSize(gfx::Size(50, 50));
@@ -3950,7 +4073,8 @@
   TestScrollOffsetDelegate()
       : page_scale_factor_(0.f),
         min_page_scale_factor_(-1.f),
-        max_page_scale_factor_(-1.f) {}
+        max_page_scale_factor_(-1.f),
+        needs_animate_(false) {}
 
   ~TestScrollOffsetDelegate() override {}
 
@@ -3958,7 +4082,11 @@
     return getter_return_value_;
   }
 
-  bool IsExternalFlingActive() const override { return false; }
+  bool IsExternalScrollActive() const override { return false; }
+
+  void SetNeedsAnimate(const AnimationCallback&) override {
+    needs_animate_ = true;
+  }
 
   void UpdateRootLayerState(const gfx::ScrollOffset& total_scroll_offset,
                             const gfx::ScrollOffset& max_scroll_offset,
@@ -3978,6 +4106,12 @@
     set_getter_return_value(last_set_scroll_offset_);
   }
 
+  bool GetAndResetNeedsAnimate() {
+    bool needs_animate = needs_animate_;
+    needs_animate_ = false;
+    return needs_animate;
+  }
+
   gfx::ScrollOffset last_set_scroll_offset() {
     return last_set_scroll_offset_;
   }
@@ -4014,8 +4148,10 @@
   float page_scale_factor_;
   float min_page_scale_factor_;
   float max_page_scale_factor_;
+  bool needs_animate_;
 };
 
+// TODO(jdduke): Test root fling animation.
 TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
   TestScrollOffsetDelegate scroll_delegate;
   host_impl_->SetViewportSize(gfx::Size(10, 20));
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 427b649..0aa8a28 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -34,9 +34,7 @@
 #include "cc/resources/prioritized_resource.h"
 #include "cc/resources/prioritized_resource_manager.h"
 #include "cc/resources/resource_update_queue.h"
-#include "cc/test/fake_content_layer.h"
 #include "cc/test/fake_content_layer_client.h"
-#include "cc/test/fake_content_layer_impl.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_painted_scrollbar_layer.h"
@@ -644,10 +642,7 @@
     root_layer_->SetBounds(gfx::Size(10, 20));
     root_layer_->CreateRenderSurface();
 
-    if (layer_tree_host()->settings().impl_side_painting)
-      scaled_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
-    else
-      scaled_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    scaled_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     scaled_layer_->SetBounds(gfx::Size(1, 1));
     root_layer_->AddChild(scaled_layer_);
 
@@ -841,8 +836,6 @@
 // its damage is preserved until the next time it is drawn.
 class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
  public:
-  LayerTreeHostTestUndrawnLayersDamageLater() {}
-
   void InitializeSettings(LayerTreeSettings* settings) override {
     // If we don't set the minimum contents scale, it's harder to verify whether
     // the damage we get is correct. For other scale amounts, please see
@@ -861,18 +854,12 @@
 
     // The initially transparent layer has a larger child layer, which is
     // not initially drawn because of the this (parent) layer.
-    if (layer_tree_host()->settings().impl_side_painting)
-      parent_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
-    else
-      parent_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    parent_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     parent_layer_->SetBounds(gfx::Size(15, 15));
     parent_layer_->SetOpacity(0.0f);
     root_layer_->AddChild(parent_layer_);
 
-    if (layer_tree_host()->settings().impl_side_painting)
-      child_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
-    else
-      child_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    child_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     child_layer_->SetBounds(gfx::Size(25, 25));
     parent_layer_->AddChild(child_layer_);
 
@@ -1456,7 +1443,7 @@
   void AfterTest() override {
     // Update() should have been called once.
     if (is_impl_paint_)
-      EXPECT_EQ(1u, update_check_picture_layer_->update_count());
+      EXPECT_EQ(1, update_check_picture_layer_->update_count());
     else
       EXPECT_EQ(1, update_check_content_layer_->PaintContentsCount());
   }
@@ -1578,164 +1565,6 @@
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers);
 
-// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
-// Verify atomicity of commits and reuse of textures.
-class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
- public:
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->renderer_settings.texture_id_allocation_chunk_size = 1;
-    // Make sure partial texture updates are turned off.
-    settings->max_partial_texture_updates = 0;
-    // Linear fade animator prevents scrollbars from drawing immediately.
-    settings->scrollbar_animator = LayerTreeSettings::NO_ANIMATOR;
-  }
-
-  void SetupTree() override {
-    layer_ = FakeContentLayer::Create(layer_settings(), &client_);
-    layer_->SetBounds(gfx::Size(10, 20));
-
-    bool paint_scrollbar = true;
-    bool has_thumb = false;
-    scrollbar_ = FakePaintedScrollbarLayer::Create(
-        layer_settings(), paint_scrollbar, has_thumb, layer_->id());
-    scrollbar_->SetPosition(gfx::Point(0, 10));
-    scrollbar_->SetBounds(gfx::Size(10, 10));
-
-    layer_->AddChild(scrollbar_);
-
-    layer_tree_host()->SetRootLayer(layer_);
-    LayerTreeHostTest::SetupTree();
-  }
-
-  void BeginTest() override {
-    drew_frame_ = -1;
-    PostSetNeedsCommitToMainThread();
-  }
-
-  void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
-    ASSERT_EQ(0u, impl->settings().max_partial_texture_updates);
-
-    TestWebGraphicsContext3D* context = TestContext();
-
-    switch (impl->active_tree()->source_frame_number()) {
-      case 0:
-        // Number of textures should be one for each layer
-        ASSERT_EQ(2u, context->NumTextures());
-        // Number of textures used for commit should be one for each layer.
-        EXPECT_EQ(2u, context->NumUsedTextures());
-        // Verify that used texture is correct.
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(0)));
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
-
-        context->ResetUsedTextures();
-        break;
-      case 1:
-        // Number of textures should be one for scrollbar layer since it was
-        // requested and deleted on the impl-thread, and double for the content
-        // layer since its first texture is used by impl thread and cannot by
-        // used for update.
-        ASSERT_EQ(3u, context->NumTextures());
-        // Number of textures used for commit should be one for each layer.
-        EXPECT_EQ(2u, context->NumUsedTextures());
-        // First textures should not have been used.
-        EXPECT_FALSE(context->UsedTexture(context->TextureAt(0)));
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
-        // New textures should have been used.
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
-        context->ResetUsedTextures();
-        break;
-      case 2:
-        EndTest();
-        break;
-      default:
-        NOTREACHED();
-        break;
-    }
-  }
-
-  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
-    TestWebGraphicsContext3D* context = TestContext();
-
-    if (drew_frame_ == impl->active_tree()->source_frame_number()) {
-      EXPECT_EQ(0u, context->NumUsedTextures()) << "For frame " << drew_frame_;
-      return;
-    }
-    drew_frame_ = impl->active_tree()->source_frame_number();
-
-    // We draw/ship one texture each frame for each layer.
-    EXPECT_EQ(2u, context->NumUsedTextures());
-    context->ResetUsedTextures();
-
-    if (!TestEnded())
-      PostSetNeedsCommitToMainThread();
-  }
-
-  void Layout() override {
-    layer_->SetNeedsDisplay();
-    scrollbar_->SetNeedsDisplay();
-  }
-
-  void AfterTest() override {}
-
- protected:
-  FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> layer_;
-  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_;
-  int drew_frame_;
-};
-
-MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
-    LayerTreeHostTestDirectRendererAtomicCommit);
-
-// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
-class LayerTreeHostTestDelegatingRendererAtomicCommit
-    : public LayerTreeHostTestDirectRendererAtomicCommit {
- public:
-  void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
-    ASSERT_EQ(0u, impl->settings().max_partial_texture_updates);
-
-    TestWebGraphicsContext3D* context = TestContext();
-
-    switch (impl->active_tree()->source_frame_number()) {
-      case 0:
-        // Number of textures should be one for each layer
-        ASSERT_EQ(2u, context->NumTextures());
-        // Number of textures used for commit should be one for each layer.
-        EXPECT_EQ(2u, context->NumUsedTextures());
-        // Verify that used texture is correct.
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(0)));
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
-        break;
-      case 1:
-        // Number of textures should be doubled as the first context layer
-        // texture is being used by the impl-thread and cannot be used for
-        // update.  The scrollbar behavior is different direct renderer because
-        // UI resource deletion with delegating renderer occurs after tree
-        // activation.
-        ASSERT_EQ(4u, context->NumTextures());
-        // Number of textures used for commit should still be
-        // one for each layer.
-        EXPECT_EQ(2u, context->NumUsedTextures());
-        // First textures should not have been used.
-        EXPECT_FALSE(context->UsedTexture(context->TextureAt(0)));
-        EXPECT_FALSE(context->UsedTexture(context->TextureAt(1)));
-        // New textures should have been used.
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(3)));
-        break;
-      case 2:
-        EndTest();
-        break;
-      default:
-        NOTREACHED();
-        break;
-    }
-  }
-};
-
-MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(
-    LayerTreeHostTestDelegatingRendererAtomicCommit);
-
 static void SetLayerPropertiesForTesting(Layer* layer,
                                          Layer* parent,
                                          const gfx::Transform& transform,
@@ -1753,272 +1582,6 @@
   layer->SetContentsOpaque(opaque);
 }
 
-// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
-class LayerTreeHostTestAtomicCommitWithPartialUpdate
-    : public LayerTreeHostTest {
- public:
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->renderer_settings.texture_id_allocation_chunk_size = 1;
-    // Allow one partial texture update.
-    settings->max_partial_texture_updates = 1;
-    // No partial updates when impl side painting is enabled.
-    settings->impl_side_painting = false;
-  }
-
-  void SetupTree() override {
-    parent_ = FakeContentLayer::Create(layer_settings(), &client_);
-    parent_->SetBounds(gfx::Size(10, 20));
-
-    child_ = FakeContentLayer::Create(layer_settings(), &client_);
-    child_->SetPosition(gfx::Point(0, 10));
-    child_->SetBounds(gfx::Size(3, 10));
-
-    parent_->AddChild(child_);
-
-    layer_tree_host()->SetRootLayer(parent_);
-    LayerTreeHostTest::SetupTree();
-  }
-
-  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-
-  void DidCommitAndDrawFrame() override {
-    switch (layer_tree_host()->source_frame_number()) {
-      case 1:
-        parent_->SetNeedsDisplay();
-        child_->SetNeedsDisplay();
-        break;
-      case 2:
-        // Damage part of layers.
-        parent_->SetNeedsDisplayRect(gfx::Rect(5, 5));
-        child_->SetNeedsDisplayRect(gfx::Rect(5, 5));
-        break;
-      case 3:
-        child_->SetNeedsDisplay();
-        layer_tree_host()->SetViewportSize(gfx::Size(10, 10));
-        break;
-      case 4:
-        layer_tree_host()->SetViewportSize(gfx::Size(10, 20));
-        break;
-      case 5:
-        EndTest();
-        break;
-      default:
-        NOTREACHED() << layer_tree_host()->source_frame_number();
-        break;
-    }
-  }
-
-  void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
-    ASSERT_EQ(1u, impl->settings().max_partial_texture_updates);
-
-    TestWebGraphicsContext3D* context = TestContext();
-
-    switch (impl->active_tree()->source_frame_number()) {
-      case 0:
-        // Number of textures should be one for each layer.
-        ASSERT_EQ(2u, context->NumTextures());
-        // Number of textures used for commit should be one for each layer.
-        EXPECT_EQ(2u, context->NumUsedTextures());
-        // Verify that used textures are correct.
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(0)));
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
-        context->ResetUsedTextures();
-        break;
-      case 1:
-        if (HasImplThread()) {
-          // Number of textures should be two for each content layer.
-          ASSERT_EQ(4u, context->NumTextures());
-        } else {
-          // In single thread we can always do partial updates, so the limit has
-          // no effect.
-          ASSERT_EQ(2u, context->NumTextures());
-        }
-        // Number of textures used for commit should be one for each content
-        // layer.
-        EXPECT_EQ(2u, context->NumUsedTextures());
-
-        if (HasImplThread()) {
-          // First content textures should not have been used.
-          EXPECT_FALSE(context->UsedTexture(context->TextureAt(0)));
-          EXPECT_FALSE(context->UsedTexture(context->TextureAt(1)));
-          // New textures should have been used.
-          EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
-          EXPECT_TRUE(context->UsedTexture(context->TextureAt(3)));
-        } else {
-          // In single thread we can always do partial updates, so the limit has
-          // no effect.
-          EXPECT_TRUE(context->UsedTexture(context->TextureAt(0)));
-          EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
-        }
-
-        context->ResetUsedTextures();
-        break;
-      case 2:
-        if (HasImplThread()) {
-          // Number of textures should be two for each content layer.
-          ASSERT_EQ(4u, context->NumTextures());
-        } else {
-          // In single thread we can always do partial updates, so the limit has
-          // no effect.
-          ASSERT_EQ(2u, context->NumTextures());
-        }
-        // Number of textures used for commit should be one for each content
-        // layer.
-        EXPECT_EQ(2u, context->NumUsedTextures());
-
-        if (HasImplThread()) {
-          // One content layer does a partial update also.
-          EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
-          EXPECT_FALSE(context->UsedTexture(context->TextureAt(3)));
-        } else {
-          // In single thread we can always do partial updates, so the limit has
-          // no effect.
-          EXPECT_TRUE(context->UsedTexture(context->TextureAt(0)));
-          EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
-        }
-
-        context->ResetUsedTextures();
-        break;
-      case 3:
-        // No textures should be used for commit.
-        EXPECT_EQ(0u, context->NumUsedTextures());
-
-        context->ResetUsedTextures();
-        break;
-      case 4:
-        // Number of textures used for commit should be one, for the
-        // content layer.
-        EXPECT_EQ(1u, context->NumUsedTextures());
-
-        context->ResetUsedTextures();
-        break;
-      default:
-        NOTREACHED();
-        break;
-    }
-  }
-
-  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
-    EXPECT_LT(impl->active_tree()->source_frame_number(), 5);
-
-    TestWebGraphicsContext3D* context = TestContext();
-
-    // Number of textures used for drawing should one per layer except for
-    // frame 3 where the viewport only contains one layer.
-    if (impl->active_tree()->source_frame_number() == 3) {
-      EXPECT_EQ(1u, context->NumUsedTextures());
-    } else {
-      EXPECT_EQ(2u, context->NumUsedTextures())
-          << "For frame " << impl->active_tree()->source_frame_number();
-    }
-
-    context->ResetUsedTextures();
-  }
-
-  void AfterTest() override {}
-
- private:
-  FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> parent_;
-  scoped_refptr<FakeContentLayer> child_;
-};
-
-// Partial updates are not possible with a delegating renderer.
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
-    LayerTreeHostTestAtomicCommitWithPartialUpdate);
-
-// TODO(sohanjg) : Make it work with impl-side painting.
-class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit
-    : public LayerTreeHostTest {
- protected:
-  void SetupTree() override {
-    root_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
-    root_layer_->SetBounds(gfx::Size(100, 100));
-
-    surface_layer1_ = FakeContentLayer::Create(layer_settings(), &client_);
-    surface_layer1_->SetBounds(gfx::Size(100, 100));
-    surface_layer1_->SetForceRenderSurface(true);
-    surface_layer1_->SetOpacity(0.5f);
-    root_layer_->AddChild(surface_layer1_);
-
-    surface_layer2_ = FakeContentLayer::Create(layer_settings(), &client_);
-    surface_layer2_->SetBounds(gfx::Size(100, 100));
-    surface_layer2_->SetForceRenderSurface(true);
-    surface_layer2_->SetOpacity(0.5f);
-    surface_layer1_->AddChild(surface_layer2_);
-
-    replica_layer1_ = FakeContentLayer::Create(layer_settings(), &client_);
-    surface_layer1_->SetReplicaLayer(replica_layer1_.get());
-
-    replica_layer2_ = FakeContentLayer::Create(layer_settings(), &client_);
-    surface_layer2_->SetReplicaLayer(replica_layer2_.get());
-
-    layer_tree_host()->SetRootLayer(root_layer_);
-    LayerTreeHostTest::SetupTree();
-  }
-
-  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-
-  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
-    Renderer* renderer = host_impl->renderer();
-    RenderPassId surface1_render_pass_id = host_impl->active_tree()
-                                               ->root_layer()
-                                               ->children()[0]
-                                               ->render_surface()
-                                               ->GetRenderPassId();
-    RenderPassId surface2_render_pass_id = host_impl->active_tree()
-                                               ->root_layer()
-                                               ->children()[0]
-                                               ->children()[0]
-                                               ->render_surface()
-                                               ->GetRenderPassId();
-
-    switch (host_impl->active_tree()->source_frame_number()) {
-      case 0:
-        EXPECT_TRUE(
-            renderer->HasAllocatedResourcesForTesting(surface1_render_pass_id));
-        EXPECT_TRUE(
-            renderer->HasAllocatedResourcesForTesting(surface2_render_pass_id));
-
-        // Reduce the memory limit to only fit the root layer and one render
-        // surface. This prevents any contents drawing into surfaces
-        // from being allocated.
-        host_impl->SetMemoryPolicy(ManagedMemoryPolicy(100 * 100 * 4 * 2));
-        break;
-      case 1:
-        EXPECT_FALSE(
-            renderer->HasAllocatedResourcesForTesting(surface1_render_pass_id));
-        EXPECT_FALSE(
-            renderer->HasAllocatedResourcesForTesting(surface2_render_pass_id));
-
-        EndTest();
-        break;
-    }
-  }
-
-  void DidCommitAndDrawFrame() override {
-    if (layer_tree_host()->source_frame_number() < 2)
-      root_layer_->SetNeedsDisplay();
-  }
-
-  void AfterTest() override {
-    EXPECT_LE(2u, root_layer_->update_count());
-    EXPECT_LE(2u, surface_layer1_->update_count());
-    EXPECT_LE(2u, surface_layer2_->update_count());
-  }
-
-  FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_layer_;
-  scoped_refptr<FakeContentLayer> surface_layer1_;
-  scoped_refptr<FakeContentLayer> replica_layer1_;
-  scoped_refptr<FakeContentLayer> surface_layer2_;
-  scoped_refptr<FakeContentLayer> replica_layer2_;
-};
-
-// Surfaces don't exist with a delegated renderer.
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
-    LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit);
-
 class EvictionTestLayer : public Layer {
  public:
   static scoped_refptr<EvictionTestLayer> Create(
@@ -2248,11 +1811,7 @@
     layer_tree_host()->SetViewportSize(gfx::Size(10, 10));
     layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10));
 
-    if (layer_tree_host()->settings().impl_side_painting)
-      layer_ = FakePictureLayer::Create(layer_settings(), &client_);
-    else
-      layer_ = FakeContentLayer::Create(layer_settings(), &client_);
-
+    layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     layer_->SetBounds(gfx::Size(10, 10));
     layer_->SetPosition(gfx::PointF(0.f, 0.f));
     layer_->SetIsDrawable(true);
@@ -2590,88 +2149,6 @@
   EXPECT_EQ(0u, host->MaxPartialTextureUpdates());
 }
 
-// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
-class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted
-    : public LayerTreeHostTest {
- public:
-  LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted()
-      : root_layer_(FakeContentLayer::Create(layer_settings(), &client_)),
-        child_layer1_(FakeContentLayer::Create(layer_settings(), &client_)),
-        child_layer2_(FakeContentLayer::Create(layer_settings(), &client_)),
-        num_commits_(0) {}
-
-  void BeginTest() override {
-    layer_tree_host()->SetViewportSize(gfx::Size(100, 100));
-    root_layer_->SetBounds(gfx::Size(100, 100));
-    child_layer1_->SetBounds(gfx::Size(100, 100));
-    child_layer2_->SetBounds(gfx::Size(100, 100));
-    root_layer_->AddChild(child_layer1_);
-    root_layer_->AddChild(child_layer2_);
-    layer_tree_host()->SetRootLayer(root_layer_);
-    PostSetNeedsCommitToMainThread();
-  }
-
-  void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl,
-                               bool visible) override {
-    if (visible) {
-      // One backing should remain unevicted.
-      EXPECT_EQ(100u * 100u * 4u * 1u,
-                contents_texture_manager_->MemoryUseBytes());
-    } else {
-      EXPECT_EQ(0u, contents_texture_manager_->MemoryUseBytes());
-    }
-
-    // Make sure that contents textures are marked as having been
-    // purged.
-    EXPECT_TRUE(host_impl->active_tree()->ContentsTexturesPurged());
-    // End the test in this state.
-    EndTest();
-  }
-
-  void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
-    ++num_commits_;
-    switch (num_commits_) {
-      case 1:
-        // All three backings should have memory.
-        EXPECT_EQ(100u * 100u * 4u * 3u,
-                  contents_texture_manager_->MemoryUseBytes());
-
-        // Set a new policy that will kick out 1 of the 3 resources.
-        // Because a resource was evicted, a commit will be kicked off.
-        host_impl->SetMemoryPolicy(
-            ManagedMemoryPolicy(100 * 100 * 4 * 2,
-                                gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
-                                1000));
-        break;
-      case 2:
-        // Only two backings should have memory.
-        EXPECT_EQ(100u * 100u * 4u * 2u,
-                  contents_texture_manager_->MemoryUseBytes());
-        // Become backgrounded, which will cause 1 more resource to be
-        // evicted.
-        PostSetVisibleToMainThread(false);
-        break;
-      default:
-        // No further commits should happen because this is not visible
-        // anymore.
-        NOTREACHED();
-        break;
-    }
-  }
-
-  void AfterTest() override {}
-
- private:
-  FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_layer_;
-  scoped_refptr<FakeContentLayer> child_layer1_;
-  scoped_refptr<FakeContentLayer> child_layer2_;
-  int num_commits_;
-};
-
-SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
-    LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted);
-
 class LayerTreeHostTestLCDChange : public LayerTreeHostTest {
  public:
   void SetupTree() override {
@@ -4642,7 +4119,7 @@
   void DidCommit() override {
     // The layer should be updated even though the viewport is empty, so we
     // are capable of drawing it on the impl tree.
-    EXPECT_GT(root_layer_->update_count(), 0u);
+    EXPECT_GT(root_layer_->update_count(), 0);
     EndTest();
   }
 
@@ -4892,10 +4369,7 @@
   }
 
   void SetupTree() override {
-    if (layer_tree_host()->settings().impl_side_painting)
-      root_ = FakePictureLayer::Create(layer_settings(), &client_);
-    else
-      root_ = FakeContentLayer::Create(layer_settings(), &client_);
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
     root_->SetBounds(gfx::Size(20, 20));
     layer_tree_host()->SetRootLayer(root_);
     LayerTreeHostTest::SetupTree();
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index e6f2b5c2..5585cfe 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -385,7 +385,7 @@
   void AfterTest() override {
     // Update() should have been called once, proving that the layer was not
     // skipped.
-    EXPECT_EQ(1u, update_check_layer_->update_count());
+    EXPECT_EQ(1, update_check_layer_->update_count());
 
     // clear update_check_layer_ so LayerTreeHost dies.
     update_check_layer_ = NULL;
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index e440260..8eb4dc8 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -20,9 +20,7 @@
 #include "cc/output/filter_operations.h"
 #include "cc/resources/single_release_callback.h"
 #include "cc/test/failure_output_surface.h"
-#include "cc/test/fake_content_layer.h"
 #include "cc/test/fake_content_layer_client.h"
-#include "cc/test/fake_content_layer_impl.h"
 #include "cc/test/fake_delegated_renderer_layer.h"
 #include "cc/test/fake_delegated_renderer_layer_impl.h"
 #include "cc/test/fake_layer_tree_host_client.h"
@@ -67,7 +65,7 @@
         context_should_support_io_surface_(false),
         fallback_context_works_(false),
         async_output_surface_creation_(false) {
-    media::InitializeMediaLibraryForTesting();
+    media::InitializeMediaLibrary();
   }
 
   void LoseContext() {
@@ -555,10 +553,7 @@
     paint.setColor(SkColorSetARGB(100, 80, 200, 200));
     client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint);
 
-    if (layer_tree_host()->settings().impl_side_painting)
-      layer_ = FakePictureLayer::Create(layer_settings(), &client_);
-    else
-      layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     layer_->SetBounds(gfx::Size(10, 10));
     layer_->SetIsDrawable(true);
 
@@ -577,21 +572,12 @@
   }
 
   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
-    if (!host_impl->settings().impl_side_painting) {
-      FakeContentLayerImpl* content_impl = static_cast<FakeContentLayerImpl*>(
-          host_impl->active_tree()->root_layer()->children()[0]);
-      // Even though the context was lost, we should have a resource. The
-      // TestWebGraphicsContext3D ensures that this resource is created with
-      // the active context.
-      EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
-    } else {
-      FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(
-          host_impl->active_tree()->root_layer()->children()[0]);
-      EXPECT_TRUE(picture_impl->HighResTiling()
-                      ->TileAt(0, 0)
-                      ->draw_info()
-                      .IsReadyToDraw());
-    }
+    FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(
+        host_impl->active_tree()->root_layer()->children()[0]);
+    EXPECT_TRUE(picture_impl->HighResTiling()
+                    ->TileAt(0, 0)
+                    ->draw_info()
+                    .IsReadyToDraw());
   }
 
  protected:
@@ -600,8 +586,8 @@
   scoped_refptr<Layer> layer_;
 };
 
-// This test uses TiledLayer and PictureLayer to check for a working context.
-SINGLE_AND_MULTI_THREAD_TEST_F(
+// This test uses PictureLayer to check for a working context.
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(
     LayerTreeHostContextTestLostContextSucceedsWithContent);
 
 class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
@@ -646,15 +632,10 @@
     paint.setColor(SkColorSetARGB(100, 80, 200, 200));
     client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint);
 
-    if (layer_tree_host()->settings().impl_side_painting) {
-      picture_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
-      picture_layer_->SetBounds(gfx::Size(10, 20));
-      layer_tree_host()->SetRootLayer(picture_layer_);
-    } else {
-      content_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
-      content_layer_->SetBounds(gfx::Size(10, 20));
-      layer_tree_host()->SetRootLayer(content_layer_);
-    }
+    scoped_refptr<FakePictureLayer> picture_layer =
+        FakePictureLayer::Create(layer_settings(), &client_);
+    picture_layer->SetBounds(gfx::Size(10, 20));
+    layer_tree_host()->SetRootLayer(picture_layer);
 
     LayerTreeHostContextTest::SetupTree();
   }
@@ -686,9 +667,6 @@
   void DidCommitAndDrawFrame() override {
     if (num_commits_ > 1)
       return;
-    if (!layer_tree_host()->settings().impl_side_painting) {
-      EXPECT_TRUE(content_layer_->HaveBackingAt(0, 0));
-    }
     PostEvictTextures();
   }
 
@@ -704,18 +682,12 @@
   }
 
   void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
-    if (impl->settings().impl_side_painting) {
-      FakePictureLayerImpl* picture_impl =
-          static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
-      EXPECT_TRUE(picture_impl->HighResTiling()
-                      ->TileAt(0, 0)
-                      ->draw_info()
-                      .IsReadyToDraw());
-    } else {
-      FakeContentLayerImpl* content_impl =
-          static_cast<FakeContentLayerImpl*>(impl->active_tree()->root_layer());
-      EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
-    }
+    FakePictureLayerImpl* picture_impl =
+        static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
+    EXPECT_TRUE(picture_impl->HighResTiling()
+                    ->TileAt(0, 0)
+                    ->draw_info()
+                    .IsReadyToDraw());
 
     impl_host_ = impl;
     if (lost_context_)
@@ -729,8 +701,6 @@
  protected:
   bool lose_after_evict_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> content_layer_;
-  scoped_refptr<FakePictureLayer> picture_layer_;
   LayerTreeHostImpl* impl_host_;
   int num_commits_;
   bool lost_context_;
@@ -739,30 +709,23 @@
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseAfterEvict_SingleThread_DirectRenderer) {
   lose_after_evict_ = true;
-  RunTest(false, false, false);
+  RunTest(false, false, true);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseAfterEvict_SingleThread_DelegatingRenderer) {
   lose_after_evict_ = true;
-  RunTest(false, true, false);
+  RunTest(false, true, true);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
-       LoseAfterEvict_MultiThread_DirectRenderer_MainThreadPaint) {
+       LoseAfterEvict_MultiThread_DirectRenderer) {
   lose_after_evict_ = true;
-  RunTest(true, false, false);
+  RunTest(true, false, true);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
-       LoseAfterEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
-  lose_after_evict_ = true;
-  RunTest(true, true, false);
-}
-
-// Flaky on all platforms, http://crbug.com/310979
-TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
-       DISABLED_LoseAfterEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
+       LoseAfterEvict_MultiThread_DelegatingRenderer) {
   lose_after_evict_ = true;
   RunTest(true, true, true);
 }
@@ -770,112 +733,36 @@
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseBeforeEvict_SingleThread_DirectRenderer) {
   lose_after_evict_ = false;
-  RunTest(false, false, false);
+  RunTest(false, false, true);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
        LoseBeforeEvict_SingleThread_DelegatingRenderer) {
   lose_after_evict_ = false;
-  RunTest(false, true, false);
+  RunTest(false, true, true);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
-       LoseBeforeEvict_MultiThread_DirectRenderer_MainThreadPaint) {
-  lose_after_evict_ = false;
-  RunTest(true, false, false);
-}
-
-TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
-       LoseBeforeEvict_MultiThread_DirectRenderer_ImplSidePaint) {
+       LoseBeforeEvict_MultiThread_DirectRenderer) {
   lose_after_evict_ = false;
   RunTest(true, false, true);
 }
 
 TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
-       LoseBeforeEvict_MultiThread_DelegatingRenderer_MainThreadPaint) {
-  lose_after_evict_ = false;
-  RunTest(true, true, false);
-}
-
-TEST_F(LayerTreeHostContextTestLostContextAndEvictTextures,
-       LoseBeforeEvict_MultiThread_DelegatingRenderer_ImplSidePaint) {
+       LoseBeforeEvict_MultiThread_DelegatingRenderer) {
   lose_after_evict_ = false;
   RunTest(true, true, true);
 }
 
-class LayerTreeHostContextTestLostContextWhileUpdatingResources
-    : public LayerTreeHostContextTest {
- public:
-  LayerTreeHostContextTestLostContextWhileUpdatingResources()
-      : num_children_(50), times_to_lose_on_end_query_(3) {}
-
-  scoped_ptr<TestWebGraphicsContext3D> CreateContext3d() override {
-    scoped_ptr<TestWebGraphicsContext3D> context =
-        LayerTreeHostContextTest::CreateContext3d();
-    if (times_to_lose_on_end_query_) {
-      --times_to_lose_on_end_query_;
-      context->set_times_end_query_succeeds(5);
-    }
-    return context.Pass();
-  }
-
-  void SetupTree() override {
-    if (layer_tree_host()->settings().impl_side_painting)
-      parent_ = FakePictureLayer::Create(layer_settings(), &client_);
-    else
-      parent_ = FakeContentLayer::Create(layer_settings(), &client_);
-
-    parent_->SetBounds(gfx::Size(num_children_, 1));
-
-    for (int i = 0; i < num_children_; i++) {
-      scoped_refptr<Layer> child;
-      if (layer_tree_host()->settings().impl_side_painting)
-        child = FakePictureLayer::Create(layer_settings(), &client_);
-      else
-        child = FakeContentLayer::Create(layer_settings(), &client_);
-      child->SetPosition(gfx::PointF(i, 0.f));
-      child->SetBounds(gfx::Size(1, 1));
-      parent_->AddChild(child);
-    }
-
-    layer_tree_host()->SetRootLayer(parent_);
-    LayerTreeHostContextTest::SetupTree();
-  }
-
-  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-
-  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
-    EXPECT_EQ(0, times_to_lose_on_end_query_);
-    EndTest();
-  }
-
-  void AfterTest() override { EXPECT_EQ(0, times_to_lose_on_end_query_); }
-
- private:
-  FakeContentLayerClient client_;
-  scoped_refptr<Layer> parent_;
-  int num_children_;
-  int times_to_lose_on_end_query_;
-};
-
-SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
-    LayerTreeHostContextTestLostContextWhileUpdatingResources);
-
 class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
  public:
   LayerTreeHostContextTestLayersNotified()
       : LayerTreeHostContextTest(), num_commits_(0) {}
 
   void SetupTree() override {
-    if (layer_tree_host()->settings().impl_side_painting) {
-      root_ = FakePictureLayer::Create(layer_settings(), &client_);
-      child_ = FakePictureLayer::Create(layer_settings(), &client_);
-      grandchild_ = FakePictureLayer::Create(layer_settings(), &client_);
-    } else {
-      root_ = FakeContentLayer::Create(layer_settings(), &client_);
-      child_ = FakeContentLayer::Create(layer_settings(), &client_);
-      grandchild_ = FakeContentLayer::Create(layer_settings(), &client_);
-    }
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
+    child_ = FakePictureLayer::Create(layer_settings(), &client_);
+    grandchild_ = FakePictureLayer::Create(layer_settings(), &client_);
 
     root_->AddChild(child_);
     child_->AddChild(grandchild_);
@@ -892,54 +779,29 @@
     FakePictureLayerImpl* root_picture = NULL;
     FakePictureLayerImpl* child_picture = NULL;
     FakePictureLayerImpl* grandchild_picture = NULL;
-    FakeContentLayerImpl* root_content = NULL;
-    FakeContentLayerImpl* child_content = NULL;
-    FakeContentLayerImpl* grandchild_content = NULL;
 
-    if (host_impl->settings().impl_side_painting) {
-      root_picture = static_cast<FakePictureLayerImpl*>(
-          host_impl->active_tree()->root_layer());
-      child_picture =
-          static_cast<FakePictureLayerImpl*>(root_picture->children()[0]);
-      grandchild_picture =
-          static_cast<FakePictureLayerImpl*>(child_picture->children()[0]);
-
-    } else {
-      root_content = static_cast<FakeContentLayerImpl*>(
-          host_impl->active_tree()->root_layer());
-      child_content =
-          static_cast<FakeContentLayerImpl*>(root_content->children()[0]);
-      grandchild_content =
-          static_cast<FakeContentLayerImpl*>(child_content->children()[0]);
-    }
+    root_picture = static_cast<FakePictureLayerImpl*>(
+        host_impl->active_tree()->root_layer());
+    child_picture =
+        static_cast<FakePictureLayerImpl*>(root_picture->children()[0]);
+    grandchild_picture =
+        static_cast<FakePictureLayerImpl*>(child_picture->children()[0]);
 
     ++num_commits_;
     switch (num_commits_) {
       case 1:
-        if (host_impl->settings().impl_side_painting) {
-          EXPECT_EQ(0u, root_picture->release_resources_count());
-          EXPECT_EQ(0u, child_picture->release_resources_count());
-          EXPECT_EQ(0u, grandchild_picture->release_resources_count());
-        } else {
-          EXPECT_EQ(0u, root_content->lost_output_surface_count());
-          EXPECT_EQ(0u, child_content->lost_output_surface_count());
-          EXPECT_EQ(0u, grandchild_content->lost_output_surface_count());
-        }
+        EXPECT_EQ(0u, root_picture->release_resources_count());
+        EXPECT_EQ(0u, child_picture->release_resources_count());
+        EXPECT_EQ(0u, grandchild_picture->release_resources_count());
 
         // Lose the context and struggle to recreate it.
         LoseContext();
         times_to_fail_create_ = 1;
         break;
       case 2:
-        if (host_impl->settings().impl_side_painting) {
-          EXPECT_TRUE(root_picture->release_resources_count());
-          EXPECT_TRUE(child_picture->release_resources_count());
-          EXPECT_TRUE(grandchild_picture->release_resources_count());
-        } else {
-          EXPECT_TRUE(root_content->lost_output_surface_count());
-          EXPECT_TRUE(child_content->lost_output_surface_count());
-          EXPECT_TRUE(grandchild_content->lost_output_surface_count());
-        }
+        EXPECT_TRUE(root_picture->release_resources_count());
+        EXPECT_TRUE(child_picture->release_resources_count());
+        EXPECT_TRUE(grandchild_picture->release_resources_count());
 
         EndTest();
         break;
@@ -1026,11 +888,8 @@
     delegated->SetIsDrawable(true);
     root->AddChild(delegated);
 
-    scoped_refptr<Layer> layer;
-    if (layer_tree_host()->settings().impl_side_painting)
-      layer = PictureLayer::Create(layer_settings(), &client_);
-    else
-      layer = ContentLayer::Create(layer_settings(), &client_);
+    scoped_refptr<PictureLayer> layer =
+        PictureLayer::Create(layer_settings(), &client_);
     layer->SetBounds(gfx::Size(10, 10));
     layer->SetIsDrawable(true);
     root->AddChild(layer);
@@ -1046,18 +905,12 @@
                             EmptyReleaseCallback)));
     root->AddChild(texture);
 
-    scoped_refptr<Layer> mask;
-    if (layer_tree_host()->settings().impl_side_painting)
-      mask = PictureLayer::Create(layer_settings_, &client_);
-    else
-      mask = ContentLayer::Create(layer_settings_, &client_);
+    scoped_refptr<PictureLayer> mask =
+        PictureLayer::Create(layer_settings_, &client_);
     mask->SetBounds(gfx::Size(10, 10));
 
-    scoped_refptr<Layer> layer_with_mask;
-    if (layer_tree_host()->settings().impl_side_painting)
-      layer_with_mask = PictureLayer::Create(layer_settings_, &client_);
-    else
-      layer_with_mask = ContentLayer::Create(layer_settings_, &client_);
+    scoped_refptr<PictureLayer> layer_with_mask =
+        PictureLayer::Create(layer_settings_, &client_);
     layer_with_mask->SetBounds(gfx::Size(10, 10));
     layer_with_mask->SetIsDrawable(true);
     layer_with_mask->SetMaskLayer(mask.get());
@@ -1084,15 +937,15 @@
     color_video_frame_ = VideoFrame::CreateColorFrame(
         gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
     hw_video_frame_ = VideoFrame::WrapNativeTexture(
+        media::VideoFrame::ARGB,
         gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point),
         media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
-        gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta(),
-        false /* allow_overlay */, true /* has_alpha */);
+        gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta());
     scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
+        media::VideoFrame::ARGB,
         gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point),
         media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
-        gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta(),
-        false /* allow_overlay */, true /* has_alpha */);
+        gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta());
 
     color_frame_provider_.set_frame(color_video_frame_);
     hw_frame_provider_.set_frame(hw_video_frame_);
@@ -1199,16 +1052,8 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
 
-class ImplSidePaintingLayerTreeHostContextTest
-    : public LayerTreeHostContextTest {
- public:
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->impl_side_painting = true;
-  }
-};
-
 class LayerTreeHostContextTestImplSidePainting
-    : public ImplSidePaintingLayerTreeHostContextTest {
+    : public LayerTreeHostContextTest {
  public:
   void SetupTree() override {
     scoped_refptr<Layer> root = Layer::Create(layer_settings());
@@ -1238,7 +1083,7 @@
   FakeContentLayerClient client_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostContextTestImplSidePainting);
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostContextTestImplSidePainting);
 
 class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
  public:
@@ -1692,15 +1537,9 @@
       : LayerTreeHostContextTest() {}
 
   void SetupTree() override {
-    if (layer_tree_host()->settings().impl_side_painting) {
-      picture_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
-      picture_layer_->SetBounds(gfx::Size(10, 20));
-      layer_tree_host()->SetRootLayer(picture_layer_);
-    } else {
-      content_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
-      content_layer_->SetBounds(gfx::Size(10, 20));
-      layer_tree_host()->SetRootLayer(content_layer_);
-    }
+    picture_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
+    picture_layer_->SetBounds(gfx::Size(10, 20));
+    layer_tree_host()->SetRootLayer(picture_layer_);
 
     LayerTreeHostContextTest::SetupTree();
   }
@@ -1710,30 +1549,18 @@
   void DidCommit() override {
     switch (layer_tree_host()->source_frame_number()) {
       case 1:
-        if (layer_tree_host()->settings().impl_side_painting)
-          EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
-        else
-          EXPECT_EQ(1u, content_layer_->output_surface_created_count());
+        EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
         layer_tree_host()->SetNeedsCommit();
         break;
       case 2:
-        if (layer_tree_host()->settings().impl_side_painting)
-          EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
-        else
-          EXPECT_EQ(1u, content_layer_->output_surface_created_count());
+        EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
         layer_tree_host()->SetNeedsCommit();
         break;
       case 3:
-        if (layer_tree_host()->settings().impl_side_painting)
-          EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
-        else
-          EXPECT_EQ(1u, content_layer_->output_surface_created_count());
+        EXPECT_EQ(1u, picture_layer_->output_surface_created_count());
         break;
       case 4:
-        if (layer_tree_host()->settings().impl_side_painting)
-          EXPECT_EQ(2u, picture_layer_->output_surface_created_count());
-        else
-          EXPECT_EQ(2u, content_layer_->output_surface_created_count());
+        EXPECT_EQ(2u, picture_layer_->output_surface_created_count());
         layer_tree_host()->SetNeedsCommit();
         break;
     }
@@ -1760,7 +1587,6 @@
  protected:
   FakeContentLayerClient client_;
   scoped_refptr<FakePictureLayer> picture_layer_;
-  scoped_refptr<FakeContentLayer> content_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index c44eecc1..1064aac 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -112,9 +112,9 @@
       });
 }
 
-bool LayerTreeImpl::IsExternalFlingActive() const {
+bool LayerTreeImpl::IsExternalScrollActive() const {
   return root_layer_scroll_offset_delegate_ &&
-         root_layer_scroll_offset_delegate_->IsExternalFlingActive();
+         root_layer_scroll_offset_delegate_->IsExternalScrollActive();
 }
 
 void LayerTreeImpl::DidUpdateScrollOffset(int layer_id) {
@@ -1361,9 +1361,11 @@
     LayerImpl* layer,
     const Functor& func,
     FindClosestMatchingLayerDataForRecursion* data_for_recursion) {
-  for (int i = layer->children().size() - 1; i >= 0; --i) {
-    FindClosestMatchingLayer(
-        screen_space_point, layer->children()[i], func, data_for_recursion);
+  size_t children_size = layer->children().size();
+  for (size_t i = 0; i < children_size; ++i) {
+    size_t index = children_size - 1 - i;
+    FindClosestMatchingLayer(screen_space_point, layer->children()[index], func,
+                             data_for_recursion);
   }
 
   float distance_to_intersection = 0.f;
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 01c8c1b..7a97f01 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -343,7 +343,7 @@
 
   void GatherFrameTimingRequestIds(std::vector<int64_t>* request_ids);
 
-  bool IsExternalFlingActive() const;
+  bool IsExternalScrollActive() const;
   void DidUpdateScrollOffset(int layer_id);
 
  protected:
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index b7b645e2..80e356e0 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -75,7 +75,7 @@
       verify_property_trees(false),
       gather_pixel_refs(false),
       use_compositor_animation_timelines(false),
-      max_bytes_per_copy_operation(std::numeric_limits<int>::max()) {
+      invert_viewport_scroll_order(false) {
 }
 
 LayerTreeSettings::~LayerTreeSettings() {}
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 8ae544e..a38e58c 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -90,7 +90,7 @@
   bool verify_property_trees;
   bool gather_pixel_refs;
   bool use_compositor_animation_timelines;
-  int max_bytes_per_copy_operation;
+  bool invert_viewport_scroll_order;
 
   LayerTreeDebugState initial_debug_state;
 
diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc
index 0f0ce158..d11a813 100644
--- a/cc/trees/occlusion_tracker.cc
+++ b/cc/trees/occlusion_tracker.cc
@@ -213,7 +213,7 @@
   if (!copy_outside_occlusion_forward)
     return;
 
-  int last_index = stack_.size() - 1;
+  size_t last_index = stack_.size() - 1;
   gfx::Transform old_target_to_new_target_transform(
       inverse_new_target_screen_space_transform,
       old_target->render_surface()->screen_space_transform());
@@ -318,7 +318,8 @@
 template <typename LayerType>
 void OcclusionTracker<LayerType>::LeaveToRenderTarget(
     const LayerType* new_target) {
-  int last_index = stack_.size() - 1;
+  DCHECK(!stack_.empty());
+  size_t last_index = stack_.size() - 1;
   bool surface_will_be_at_top_after_pop =
       stack_.size() > 1 && stack_[last_index - 1].target == new_target;
 
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index e155ee7..e85eadbc 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -239,8 +239,10 @@
         SkDoubleToMScalar(1e-4)));
   }
 
-  for (int i = source_to_destination.size() - 1; i >= 0; i--) {
-    const TransformNode* node = Node(source_to_destination[i]);
+  size_t source_to_destination_size = source_to_destination.size();
+  for (size_t i = 0; i < source_to_destination_size; ++i) {
+    size_t index = source_to_destination_size - 1 - i;
+    const TransformNode* node = Node(source_to_destination[index]);
     if (node->data.flattens_inherited_transform)
       combined_transform.FlattenTo2d();
     combined_transform.PreconcatTransform(node->data.to_parent);
diff --git a/cc/trees/tree_synchronizer.cc b/cc/trees/tree_synchronizer.cc
index 8fe23077..3646dcaa 100644
--- a/cc/trees/tree_synchronizer.cc
+++ b/cc/trees/tree_synchronizer.cc
@@ -188,7 +188,7 @@
 void TreeSynchronizer::PushPropertiesInternal(
     LayerType* layer,
     LayerImpl* layer_impl,
-    size_t* num_dependents_need_push_properties_for_parent) {
+    int* num_dependents_need_push_properties_for_parent) {
   if (!layer) {
     DCHECK(!layer_impl);
     return;
@@ -205,7 +205,7 @@
   else if (layer->ToScrollbarLayer())
     layer->ToScrollbarLayer()->PushScrollClipPropertiesTo(layer_impl);
 
-  size_t num_dependents_need_push_properties = 0;
+  int num_dependents_need_push_properties = 0;
   if (recurse_on_children_and_dependents) {
     PushPropertiesInternal(layer->mask_layer(),
                            layer_impl->mask_layer(),
@@ -295,7 +295,7 @@
 
 void TreeSynchronizer::PushProperties(Layer* layer,
                                       LayerImpl* layer_impl) {
-  size_t num_dependents_need_push_properties = 0;
+  int num_dependents_need_push_properties = 0;
   PushPropertiesInternal(
       layer, layer_impl, &num_dependents_need_push_properties);
 #if DCHECK_IS_ON()
@@ -304,7 +304,7 @@
 }
 
 void TreeSynchronizer::PushProperties(LayerImpl* layer, LayerImpl* layer_impl) {
-  size_t num_dependents_need_push_properties = 0;
+  int num_dependents_need_push_properties = 0;
   PushPropertiesInternal(
       layer, layer_impl, &num_dependents_need_push_properties);
 }
diff --git a/cc/trees/tree_synchronizer.h b/cc/trees/tree_synchronizer.h
index e7b2e2bd..ef13b1d 100644
--- a/cc/trees/tree_synchronizer.h
+++ b/cc/trees/tree_synchronizer.h
@@ -42,7 +42,7 @@
   static void PushPropertiesInternal(
       LayerType* layer,
       LayerImpl* layer_impl,
-      size_t* num_dependents_need_push_properties_for_parent);
+      int* num_dependents_need_push_properties_for_parent);
 
   DISALLOW_COPY_AND_ASSIGN(TreeSynchronizer);
 };
diff --git a/chrome/VERSION b/chrome/VERSION
index 1f0c08d..c256d29 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=45
 MINOR=0
-BUILD=2427
+BUILD=2431
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 055e8ed..51afa6b 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -568,8 +568,8 @@
   interface_file =
       "java_staging/src/org/chromium/chrome/browser/customtabs/common.aidl"
   sources = [
-    "java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionCallback.aidl",
-    "java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionService.aidl",
+    "java_staging/src/org/chromium/chrome/browser/customtabs/ICustomTabsConnectionCallback.aidl",
+    "java_staging/src/org/chromium/chrome/browser/customtabs/ICustomTabsConnectionService.aidl",
   ]
 }
 
@@ -750,7 +750,11 @@
 jinja_template("chrome_public_apk_manifest") {
   input = "java_staging/AndroidManifest.xml"
   output = "$root_gen_dir/chrome_public_apk_manifest/AndroidManifest.xml"
-  variables = jinja_variables + [ "min_sdk_version=16" ]
+  variables = jinja_variables
+  variables += [
+    "min_sdk_version=16",
+    "target_sdk_version=22",
+  ]
 }
 
 # GYP: //chrome/android/chrome_apk.gyp:chrome_public_template_resources
diff --git a/chrome/android/chrome_apk.gyp b/chrome/android/chrome_apk.gyp
index 5a4b5f7..d504b57 100644
--- a/chrome/android/chrome_apk.gyp
+++ b/chrome/android/chrome_apk.gyp
@@ -198,8 +198,8 @@
         'aidl_import_include': '<(chrome_java_dir)/src/org/chromium/chrome/browser/customtabs',
       },
       'sources': [
-        '<(chrome_java_dir)/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionCallback.aidl',
-        '<(chrome_java_dir)/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionService.aidl',
+        '<(chrome_java_dir)/src/org/chromium/chrome/browser/customtabs/ICustomTabsConnectionCallback.aidl',
+        '<(chrome_java_dir)/src/org/chromium/chrome/browser/customtabs/ICustomTabsConnectionService.aidl',
       ],
       'includes': [ '../../build/java_aidl.gypi' ],
     },
@@ -281,6 +281,7 @@
           'configuration_policy=<(configuration_policy)',
           'manifest_package=<(manifest_package)',
           'min_sdk_version=16',
+          'target_sdk_version=22',
         ],
       },
       'includes': [ '../../build/android/jinja_template.gypi' ],
@@ -392,6 +393,8 @@
       'dependencies': [
         'chrome_shared_test_java',
         'chrome_public_apk_java',
+        '<(DEPTH)/testing/android/on_device_instrumentation.gyp:broker_java',
+        '<(DEPTH)/testing/android/on_device_instrumentation.gyp:require_driver_apk',
       ],
       'variables': {
         'android_manifest_path': '<(chrome_public_test_apk_manifest)',
diff --git a/chrome/android/java/res/color/edit_text_tint.xml b/chrome/android/java/res/color/edit_text_tint.xml
deleted file mode 100644
index 228f36b..0000000
--- a/chrome/android/java/res/color/edit_text_tint.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2014 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="true" android:state_focused="true"
-          android:color="@color/pref_accent_color"/>
-    <item android:state_enabled="true" android:state_activated="true"
-          android:color="@color/pref_accent_color"/>
-    <item android:state_enabled="false"
-          android:alpha="@dimen/disabled_alpha_material_dark"
-          android:color="@color/default_text_color" />
-    <item android:color="@color/input_underline_color" />
-</selector>
\ No newline at end of file
diff --git a/chrome/android/java_staging/res/drawable-hdpi/audio_playing.png b/chrome/android/java/res/drawable-hdpi/audio_playing.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/audio_playing.png
rename to chrome/android/java/res/drawable-hdpi/audio_playing.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/bg_find_toolbar_popup.9.png b/chrome/android/java/res/drawable-hdpi/bg_find_toolbar_popup.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/bg_find_toolbar_popup.9.png
rename to chrome/android/java/res/drawable-hdpi/bg_find_toolbar_popup.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/bg_tabstrip_background_tab.9.png b/chrome/android/java/res/drawable-hdpi/bg_tabstrip_background_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/bg_tabstrip_background_tab.9.png
rename to chrome/android/java/res/drawable-hdpi/bg_tabstrip_background_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/bg_tabstrip_incognito_background_tab.9.png b/chrome/android/java/res/drawable-hdpi/bg_tabstrip_incognito_background_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/bg_tabstrip_incognito_background_tab.9.png
rename to chrome/android/java/res/drawable-hdpi/bg_tabstrip_incognito_background_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/bg_tabstrip_incognito_tab.9.png b/chrome/android/java/res/drawable-hdpi/bg_tabstrip_incognito_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/bg_tabstrip_incognito_tab.9.png
rename to chrome/android/java/res/drawable-hdpi/bg_tabstrip_incognito_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/bg_tabstrip_tab.9.png b/chrome/android/java/res/drawable-hdpi/bg_tabstrip_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/bg_tabstrip_tab.9.png
rename to chrome/android/java/res/drawable-hdpi/bg_tabstrip_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/blue_google_icon.png b/chrome/android/java/res/drawable-hdpi/blue_google_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/blue_google_icon.png
rename to chrome/android/java/res/drawable-hdpi/blue_google_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/bookmarks_widget_thumb_selector_pressed.9.png b/chrome/android/java/res/drawable-hdpi/bookmarks_widget_thumb_selector_pressed.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/bookmarks_widget_thumb_selector_pressed.9.png
rename to chrome/android/java/res/drawable-hdpi/bookmarks_widget_thumb_selector_pressed.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/border_thumb_bookmarks_widget_holo.9.png b/chrome/android/java/res/drawable-hdpi/border_thumb_bookmarks_widget_holo.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/border_thumb_bookmarks_widget_holo.9.png
rename to chrome/android/java/res/drawable-hdpi/border_thumb_bookmarks_widget_holo.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/breadcrumb_arrow.png b/chrome/android/java/res/drawable-hdpi/breadcrumb_arrow.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/breadcrumb_arrow.png
rename to chrome/android/java/res/drawable-hdpi/breadcrumb_arrow.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/browser_thumbnail.png b/chrome/android/java/res/drawable-hdpi/browser_thumbnail.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/browser_thumbnail.png
rename to chrome/android/java/res/drawable-hdpi/browser_thumbnail.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_chevron_left.png b/chrome/android/java/res/drawable-hdpi/btn_chevron_left.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_chevron_left.png
rename to chrome/android/java/res/drawable-hdpi/btn_chevron_left.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_delete_url.png b/chrome/android/java/res/drawable-hdpi/btn_delete_url.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_delete_url.png
rename to chrome/android/java/res/drawable-hdpi/btn_delete_url.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_mic.png b/chrome/android/java/res/drawable-hdpi/btn_mic.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_mic.png
rename to chrome/android/java/res/drawable-hdpi/btn_mic.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_new_tab_incognito_normal.png b/chrome/android/java/res/drawable-hdpi/btn_new_tab_incognito_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_new_tab_incognito_normal.png
rename to chrome/android/java/res/drawable-hdpi/btn_new_tab_incognito_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_new_tab_incognito_pressed.png b/chrome/android/java/res/drawable-hdpi/btn_new_tab_incognito_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_new_tab_incognito_pressed.png
rename to chrome/android/java/res/drawable-hdpi/btn_new_tab_incognito_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_new_tab_white_normal.png b/chrome/android/java/res/drawable-hdpi/btn_new_tab_white_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_new_tab_white_normal.png
rename to chrome/android/java/res/drawable-hdpi/btn_new_tab_white_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_new_tab_white_pressed.png b/chrome/android/java/res/drawable-hdpi/btn_new_tab_white_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_new_tab_white_pressed.png
rename to chrome/android/java/res/drawable-hdpi/btn_new_tab_white_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_recents.png b/chrome/android/java/res/drawable-hdpi/btn_recents.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_recents.png
rename to chrome/android/java/res/drawable-hdpi/btn_recents.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_suggestion_refine.png b/chrome/android/java/res/drawable-hdpi/btn_suggestion_refine.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_suggestion_refine.png
rename to chrome/android/java/res/drawable-hdpi/btn_suggestion_refine.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_tab_close_normal.png b/chrome/android/java/res/drawable-hdpi/btn_tab_close_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_tab_close_normal.png
rename to chrome/android/java/res/drawable-hdpi/btn_tab_close_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_tab_close_pressed.png b/chrome/android/java/res/drawable-hdpi/btn_tab_close_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_tab_close_pressed.png
rename to chrome/android/java/res/drawable-hdpi/btn_tab_close_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_tab_close_white_normal.png b/chrome/android/java/res/drawable-hdpi/btn_tab_close_white_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_tab_close_white_normal.png
rename to chrome/android/java/res/drawable-hdpi/btn_tab_close_white_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_tab_close_white_pressed.png b/chrome/android/java/res/drawable-hdpi/btn_tab_close_white_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_tab_close_white_pressed.png
rename to chrome/android/java/res/drawable-hdpi/btn_tab_close_white_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_new_incognito_tab_normal.png b/chrome/android/java/res/drawable-hdpi/btn_tabstrip_new_incognito_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_new_incognito_tab_normal.png
rename to chrome/android/java/res/drawable-hdpi/btn_tabstrip_new_incognito_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_new_incognito_tab_pressed.png b/chrome/android/java/res/drawable-hdpi/btn_tabstrip_new_incognito_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_new_incognito_tab_pressed.png
rename to chrome/android/java/res/drawable-hdpi/btn_tabstrip_new_incognito_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_new_tab_normal.png b/chrome/android/java/res/drawable-hdpi/btn_tabstrip_new_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_new_tab_normal.png
rename to chrome/android/java/res/drawable-hdpi/btn_tabstrip_new_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_new_tab_pressed.png b/chrome/android/java/res/drawable-hdpi/btn_tabstrip_new_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_new_tab_pressed.png
rename to chrome/android/java/res/drawable-hdpi/btn_tabstrip_new_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_switch_incognito.png b/chrome/android/java/res/drawable-hdpi/btn_tabstrip_switch_incognito.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_switch_incognito.png
rename to chrome/android/java/res/drawable-hdpi/btn_tabstrip_switch_incognito.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_switch_normal.png b/chrome/android/java/res/drawable-hdpi/btn_tabstrip_switch_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_tabstrip_switch_normal.png
rename to chrome/android/java/res/drawable-hdpi/btn_tabstrip_switch_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/btn_toolbar_home.png b/chrome/android/java/res/drawable-hdpi/btn_toolbar_home.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/btn_toolbar_home.png
rename to chrome/android/java/res/drawable-hdpi/btn_toolbar_home.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/contextual_search_bar_background.9.png b/chrome/android/java/res/drawable-hdpi/contextual_search_bar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/contextual_search_bar_background.9.png
rename to chrome/android/java/res/drawable-hdpi/contextual_search_bar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/contextual_search_bar_shadow.png b/chrome/android/java/res/drawable-hdpi/contextual_search_bar_shadow.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/contextual_search_bar_shadow.png
rename to chrome/android/java/res/drawable-hdpi/contextual_search_bar_shadow.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/default_favicon.png b/chrome/android/java/res/drawable-hdpi/default_favicon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/default_favicon.png
rename to chrome/android/java/res/drawable-hdpi/default_favicon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/default_favicon_white.png b/chrome/android/java/res/drawable-hdpi/default_favicon_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/default_favicon_white.png
rename to chrome/android/java/res/drawable-hdpi/default_favicon_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_add_folder.png b/chrome/android/java/res/drawable-hdpi/eb_add_folder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_add_folder.png
rename to chrome/android/java/res/drawable-hdpi/eb_add_folder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_back_normal.png b/chrome/android/java/res/drawable-hdpi/eb_back_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_back_normal.png
rename to chrome/android/java/res/drawable-hdpi/eb_back_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_bookmarks_bar.png b/chrome/android/java/res/drawable-hdpi/eb_bookmarks_bar.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_bookmarks_bar.png
rename to chrome/android/java/res/drawable-hdpi/eb_bookmarks_bar.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_cancel_active.png b/chrome/android/java/res/drawable-hdpi/eb_cancel_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_cancel_active.png
rename to chrome/android/java/res/drawable-hdpi/eb_cancel_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_check_blue.png b/chrome/android/java/res/drawable-hdpi/eb_check_blue.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_check_blue.png
rename to chrome/android/java/res/drawable-hdpi/eb_check_blue.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_check_gray.png b/chrome/android/java/res/drawable-hdpi/eb_check_gray.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_check_gray.png
rename to chrome/android/java/res/drawable-hdpi/eb_check_gray.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_check_white.png b/chrome/android/java/res/drawable-hdpi/eb_check_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_check_white.png
rename to chrome/android/java/res/drawable-hdpi/eb_check_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_delete_white.png b/chrome/android/java/res/drawable-hdpi/eb_delete_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_delete_white.png
rename to chrome/android/java/res/drawable-hdpi/eb_delete_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_edit_active.png b/chrome/android/java/res/drawable-hdpi/eb_edit_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_edit_active.png
rename to chrome/android/java/res/drawable-hdpi/eb_edit_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_edit_normal.png b/chrome/android/java/res/drawable-hdpi/eb_edit_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_edit_normal.png
rename to chrome/android/java/res/drawable-hdpi/eb_edit_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_folder.png b/chrome/android/java/res/drawable-hdpi/eb_folder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_folder.png
rename to chrome/android/java/res/drawable-hdpi/eb_folder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_grid_icon.png b/chrome/android/java/res/drawable-hdpi/eb_grid_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_grid_icon.png
rename to chrome/android/java/res/drawable-hdpi/eb_grid_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_item_more.png b/chrome/android/java/res/drawable-hdpi/eb_item_more.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_item_more.png
rename to chrome/android/java/res/drawable-hdpi/eb_item_more.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_item_tile.9.png b/chrome/android/java/res/drawable-hdpi/eb_item_tile.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_item_tile.9.png
rename to chrome/android/java/res/drawable-hdpi/eb_item_tile.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_list_icon.png b/chrome/android/java/res/drawable-hdpi/eb_list_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_list_icon.png
rename to chrome/android/java/res/drawable-hdpi/eb_list_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_logo_large.png b/chrome/android/java/res/drawable-hdpi/eb_logo_large.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_logo_large.png
rename to chrome/android/java/res/drawable-hdpi/eb_logo_large.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_managed.png b/chrome/android/java/res/drawable-hdpi/eb_managed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_managed.png
rename to chrome/android/java/res/drawable-hdpi/eb_managed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_mobile.png b/chrome/android/java/res/drawable-hdpi/eb_mobile.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_mobile.png
rename to chrome/android/java/res/drawable-hdpi/eb_mobile.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_move_active.png b/chrome/android/java/res/drawable-hdpi/eb_move_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_move_active.png
rename to chrome/android/java/res/drawable-hdpi/eb_move_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/eb_others.png b/chrome/android/java/res/drawable-hdpi/eb_others.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/eb_others.png
rename to chrome/android/java/res/drawable-hdpi/eb_others.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/google_logo.png b/chrome/android/java/res/drawable-hdpi/google_logo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/google_logo.png
rename to chrome/android/java/res/drawable-hdpi/google_logo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/history_favicon.png b/chrome/android/java/res/drawable-hdpi/history_favicon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/history_favicon.png
rename to chrome/android/java/res/drawable-hdpi/history_favicon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/ic_bookmark_widget_bookmark_holo_dark.png b/chrome/android/java/res/drawable-hdpi/ic_bookmark_widget_bookmark_holo_dark.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/ic_bookmark_widget_bookmark_holo_dark.png
rename to chrome/android/java/res/drawable-hdpi/ic_bookmark_widget_bookmark_holo_dark.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/ic_most_visited_placeholder.png b/chrome/android/java/res/drawable-hdpi/ic_most_visited_placeholder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/ic_most_visited_placeholder.png
rename to chrome/android/java/res/drawable-hdpi/ic_most_visited_placeholder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-hdpi/ic_omnibox_incognito_badge.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/ic_omnibox_incognito_badge.png
rename to chrome/android/java/res/drawable-hdpi/ic_omnibox_incognito_badge.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/ic_omnibox_magnifier.png b/chrome/android/java/res/drawable-hdpi/ic_omnibox_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/ic_omnibox_magnifier.png
rename to chrome/android/java/res/drawable-hdpi/ic_omnibox_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/ic_omnibox_page.png b/chrome/android/java/res/drawable-hdpi/ic_omnibox_page.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/ic_omnibox_page.png
rename to chrome/android/java/res/drawable-hdpi/ic_omnibox_page.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/ic_suggestion_history.png b/chrome/android/java/res/drawable-hdpi/ic_suggestion_history.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/ic_suggestion_history.png
rename to chrome/android/java/res/drawable-hdpi/ic_suggestion_history.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/ic_suggestion_magnifier.png b/chrome/android/java/res/drawable-hdpi/ic_suggestion_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/ic_suggestion_magnifier.png
rename to chrome/android/java/res/drawable-hdpi/ic_suggestion_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/incognito_splash.png b/chrome/android/java/res/drawable-hdpi/incognito_splash.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/incognito_splash.png
rename to chrome/android/java/res/drawable-hdpi/incognito_splash.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/logo_card_back.png b/chrome/android/java/res/drawable-hdpi/logo_card_back.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/logo_card_back.png
rename to chrome/android/java/res/drawable-hdpi/logo_card_back.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/more_horiz.png b/chrome/android/java/res/drawable-hdpi/more_horiz.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/more_horiz.png
rename to chrome/android/java/res/drawable-hdpi/more_horiz.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/omnibox_https_invalid.png b/chrome/android/java/res/drawable-hdpi/omnibox_https_invalid.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/omnibox_https_invalid.png
rename to chrome/android/java/res/drawable-hdpi/omnibox_https_invalid.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/omnibox_https_valid.png b/chrome/android/java/res/drawable-hdpi/omnibox_https_valid.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/omnibox_https_valid.png
rename to chrome/android/java/res/drawable-hdpi/omnibox_https_valid.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/omnibox_https_valid_light.png b/chrome/android/java/res/drawable-hdpi/omnibox_https_valid_light.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/omnibox_https_valid_light.png
rename to chrome/android/java/res/drawable-hdpi/omnibox_https_valid_light.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/omnibox_https_warning.png b/chrome/android/java/res/drawable-hdpi/omnibox_https_warning.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/omnibox_https_warning.png
rename to chrome/android/java/res/drawable-hdpi/omnibox_https_warning.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/overlay_url_bookmark_widget_holo.9.png b/chrome/android/java/res/drawable-hdpi/overlay_url_bookmark_widget_holo.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/overlay_url_bookmark_widget_holo.9.png
rename to chrome/android/java/res/drawable-hdpi/overlay_url_bookmark_widget_holo.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/progress_bar_background.9.png b/chrome/android/java/res/drawable-hdpi/progress_bar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/progress_bar_background.9.png
rename to chrome/android/java/res/drawable-hdpi/progress_bar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/progress_bar_background_white.9.png b/chrome/android/java/res/drawable-hdpi/progress_bar_background_white.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/progress_bar_background_white.9.png
rename to chrome/android/java/res/drawable-hdpi/progress_bar_background_white.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/progress_bar_foreground.9.png b/chrome/android/java/res/drawable-hdpi/progress_bar_foreground.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/progress_bar_foreground.9.png
rename to chrome/android/java/res/drawable-hdpi/progress_bar_foreground.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/reader_mode_icon.png b/chrome/android/java/res/drawable-hdpi/reader_mode_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/reader_mode_icon.png
rename to chrome/android/java/res/drawable-hdpi/reader_mode_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/reader_mode_prefs_icon.png b/chrome/android/java/res/drawable-hdpi/reader_mode_prefs_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/reader_mode_prefs_icon.png
rename to chrome/android/java/res/drawable-hdpi/reader_mode_prefs_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/recent_laptop.png b/chrome/android/java/res/drawable-hdpi/recent_laptop.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/recent_laptop.png
rename to chrome/android/java/res/drawable-hdpi/recent_laptop.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/recent_phone.png b/chrome/android/java/res/drawable-hdpi/recent_phone.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/recent_phone.png
rename to chrome/android/java/res/drawable-hdpi/recent_phone.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/recent_recently_closed.png b/chrome/android/java/res/drawable-hdpi/recent_recently_closed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/recent_recently_closed.png
rename to chrome/android/java/res/drawable-hdpi/recent_recently_closed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/recent_tablet.png b/chrome/android/java/res/drawable-hdpi/recent_tablet.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/recent_tablet.png
rename to chrome/android/java/res/drawable-hdpi/recent_tablet.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/sad_tab.png b/chrome/android/java/res/drawable-hdpi/sad_tab.png
index 5e75f1c0..f339fac 100644
--- a/chrome/android/java/res/drawable-hdpi/sad_tab.png
+++ b/chrome/android/java/res/drawable-hdpi/sad_tab.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/tabswitcher_border_frame.9.png b/chrome/android/java/res/drawable-hdpi/tabswitcher_border_frame.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/tabswitcher_border_frame.9.png
rename to chrome/android/java/res/drawable-hdpi/tabswitcher_border_frame.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/tabswitcher_border_frame_decoration.9.png b/chrome/android/java/res/drawable-hdpi/tabswitcher_border_frame_decoration.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/tabswitcher_border_frame_decoration.9.png
rename to chrome/android/java/res/drawable-hdpi/tabswitcher_border_frame_decoration.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/tabswitcher_border_frame_incognito.9.png b/chrome/android/java/res/drawable-hdpi/tabswitcher_border_frame_incognito.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/tabswitcher_border_frame_incognito.9.png
rename to chrome/android/java/res/drawable-hdpi/tabswitcher_border_frame_incognito.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/tabswitcher_border_frame_shadow.9.png b/chrome/android/java/res/drawable-hdpi/tabswitcher_border_frame_shadow.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/tabswitcher_border_frame_shadow.9.png
rename to chrome/android/java/res/drawable-hdpi/tabswitcher_border_frame_shadow.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/textbox.9.png b/chrome/android/java/res/drawable-hdpi/textbox.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/textbox.9.png
rename to chrome/android/java/res/drawable-hdpi/textbox.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/thumb_bookmark_widget_folder_back_holo.png b/chrome/android/java/res/drawable-hdpi/thumb_bookmark_widget_folder_back_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/thumb_bookmark_widget_folder_back_holo.png
rename to chrome/android/java/res/drawable-hdpi/thumb_bookmark_widget_folder_back_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/thumb_bookmark_widget_folder_holo.png b/chrome/android/java/res/drawable-hdpi/thumb_bookmark_widget_folder_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/thumb_bookmark_widget_folder_holo.png
rename to chrome/android/java/res/drawable-hdpi/thumb_bookmark_widget_folder_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png b/chrome/android/java/res/drawable-hdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png
rename to chrome/android/java/res/drawable-hdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/toolbar_background.9.png b/chrome/android/java/res/drawable-hdpi/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/toolbar_background.9.png
rename to chrome/android/java/res/drawable-hdpi/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/toolbar_shadow_focused.png b/chrome/android/java/res/drawable-hdpi/toolbar_shadow_focused.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/toolbar_shadow_focused.png
rename to chrome/android/java/res/drawable-hdpi/toolbar_shadow_focused.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/toolbar_shadow_normal.png b/chrome/android/java/res/drawable-hdpi/toolbar_shadow_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/toolbar_shadow_normal.png
rename to chrome/android/java/res/drawable-hdpi/toolbar_shadow_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/webrtc_audio.png b/chrome/android/java/res/drawable-hdpi/webrtc_audio.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/webrtc_audio.png
rename to chrome/android/java/res/drawable-hdpi/webrtc_audio.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-hdpi/webrtc_video.png b/chrome/android/java/res/drawable-hdpi/webrtc_video.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-hdpi/webrtc_video.png
rename to chrome/android/java/res/drawable-hdpi/webrtc_video.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/btn_suggestion_refine.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/btn_suggestion_refine.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/btn_suggestion_refine.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/btn_suggestion_refine.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_incognito_tab_normal.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_tab_normal.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_tab_normal.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_tab_pressed.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_tab_pressed.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/btn_tabstrip_new_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_omnibox_incognito_badge.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/ic_omnibox_incognito_badge.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_omnibox_incognito_badge.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/ic_omnibox_magnifier.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_omnibox_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/ic_omnibox_magnifier.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_omnibox_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/ic_suggestion_magnifier.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_suggestion_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/ic_suggestion_magnifier.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/ic_suggestion_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/thumb_bookmark_widget_folder_back_holo.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/thumb_bookmark_widget_folder_back_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/thumb_bookmark_widget_folder_back_holo.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/thumb_bookmark_widget_folder_back_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/thumb_bookmark_widget_folder_holo.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/thumb_bookmark_widget_folder_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/thumb_bookmark_widget_folder_holo.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/thumb_bookmark_widget_folder_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/toolbar_background.9.png b/chrome/android/java/res/drawable-ldrtl-hdpi-v17/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-hdpi-v17/toolbar_background.9.png
rename to chrome/android/java/res/drawable-ldrtl-hdpi-v17/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/btn_suggestion_refine.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/btn_suggestion_refine.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/btn_suggestion_refine.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/btn_suggestion_refine.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_incognito_tab_normal.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_tab_normal.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_tab_normal.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_tab_pressed.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_tab_pressed.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/btn_tabstrip_new_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_omnibox_incognito_badge.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/ic_omnibox_incognito_badge.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_omnibox_incognito_badge.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/ic_omnibox_magnifier.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_omnibox_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/ic_omnibox_magnifier.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_omnibox_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/ic_suggestion_magnifier.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_suggestion_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/ic_suggestion_magnifier.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/ic_suggestion_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/thumb_bookmark_widget_folder_back_holo.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/thumb_bookmark_widget_folder_back_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/thumb_bookmark_widget_folder_back_holo.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/thumb_bookmark_widget_folder_back_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/thumb_bookmark_widget_folder_holo.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/thumb_bookmark_widget_folder_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/thumb_bookmark_widget_folder_holo.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/thumb_bookmark_widget_folder_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/toolbar_background.9.png b/chrome/android/java/res/drawable-ldrtl-mdpi-v17/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-mdpi-v17/toolbar_background.9.png
rename to chrome/android/java/res/drawable-ldrtl-mdpi-v17/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-sw600dp-tvdpi-v17/toolbar_background.9.png b/chrome/android/java/res/drawable-ldrtl-sw600dp-tvdpi-v17/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-sw600dp-tvdpi-v17/toolbar_background.9.png
rename to chrome/android/java/res/drawable-ldrtl-sw600dp-tvdpi-v17/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-sw600dp-xhdpi-v17/toolbar_background.9.png b/chrome/android/java/res/drawable-ldrtl-sw600dp-xhdpi-v17/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-sw600dp-xhdpi-v17/toolbar_background.9.png
rename to chrome/android/java/res/drawable-ldrtl-sw600dp-xhdpi-v17/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/btn_suggestion_refine.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/btn_suggestion_refine.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/btn_suggestion_refine.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/btn_suggestion_refine.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_tab_normal.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_tab_normal.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_tab_pressed.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_tab_pressed.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/btn_tabstrip_new_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_incognito_badge.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_incognito_badge.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_incognito_badge.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_magnifier.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_magnifier.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_omnibox_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/ic_suggestion_magnifier.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_suggestion_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/ic_suggestion_magnifier.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/ic_suggestion_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/thumb_bookmark_widget_folder_back_holo.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/thumb_bookmark_widget_folder_back_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/thumb_bookmark_widget_folder_back_holo.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/thumb_bookmark_widget_folder_back_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/thumb_bookmark_widget_folder_holo.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/thumb_bookmark_widget_folder_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/thumb_bookmark_widget_folder_holo.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/thumb_bookmark_widget_folder_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/toolbar_background.9.png b/chrome/android/java/res/drawable-ldrtl-xhdpi-v17/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xhdpi-v17/toolbar_background.9.png
rename to chrome/android/java/res/drawable-ldrtl-xhdpi-v17/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/btn_suggestion_refine.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/btn_suggestion_refine.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/btn_suggestion_refine.png
rename to chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/btn_suggestion_refine.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
rename to chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
rename to chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_tab_normal.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_tab_normal.png
rename to chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_tab_pressed.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_tab_pressed.png
rename to chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/btn_tabstrip_new_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_incognito_badge.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_incognito_badge.png
rename to chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_incognito_badge.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_magnifier.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_magnifier.png
rename to chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_omnibox_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/ic_suggestion_magnifier.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_suggestion_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/ic_suggestion_magnifier.png
rename to chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/ic_suggestion_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/toolbar_background.9.png b/chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxhdpi-v17/toolbar_background.9.png
rename to chrome/android/java/res/drawable-ldrtl-xxhdpi-v17/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/btn_suggestion_refine.png b/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/btn_suggestion_refine.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/btn_suggestion_refine.png
rename to chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/btn_suggestion_refine.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png b/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
rename to chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_incognito_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png b/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
rename to chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_incognito_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_tab_normal.png b/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_tab_normal.png
rename to chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_tab_pressed.png b/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_tab_pressed.png
rename to chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/btn_tabstrip_new_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_incognito_badge.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_incognito_badge.png
rename to chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_incognito_badge.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_magnifier.png b/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_magnifier.png
rename to chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_omnibox_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/ic_suggestion_magnifier.png b/chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_suggestion_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-ldrtl-xxxhdpi-v17/ic_suggestion_magnifier.png
rename to chrome/android/java/res/drawable-ldrtl-xxxhdpi-v17/ic_suggestion_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/audio_playing.png b/chrome/android/java/res/drawable-mdpi/audio_playing.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/audio_playing.png
rename to chrome/android/java/res/drawable-mdpi/audio_playing.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/bg_find_toolbar_popup.9.png b/chrome/android/java/res/drawable-mdpi/bg_find_toolbar_popup.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/bg_find_toolbar_popup.9.png
rename to chrome/android/java/res/drawable-mdpi/bg_find_toolbar_popup.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/bg_tabstrip_background_tab.9.png b/chrome/android/java/res/drawable-mdpi/bg_tabstrip_background_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/bg_tabstrip_background_tab.9.png
rename to chrome/android/java/res/drawable-mdpi/bg_tabstrip_background_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/bg_tabstrip_incognito_background_tab.9.png b/chrome/android/java/res/drawable-mdpi/bg_tabstrip_incognito_background_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/bg_tabstrip_incognito_background_tab.9.png
rename to chrome/android/java/res/drawable-mdpi/bg_tabstrip_incognito_background_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/bg_tabstrip_incognito_tab.9.png b/chrome/android/java/res/drawable-mdpi/bg_tabstrip_incognito_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/bg_tabstrip_incognito_tab.9.png
rename to chrome/android/java/res/drawable-mdpi/bg_tabstrip_incognito_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/bg_tabstrip_tab.9.png b/chrome/android/java/res/drawable-mdpi/bg_tabstrip_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/bg_tabstrip_tab.9.png
rename to chrome/android/java/res/drawable-mdpi/bg_tabstrip_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/blue_google_icon.png b/chrome/android/java/res/drawable-mdpi/blue_google_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/blue_google_icon.png
rename to chrome/android/java/res/drawable-mdpi/blue_google_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/bookmarks_widget_thumb_selector_pressed.9.png b/chrome/android/java/res/drawable-mdpi/bookmarks_widget_thumb_selector_pressed.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/bookmarks_widget_thumb_selector_pressed.9.png
rename to chrome/android/java/res/drawable-mdpi/bookmarks_widget_thumb_selector_pressed.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/border_thumb_bookmarks_widget_holo.9.png b/chrome/android/java/res/drawable-mdpi/border_thumb_bookmarks_widget_holo.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/border_thumb_bookmarks_widget_holo.9.png
rename to chrome/android/java/res/drawable-mdpi/border_thumb_bookmarks_widget_holo.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/breadcrumb_arrow.png b/chrome/android/java/res/drawable-mdpi/breadcrumb_arrow.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/breadcrumb_arrow.png
rename to chrome/android/java/res/drawable-mdpi/breadcrumb_arrow.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/browser_thumbnail.png b/chrome/android/java/res/drawable-mdpi/browser_thumbnail.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/browser_thumbnail.png
rename to chrome/android/java/res/drawable-mdpi/browser_thumbnail.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_chevron_left.png b/chrome/android/java/res/drawable-mdpi/btn_chevron_left.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_chevron_left.png
rename to chrome/android/java/res/drawable-mdpi/btn_chevron_left.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_delete_url.png b/chrome/android/java/res/drawable-mdpi/btn_delete_url.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_delete_url.png
rename to chrome/android/java/res/drawable-mdpi/btn_delete_url.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_mic.png b/chrome/android/java/res/drawable-mdpi/btn_mic.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_mic.png
rename to chrome/android/java/res/drawable-mdpi/btn_mic.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_new_tab_incognito_normal.png b/chrome/android/java/res/drawable-mdpi/btn_new_tab_incognito_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_new_tab_incognito_normal.png
rename to chrome/android/java/res/drawable-mdpi/btn_new_tab_incognito_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_new_tab_incognito_pressed.png b/chrome/android/java/res/drawable-mdpi/btn_new_tab_incognito_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_new_tab_incognito_pressed.png
rename to chrome/android/java/res/drawable-mdpi/btn_new_tab_incognito_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_new_tab_white_normal.png b/chrome/android/java/res/drawable-mdpi/btn_new_tab_white_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_new_tab_white_normal.png
rename to chrome/android/java/res/drawable-mdpi/btn_new_tab_white_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_new_tab_white_pressed.png b/chrome/android/java/res/drawable-mdpi/btn_new_tab_white_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_new_tab_white_pressed.png
rename to chrome/android/java/res/drawable-mdpi/btn_new_tab_white_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_recents.png b/chrome/android/java/res/drawable-mdpi/btn_recents.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_recents.png
rename to chrome/android/java/res/drawable-mdpi/btn_recents.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_suggestion_refine.png b/chrome/android/java/res/drawable-mdpi/btn_suggestion_refine.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_suggestion_refine.png
rename to chrome/android/java/res/drawable-mdpi/btn_suggestion_refine.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_tab_close_normal.png b/chrome/android/java/res/drawable-mdpi/btn_tab_close_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_tab_close_normal.png
rename to chrome/android/java/res/drawable-mdpi/btn_tab_close_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_tab_close_pressed.png b/chrome/android/java/res/drawable-mdpi/btn_tab_close_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_tab_close_pressed.png
rename to chrome/android/java/res/drawable-mdpi/btn_tab_close_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_tab_close_white_normal.png b/chrome/android/java/res/drawable-mdpi/btn_tab_close_white_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_tab_close_white_normal.png
rename to chrome/android/java/res/drawable-mdpi/btn_tab_close_white_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_tab_close_white_pressed.png b/chrome/android/java/res/drawable-mdpi/btn_tab_close_white_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_tab_close_white_pressed.png
rename to chrome/android/java/res/drawable-mdpi/btn_tab_close_white_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_new_incognito_tab_normal.png b/chrome/android/java/res/drawable-mdpi/btn_tabstrip_new_incognito_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_new_incognito_tab_normal.png
rename to chrome/android/java/res/drawable-mdpi/btn_tabstrip_new_incognito_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_new_incognito_tab_pressed.png b/chrome/android/java/res/drawable-mdpi/btn_tabstrip_new_incognito_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_new_incognito_tab_pressed.png
rename to chrome/android/java/res/drawable-mdpi/btn_tabstrip_new_incognito_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_new_tab_normal.png b/chrome/android/java/res/drawable-mdpi/btn_tabstrip_new_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_new_tab_normal.png
rename to chrome/android/java/res/drawable-mdpi/btn_tabstrip_new_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_new_tab_pressed.png b/chrome/android/java/res/drawable-mdpi/btn_tabstrip_new_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_new_tab_pressed.png
rename to chrome/android/java/res/drawable-mdpi/btn_tabstrip_new_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_switch_incognito.png b/chrome/android/java/res/drawable-mdpi/btn_tabstrip_switch_incognito.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_switch_incognito.png
rename to chrome/android/java/res/drawable-mdpi/btn_tabstrip_switch_incognito.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_switch_normal.png b/chrome/android/java/res/drawable-mdpi/btn_tabstrip_switch_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_tabstrip_switch_normal.png
rename to chrome/android/java/res/drawable-mdpi/btn_tabstrip_switch_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/btn_toolbar_home.png b/chrome/android/java/res/drawable-mdpi/btn_toolbar_home.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/btn_toolbar_home.png
rename to chrome/android/java/res/drawable-mdpi/btn_toolbar_home.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/contextual_search_bar_background.9.png b/chrome/android/java/res/drawable-mdpi/contextual_search_bar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/contextual_search_bar_background.9.png
rename to chrome/android/java/res/drawable-mdpi/contextual_search_bar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/contextual_search_bar_shadow.png b/chrome/android/java/res/drawable-mdpi/contextual_search_bar_shadow.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/contextual_search_bar_shadow.png
rename to chrome/android/java/res/drawable-mdpi/contextual_search_bar_shadow.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/default_favicon.png b/chrome/android/java/res/drawable-mdpi/default_favicon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/default_favicon.png
rename to chrome/android/java/res/drawable-mdpi/default_favicon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/default_favicon_white.png b/chrome/android/java/res/drawable-mdpi/default_favicon_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/default_favicon_white.png
rename to chrome/android/java/res/drawable-mdpi/default_favicon_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_add_folder.png b/chrome/android/java/res/drawable-mdpi/eb_add_folder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_add_folder.png
rename to chrome/android/java/res/drawable-mdpi/eb_add_folder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_back_normal.png b/chrome/android/java/res/drawable-mdpi/eb_back_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_back_normal.png
rename to chrome/android/java/res/drawable-mdpi/eb_back_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_bookmarks_bar.png b/chrome/android/java/res/drawable-mdpi/eb_bookmarks_bar.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_bookmarks_bar.png
rename to chrome/android/java/res/drawable-mdpi/eb_bookmarks_bar.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_cancel_active.png b/chrome/android/java/res/drawable-mdpi/eb_cancel_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_cancel_active.png
rename to chrome/android/java/res/drawable-mdpi/eb_cancel_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_check_blue.png b/chrome/android/java/res/drawable-mdpi/eb_check_blue.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_check_blue.png
rename to chrome/android/java/res/drawable-mdpi/eb_check_blue.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_check_gray.png b/chrome/android/java/res/drawable-mdpi/eb_check_gray.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_check_gray.png
rename to chrome/android/java/res/drawable-mdpi/eb_check_gray.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_check_white.png b/chrome/android/java/res/drawable-mdpi/eb_check_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_check_white.png
rename to chrome/android/java/res/drawable-mdpi/eb_check_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_delete_white.png b/chrome/android/java/res/drawable-mdpi/eb_delete_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_delete_white.png
rename to chrome/android/java/res/drawable-mdpi/eb_delete_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_edit_active.png b/chrome/android/java/res/drawable-mdpi/eb_edit_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_edit_active.png
rename to chrome/android/java/res/drawable-mdpi/eb_edit_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_edit_normal.png b/chrome/android/java/res/drawable-mdpi/eb_edit_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_edit_normal.png
rename to chrome/android/java/res/drawable-mdpi/eb_edit_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_folder.png b/chrome/android/java/res/drawable-mdpi/eb_folder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_folder.png
rename to chrome/android/java/res/drawable-mdpi/eb_folder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_grid_icon.png b/chrome/android/java/res/drawable-mdpi/eb_grid_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_grid_icon.png
rename to chrome/android/java/res/drawable-mdpi/eb_grid_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_item_more.png b/chrome/android/java/res/drawable-mdpi/eb_item_more.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_item_more.png
rename to chrome/android/java/res/drawable-mdpi/eb_item_more.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_item_tile.9.png b/chrome/android/java/res/drawable-mdpi/eb_item_tile.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_item_tile.9.png
rename to chrome/android/java/res/drawable-mdpi/eb_item_tile.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_list_icon.png b/chrome/android/java/res/drawable-mdpi/eb_list_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_list_icon.png
rename to chrome/android/java/res/drawable-mdpi/eb_list_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_logo_large.png b/chrome/android/java/res/drawable-mdpi/eb_logo_large.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_logo_large.png
rename to chrome/android/java/res/drawable-mdpi/eb_logo_large.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_managed.png b/chrome/android/java/res/drawable-mdpi/eb_managed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_managed.png
rename to chrome/android/java/res/drawable-mdpi/eb_managed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_mobile.png b/chrome/android/java/res/drawable-mdpi/eb_mobile.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_mobile.png
rename to chrome/android/java/res/drawable-mdpi/eb_mobile.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_move_active.png b/chrome/android/java/res/drawable-mdpi/eb_move_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_move_active.png
rename to chrome/android/java/res/drawable-mdpi/eb_move_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/eb_others.png b/chrome/android/java/res/drawable-mdpi/eb_others.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/eb_others.png
rename to chrome/android/java/res/drawable-mdpi/eb_others.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/google_logo.png b/chrome/android/java/res/drawable-mdpi/google_logo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/google_logo.png
rename to chrome/android/java/res/drawable-mdpi/google_logo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/history_favicon.png b/chrome/android/java/res/drawable-mdpi/history_favicon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/history_favicon.png
rename to chrome/android/java/res/drawable-mdpi/history_favicon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/ic_bookmark_widget_bookmark_holo_dark.png b/chrome/android/java/res/drawable-mdpi/ic_bookmark_widget_bookmark_holo_dark.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/ic_bookmark_widget_bookmark_holo_dark.png
rename to chrome/android/java/res/drawable-mdpi/ic_bookmark_widget_bookmark_holo_dark.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/ic_most_visited_placeholder.png b/chrome/android/java/res/drawable-mdpi/ic_most_visited_placeholder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/ic_most_visited_placeholder.png
rename to chrome/android/java/res/drawable-mdpi/ic_most_visited_placeholder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-mdpi/ic_omnibox_incognito_badge.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/ic_omnibox_incognito_badge.png
rename to chrome/android/java/res/drawable-mdpi/ic_omnibox_incognito_badge.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/ic_omnibox_magnifier.png b/chrome/android/java/res/drawable-mdpi/ic_omnibox_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/ic_omnibox_magnifier.png
rename to chrome/android/java/res/drawable-mdpi/ic_omnibox_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/ic_omnibox_page.png b/chrome/android/java/res/drawable-mdpi/ic_omnibox_page.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/ic_omnibox_page.png
rename to chrome/android/java/res/drawable-mdpi/ic_omnibox_page.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/ic_suggestion_history.png b/chrome/android/java/res/drawable-mdpi/ic_suggestion_history.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/ic_suggestion_history.png
rename to chrome/android/java/res/drawable-mdpi/ic_suggestion_history.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/ic_suggestion_magnifier.png b/chrome/android/java/res/drawable-mdpi/ic_suggestion_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/ic_suggestion_magnifier.png
rename to chrome/android/java/res/drawable-mdpi/ic_suggestion_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/incognito_splash.png b/chrome/android/java/res/drawable-mdpi/incognito_splash.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/incognito_splash.png
rename to chrome/android/java/res/drawable-mdpi/incognito_splash.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/logo_card_back.png b/chrome/android/java/res/drawable-mdpi/logo_card_back.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/logo_card_back.png
rename to chrome/android/java/res/drawable-mdpi/logo_card_back.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/more_horiz.png b/chrome/android/java/res/drawable-mdpi/more_horiz.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/more_horiz.png
rename to chrome/android/java/res/drawable-mdpi/more_horiz.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/omnibox_https_invalid.png b/chrome/android/java/res/drawable-mdpi/omnibox_https_invalid.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/omnibox_https_invalid.png
rename to chrome/android/java/res/drawable-mdpi/omnibox_https_invalid.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/omnibox_https_valid.png b/chrome/android/java/res/drawable-mdpi/omnibox_https_valid.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/omnibox_https_valid.png
rename to chrome/android/java/res/drawable-mdpi/omnibox_https_valid.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/omnibox_https_valid_light.png b/chrome/android/java/res/drawable-mdpi/omnibox_https_valid_light.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/omnibox_https_valid_light.png
rename to chrome/android/java/res/drawable-mdpi/omnibox_https_valid_light.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/omnibox_https_warning.png b/chrome/android/java/res/drawable-mdpi/omnibox_https_warning.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/omnibox_https_warning.png
rename to chrome/android/java/res/drawable-mdpi/omnibox_https_warning.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/overlay_url_bookmark_widget_holo.9.png b/chrome/android/java/res/drawable-mdpi/overlay_url_bookmark_widget_holo.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/overlay_url_bookmark_widget_holo.9.png
rename to chrome/android/java/res/drawable-mdpi/overlay_url_bookmark_widget_holo.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/progress_bar_background.9.png b/chrome/android/java/res/drawable-mdpi/progress_bar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/progress_bar_background.9.png
rename to chrome/android/java/res/drawable-mdpi/progress_bar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/progress_bar_background_white.9.png b/chrome/android/java/res/drawable-mdpi/progress_bar_background_white.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/progress_bar_background_white.9.png
rename to chrome/android/java/res/drawable-mdpi/progress_bar_background_white.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/progress_bar_foreground.9.png b/chrome/android/java/res/drawable-mdpi/progress_bar_foreground.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/progress_bar_foreground.9.png
rename to chrome/android/java/res/drawable-mdpi/progress_bar_foreground.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/reader_mode_icon.png b/chrome/android/java/res/drawable-mdpi/reader_mode_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/reader_mode_icon.png
rename to chrome/android/java/res/drawable-mdpi/reader_mode_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/reader_mode_prefs_icon.png b/chrome/android/java/res/drawable-mdpi/reader_mode_prefs_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/reader_mode_prefs_icon.png
rename to chrome/android/java/res/drawable-mdpi/reader_mode_prefs_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/recent_laptop.png b/chrome/android/java/res/drawable-mdpi/recent_laptop.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/recent_laptop.png
rename to chrome/android/java/res/drawable-mdpi/recent_laptop.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/recent_phone.png b/chrome/android/java/res/drawable-mdpi/recent_phone.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/recent_phone.png
rename to chrome/android/java/res/drawable-mdpi/recent_phone.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/recent_recently_closed.png b/chrome/android/java/res/drawable-mdpi/recent_recently_closed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/recent_recently_closed.png
rename to chrome/android/java/res/drawable-mdpi/recent_recently_closed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/recent_tablet.png b/chrome/android/java/res/drawable-mdpi/recent_tablet.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/recent_tablet.png
rename to chrome/android/java/res/drawable-mdpi/recent_tablet.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/sad_tab.png b/chrome/android/java/res/drawable-mdpi/sad_tab.png
index 304d3dc1..d9f17114 100644
--- a/chrome/android/java/res/drawable-mdpi/sad_tab.png
+++ b/chrome/android/java/res/drawable-mdpi/sad_tab.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/tabswitcher_border_frame.9.png b/chrome/android/java/res/drawable-mdpi/tabswitcher_border_frame.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/tabswitcher_border_frame.9.png
rename to chrome/android/java/res/drawable-mdpi/tabswitcher_border_frame.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/tabswitcher_border_frame_decoration.9.png b/chrome/android/java/res/drawable-mdpi/tabswitcher_border_frame_decoration.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/tabswitcher_border_frame_decoration.9.png
rename to chrome/android/java/res/drawable-mdpi/tabswitcher_border_frame_decoration.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/tabswitcher_border_frame_incognito.9.png b/chrome/android/java/res/drawable-mdpi/tabswitcher_border_frame_incognito.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/tabswitcher_border_frame_incognito.9.png
rename to chrome/android/java/res/drawable-mdpi/tabswitcher_border_frame_incognito.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/tabswitcher_border_frame_shadow.9.png b/chrome/android/java/res/drawable-mdpi/tabswitcher_border_frame_shadow.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/tabswitcher_border_frame_shadow.9.png
rename to chrome/android/java/res/drawable-mdpi/tabswitcher_border_frame_shadow.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/textbox.9.png b/chrome/android/java/res/drawable-mdpi/textbox.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/textbox.9.png
rename to chrome/android/java/res/drawable-mdpi/textbox.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/thumb_bookmark_widget_folder_back_holo.png b/chrome/android/java/res/drawable-mdpi/thumb_bookmark_widget_folder_back_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/thumb_bookmark_widget_folder_back_holo.png
rename to chrome/android/java/res/drawable-mdpi/thumb_bookmark_widget_folder_back_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/thumb_bookmark_widget_folder_holo.png b/chrome/android/java/res/drawable-mdpi/thumb_bookmark_widget_folder_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/thumb_bookmark_widget_folder_holo.png
rename to chrome/android/java/res/drawable-mdpi/thumb_bookmark_widget_folder_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png b/chrome/android/java/res/drawable-mdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png
rename to chrome/android/java/res/drawable-mdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/toolbar_background.9.png b/chrome/android/java/res/drawable-mdpi/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/toolbar_background.9.png
rename to chrome/android/java/res/drawable-mdpi/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/toolbar_shadow_focused.png b/chrome/android/java/res/drawable-mdpi/toolbar_shadow_focused.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/toolbar_shadow_focused.png
rename to chrome/android/java/res/drawable-mdpi/toolbar_shadow_focused.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/toolbar_shadow_normal.png b/chrome/android/java/res/drawable-mdpi/toolbar_shadow_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/toolbar_shadow_normal.png
rename to chrome/android/java/res/drawable-mdpi/toolbar_shadow_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/webrtc_audio.png b/chrome/android/java/res/drawable-mdpi/webrtc_audio.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/webrtc_audio.png
rename to chrome/android/java/res/drawable-mdpi/webrtc_audio.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-mdpi/webrtc_video.png b/chrome/android/java/res/drawable-mdpi/webrtc_video.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-mdpi/webrtc_video.png
rename to chrome/android/java/res/drawable-mdpi/webrtc_video.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-nodpi/bg_bookmarks_widget_holo.9.png b/chrome/android/java/res/drawable-nodpi/bg_bookmarks_widget_holo.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-nodpi/bg_bookmarks_widget_holo.9.png
rename to chrome/android/java/res/drawable-nodpi/bg_bookmarks_widget_holo.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-nodpi/bookmark_widget_preview.png b/chrome/android/java/res/drawable-nodpi/bookmark_widget_preview.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-nodpi/bookmark_widget_preview.png
rename to chrome/android/java/res/drawable-nodpi/bookmark_widget_preview.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-sw600dp-hdpi/google_logo.png b/chrome/android/java/res/drawable-sw600dp-hdpi/google_logo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw600dp-hdpi/google_logo.png
rename to chrome/android/java/res/drawable-sw600dp-hdpi/google_logo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-sw600dp-mdpi/google_logo.png b/chrome/android/java/res/drawable-sw600dp-mdpi/google_logo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw600dp-mdpi/google_logo.png
rename to chrome/android/java/res/drawable-sw600dp-mdpi/google_logo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-sw600dp-tvdpi/toolbar_background.9.png b/chrome/android/java/res/drawable-sw600dp-tvdpi/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw600dp-tvdpi/toolbar_background.9.png
rename to chrome/android/java/res/drawable-sw600dp-tvdpi/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-sw600dp-xhdpi/google_logo.png b/chrome/android/java/res/drawable-sw600dp-xhdpi/google_logo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw600dp-xhdpi/google_logo.png
rename to chrome/android/java/res/drawable-sw600dp-xhdpi/google_logo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-sw600dp-xhdpi/toolbar_background.9.png b/chrome/android/java/res/drawable-sw600dp-xhdpi/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw600dp-xhdpi/toolbar_background.9.png
rename to chrome/android/java/res/drawable-sw600dp-xhdpi/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-sw600dp-xxhdpi/google_logo.png b/chrome/android/java/res/drawable-sw600dp-xxhdpi/google_logo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw600dp-xxhdpi/google_logo.png
rename to chrome/android/java/res/drawable-sw600dp-xxhdpi/google_logo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-sw600dp-xxxhdpi/google_logo.png b/chrome/android/java/res/drawable-sw600dp-xxxhdpi/google_logo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw600dp-xxxhdpi/google_logo.png
rename to chrome/android/java/res/drawable-sw600dp-xxxhdpi/google_logo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-sw600dp/bg_white_dialog.xml b/chrome/android/java/res/drawable-sw600dp/bg_white_dialog.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw600dp/bg_white_dialog.xml
rename to chrome/android/java/res/drawable-sw600dp/bg_white_dialog.xml
diff --git a/chrome/android/java_staging/res/drawable-sw600dp/toolbar_shadow.xml b/chrome/android/java/res/drawable-sw600dp/toolbar_shadow.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw600dp/toolbar_shadow.xml
rename to chrome/android/java/res/drawable-sw600dp/toolbar_shadow.xml
diff --git a/chrome/android/java_staging/res/drawable-sw600dp/window_background.xml b/chrome/android/java/res/drawable-sw600dp/window_background.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw600dp/window_background.xml
rename to chrome/android/java/res/drawable-sw600dp/window_background.xml
diff --git a/chrome/android/java_staging/res/drawable-sw720dp-v19/window_background.xml b/chrome/android/java/res/drawable-sw720dp-v19/window_background.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw720dp-v19/window_background.xml
rename to chrome/android/java/res/drawable-sw720dp-v19/window_background.xml
diff --git a/chrome/android/java_staging/res/drawable-sw720dp/window_background.xml b/chrome/android/java/res/drawable-sw720dp/window_background.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable-sw720dp/window_background.xml
rename to chrome/android/java/res/drawable-sw720dp/window_background.xml
diff --git a/chrome/android/java_staging/res/drawable-xhdpi-v21/ic_vidcontrol_play.png b/chrome/android/java/res/drawable-xhdpi-v21/ic_vidcontrol_play.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi-v21/ic_vidcontrol_play.png
rename to chrome/android/java/res/drawable-xhdpi-v21/ic_vidcontrol_play.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/audio_playing.png b/chrome/android/java/res/drawable-xhdpi/audio_playing.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/audio_playing.png
rename to chrome/android/java/res/drawable-xhdpi/audio_playing.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/bg_find_toolbar_popup.9.png b/chrome/android/java/res/drawable-xhdpi/bg_find_toolbar_popup.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/bg_find_toolbar_popup.9.png
rename to chrome/android/java/res/drawable-xhdpi/bg_find_toolbar_popup.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/bg_tabstrip_background_tab.9.png b/chrome/android/java/res/drawable-xhdpi/bg_tabstrip_background_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/bg_tabstrip_background_tab.9.png
rename to chrome/android/java/res/drawable-xhdpi/bg_tabstrip_background_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/bg_tabstrip_incognito_background_tab.9.png b/chrome/android/java/res/drawable-xhdpi/bg_tabstrip_incognito_background_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/bg_tabstrip_incognito_background_tab.9.png
rename to chrome/android/java/res/drawable-xhdpi/bg_tabstrip_incognito_background_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/bg_tabstrip_incognito_tab.9.png b/chrome/android/java/res/drawable-xhdpi/bg_tabstrip_incognito_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/bg_tabstrip_incognito_tab.9.png
rename to chrome/android/java/res/drawable-xhdpi/bg_tabstrip_incognito_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/bg_tabstrip_tab.9.png b/chrome/android/java/res/drawable-xhdpi/bg_tabstrip_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/bg_tabstrip_tab.9.png
rename to chrome/android/java/res/drawable-xhdpi/bg_tabstrip_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/blue_google_icon.png b/chrome/android/java/res/drawable-xhdpi/blue_google_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/blue_google_icon.png
rename to chrome/android/java/res/drawable-xhdpi/blue_google_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/bookmarks_widget_thumb_selector_pressed.9.png b/chrome/android/java/res/drawable-xhdpi/bookmarks_widget_thumb_selector_pressed.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/bookmarks_widget_thumb_selector_pressed.9.png
rename to chrome/android/java/res/drawable-xhdpi/bookmarks_widget_thumb_selector_pressed.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/border_thumb_bookmarks_widget_holo.9.png b/chrome/android/java/res/drawable-xhdpi/border_thumb_bookmarks_widget_holo.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/border_thumb_bookmarks_widget_holo.9.png
rename to chrome/android/java/res/drawable-xhdpi/border_thumb_bookmarks_widget_holo.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/breadcrumb_arrow.png b/chrome/android/java/res/drawable-xhdpi/breadcrumb_arrow.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/breadcrumb_arrow.png
rename to chrome/android/java/res/drawable-xhdpi/breadcrumb_arrow.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/browser_thumbnail.png b/chrome/android/java/res/drawable-xhdpi/browser_thumbnail.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/browser_thumbnail.png
rename to chrome/android/java/res/drawable-xhdpi/browser_thumbnail.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_chevron_left.png b/chrome/android/java/res/drawable-xhdpi/btn_chevron_left.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_chevron_left.png
rename to chrome/android/java/res/drawable-xhdpi/btn_chevron_left.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_delete_url.png b/chrome/android/java/res/drawable-xhdpi/btn_delete_url.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_delete_url.png
rename to chrome/android/java/res/drawable-xhdpi/btn_delete_url.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_mic.png b/chrome/android/java/res/drawable-xhdpi/btn_mic.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_mic.png
rename to chrome/android/java/res/drawable-xhdpi/btn_mic.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_new_tab_incognito_normal.png b/chrome/android/java/res/drawable-xhdpi/btn_new_tab_incognito_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_new_tab_incognito_normal.png
rename to chrome/android/java/res/drawable-xhdpi/btn_new_tab_incognito_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_new_tab_incognito_pressed.png b/chrome/android/java/res/drawable-xhdpi/btn_new_tab_incognito_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_new_tab_incognito_pressed.png
rename to chrome/android/java/res/drawable-xhdpi/btn_new_tab_incognito_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_new_tab_white_normal.png b/chrome/android/java/res/drawable-xhdpi/btn_new_tab_white_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_new_tab_white_normal.png
rename to chrome/android/java/res/drawable-xhdpi/btn_new_tab_white_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_new_tab_white_pressed.png b/chrome/android/java/res/drawable-xhdpi/btn_new_tab_white_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_new_tab_white_pressed.png
rename to chrome/android/java/res/drawable-xhdpi/btn_new_tab_white_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_recents.png b/chrome/android/java/res/drawable-xhdpi/btn_recents.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_recents.png
rename to chrome/android/java/res/drawable-xhdpi/btn_recents.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_suggestion_refine.png b/chrome/android/java/res/drawable-xhdpi/btn_suggestion_refine.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_suggestion_refine.png
rename to chrome/android/java/res/drawable-xhdpi/btn_suggestion_refine.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_tab_close_normal.png b/chrome/android/java/res/drawable-xhdpi/btn_tab_close_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_tab_close_normal.png
rename to chrome/android/java/res/drawable-xhdpi/btn_tab_close_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_tab_close_pressed.png b/chrome/android/java/res/drawable-xhdpi/btn_tab_close_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_tab_close_pressed.png
rename to chrome/android/java/res/drawable-xhdpi/btn_tab_close_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_tab_close_white_normal.png b/chrome/android/java/res/drawable-xhdpi/btn_tab_close_white_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_tab_close_white_normal.png
rename to chrome/android/java/res/drawable-xhdpi/btn_tab_close_white_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_tab_close_white_pressed.png b/chrome/android/java/res/drawable-xhdpi/btn_tab_close_white_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_tab_close_white_pressed.png
rename to chrome/android/java/res/drawable-xhdpi/btn_tab_close_white_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_new_incognito_tab_normal.png b/chrome/android/java/res/drawable-xhdpi/btn_tabstrip_new_incognito_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_new_incognito_tab_normal.png
rename to chrome/android/java/res/drawable-xhdpi/btn_tabstrip_new_incognito_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_new_incognito_tab_pressed.png b/chrome/android/java/res/drawable-xhdpi/btn_tabstrip_new_incognito_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_new_incognito_tab_pressed.png
rename to chrome/android/java/res/drawable-xhdpi/btn_tabstrip_new_incognito_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_new_tab_normal.png b/chrome/android/java/res/drawable-xhdpi/btn_tabstrip_new_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_new_tab_normal.png
rename to chrome/android/java/res/drawable-xhdpi/btn_tabstrip_new_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_new_tab_pressed.png b/chrome/android/java/res/drawable-xhdpi/btn_tabstrip_new_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_new_tab_pressed.png
rename to chrome/android/java/res/drawable-xhdpi/btn_tabstrip_new_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_switch_incognito.png b/chrome/android/java/res/drawable-xhdpi/btn_tabstrip_switch_incognito.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_switch_incognito.png
rename to chrome/android/java/res/drawable-xhdpi/btn_tabstrip_switch_incognito.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_switch_normal.png b/chrome/android/java/res/drawable-xhdpi/btn_tabstrip_switch_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_tabstrip_switch_normal.png
rename to chrome/android/java/res/drawable-xhdpi/btn_tabstrip_switch_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/btn_toolbar_home.png b/chrome/android/java/res/drawable-xhdpi/btn_toolbar_home.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/btn_toolbar_home.png
rename to chrome/android/java/res/drawable-xhdpi/btn_toolbar_home.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/contextual_search_bar_background.9.png b/chrome/android/java/res/drawable-xhdpi/contextual_search_bar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/contextual_search_bar_background.9.png
rename to chrome/android/java/res/drawable-xhdpi/contextual_search_bar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/contextual_search_bar_shadow.png b/chrome/android/java/res/drawable-xhdpi/contextual_search_bar_shadow.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/contextual_search_bar_shadow.png
rename to chrome/android/java/res/drawable-xhdpi/contextual_search_bar_shadow.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/default_favicon.png b/chrome/android/java/res/drawable-xhdpi/default_favicon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/default_favicon.png
rename to chrome/android/java/res/drawable-xhdpi/default_favicon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/default_favicon_white.png b/chrome/android/java/res/drawable-xhdpi/default_favicon_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/default_favicon_white.png
rename to chrome/android/java/res/drawable-xhdpi/default_favicon_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_add_folder.png b/chrome/android/java/res/drawable-xhdpi/eb_add_folder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_add_folder.png
rename to chrome/android/java/res/drawable-xhdpi/eb_add_folder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_back_normal.png b/chrome/android/java/res/drawable-xhdpi/eb_back_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_back_normal.png
rename to chrome/android/java/res/drawable-xhdpi/eb_back_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_bookmarks_bar.png b/chrome/android/java/res/drawable-xhdpi/eb_bookmarks_bar.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_bookmarks_bar.png
rename to chrome/android/java/res/drawable-xhdpi/eb_bookmarks_bar.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_cancel_active.png b/chrome/android/java/res/drawable-xhdpi/eb_cancel_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_cancel_active.png
rename to chrome/android/java/res/drawable-xhdpi/eb_cancel_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_check_blue.png b/chrome/android/java/res/drawable-xhdpi/eb_check_blue.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_check_blue.png
rename to chrome/android/java/res/drawable-xhdpi/eb_check_blue.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_check_gray.png b/chrome/android/java/res/drawable-xhdpi/eb_check_gray.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_check_gray.png
rename to chrome/android/java/res/drawable-xhdpi/eb_check_gray.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_check_white.png b/chrome/android/java/res/drawable-xhdpi/eb_check_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_check_white.png
rename to chrome/android/java/res/drawable-xhdpi/eb_check_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_delete_white.png b/chrome/android/java/res/drawable-xhdpi/eb_delete_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_delete_white.png
rename to chrome/android/java/res/drawable-xhdpi/eb_delete_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_edit_active.png b/chrome/android/java/res/drawable-xhdpi/eb_edit_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_edit_active.png
rename to chrome/android/java/res/drawable-xhdpi/eb_edit_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_edit_normal.png b/chrome/android/java/res/drawable-xhdpi/eb_edit_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_edit_normal.png
rename to chrome/android/java/res/drawable-xhdpi/eb_edit_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_folder.png b/chrome/android/java/res/drawable-xhdpi/eb_folder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_folder.png
rename to chrome/android/java/res/drawable-xhdpi/eb_folder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_grid_icon.png b/chrome/android/java/res/drawable-xhdpi/eb_grid_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_grid_icon.png
rename to chrome/android/java/res/drawable-xhdpi/eb_grid_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_item_more.png b/chrome/android/java/res/drawable-xhdpi/eb_item_more.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_item_more.png
rename to chrome/android/java/res/drawable-xhdpi/eb_item_more.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_item_tile.9.png b/chrome/android/java/res/drawable-xhdpi/eb_item_tile.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_item_tile.9.png
rename to chrome/android/java/res/drawable-xhdpi/eb_item_tile.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_list_icon.png b/chrome/android/java/res/drawable-xhdpi/eb_list_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_list_icon.png
rename to chrome/android/java/res/drawable-xhdpi/eb_list_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_logo_large.png b/chrome/android/java/res/drawable-xhdpi/eb_logo_large.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_logo_large.png
rename to chrome/android/java/res/drawable-xhdpi/eb_logo_large.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_managed.png b/chrome/android/java/res/drawable-xhdpi/eb_managed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_managed.png
rename to chrome/android/java/res/drawable-xhdpi/eb_managed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_mobile.png b/chrome/android/java/res/drawable-xhdpi/eb_mobile.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_mobile.png
rename to chrome/android/java/res/drawable-xhdpi/eb_mobile.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_move_active.png b/chrome/android/java/res/drawable-xhdpi/eb_move_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_move_active.png
rename to chrome/android/java/res/drawable-xhdpi/eb_move_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/eb_others.png b/chrome/android/java/res/drawable-xhdpi/eb_others.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/eb_others.png
rename to chrome/android/java/res/drawable-xhdpi/eb_others.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/google_logo.png b/chrome/android/java/res/drawable-xhdpi/google_logo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/google_logo.png
rename to chrome/android/java/res/drawable-xhdpi/google_logo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/history_favicon.png b/chrome/android/java/res/drawable-xhdpi/history_favicon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/history_favicon.png
rename to chrome/android/java/res/drawable-xhdpi/history_favicon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/ic_bookmark_widget_bookmark_holo_dark.png b/chrome/android/java/res/drawable-xhdpi/ic_bookmark_widget_bookmark_holo_dark.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/ic_bookmark_widget_bookmark_holo_dark.png
rename to chrome/android/java/res/drawable-xhdpi/ic_bookmark_widget_bookmark_holo_dark.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/ic_most_visited_placeholder.png b/chrome/android/java/res/drawable-xhdpi/ic_most_visited_placeholder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/ic_most_visited_placeholder.png
rename to chrome/android/java/res/drawable-xhdpi/ic_most_visited_placeholder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-xhdpi/ic_omnibox_incognito_badge.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/ic_omnibox_incognito_badge.png
rename to chrome/android/java/res/drawable-xhdpi/ic_omnibox_incognito_badge.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/ic_omnibox_magnifier.png b/chrome/android/java/res/drawable-xhdpi/ic_omnibox_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/ic_omnibox_magnifier.png
rename to chrome/android/java/res/drawable-xhdpi/ic_omnibox_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/ic_omnibox_page.png b/chrome/android/java/res/drawable-xhdpi/ic_omnibox_page.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/ic_omnibox_page.png
rename to chrome/android/java/res/drawable-xhdpi/ic_omnibox_page.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/ic_suggestion_history.png b/chrome/android/java/res/drawable-xhdpi/ic_suggestion_history.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/ic_suggestion_history.png
rename to chrome/android/java/res/drawable-xhdpi/ic_suggestion_history.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/ic_suggestion_magnifier.png b/chrome/android/java/res/drawable-xhdpi/ic_suggestion_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/ic_suggestion_magnifier.png
rename to chrome/android/java/res/drawable-xhdpi/ic_suggestion_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/incognito_splash.png b/chrome/android/java/res/drawable-xhdpi/incognito_splash.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/incognito_splash.png
rename to chrome/android/java/res/drawable-xhdpi/incognito_splash.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/logo_card_back.png b/chrome/android/java/res/drawable-xhdpi/logo_card_back.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/logo_card_back.png
rename to chrome/android/java/res/drawable-xhdpi/logo_card_back.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/more_horiz.png b/chrome/android/java/res/drawable-xhdpi/more_horiz.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/more_horiz.png
rename to chrome/android/java/res/drawable-xhdpi/more_horiz.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/omnibox_https_invalid.png b/chrome/android/java/res/drawable-xhdpi/omnibox_https_invalid.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/omnibox_https_invalid.png
rename to chrome/android/java/res/drawable-xhdpi/omnibox_https_invalid.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/omnibox_https_valid.png b/chrome/android/java/res/drawable-xhdpi/omnibox_https_valid.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/omnibox_https_valid.png
rename to chrome/android/java/res/drawable-xhdpi/omnibox_https_valid.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/omnibox_https_valid_light.png b/chrome/android/java/res/drawable-xhdpi/omnibox_https_valid_light.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/omnibox_https_valid_light.png
rename to chrome/android/java/res/drawable-xhdpi/omnibox_https_valid_light.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/omnibox_https_warning.png b/chrome/android/java/res/drawable-xhdpi/omnibox_https_warning.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/omnibox_https_warning.png
rename to chrome/android/java/res/drawable-xhdpi/omnibox_https_warning.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/overlay_url_bookmark_widget_holo.9.png b/chrome/android/java/res/drawable-xhdpi/overlay_url_bookmark_widget_holo.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/overlay_url_bookmark_widget_holo.9.png
rename to chrome/android/java/res/drawable-xhdpi/overlay_url_bookmark_widget_holo.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/progress_bar_background.9.png b/chrome/android/java/res/drawable-xhdpi/progress_bar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/progress_bar_background.9.png
rename to chrome/android/java/res/drawable-xhdpi/progress_bar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/progress_bar_background_white.9.png b/chrome/android/java/res/drawable-xhdpi/progress_bar_background_white.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/progress_bar_background_white.9.png
rename to chrome/android/java/res/drawable-xhdpi/progress_bar_background_white.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/progress_bar_foreground.9.png b/chrome/android/java/res/drawable-xhdpi/progress_bar_foreground.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/progress_bar_foreground.9.png
rename to chrome/android/java/res/drawable-xhdpi/progress_bar_foreground.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/reader_mode_icon.png b/chrome/android/java/res/drawable-xhdpi/reader_mode_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/reader_mode_icon.png
rename to chrome/android/java/res/drawable-xhdpi/reader_mode_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/reader_mode_prefs_icon.png b/chrome/android/java/res/drawable-xhdpi/reader_mode_prefs_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/reader_mode_prefs_icon.png
rename to chrome/android/java/res/drawable-xhdpi/reader_mode_prefs_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/recent_laptop.png b/chrome/android/java/res/drawable-xhdpi/recent_laptop.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/recent_laptop.png
rename to chrome/android/java/res/drawable-xhdpi/recent_laptop.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/recent_phone.png b/chrome/android/java/res/drawable-xhdpi/recent_phone.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/recent_phone.png
rename to chrome/android/java/res/drawable-xhdpi/recent_phone.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/recent_recently_closed.png b/chrome/android/java/res/drawable-xhdpi/recent_recently_closed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/recent_recently_closed.png
rename to chrome/android/java/res/drawable-xhdpi/recent_recently_closed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/recent_tablet.png b/chrome/android/java/res/drawable-xhdpi/recent_tablet.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/recent_tablet.png
rename to chrome/android/java/res/drawable-xhdpi/recent_tablet.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/sad_tab.png b/chrome/android/java/res/drawable-xhdpi/sad_tab.png
index 1d11dcf..1145065 100644
--- a/chrome/android/java/res/drawable-xhdpi/sad_tab.png
+++ b/chrome/android/java/res/drawable-xhdpi/sad_tab.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/tabswitcher_border_frame.9.png b/chrome/android/java/res/drawable-xhdpi/tabswitcher_border_frame.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/tabswitcher_border_frame.9.png
rename to chrome/android/java/res/drawable-xhdpi/tabswitcher_border_frame.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/tabswitcher_border_frame_decoration.9.png b/chrome/android/java/res/drawable-xhdpi/tabswitcher_border_frame_decoration.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/tabswitcher_border_frame_decoration.9.png
rename to chrome/android/java/res/drawable-xhdpi/tabswitcher_border_frame_decoration.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/tabswitcher_border_frame_incognito.9.png b/chrome/android/java/res/drawable-xhdpi/tabswitcher_border_frame_incognito.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/tabswitcher_border_frame_incognito.9.png
rename to chrome/android/java/res/drawable-xhdpi/tabswitcher_border_frame_incognito.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/tabswitcher_border_frame_shadow.9.png b/chrome/android/java/res/drawable-xhdpi/tabswitcher_border_frame_shadow.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/tabswitcher_border_frame_shadow.9.png
rename to chrome/android/java/res/drawable-xhdpi/tabswitcher_border_frame_shadow.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/textbox.9.png b/chrome/android/java/res/drawable-xhdpi/textbox.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/textbox.9.png
rename to chrome/android/java/res/drawable-xhdpi/textbox.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/thumb_bookmark_widget_folder_back_holo.png b/chrome/android/java/res/drawable-xhdpi/thumb_bookmark_widget_folder_back_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/thumb_bookmark_widget_folder_back_holo.png
rename to chrome/android/java/res/drawable-xhdpi/thumb_bookmark_widget_folder_back_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/thumb_bookmark_widget_folder_holo.png b/chrome/android/java/res/drawable-xhdpi/thumb_bookmark_widget_folder_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/thumb_bookmark_widget_folder_holo.png
rename to chrome/android/java/res/drawable-xhdpi/thumb_bookmark_widget_folder_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png b/chrome/android/java/res/drawable-xhdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png
rename to chrome/android/java/res/drawable-xhdpi/thumbnail_bookmarks_widget_no_bookmark_holo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/toolbar_background.9.png b/chrome/android/java/res/drawable-xhdpi/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/toolbar_background.9.png
rename to chrome/android/java/res/drawable-xhdpi/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/toolbar_shadow_focused.png b/chrome/android/java/res/drawable-xhdpi/toolbar_shadow_focused.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/toolbar_shadow_focused.png
rename to chrome/android/java/res/drawable-xhdpi/toolbar_shadow_focused.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/toolbar_shadow_normal.png b/chrome/android/java/res/drawable-xhdpi/toolbar_shadow_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/toolbar_shadow_normal.png
rename to chrome/android/java/res/drawable-xhdpi/toolbar_shadow_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/webrtc_audio.png b/chrome/android/java/res/drawable-xhdpi/webrtc_audio.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/webrtc_audio.png
rename to chrome/android/java/res/drawable-xhdpi/webrtc_audio.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xhdpi/webrtc_video.png b/chrome/android/java/res/drawable-xhdpi/webrtc_video.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xhdpi/webrtc_video.png
rename to chrome/android/java/res/drawable-xhdpi/webrtc_video.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/audio_playing.png b/chrome/android/java/res/drawable-xxhdpi/audio_playing.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/audio_playing.png
rename to chrome/android/java/res/drawable-xxhdpi/audio_playing.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/bg_find_toolbar_popup.9.png b/chrome/android/java/res/drawable-xxhdpi/bg_find_toolbar_popup.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/bg_find_toolbar_popup.9.png
rename to chrome/android/java/res/drawable-xxhdpi/bg_find_toolbar_popup.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/bg_tabstrip_background_tab.9.png b/chrome/android/java/res/drawable-xxhdpi/bg_tabstrip_background_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/bg_tabstrip_background_tab.9.png
rename to chrome/android/java/res/drawable-xxhdpi/bg_tabstrip_background_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/bg_tabstrip_incognito_background_tab.9.png b/chrome/android/java/res/drawable-xxhdpi/bg_tabstrip_incognito_background_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/bg_tabstrip_incognito_background_tab.9.png
rename to chrome/android/java/res/drawable-xxhdpi/bg_tabstrip_incognito_background_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/bg_tabstrip_incognito_tab.9.png b/chrome/android/java/res/drawable-xxhdpi/bg_tabstrip_incognito_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/bg_tabstrip_incognito_tab.9.png
rename to chrome/android/java/res/drawable-xxhdpi/bg_tabstrip_incognito_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/bg_tabstrip_tab.9.png b/chrome/android/java/res/drawable-xxhdpi/bg_tabstrip_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/bg_tabstrip_tab.9.png
rename to chrome/android/java/res/drawable-xxhdpi/bg_tabstrip_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/blue_google_icon.png b/chrome/android/java/res/drawable-xxhdpi/blue_google_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/blue_google_icon.png
rename to chrome/android/java/res/drawable-xxhdpi/blue_google_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/breadcrumb_arrow.png b/chrome/android/java/res/drawable-xxhdpi/breadcrumb_arrow.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/breadcrumb_arrow.png
rename to chrome/android/java/res/drawable-xxhdpi/breadcrumb_arrow.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_chevron_left.png b/chrome/android/java/res/drawable-xxhdpi/btn_chevron_left.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_chevron_left.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_chevron_left.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_delete_url.png b/chrome/android/java/res/drawable-xxhdpi/btn_delete_url.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_delete_url.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_delete_url.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_mic.png b/chrome/android/java/res/drawable-xxhdpi/btn_mic.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_mic.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_mic.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_new_tab_incognito_normal.png b/chrome/android/java/res/drawable-xxhdpi/btn_new_tab_incognito_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_new_tab_incognito_normal.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_new_tab_incognito_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_new_tab_incognito_pressed.png b/chrome/android/java/res/drawable-xxhdpi/btn_new_tab_incognito_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_new_tab_incognito_pressed.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_new_tab_incognito_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_new_tab_white_normal.png b/chrome/android/java/res/drawable-xxhdpi/btn_new_tab_white_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_new_tab_white_normal.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_new_tab_white_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_new_tab_white_pressed.png b/chrome/android/java/res/drawable-xxhdpi/btn_new_tab_white_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_new_tab_white_pressed.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_new_tab_white_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_recents.png b/chrome/android/java/res/drawable-xxhdpi/btn_recents.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_recents.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_recents.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_suggestion_refine.png b/chrome/android/java/res/drawable-xxhdpi/btn_suggestion_refine.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_suggestion_refine.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_suggestion_refine.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_tab_close_normal.png b/chrome/android/java/res/drawable-xxhdpi/btn_tab_close_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_tab_close_normal.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_tab_close_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_tab_close_pressed.png b/chrome/android/java/res/drawable-xxhdpi/btn_tab_close_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_tab_close_pressed.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_tab_close_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_tab_close_white_normal.png b/chrome/android/java/res/drawable-xxhdpi/btn_tab_close_white_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_tab_close_white_normal.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_tab_close_white_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_tab_close_white_pressed.png b/chrome/android/java/res/drawable-xxhdpi/btn_tab_close_white_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_tab_close_white_pressed.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_tab_close_white_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_new_incognito_tab_normal.png b/chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_new_incognito_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_new_incognito_tab_normal.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_new_incognito_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_new_incognito_tab_pressed.png b/chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_new_incognito_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_new_incognito_tab_pressed.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_new_incognito_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_new_tab_normal.png b/chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_new_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_new_tab_normal.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_new_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_new_tab_pressed.png b/chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_new_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_new_tab_pressed.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_new_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_switch_incognito.png b/chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_switch_incognito.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_switch_incognito.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_switch_incognito.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_switch_normal.png b/chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_switch_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_tabstrip_switch_normal.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_tabstrip_switch_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/btn_toolbar_home.png b/chrome/android/java/res/drawable-xxhdpi/btn_toolbar_home.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/btn_toolbar_home.png
rename to chrome/android/java/res/drawable-xxhdpi/btn_toolbar_home.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/contextual_search_bar_background.9.png b/chrome/android/java/res/drawable-xxhdpi/contextual_search_bar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/contextual_search_bar_background.9.png
rename to chrome/android/java/res/drawable-xxhdpi/contextual_search_bar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/contextual_search_bar_shadow.png b/chrome/android/java/res/drawable-xxhdpi/contextual_search_bar_shadow.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/contextual_search_bar_shadow.png
rename to chrome/android/java/res/drawable-xxhdpi/contextual_search_bar_shadow.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/default_favicon.png b/chrome/android/java/res/drawable-xxhdpi/default_favicon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/default_favicon.png
rename to chrome/android/java/res/drawable-xxhdpi/default_favicon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/default_favicon_white.png b/chrome/android/java/res/drawable-xxhdpi/default_favicon_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/default_favicon_white.png
rename to chrome/android/java/res/drawable-xxhdpi/default_favicon_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_add_folder.png b/chrome/android/java/res/drawable-xxhdpi/eb_add_folder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_add_folder.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_add_folder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_back_normal.png b/chrome/android/java/res/drawable-xxhdpi/eb_back_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_back_normal.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_back_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_bookmarks_bar.png b/chrome/android/java/res/drawable-xxhdpi/eb_bookmarks_bar.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_bookmarks_bar.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_bookmarks_bar.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_cancel_active.png b/chrome/android/java/res/drawable-xxhdpi/eb_cancel_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_cancel_active.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_cancel_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_check_blue.png b/chrome/android/java/res/drawable-xxhdpi/eb_check_blue.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_check_blue.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_check_blue.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_check_gray.png b/chrome/android/java/res/drawable-xxhdpi/eb_check_gray.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_check_gray.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_check_gray.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_check_white.png b/chrome/android/java/res/drawable-xxhdpi/eb_check_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_check_white.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_check_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_delete_white.png b/chrome/android/java/res/drawable-xxhdpi/eb_delete_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_delete_white.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_delete_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_edit_active.png b/chrome/android/java/res/drawable-xxhdpi/eb_edit_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_edit_active.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_edit_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_edit_normal.png b/chrome/android/java/res/drawable-xxhdpi/eb_edit_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_edit_normal.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_edit_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_folder.png b/chrome/android/java/res/drawable-xxhdpi/eb_folder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_folder.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_folder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_grid_icon.png b/chrome/android/java/res/drawable-xxhdpi/eb_grid_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_grid_icon.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_grid_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_item_more.png b/chrome/android/java/res/drawable-xxhdpi/eb_item_more.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_item_more.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_item_more.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_item_tile.9.png b/chrome/android/java/res/drawable-xxhdpi/eb_item_tile.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_item_tile.9.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_item_tile.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_list_icon.png b/chrome/android/java/res/drawable-xxhdpi/eb_list_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_list_icon.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_list_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_logo_large.png b/chrome/android/java/res/drawable-xxhdpi/eb_logo_large.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_logo_large.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_logo_large.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_managed.png b/chrome/android/java/res/drawable-xxhdpi/eb_managed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_managed.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_managed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_mobile.png b/chrome/android/java/res/drawable-xxhdpi/eb_mobile.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_mobile.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_mobile.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_move_active.png b/chrome/android/java/res/drawable-xxhdpi/eb_move_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_move_active.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_move_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/eb_others.png b/chrome/android/java/res/drawable-xxhdpi/eb_others.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/eb_others.png
rename to chrome/android/java/res/drawable-xxhdpi/eb_others.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/google_logo.png b/chrome/android/java/res/drawable-xxhdpi/google_logo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/google_logo.png
rename to chrome/android/java/res/drawable-xxhdpi/google_logo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/history_favicon.png b/chrome/android/java/res/drawable-xxhdpi/history_favicon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/history_favicon.png
rename to chrome/android/java/res/drawable-xxhdpi/history_favicon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/ic_most_visited_placeholder.png b/chrome/android/java/res/drawable-xxhdpi/ic_most_visited_placeholder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/ic_most_visited_placeholder.png
rename to chrome/android/java/res/drawable-xxhdpi/ic_most_visited_placeholder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-xxhdpi/ic_omnibox_incognito_badge.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/ic_omnibox_incognito_badge.png
rename to chrome/android/java/res/drawable-xxhdpi/ic_omnibox_incognito_badge.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/ic_omnibox_magnifier.png b/chrome/android/java/res/drawable-xxhdpi/ic_omnibox_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/ic_omnibox_magnifier.png
rename to chrome/android/java/res/drawable-xxhdpi/ic_omnibox_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/ic_omnibox_page.png b/chrome/android/java/res/drawable-xxhdpi/ic_omnibox_page.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/ic_omnibox_page.png
rename to chrome/android/java/res/drawable-xxhdpi/ic_omnibox_page.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/ic_suggestion_history.png b/chrome/android/java/res/drawable-xxhdpi/ic_suggestion_history.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/ic_suggestion_history.png
rename to chrome/android/java/res/drawable-xxhdpi/ic_suggestion_history.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/ic_suggestion_magnifier.png b/chrome/android/java/res/drawable-xxhdpi/ic_suggestion_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/ic_suggestion_magnifier.png
rename to chrome/android/java/res/drawable-xxhdpi/ic_suggestion_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/incognito_splash.png b/chrome/android/java/res/drawable-xxhdpi/incognito_splash.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/incognito_splash.png
rename to chrome/android/java/res/drawable-xxhdpi/incognito_splash.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/more_horiz.png b/chrome/android/java/res/drawable-xxhdpi/more_horiz.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/more_horiz.png
rename to chrome/android/java/res/drawable-xxhdpi/more_horiz.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/omnibox_https_invalid.png b/chrome/android/java/res/drawable-xxhdpi/omnibox_https_invalid.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/omnibox_https_invalid.png
rename to chrome/android/java/res/drawable-xxhdpi/omnibox_https_invalid.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/omnibox_https_valid.png b/chrome/android/java/res/drawable-xxhdpi/omnibox_https_valid.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/omnibox_https_valid.png
rename to chrome/android/java/res/drawable-xxhdpi/omnibox_https_valid.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/omnibox_https_valid_light.png b/chrome/android/java/res/drawable-xxhdpi/omnibox_https_valid_light.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/omnibox_https_valid_light.png
rename to chrome/android/java/res/drawable-xxhdpi/omnibox_https_valid_light.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/omnibox_https_warning.png b/chrome/android/java/res/drawable-xxhdpi/omnibox_https_warning.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/omnibox_https_warning.png
rename to chrome/android/java/res/drawable-xxhdpi/omnibox_https_warning.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/progress_bar_background.9.png b/chrome/android/java/res/drawable-xxhdpi/progress_bar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/progress_bar_background.9.png
rename to chrome/android/java/res/drawable-xxhdpi/progress_bar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/progress_bar_background_white.9.png b/chrome/android/java/res/drawable-xxhdpi/progress_bar_background_white.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/progress_bar_background_white.9.png
rename to chrome/android/java/res/drawable-xxhdpi/progress_bar_background_white.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/progress_bar_foreground.9.png b/chrome/android/java/res/drawable-xxhdpi/progress_bar_foreground.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/progress_bar_foreground.9.png
rename to chrome/android/java/res/drawable-xxhdpi/progress_bar_foreground.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/reader_mode_icon.png b/chrome/android/java/res/drawable-xxhdpi/reader_mode_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/reader_mode_icon.png
rename to chrome/android/java/res/drawable-xxhdpi/reader_mode_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/reader_mode_prefs_icon.png b/chrome/android/java/res/drawable-xxhdpi/reader_mode_prefs_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/reader_mode_prefs_icon.png
rename to chrome/android/java/res/drawable-xxhdpi/reader_mode_prefs_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/recent_laptop.png b/chrome/android/java/res/drawable-xxhdpi/recent_laptop.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/recent_laptop.png
rename to chrome/android/java/res/drawable-xxhdpi/recent_laptop.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/recent_phone.png b/chrome/android/java/res/drawable-xxhdpi/recent_phone.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/recent_phone.png
rename to chrome/android/java/res/drawable-xxhdpi/recent_phone.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/recent_recently_closed.png b/chrome/android/java/res/drawable-xxhdpi/recent_recently_closed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/recent_recently_closed.png
rename to chrome/android/java/res/drawable-xxhdpi/recent_recently_closed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/recent_tablet.png b/chrome/android/java/res/drawable-xxhdpi/recent_tablet.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/recent_tablet.png
rename to chrome/android/java/res/drawable-xxhdpi/recent_tablet.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/sad_tab.png b/chrome/android/java/res/drawable-xxhdpi/sad_tab.png
index f24a8c9a..34e75fa 100644
--- a/chrome/android/java/res/drawable-xxhdpi/sad_tab.png
+++ b/chrome/android/java/res/drawable-xxhdpi/sad_tab.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/tabswitcher_border_frame.9.png b/chrome/android/java/res/drawable-xxhdpi/tabswitcher_border_frame.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/tabswitcher_border_frame.9.png
rename to chrome/android/java/res/drawable-xxhdpi/tabswitcher_border_frame.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/tabswitcher_border_frame_decoration.9.png b/chrome/android/java/res/drawable-xxhdpi/tabswitcher_border_frame_decoration.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/tabswitcher_border_frame_decoration.9.png
rename to chrome/android/java/res/drawable-xxhdpi/tabswitcher_border_frame_decoration.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/tabswitcher_border_frame_incognito.9.png b/chrome/android/java/res/drawable-xxhdpi/tabswitcher_border_frame_incognito.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/tabswitcher_border_frame_incognito.9.png
rename to chrome/android/java/res/drawable-xxhdpi/tabswitcher_border_frame_incognito.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/tabswitcher_border_frame_shadow.9.png b/chrome/android/java/res/drawable-xxhdpi/tabswitcher_border_frame_shadow.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/tabswitcher_border_frame_shadow.9.png
rename to chrome/android/java/res/drawable-xxhdpi/tabswitcher_border_frame_shadow.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/textbox.9.png b/chrome/android/java/res/drawable-xxhdpi/textbox.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/textbox.9.png
rename to chrome/android/java/res/drawable-xxhdpi/textbox.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/toolbar_background.9.png b/chrome/android/java/res/drawable-xxhdpi/toolbar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/toolbar_background.9.png
rename to chrome/android/java/res/drawable-xxhdpi/toolbar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/toolbar_shadow_focused.png b/chrome/android/java/res/drawable-xxhdpi/toolbar_shadow_focused.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/toolbar_shadow_focused.png
rename to chrome/android/java/res/drawable-xxhdpi/toolbar_shadow_focused.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/toolbar_shadow_normal.png b/chrome/android/java/res/drawable-xxhdpi/toolbar_shadow_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/toolbar_shadow_normal.png
rename to chrome/android/java/res/drawable-xxhdpi/toolbar_shadow_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/webrtc_audio.png b/chrome/android/java/res/drawable-xxhdpi/webrtc_audio.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/webrtc_audio.png
rename to chrome/android/java/res/drawable-xxhdpi/webrtc_audio.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxhdpi/webrtc_video.png b/chrome/android/java/res/drawable-xxhdpi/webrtc_video.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxhdpi/webrtc_video.png
rename to chrome/android/java/res/drawable-xxhdpi/webrtc_video.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/audio_playing.png b/chrome/android/java/res/drawable-xxxhdpi/audio_playing.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/audio_playing.png
rename to chrome/android/java/res/drawable-xxxhdpi/audio_playing.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/bg_find_toolbar_popup.9.png b/chrome/android/java/res/drawable-xxxhdpi/bg_find_toolbar_popup.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/bg_find_toolbar_popup.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/bg_find_toolbar_popup.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/bg_tabstrip_background_tab.9.png b/chrome/android/java/res/drawable-xxxhdpi/bg_tabstrip_background_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/bg_tabstrip_background_tab.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/bg_tabstrip_background_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/bg_tabstrip_incognito_background_tab.9.png b/chrome/android/java/res/drawable-xxxhdpi/bg_tabstrip_incognito_background_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/bg_tabstrip_incognito_background_tab.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/bg_tabstrip_incognito_background_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/bg_tabstrip_incognito_tab.9.png b/chrome/android/java/res/drawable-xxxhdpi/bg_tabstrip_incognito_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/bg_tabstrip_incognito_tab.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/bg_tabstrip_incognito_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/bg_tabstrip_tab.9.png b/chrome/android/java/res/drawable-xxxhdpi/bg_tabstrip_tab.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/bg_tabstrip_tab.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/bg_tabstrip_tab.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/blue_google_icon.png b/chrome/android/java/res/drawable-xxxhdpi/blue_google_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/blue_google_icon.png
rename to chrome/android/java/res/drawable-xxxhdpi/blue_google_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/breadcrumb_arrow.png b/chrome/android/java/res/drawable-xxxhdpi/breadcrumb_arrow.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/breadcrumb_arrow.png
rename to chrome/android/java/res/drawable-xxxhdpi/breadcrumb_arrow.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_chevron_left.png b/chrome/android/java/res/drawable-xxxhdpi/btn_chevron_left.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_chevron_left.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_chevron_left.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_delete_url.png b/chrome/android/java/res/drawable-xxxhdpi/btn_delete_url.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_delete_url.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_delete_url.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_mic.png b/chrome/android/java/res/drawable-xxxhdpi/btn_mic.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_mic.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_mic.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_new_tab_incognito_normal.png b/chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_incognito_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_new_tab_incognito_normal.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_incognito_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_new_tab_incognito_pressed.png b/chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_incognito_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_new_tab_incognito_pressed.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_incognito_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_new_tab_white_normal.png b/chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_white_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_new_tab_white_normal.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_white_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_new_tab_white_pressed.png b/chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_white_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_new_tab_white_pressed.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_new_tab_white_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_recents.png b/chrome/android/java/res/drawable-xxxhdpi/btn_recents.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_recents.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_recents.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_suggestion_refine.png b/chrome/android/java/res/drawable-xxxhdpi/btn_suggestion_refine.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_suggestion_refine.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_suggestion_refine.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_tab_close_normal.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tab_close_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_tab_close_normal.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_tab_close_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_tab_close_pressed.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tab_close_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_tab_close_pressed.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_tab_close_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_tab_close_white_normal.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tab_close_white_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_tab_close_white_normal.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_tab_close_white_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_tab_close_white_pressed.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tab_close_white_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_tab_close_white_pressed.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_tab_close_white_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_new_incognito_tab_normal.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_new_incognito_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_new_incognito_tab_normal.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_new_incognito_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_new_incognito_tab_pressed.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_new_incognito_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_new_incognito_tab_pressed.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_new_incognito_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_new_tab_normal.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_new_tab_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_new_tab_normal.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_new_tab_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_new_tab_pressed.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_new_tab_pressed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_new_tab_pressed.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_new_tab_pressed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_switch_incognito.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_switch_incognito.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_switch_incognito.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_switch_incognito.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_switch_normal.png b/chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_switch_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_tabstrip_switch_normal.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_tabstrip_switch_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/btn_toolbar_home.png b/chrome/android/java/res/drawable-xxxhdpi/btn_toolbar_home.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/btn_toolbar_home.png
rename to chrome/android/java/res/drawable-xxxhdpi/btn_toolbar_home.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/contextual_search_bar_background.9.png b/chrome/android/java/res/drawable-xxxhdpi/contextual_search_bar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/contextual_search_bar_background.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/contextual_search_bar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/contextual_search_bar_shadow.png b/chrome/android/java/res/drawable-xxxhdpi/contextual_search_bar_shadow.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/contextual_search_bar_shadow.png
rename to chrome/android/java/res/drawable-xxxhdpi/contextual_search_bar_shadow.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/default_favicon.png b/chrome/android/java/res/drawable-xxxhdpi/default_favicon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/default_favicon.png
rename to chrome/android/java/res/drawable-xxxhdpi/default_favicon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/default_favicon_white.png b/chrome/android/java/res/drawable-xxxhdpi/default_favicon_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/default_favicon_white.png
rename to chrome/android/java/res/drawable-xxxhdpi/default_favicon_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_add_folder.png b/chrome/android/java/res/drawable-xxxhdpi/eb_add_folder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_add_folder.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_add_folder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_back_normal.png b/chrome/android/java/res/drawable-xxxhdpi/eb_back_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_back_normal.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_back_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_bookmarks_bar.png b/chrome/android/java/res/drawable-xxxhdpi/eb_bookmarks_bar.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_bookmarks_bar.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_bookmarks_bar.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_cancel_active.png b/chrome/android/java/res/drawable-xxxhdpi/eb_cancel_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_cancel_active.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_cancel_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_check_blue.png b/chrome/android/java/res/drawable-xxxhdpi/eb_check_blue.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_check_blue.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_check_blue.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_check_gray.png b/chrome/android/java/res/drawable-xxxhdpi/eb_check_gray.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_check_gray.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_check_gray.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_check_white.png b/chrome/android/java/res/drawable-xxxhdpi/eb_check_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_check_white.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_check_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_delete_white.png b/chrome/android/java/res/drawable-xxxhdpi/eb_delete_white.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_delete_white.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_delete_white.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_edit_active.png b/chrome/android/java/res/drawable-xxxhdpi/eb_edit_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_edit_active.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_edit_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_edit_normal.png b/chrome/android/java/res/drawable-xxxhdpi/eb_edit_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_edit_normal.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_edit_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_folder.png b/chrome/android/java/res/drawable-xxxhdpi/eb_folder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_folder.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_folder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_grid_icon.png b/chrome/android/java/res/drawable-xxxhdpi/eb_grid_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_grid_icon.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_grid_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_item_more.png b/chrome/android/java/res/drawable-xxxhdpi/eb_item_more.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_item_more.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_item_more.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_item_tile.9.png b/chrome/android/java/res/drawable-xxxhdpi/eb_item_tile.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_item_tile.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_item_tile.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_list_icon.png b/chrome/android/java/res/drawable-xxxhdpi/eb_list_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_list_icon.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_list_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_logo_large.png b/chrome/android/java/res/drawable-xxxhdpi/eb_logo_large.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_logo_large.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_logo_large.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_managed.png b/chrome/android/java/res/drawable-xxxhdpi/eb_managed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_managed.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_managed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_mobile.png b/chrome/android/java/res/drawable-xxxhdpi/eb_mobile.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_mobile.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_mobile.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_move_active.png b/chrome/android/java/res/drawable-xxxhdpi/eb_move_active.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_move_active.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_move_active.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/eb_others.png b/chrome/android/java/res/drawable-xxxhdpi/eb_others.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/eb_others.png
rename to chrome/android/java/res/drawable-xxxhdpi/eb_others.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/google_logo.png b/chrome/android/java/res/drawable-xxxhdpi/google_logo.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/google_logo.png
rename to chrome/android/java/res/drawable-xxxhdpi/google_logo.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/history_favicon.png b/chrome/android/java/res/drawable-xxxhdpi/history_favicon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/history_favicon.png
rename to chrome/android/java/res/drawable-xxxhdpi/history_favicon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/ic_most_visited_placeholder.png b/chrome/android/java/res/drawable-xxxhdpi/ic_most_visited_placeholder.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/ic_most_visited_placeholder.png
rename to chrome/android/java/res/drawable-xxxhdpi/ic_most_visited_placeholder.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/ic_omnibox_incognito_badge.png b/chrome/android/java/res/drawable-xxxhdpi/ic_omnibox_incognito_badge.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/ic_omnibox_incognito_badge.png
rename to chrome/android/java/res/drawable-xxxhdpi/ic_omnibox_incognito_badge.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/ic_omnibox_magnifier.png b/chrome/android/java/res/drawable-xxxhdpi/ic_omnibox_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/ic_omnibox_magnifier.png
rename to chrome/android/java/res/drawable-xxxhdpi/ic_omnibox_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/ic_omnibox_page.png b/chrome/android/java/res/drawable-xxxhdpi/ic_omnibox_page.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/ic_omnibox_page.png
rename to chrome/android/java/res/drawable-xxxhdpi/ic_omnibox_page.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/ic_suggestion_history.png b/chrome/android/java/res/drawable-xxxhdpi/ic_suggestion_history.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/ic_suggestion_history.png
rename to chrome/android/java/res/drawable-xxxhdpi/ic_suggestion_history.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/ic_suggestion_magnifier.png b/chrome/android/java/res/drawable-xxxhdpi/ic_suggestion_magnifier.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/ic_suggestion_magnifier.png
rename to chrome/android/java/res/drawable-xxxhdpi/ic_suggestion_magnifier.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/incognito_splash.png b/chrome/android/java/res/drawable-xxxhdpi/incognito_splash.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/incognito_splash.png
rename to chrome/android/java/res/drawable-xxxhdpi/incognito_splash.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/omnibox_https_invalid.png b/chrome/android/java/res/drawable-xxxhdpi/omnibox_https_invalid.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/omnibox_https_invalid.png
rename to chrome/android/java/res/drawable-xxxhdpi/omnibox_https_invalid.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/omnibox_https_valid.png b/chrome/android/java/res/drawable-xxxhdpi/omnibox_https_valid.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/omnibox_https_valid.png
rename to chrome/android/java/res/drawable-xxxhdpi/omnibox_https_valid.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/omnibox_https_valid_light.png b/chrome/android/java/res/drawable-xxxhdpi/omnibox_https_valid_light.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/omnibox_https_valid_light.png
rename to chrome/android/java/res/drawable-xxxhdpi/omnibox_https_valid_light.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/omnibox_https_warning.png b/chrome/android/java/res/drawable-xxxhdpi/omnibox_https_warning.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/omnibox_https_warning.png
rename to chrome/android/java/res/drawable-xxxhdpi/omnibox_https_warning.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/progress_bar_background.9.png b/chrome/android/java/res/drawable-xxxhdpi/progress_bar_background.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/progress_bar_background.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/progress_bar_background.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/progress_bar_background_white.9.png b/chrome/android/java/res/drawable-xxxhdpi/progress_bar_background_white.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/progress_bar_background_white.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/progress_bar_background_white.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/progress_bar_foreground.9.png b/chrome/android/java/res/drawable-xxxhdpi/progress_bar_foreground.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/progress_bar_foreground.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/progress_bar_foreground.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/reader_mode_icon.png b/chrome/android/java/res/drawable-xxxhdpi/reader_mode_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/reader_mode_icon.png
rename to chrome/android/java/res/drawable-xxxhdpi/reader_mode_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/recent_laptop.png b/chrome/android/java/res/drawable-xxxhdpi/recent_laptop.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/recent_laptop.png
rename to chrome/android/java/res/drawable-xxxhdpi/recent_laptop.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/recent_phone.png b/chrome/android/java/res/drawable-xxxhdpi/recent_phone.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/recent_phone.png
rename to chrome/android/java/res/drawable-xxxhdpi/recent_phone.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/recent_recently_closed.png b/chrome/android/java/res/drawable-xxxhdpi/recent_recently_closed.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/recent_recently_closed.png
rename to chrome/android/java/res/drawable-xxxhdpi/recent_recently_closed.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/recent_tablet.png b/chrome/android/java/res/drawable-xxxhdpi/recent_tablet.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/recent_tablet.png
rename to chrome/android/java/res/drawable-xxxhdpi/recent_tablet.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/sad_tab.png b/chrome/android/java/res/drawable-xxxhdpi/sad_tab.png
index ecdd9724..09d11d5 100644
--- a/chrome/android/java/res/drawable-xxxhdpi/sad_tab.png
+++ b/chrome/android/java/res/drawable-xxxhdpi/sad_tab.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/tabswitcher_border_frame.9.png b/chrome/android/java/res/drawable-xxxhdpi/tabswitcher_border_frame.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/tabswitcher_border_frame.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/tabswitcher_border_frame.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/tabswitcher_border_frame_decoration.9.png b/chrome/android/java/res/drawable-xxxhdpi/tabswitcher_border_frame_decoration.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/tabswitcher_border_frame_decoration.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/tabswitcher_border_frame_decoration.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/tabswitcher_border_frame_incognito.9.png b/chrome/android/java/res/drawable-xxxhdpi/tabswitcher_border_frame_incognito.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/tabswitcher_border_frame_incognito.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/tabswitcher_border_frame_incognito.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/tabswitcher_border_frame_shadow.9.png b/chrome/android/java/res/drawable-xxxhdpi/tabswitcher_border_frame_shadow.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/tabswitcher_border_frame_shadow.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/tabswitcher_border_frame_shadow.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/textbox.9.png b/chrome/android/java/res/drawable-xxxhdpi/textbox.9.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/textbox.9.png
rename to chrome/android/java/res/drawable-xxxhdpi/textbox.9.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/toolbar_shadow_focused.png b/chrome/android/java/res/drawable-xxxhdpi/toolbar_shadow_focused.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/toolbar_shadow_focused.png
rename to chrome/android/java/res/drawable-xxxhdpi/toolbar_shadow_focused.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/toolbar_shadow_normal.png b/chrome/android/java/res/drawable-xxxhdpi/toolbar_shadow_normal.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/toolbar_shadow_normal.png
rename to chrome/android/java/res/drawable-xxxhdpi/toolbar_shadow_normal.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/webrtc_audio.png b/chrome/android/java/res/drawable-xxxhdpi/webrtc_audio.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/webrtc_audio.png
rename to chrome/android/java/res/drawable-xxxhdpi/webrtc_audio.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable-xxxhdpi/webrtc_video.png b/chrome/android/java/res/drawable-xxxhdpi/webrtc_video.png
similarity index 100%
rename from chrome/android/java_staging/res/drawable-xxxhdpi/webrtc_video.png
rename to chrome/android/java/res/drawable-xxxhdpi/webrtc_video.png
Binary files differ
diff --git a/chrome/android/java_staging/res/drawable/bg_ntp_search_box.xml b/chrome/android/java/res/drawable/bg_ntp_search_box.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/bg_ntp_search_box.xml
rename to chrome/android/java/res/drawable/bg_ntp_search_box.xml
diff --git a/chrome/android/java_staging/res/drawable/bg_white_dialog.xml b/chrome/android/java/res/drawable/bg_white_dialog.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/bg_white_dialog.xml
rename to chrome/android/java/res/drawable/bg_white_dialog.xml
diff --git a/chrome/android/java_staging/res/drawable/bookmark_widget_thumb_selector.xml b/chrome/android/java/res/drawable/bookmark_widget_thumb_selector.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/bookmark_widget_thumb_selector.xml
rename to chrome/android/java/res/drawable/bookmark_widget_thumb_selector.xml
diff --git a/chrome/android/java_staging/res/drawable/btn_enhanced_bookmark_auto_folder.xml b/chrome/android/java/res/drawable/btn_enhanced_bookmark_auto_folder.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/btn_enhanced_bookmark_auto_folder.xml
rename to chrome/android/java/res/drawable/btn_enhanced_bookmark_auto_folder.xml
diff --git a/chrome/android/java_staging/res/drawable/btn_new_tab_incognito.xml b/chrome/android/java/res/drawable/btn_new_tab_incognito.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/btn_new_tab_incognito.xml
rename to chrome/android/java/res/drawable/btn_new_tab_incognito.xml
diff --git a/chrome/android/java_staging/res/drawable/btn_new_tab_white.xml b/chrome/android/java/res/drawable/btn_new_tab_white.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/btn_new_tab_white.xml
rename to chrome/android/java/res/drawable/btn_new_tab_white.xml
diff --git a/chrome/android/java_staging/res/drawable/btn_reload_stop.xml b/chrome/android/java/res/drawable/btn_reload_stop.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/btn_reload_stop.xml
rename to chrome/android/java/res/drawable/btn_reload_stop.xml
diff --git a/chrome/android/java_staging/res/drawable/eb_item_highlight.xml b/chrome/android/java/res/drawable/eb_item_highlight.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/eb_item_highlight.xml
rename to chrome/android/java/res/drawable/eb_item_highlight.xml
diff --git a/chrome/android/java_staging/res/drawable/eb_list_toggle.xml b/chrome/android/java/res/drawable/eb_list_toggle.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/eb_list_toggle.xml
rename to chrome/android/java/res/drawable/eb_list_toggle.xml
diff --git a/chrome/android/java_staging/res/drawable/eb_title_bar_shadow.xml b/chrome/android/java/res/drawable/eb_title_bar_shadow.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/eb_title_bar_shadow.xml
rename to chrome/android/java/res/drawable/eb_title_bar_shadow.xml
diff --git a/chrome/android/java_staging/res/drawable/inset_textbox.xml b/chrome/android/java/res/drawable/inset_textbox.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/inset_textbox.xml
rename to chrome/android/java/res/drawable/inset_textbox.xml
diff --git a/chrome/android/java_staging/res/drawable/most_visited_item_bg.xml b/chrome/android/java/res/drawable/most_visited_item_bg.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/most_visited_item_bg.xml
rename to chrome/android/java/res/drawable/most_visited_item_bg.xml
diff --git a/chrome/android/java_staging/res/drawable/most_visited_item_empty.xml b/chrome/android/java/res/drawable/most_visited_item_empty.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/most_visited_item_empty.xml
rename to chrome/android/java/res/drawable/most_visited_item_empty.xml
diff --git a/chrome/android/java_staging/res/drawable/most_visited_thumbnail_placeholder.xml b/chrome/android/java/res/drawable/most_visited_thumbnail_placeholder.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/most_visited_thumbnail_placeholder.xml
rename to chrome/android/java/res/drawable/most_visited_thumbnail_placeholder.xml
diff --git a/chrome/android/java_staging/res/drawable/progress_bar.xml b/chrome/android/java/res/drawable/progress_bar.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/progress_bar.xml
rename to chrome/android/java/res/drawable/progress_bar.xml
diff --git a/chrome/android/java_staging/res/drawable/progress_bar_white.xml b/chrome/android/java/res/drawable/progress_bar_white.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/progress_bar_white.xml
rename to chrome/android/java/res/drawable/progress_bar_white.xml
diff --git a/chrome/android/java/res/drawable/sad_tab_background.xml b/chrome/android/java/res/drawable/sad_tab_background.xml
deleted file mode 100644
index 9441866..0000000
--- a/chrome/android/java/res/drawable/sad_tab_background.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:drawable="@drawable/sad_tab_background_inner"
-    android:insetTop="15dp"
-    android:insetRight="15dp"
-    android:insetBottom="15dp"
-    android:insetLeft="15dp" />
diff --git a/chrome/android/java/res/drawable/sad_tab_background_inner.xml b/chrome/android/java/res/drawable/sad_tab_background_inner.xml
deleted file mode 100644
index a66fad9d..0000000
--- a/chrome/android/java/res/drawable/sad_tab_background_inner.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android" >
-    <solid android:color="#fbfbfb" />
-    <corners android:radius="3dp" />
-    <padding
-        android:bottom="1dp"
-        android:left="1dp"
-        android:right="1dp"
-        android:top="1dp" />
-    <stroke
-        android:width="1dp"
-        android:color="#ababab" />
-</shape>
\ No newline at end of file
diff --git a/chrome/android/java/res/drawable/sad_tab_lower_panel_background.xml b/chrome/android/java/res/drawable/sad_tab_lower_panel_background.xml
deleted file mode 100644
index b84819d9..0000000
--- a/chrome/android/java/res/drawable/sad_tab_lower_panel_background.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android" >
-    <solid android:color="#f9f9f9" />
-    <corners
-        android:bottomLeftRadius="3dp"
-        android:bottomRightRadius="3dp"
-        android:topLeftRadius="0dp"
-        android:topRightRadius="0dp" />
-</shape>
\ No newline at end of file
diff --git a/chrome/android/java_staging/res/drawable/toolbar_shadow.xml b/chrome/android/java/res/drawable/toolbar_shadow.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/toolbar_shadow.xml
rename to chrome/android/java/res/drawable/toolbar_shadow.xml
diff --git a/chrome/android/java_staging/res/drawable/window_background.xml b/chrome/android/java/res/drawable/window_background.xml
similarity index 100%
rename from chrome/android/java_staging/res/drawable/window_background.xml
rename to chrome/android/java/res/drawable/window_background.xml
diff --git a/chrome/android/java/res/layout/autofill_credit_card_editor.xml b/chrome/android/java/res/layout/autofill_credit_card_editor.xml
index 662c2d0..4a57db0 100644
--- a/chrome/android/java/res/layout/autofill_credit_card_editor.xml
+++ b/chrome/android/java/res/layout/autofill_credit_card_editor.xml
@@ -99,7 +99,7 @@
             </LinearLayout>
         </LinearLayout>
 
-        <View style="@style/ButtonBarTopSpacer" />
+        <Space style="@style/ButtonBarTopSpacer" />
         <View style="@style/ButtonBarTopDivider" />
 
         <LinearLayout style="@style/ButtonBar" >
diff --git a/chrome/android/java/res/layout/autofill_profile_editor.xml b/chrome/android/java/res/layout/autofill_profile_editor.xml
index af6a895..255c198b 100644
--- a/chrome/android/java/res/layout/autofill_profile_editor.xml
+++ b/chrome/android/java/res/layout/autofill_profile_editor.xml
@@ -83,7 +83,7 @@
 
         </LinearLayout>
 
-        <View style="@style/ButtonBarTopSpacer" />
+        <Space style="@style/ButtonBarTopSpacer" />
         <View style="@style/ButtonBarTopDivider" />
 
         <LinearLayout style="@style/ButtonBar" >
diff --git a/chrome/android/java/res/layout/homepage_editor.xml b/chrome/android/java/res/layout/homepage_editor.xml
new file mode 100644
index 0000000..b58a38949
--- /dev/null
+++ b/chrome/android/java/res/layout/homepage_editor.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fillViewport="true" >
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:focusableInTouchMode="true" >
+
+        <org.chromium.chrome.browser.widget.FloatLabelLayout
+            android:id="@+id/homepage_url"
+            style="@style/PreferenceScreenLayout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" >
+            <EditText
+                android:id="@+id/homepage_url_edit"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:inputType="textUri"
+                android:singleLine="true"
+                android:hint="@string/options_homepage_edit_label" />
+        </org.chromium.chrome.browser.widget.FloatLabelLayout>
+
+        <Space style="@style/ButtonBarTopSpacer" />
+        <View style="@style/ButtonBarTopDivider" />
+
+        <LinearLayout style="@style/ButtonBar" >
+            <Button
+                android:id="@+id/homepage_reset"
+                style="@style/ButtonBarButton"
+                android:text="@string/reset" />
+
+            <Button
+                android:id="@+id/homepage_cancel"
+                style="@style/ButtonBarButton"
+                android:text="@string/cancel" />
+
+            <Button
+                android:id="@+id/homepage_save"
+                style="@style/ButtonBarButton"
+                android:text="@string/save" />
+        </LinearLayout>
+    </LinearLayout>
+
+</ScrollView>
diff --git a/chrome/android/java/res/layout/homepage_preferences.xml b/chrome/android/java/res/layout/homepage_preferences.xml
deleted file mode 100644
index 325173bc..0000000
--- a/chrome/android/java/res/layout/homepage_preferences.xml
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fillViewport="true" >
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:clickable="true"
-        android:focusableInTouchMode="true"
-        android:orientation="vertical" >
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_vertical"
-            android:orientation="horizontal"
-            android:paddingStart="16dp"
-            android:paddingEnd="16dp"
-            android:paddingTop="16dp"
-            android:paddingBottom="16dp"
-            style="@style/PreferenceLayout" >
-
-            <TextView
-                android:id="@+id/homepage_switch_label"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                style="@style/PreferenceTitle" />
-
-            <org.chromium.chrome.browser.widget.ChromeSwitchCompat
-                android:id="@+id/homepage_switch"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textOn="@string/text_on"
-                android:textOff="@string/text_off" />
-
-        </LinearLayout>
-
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:contentDescription="@null"
-            android:src="?android:attr/listDivider"
-            android:scaleType="fitXY" />
-
-        <EditText
-            android:id="@+id/custom_uri"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="16dp"
-            android:layout_marginStart="16dp"
-            android:layout_marginEnd="16dp"
-            android:hint="@string/options_startup_pages_placeholder"
-            android:inputType="textUri"
-            android:nextFocusLeft="@id/custom_uri"
-            android:nextFocusUp="@id/custom_uri"
-            android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceMedium" />
-
-        <CheckBox
-            android:id="@+id/default_checkbox"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="16dp"
-            android:layout_marginBottom="16dp"
-            android:layout_marginStart="16dp"
-            android:layout_marginEnd="16dp"
-            android:text="@string/homepage_default_title" />
-    </LinearLayout>
-
-</ScrollView>
diff --git a/chrome/android/java/res/layout/sad_tab.xml b/chrome/android/java/res/layout/sad_tab.xml
index 3c67d055..d7b9212d 100644
--- a/chrome/android/java/res/layout/sad_tab.xml
+++ b/chrome/android/java/res/layout/sad_tab.xml
@@ -6,72 +6,66 @@
      found in the LICENSE file.
 -->
 
-<ScrollView
+<org.chromium.chrome.browser.tab.SadTabView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:chrome="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     tools:ignore="Overdraw"
+    android:background="#f7f7f7"
+    android:fillViewport="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="#e6e6e6">
+    android:paddingStart="24dp"
+    android:paddingEnd="24dp"
+    android:paddingTop="24dp"
+    android:paddingBottom="24dp"
+    android:scrollbarStyle="outsideOverlay">
+
 
     <LinearLayout
-        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"
-        android:background="@drawable/sad_tab_background"
+        android:layout_width="wrap_content"
         android:orientation="vertical"
-        android:padding="16dp">
-
+        android:layout_gravity="center"
+        android:gravity="center">
+            
         <ImageView
             android:id="@+id/sad_tab_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:layout_marginTop="17dp"
+            android:paddingBottom="26dp"
             android:src="@drawable/sad_tab"
-            android:contentDescription="@null" />
+            android:contentDescription="@null"
+            android:layout_gravity="start"/>
 
         <TextView
             android:id="@+id/sad_tab_title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:layout_marginTop="15dp"
+            android:paddingBottom="16dp"
             android:text="@string/sad_tab_title"
-            android:textColor="#666"
-            android:textSize="20sp" />
+            android:textColor="@color/sad_tab_header_text_color"
+            android:textSize="23sp"
+            android:lineSpacingMultiplier="1.4"
+            android:layout_gravity="start"/>
 
-        <org.chromium.chrome.browser.widget.ButtonCompat
-            android:id="@+id/sad_tab_reload_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:layout_marginTop="15dp"
-            android:text="@string/sad_tab_reload_label"
-            android:textColor="#fff"
-            chrome:buttonColor="@color/light_active_color" />
-
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="1dp"
-            android:layout_marginTop="15dp"
-            android:background="#eee" />
-
-        <!-- Note: Using layout_width="wrap_content" and width="538dp" forces this TextView
-             to be as wide as possible up to a maximum width of 538dp. -->
         <org.chromium.ui.widget.TextViewWithClickableSpans
             android:id="@+id/sad_tab_message"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:background="@drawable/sad_tab_lower_panel_background"
-            android:paddingTop="18dp"
-            android:paddingBottom="18dp"
-            android:paddingStart="20dp"
-            android:paddingEnd="20dp"
-            android:textColor="#444"
-            android:textSize="13.8sp"
-            android:width="538dp" />
-    </LinearLayout>
+            android:paddingBottom="22dp"
+            android:textColor="@color/sad_tab_body_text_color"
+            android:textSize="14sp"
+            android:layout_gravity="start"/>
 
-</ScrollView>
\ No newline at end of file
+        <org.chromium.chrome.browser.widget.ButtonCompat
+            android:id="@+id/sad_tab_reload_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/sad_tab_reload_label"
+            android:textColor="#fff"
+            android:minWidth="222dp"
+            chrome:buttonColor="@color/light_active_color"
+            android:layout_gravity="end"/>
+    </LinearLayout>
+</org.chromium.chrome.browser.tab.SadTabView>
diff --git a/chrome/android/java_staging/res/mipmap-hdpi/bookmark_shortcut_icon.png b/chrome/android/java/res/mipmap-hdpi/bookmark_shortcut_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/mipmap-hdpi/bookmark_shortcut_icon.png
rename to chrome/android/java/res/mipmap-hdpi/bookmark_shortcut_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/mipmap-hdpi/incognito_app_icon.png b/chrome/android/java/res/mipmap-hdpi/incognito_app_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/mipmap-hdpi/incognito_app_icon.png
rename to chrome/android/java/res/mipmap-hdpi/incognito_app_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/mipmap-mdpi/bookmark_shortcut_icon.png b/chrome/android/java/res/mipmap-mdpi/bookmark_shortcut_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/mipmap-mdpi/bookmark_shortcut_icon.png
rename to chrome/android/java/res/mipmap-mdpi/bookmark_shortcut_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/mipmap-mdpi/incognito_app_icon.png b/chrome/android/java/res/mipmap-mdpi/incognito_app_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/mipmap-mdpi/incognito_app_icon.png
rename to chrome/android/java/res/mipmap-mdpi/incognito_app_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/mipmap-xhdpi/bookmark_shortcut_icon.png b/chrome/android/java/res/mipmap-xhdpi/bookmark_shortcut_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/mipmap-xhdpi/bookmark_shortcut_icon.png
rename to chrome/android/java/res/mipmap-xhdpi/bookmark_shortcut_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/mipmap-xhdpi/incognito_app_icon.png b/chrome/android/java/res/mipmap-xhdpi/incognito_app_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/mipmap-xhdpi/incognito_app_icon.png
rename to chrome/android/java/res/mipmap-xhdpi/incognito_app_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/mipmap-xxhdpi/bookmark_shortcut_icon.png b/chrome/android/java/res/mipmap-xxhdpi/bookmark_shortcut_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/mipmap-xxhdpi/bookmark_shortcut_icon.png
rename to chrome/android/java/res/mipmap-xxhdpi/bookmark_shortcut_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/mipmap-xxhdpi/incognito_app_icon.png b/chrome/android/java/res/mipmap-xxhdpi/incognito_app_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/mipmap-xxhdpi/incognito_app_icon.png
rename to chrome/android/java/res/mipmap-xxhdpi/incognito_app_icon.png
Binary files differ
diff --git a/chrome/android/java_staging/res/mipmap-xxxhdpi/bookmark_shortcut_icon.png b/chrome/android/java/res/mipmap-xxxhdpi/bookmark_shortcut_icon.png
similarity index 100%
rename from chrome/android/java_staging/res/mipmap-xxxhdpi/bookmark_shortcut_icon.png
rename to chrome/android/java/res/mipmap-xxxhdpi/bookmark_shortcut_icon.png
Binary files differ
diff --git a/chrome/android/java/res/values-hdpi/dimens.xml b/chrome/android/java/res/values-hdpi/dimens.xml
index 499901a0..3d31d04 100644
--- a/chrome/android/java/res/values-hdpi/dimens.xml
+++ b/chrome/android/java/res/values-hdpi/dimens.xml
@@ -14,4 +14,8 @@
     <dimen name="compositor_tab_title_bar_shadow_y_offset_incognito">-0.6667dp</dimen> <!-- -1px hdpi -->
     <!-- The size of the bounding box for favicons. -->
     <dimen name="compositor_tab_title_favicon_size">16dp</dimen>
+
+    <!-- TabSwitcher -->
+    <dimen name="tabswitcher_border_frame_padding_left">5.333dp</dimen>
+    <dimen name="tabswitcher_border_frame_padding_top">49.333dp</dimen>
 </resources>
diff --git a/chrome/android/java_staging/res/values-sw320dp/dimens.xml b/chrome/android/java/res/values-sw320dp/dimens.xml
similarity index 100%
rename from chrome/android/java_staging/res/values-sw320dp/dimens.xml
rename to chrome/android/java/res/values-sw320dp/dimens.xml
diff --git a/chrome/android/java_staging/res/values-sw600dp-port/dimens.xml b/chrome/android/java/res/values-sw600dp-port/dimens.xml
similarity index 100%
rename from chrome/android/java_staging/res/values-sw600dp-port/dimens.xml
rename to chrome/android/java/res/values-sw600dp-port/dimens.xml
diff --git a/chrome/android/java/res/values-sw600dp/dimens.xml b/chrome/android/java/res/values-sw600dp/dimens.xml
index 609201f..d69b8d06b 100644
--- a/chrome/android/java/res/values-sw600dp/dimens.xml
+++ b/chrome/android/java/res/values-sw600dp/dimens.xml
@@ -24,4 +24,31 @@
     <dimen name="data_usage_chart_height">325dp</dimen>
     <dimen name="data_reduction_promo_screen_width">550dp</dimen>
 
+    <!-- Tab Strip Dimensions -->
+    <dimen name="tab_strip_height">40dp</dimen>
+
+    <!-- Full Screen Dimensions -->
+    <dimen name="control_container_height">96dp</dimen>
+    <dimen name="custom_tabs_control_container_height">64dp</dimen>
+
+    <!-- The combined height of the tab strip and toolbar. -->
+    <dimen name="tab_strip_and_toolbar_height">96dp</dimen>
+
+    <dimen name="location_bar_url_text_size">18sp</dimen>
+    <dimen name="location_bar_icon_width">40dp</dimen>
+
+    <!-- Bookmarks widget dimensions -->
+    <dimen name="widget_thumbnail_height">104dp</dimen>
+    <dimen name="widget_column_width">130dp</dimen>
+
+    <!-- NTP dimensions -->
+    <dimen name="most_visited_spacing">16dp</dimen>
+    <dimen name="ntp_logo_height">180dp</dimen>
+
+    <!-- Recent tabs page -->
+    <dimen name="recent_tabs_visible_separator_padding">28dp</dimen>
+
+    <!-- Omnibox suggestion list -->
+    <dimen name="omnibox_suggestion_list_padding_top">8dp</dimen>
+    <dimen name="omnibox_suggestion_list_padding_bottom">8dp</dimen>
 </resources>
diff --git a/chrome/android/java/res/values-v21/styles.xml b/chrome/android/java/res/values-v21/styles.xml
index 75f28bf..70fd01b 100644
--- a/chrome/android/java/res/values-v21/styles.xml
+++ b/chrome/android/java/res/values-v21/styles.xml
@@ -8,8 +8,6 @@
     <style name="PreferencesTheme" parent="ThemeWithActionBar">
         <item name="android:textColorLink">@color/pref_accent_color</item>
         <item name="android:alertDialogTheme">@style/PreferencesDialogTheme</item>
-        <item name="android:editTextBackground">@drawable/abc_edit_text_material</item>
-        <item name="android:editTextStyle">@style/PreferenceEditTextStyle</item>
         <item name="android:spinnerItemStyle">@style/PreferenceSpinnerItem</item>
         <item name="floatLabelTextAppearance">@style/PreferenceFloatLabelTextAppearance</item>
         <item name="floatLabelPaddingLeft">@dimen/pref_autofill_field_horizontal_padding</item>
@@ -28,9 +26,6 @@
         <item name="android:textColor">@color/pref_accent_color</item>
         <item name="android:textSize">14sp</item>
     </style>
-    <style name="PreferenceEditTextStyle" parent="Widget.AppCompat.EditText">
-        <item name="android:backgroundTint">@color/edit_text_tint</item>
-    </style>
     <style name="PreferenceTitle">
         <item name="android:ellipsize">end</item>
         <item name="android:singleLine">true</item>
diff --git a/chrome/android/java/res/values-xhdpi/dimens.xml b/chrome/android/java/res/values-xhdpi/dimens.xml
index 7e17cb5..de9197f 100644
--- a/chrome/android/java/res/values-xhdpi/dimens.xml
+++ b/chrome/android/java/res/values-xhdpi/dimens.xml
@@ -9,4 +9,8 @@
 <resources>
     <!-- The size of the bounding box for favicons. -->
     <dimen name="compositor_tab_title_favicon_size">18dp</dimen>
+
+    <!-- TabSwitcher -->
+    <dimen name="tabswitcher_border_frame_padding_left">5.5dp</dimen>
+    <dimen name="tabswitcher_border_frame_padding_top">49.5dp</dimen>
 </resources>
diff --git a/chrome/android/java_staging/res/values-xxhdpi/dimens.xml b/chrome/android/java/res/values-xxhdpi/dimens.xml
similarity index 100%
rename from chrome/android/java_staging/res/values-xxhdpi/dimens.xml
rename to chrome/android/java/res/values-xxhdpi/dimens.xml
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index e486e49..7a07cdc 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -22,9 +22,11 @@
     <color name="infobar_tertiary_button_text">#969696</color>
 
     <!-- Tab Switcher Colors -->
-    <color name="tab_switcher_background">#111111</color>
+    <color name="tab_switcher_background">#14181C</color>
     <color name="accessibility_tab_switcher_list_item">#252525</color>
     <color name="accessibility_close_undo_text">#3adaff</color>
+    <color name="tab_back">#F1F1F1</color>
+    <color name="tab_back_incognito">#4F4F4F</color>
 
     <!-- App banner colors -->
     <color name="app_banner_install_button_bg">#689f38</color>
@@ -81,8 +83,19 @@
     <color name="fre_light_text_color">#494949</color>
     <color name="fre_title_color">#161616</color>
 
+    <!-- Sad Tab colors -->
+    <color name="sad_tab_header_text_color">#333333</color>
+    <color name="sad_tab_body_text_color">#646464</color>
+    
     <!-- NTP Colors. Used on the bookmarks and recent tabs pages. -->
     <color name="ntp_bg">#fff</color>
+    <color name="ntp_bg_incognito">#222</color>
+    <color name="ntp_most_visited_text">#333</color>
+    <color name="ntp_most_visited_bg">#f2f2f2</color>
+    <color name="ntp_list_item_text">#333</color>
+    <color name="ntp_list_header_text">#333</color>
+    <color name="ntp_list_header_subtext">#969696</color>
+    <color name="ntp_list_header_subtext_active">#7cadff</color>
 
     <!-- Signin promo screen colors -->
     <color name="illustration_background_color">#4FC3F7</color>
@@ -90,4 +103,45 @@
     <!-- Contextual Search colors -->
     <color name="contextual_search_promo_text_color">#333333</color>
     <color name="contextual_search_promo_background_color">#EEEEEE</color>
+
+    <!-- Theme colors. Also used for toolbar background -->
+    <color name="incognito_primary_color">#505050</color>
+
+    <!-- LocationBar colors -->
+    <color name="locationbar_light_hint_text">#80ffffff</color>
+    <color name="locationbar_light_selection_color">#cc5595fe</color>
+
+    <!-- Find in Page colors -->
+    <color name="find_result_bar_background_color">#bfffffff</color>
+    <color name="find_result_bar_background_border_color">#bf666666</color>
+    <color name="find_result_bar_result_color">#ffde43</color>
+    <color name="find_result_bar_result_border_color">#c9af35</color>
+    <color name="find_result_bar_active_color">#ff9632</color>
+    <color name="find_result_bar_active_border_color">#c37e3b</color>
+    <color name="find_in_page_query_color">#333333</color>
+    <color name="find_in_page_query_white_color">#ffffff</color>
+    <color name="find_in_page_results_status_color">#969696</color>
+    <color name="find_in_page_results_status_white_color">#7f7f7f</color>
+    <color name="find_in_page_failed_results_status_color">#db4437</color>
+
+    <!-- App Launch Colors -->
+    <color name="light_background_color">#FFFFFF</color>
+
+    <!-- Reader mode colors -->
+    <color name="reader_mode_header_bg">#ff494949</color>
+
+    <!-- WebappActivity colors -->
+    <color name="webapp_url_bar_bg">#fafafa</color>
+    <color name="webapp_url_bar_separator">#e1e1e1</color>
+
+    <!-- Enhanced bookmark UI colors -->
+    <color name="enhanced_bookmark_detail_text">#212121</color>
+    <color name="enhanced_bookmark_detail_section">#7C7B79</color>
+    <color name="enhanced_bookmark_app_bar_shadow_color">#1D000000</color>
+    <color name="enhanced_bookmark_detail_dialog_shadow_color">#30000000</color>
+    <color name="enhanced_bookmark_selection_action_bar_background">#4F82F4</color>
+    <color name="enhanced_bookmark_drawer_selected_color">#4281F4</color>
+
+    <!-- Opt out promo -->
+    <color name="opt_out_text_color">#646464</color>
 </resources>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 58cdef5..4d91b9e 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -21,6 +21,30 @@
 
     <!-- TabSwitcher - The minimum distance from the edge to commit a side swap. -->
     <dimen name="swipe_commit_distance">120dp</dimen>
+    <!-- TabSwitcher - Size of the shift applied to tabs when stacked. -->
+    <dimen name="stacked_tab_visible_size">4dp</dimen>
+    <!-- TabSwitcher - Buffer space above the stack. -->
+    <dimen name="stack_buffer_height">5dp</dimen>
+    <!-- TabSwitcher - Buffer space on the side of the stack. -->
+    <dimen name="stack_buffer_width">5dp</dimen>
+    <!-- TabSwitcher - Minimum spacing between tabs. -->
+    <dimen name="min_spacing">120dp</dimen>
+    <!-- TabSwitcher - Maximum over scroll. -->
+    <dimen name="over_scroll">75dp</dimen>
+    <!-- TabSwitcher - Minimum scrolling distance to even out all the tabs. -->
+    <dimen name="even_out_scrolling">400dp</dimen>
+    <!-- TabSwitcher - The space between tabs in the toolbar swiping transition. -->
+    <dimen name="toolbar_swipe_space_between_tabs">30dp</dimen>
+    <!-- TabSwitcher - The minimum distance from the edge to commit a toolbar side swap. -->
+    <dimen name="toolbar_swipe_commit_distance">90dp</dimen>
+    <!-- TabSwitcher - Maximum amount to slide the tabs down or right in over scroll. -->
+    <dimen name="over_scroll_slide">10dp</dimen>
+
+    <!-- TabSwitcher -->
+    <dimen name="tabswitcher_border_frame_padding_left">6dp</dimen>
+    <dimen name="tabswitcher_border_frame_padding_top">50dp</dimen>
+    <dimen name="tabswitcher_border_frame_transparent_top">3dp</dimen>
+    <dimen name="tabswitcher_border_frame_transparent_side">2dp</dimen>
 
     <!-- Tab title -->
     <dimen name="border_texture_title_fade">24dp</dimen>                    <!-- 40px hdpi -->
@@ -137,4 +161,128 @@
     <!-- Alert dialog -->
     <dimen name="dialog_padding_top">@dimen/abc_dialog_padding_top_material</dimen>
     <dimen name="dialog_padding_sides">@dimen/abc_dialog_padding_material</dimen>
+
+    <!-- Tab Strip Dimensions -->
+    <dimen name="tab_strip_height">0dp</dimen>
+
+    <!-- Full Screen Dimensions -->
+    <!-- Should match toolbar_height_no_shadow -->
+    <dimen name="control_container_height">56dp</dimen>
+    <dimen name="custom_tabs_control_container_height">56dp</dimen>
+    <dimen name="webapp_control_container_height">22dp</dimen>
+
+    <!-- The combined height of the tab strip and toolbar. -->
+    <dimen name="tab_strip_and_toolbar_height">56dp</dimen>
+
+    <!-- SelectBookmarkFolder - Default indent for bookmark folders in the selection dialog. -->
+    <dimen name="select_bookmark_folder_item_left">15dp</dimen>
+    <!-- SelectBookmarkFolder - Incremental indentation for nested bookmark folders in the
+         selection dialog. -->
+    <dimen name="select_bookmark_folder_item_inc_left">10dp</dimen>
+
+    <!-- Find in Page dimensions -->
+    <dimen name="find_result_bar_touch_width">68dp</dimen>
+    <dimen name="find_result_bar_draw_width">46dp</dimen>
+    <dimen name="find_result_bar_result_min_height">8px</dimen>
+    <dimen name="find_result_bar_active_min_height">16px</dimen>
+    <dimen name="find_result_bar_vertical_padding">8px</dimen>
+    <dimen name="find_result_bar_min_gap_between_stacks">3px</dimen>
+    <dimen name="find_result_bar_stacked_result_height">3px</dimen>
+    <dimen name="find_in_page_separator_width">1dp</dimen>
+    <dimen name="find_in_page_popup_width">375dp</dimen>
+    <dimen name="find_in_page_popup_height">60dp</dimen>
+    <dimen name="find_in_page_popup_margin_end">62dp</dimen>
+
+    <!-- Toolbar dimensions -->
+    <dimen name="toolbar_tab_count_text_size_1_digit">12dp</dimen>
+    <dimen name="toolbar_tab_count_text_size_2_digit">10dp</dimen>
+    <dimen name="toolbar_height_no_shadow">56dp</dimen>
+
+    <dimen name="location_bar_margin_top">5dp</dimen>
+    <dimen name="location_bar_margin_bottom">5dp</dimen>
+
+    <dimen name="toolbar_edge_padding">8dp</dimen>
+    <dimen name="location_bar_url_text_size">17sp</dimen>
+    <dimen name="location_bar_incognito_badge_padding">7dp</dimen>
+    <dimen name="omnibox_suggestion_height">60dp</dimen>
+    <dimen name="omnibox_suggestion_answer_height">72dp</dimen>
+    <dimen name="omnibox_suggestion_list_padding_top">0dp</dimen>
+    <dimen name="omnibox_suggestion_list_padding_bottom">0dp</dimen>
+    <dimen name="location_bar_icon_width">36dp</dimen>
+    <dimen name="tablet_toolbar_end_padding">6dp</dimen>
+
+    <!-- NTP dimensions -->
+    <dimen name="most_visited_spacing">16dp</dimen>
+    <dimen name="most_visited_tile_width">156dp</dimen>
+    <dimen name="most_visited_thumbnail_width">148dp</dimen>
+    <dimen name="most_visited_thumbnail_height">94dp</dimen>
+    <dimen name="most_visited_favicon_size">16dp</dimen>
+    <dimen name="most_visited_bg_corner_radius">2dp</dimen>
+    <!-- 250dp was chosen because it's smaller than the smallest dimension on the smallest device,
+         so we'll always have at least two columns of tiles (except in multiwindow with a narrow
+         window). -->
+    <dimen name="most_visited_two_column_min_width">250dp</dimen>
+    <!-- 450dp was chosen because it's greater than the width of the largest phone in portrait yet
+         less than the width of the smallest phone in landscape. So, we'll always have two columns
+         in portrait and three in landscape (except in atypical situations, like multiwindow). -->
+    <dimen name="most_visited_three_column_min_width">450dp</dimen>
+    <dimen name="icon_most_visited_layout_max_width">504dp</dimen>
+    <dimen name="icon_most_visited_layout_padding_top">16dp</dimen>
+    <dimen name="icon_most_visited_layout_no_logo_padding_top">28dp</dimen>
+    <dimen name="icon_most_visited_layout_bleed">8dp</dimen>
+    <dimen name="icon_most_visited_vertical_spacing">7dp</dimen>
+    <dimen name="icon_most_visited_min_horizontal_spacing">4dp</dimen>
+    <dimen name="icon_most_visited_max_horizontal_spacing">16dp</dimen>
+    <dimen name="icon_most_visited_tile_width">80dp</dimen>
+    <dimen name="icon_most_visited_icon_size">48dp</dimen>
+    <dimen name="ntp_logo_height">116dp</dimen>
+    <dimen name="ntp_list_item_padding">16dp</dimen>
+    <dimen name="ntp_list_item_min_height">48dp</dimen>
+    <dimen name="ntp_list_item_text_size">16sp</dimen>
+    <dimen name="ntp_list_item_favicon_size">16dp</dimen>
+    <dimen name="ntp_list_item_favicon_container_size">24dp</dimen>
+    <dimen name="ntp_shadow_height">9dp</dimen>
+
+    <!-- Bookmarks page -->
+    <dimen name="bookmark_folder_min_height">48dp</dimen>
+    <dimen name="bookmark_folder_text_size">16sp</dimen>
+
+    <!-- Recent tabs page -->
+    <dimen name="recent_tabs_visible_separator_padding">8dp</dimen>
+    <dimen name="recent_tabs_promo_padding">16dp</dimen>
+
+    <!-- Undo bar -->
+    <dimen name="undo_bar_height">48dp</dimen>
+    <dimen name="undo_bar_tablet_width">450dp</dimen>
+    <dimen name="undo_bar_tablet_margin">24dp</dimen>
+
+    <!-- Bookmarks widget dimensions -->
+    <dimen name="widget_thumbnail_height">94dp</dimen>
+    <dimen name="widget_horizontal_spacing">6dp</dimen>
+    <dimen name="widget_vertical_spacing">6dp</dimen>
+    <dimen name="widget_column_width">80dp</dimen>
+    <dimen name="widget_favicon_size">16dp</dimen>
+
+    <!-- Reader Mode dimensions -->
+    <dimen name="reader_mode_text_size">14sp</dimen>
+
+    <!-- Enhanced bookmarks dimensions -->
+    <dimen name="enhanced_bookmark_min_grid_width">135dp</dimen>
+    <dimen name="enhanced_bookmark_item_corner_radius">3dp</dimen>
+    <dimen name="enhanced_bookmark_item_popup_width">140dp</dimen>
+    <dimen name="enhanced_bookmark_item_half_space">4dp</dimen>
+    <dimen name="enhanced_bookmark_folder_item_left">16dp</dimen>
+    <dimen name="enhanced_bookmark_folder_item_icon_size">40dp</dimen>
+    <dimen name="enhanced_bookmark_detail_image_height">232dp</dimen>
+    <dimen name="enhanced_bookmark_minimum_dialog_size_tablet">500dp</dimen>
+    <dimen name="enhanced_bookmark_list_mode_background_margin">10dp</dimen>
+    <dimen name="enhanced_bookmark_drawer_drawable_padding">18dp</dimen>
+
+    <!-- Custom Tabs dimensions -->
+    <dimen name="custom_tabs_toolbar_maxWidth">60dp</dimen>
+    <dimen name="custom_tabs_toolbar_vertical_padding">16dp</dimen>
+    <dimen name="toolbar_icon_height">24dp</dimen>
+    <dimen name="min_toolbar_icon_side_padding">6dp</dimen>
+    <dimen name="custom_tabs_url_text_size">12sp</dimen>
+    <dimen name="custom_tabs_title_text_size">16sp</dimen>
 </resources>
diff --git a/chrome/android/java/res/values/ids.xml b/chrome/android/java/res/values/ids.xml
index ffad134..cf2aaaf 100644
--- a/chrome/android/java/res/values/ids.xml
+++ b/chrome/android/java/res/values/ids.xml
@@ -7,6 +7,12 @@
 -->
 
 <resources>
-    <item name="menu_item_enter_anim_id" type="id" />
+    <item name="background_drawable" type="id"/>
+    <item name="eb_page" type="id"/>
+    <item name="foreground_drawable" type="id"/>
     <item name="fre_pager" type="id"/>
+    <item name="menu_item_enter_anim_id" type="id" />
+    <item name="refine_view_id" type="id"/>
+    <item name="tabswitcher_multiple_drawable" type="id"/>
+    <item name="tabswitcher_single_drawable" type="id"/>
 </resources>
diff --git a/chrome/android/java/res/xml/homepage_preferences.xml b/chrome/android/java/res/xml/homepage_preferences.xml
new file mode 100644
index 0000000..4ac201e3
--- /dev/null
+++ b/chrome/android/java/res/xml/homepage_preferences.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:chrome="http://schemas.android.com/apk/res-auto">
+
+    <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
+        android:key="homepage_switch"
+        android:summaryOn="@string/text_on"
+        android:summaryOff="@string/text_off" />
+
+    <Preference
+        android:key="homepage_edit"
+        android:title="@string/options_homepage_edit_label"
+        android:fragment="org.chromium.chrome.browser.preferences.HomepageEditor" />
+
+</PreferenceScreen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ContentViewUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/ContentViewUtil.java
deleted file mode 100644
index 5af6e74..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ContentViewUtil.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser;
-
-import org.chromium.content.browser.ContentViewCore;
-import org.chromium.content_public.browser.WebContents;
-
-/**
- * This class provides a way to create the native WebContents required for instantiating a
- * ContentView.
- */
-public abstract class ContentViewUtil {
-    // Don't instantiate me.
-    private ContentViewUtil() {
-    }
-
-    /**
-     * A factory method to build a {@link WebContents} object.
-     * @param incognito       Whether or not the {@link WebContents} should be built with an
-     *                        incognito profile or not.
-     * @param initiallyHidden Whether or not the {@link WebContents} should be initially hidden.
-     * @return                A newly created {@link WebContents} object.
-     */
-    public static WebContents createWebContents(boolean incognito, boolean initiallyHidden) {
-        return nativeCreateWebContents(incognito, initiallyHidden);
-    }
-
-    /**
-     * TODO(dtrainor): Remove when this is no longer used.
-     * Helper method for getting a {@link WebContents} from a native WebContents pointer.
-     * @param webContentsPtr A native WebContents pointer.
-     * @return               A {@link WebContents} object that is linked to {@code webContentsPtr}.
-     */
-    public static WebContents fromNativeWebContents(long webContentsPtr) {
-        return nativeGetWebContentsFromNative(webContentsPtr);
-    }
-
-    /**
-     * TODO(dtrainor): Remove when this is no longer used.
-     * Helper method for getting a native WebContents pointer from a {@link WebContents} object.
-     * @param webContents A {@link WebContents} object.
-     * @return            A native WebContents poniter that is linked to {@code webContents}.
-     */
-    public static long getNativeWebContentsFromWebContents(WebContents webContents) {
-        return nativeGetNativeWebContentsPtr(webContents);
-    }
-
-    /**
-     * @return pointer to native WebContents instance, suitable for using with a
-     *         (java) ContentViewCore instance.
-     */
-    public static WebContents createWebContentsWithSharedSiteInstance(
-            ContentViewCore contentViewCore) {
-        return nativeCreateWebContentsWithSharedSiteInstance(contentViewCore);
-    }
-
-    private static native WebContents nativeCreateWebContents(boolean incognito,
-            boolean initiallyHidden);
-    private static native WebContents nativeCreateWebContentsWithSharedSiteInstance(
-            ContentViewCore contentViewCore);
-    private static native WebContents nativeGetWebContentsFromNative(long webContentsPtr);
-    private static native long nativeGetNativeWebContentsPtr(WebContents webContents);
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
index 279e5e2..dbff0bed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
@@ -1382,7 +1382,7 @@
 
             boolean creatingWebContents = webContents == null;
             if (creatingWebContents) {
-                webContents = ContentViewUtil.createWebContents(isIncognito(), initiallyHidden);
+                webContents = WebContentsFactory.createWebContents(isIncognito(), initiallyHidden);
             }
 
             ContentViewCore contentViewCore = ContentViewCore.fromWebContents(webContents);
@@ -1871,7 +1871,7 @@
 
         if (mPendingLoadParams != null) {
             assert isFrozen();
-            initContentViewCore(ContentViewUtil.createWebContents(isIncognito(), isHidden()));
+            initContentViewCore(WebContentsFactory.createWebContents(isIncognito(), isHidden()));
             loadUrl(mPendingLoadParams);
             mPendingLoadParams = null;
             return true;
@@ -1943,13 +1943,13 @@
             assert getContentViewCore() == null;
 
             boolean forceNavigate = false;
-            WebContents webContents = ContentViewUtil.fromNativeWebContents(
-                    mFrozenContentsState.restoreContentsFromByteBuffer(isHidden()));
+            WebContents webContents =
+                    mFrozenContentsState.restoreContentsFromByteBuffer(isHidden());
             if (webContents == null) {
                 // State restore failed, just create a new empty web contents as that is the best
                 // that can be done at this point. TODO(jcivelli) http://b/5910521 - we should show
                 // an error page instead of a blank page in that case (and the last loaded URL).
-                webContents = ContentViewUtil.createWebContents(isIncognito(), isHidden());
+                webContents = WebContentsFactory.createWebContents(isIncognito(), isHidden());
                 forceNavigate = true;
             }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/TabState.java b/chrome/android/java/src/org/chromium/chrome/browser/TabState.java
index 8aa97293..2df2ee1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/TabState.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/TabState.java
@@ -11,6 +11,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.util.StreamUtil;
 import org.chromium.content.browser.crypto.CipherFactory;
+import org.chromium.content_public.browser.WebContents;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -80,9 +81,9 @@
         /**
          * Creates a WebContents from the buffer.
          * @param isHidden Whether or not the tab initially starts hidden.
-         * @return Pointer to the native WebContents.
+         * @return Pointer A WebContents object.
          */
-        public long restoreContentsFromByteBuffer(boolean isHidden) {
+        public WebContents restoreContentsFromByteBuffer(boolean isHidden) {
             return nativeRestoreContentsFromByteBuffer(mBuffer, mVersion, isHidden);
         }
 
@@ -420,7 +421,7 @@
         sChannelNameOverrideForTest = name;
     }
 
-    private static native long nativeRestoreContentsFromByteBuffer(
+    private static native WebContents nativeRestoreContentsFromByteBuffer(
             ByteBuffer buffer, int savedStateVersion, boolean initiallyHidden);
 
     private static native ByteBuffer nativeGetContentsStateAsByteBuffer(Tab tab);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UrlUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/UrlUtilities.java
index f51aa43..33aea29 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/UrlUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/UrlUtilities.java
@@ -237,7 +237,7 @@
             return false;
         }
 
-        URI parsed = null;
+        URI parsed;
         try {
             parsed = new URI(url);
         } catch (URISyntaxException e) {
@@ -252,7 +252,8 @@
             return false;
         }
 
-        if (!parsed.getScheme().equals("intent")) {
+        String scheme = parsed.getScheme();
+        if (scheme == null || !scheme.equals("intent")) {
             Log.d(TAG, "scheme was not 'intent'");
             return false;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WebContentsFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/WebContentsFactory.java
new file mode 100644
index 0000000..49ac2e2
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/WebContentsFactory.java
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser;
+
+import org.chromium.content_public.browser.WebContents;
+
+/**
+ * This factory creates WebContents objects and the associated native counterpart.
+ * TODO(dtrainor): Move this to the content/ layer if BrowserContext is ever supported in Java.
+ */
+public abstract class WebContentsFactory {
+    // Don't instantiate me.
+    private WebContentsFactory() {
+    }
+
+    /**
+     * A factory method to build a {@link WebContents} object.
+     * @param incognito       Whether or not the {@link WebContents} should be built with an
+     *                        off-the-record profile or not.
+     * @param initiallyHidden Whether or not the {@link WebContents} should be initially hidden.
+     * @return                A newly created {@link WebContents} object.
+     */
+    public static WebContents createWebContents(boolean incognito, boolean initiallyHidden) {
+        return nativeCreateWebContents(incognito, initiallyHidden);
+    }
+
+    private static native WebContents nativeCreateWebContents(boolean incognito,
+            boolean initiallyHidden);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchControl.java
index 17853b0..7e26eb5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchControl.java
@@ -21,6 +21,13 @@
  * Based on ToolbarControlContainer.
  */
 public class ContextualSearchControl extends LinearLayout {
+    /**
+     * Object Replacement Character that is used in place of HTML objects that cannot be represented
+     * as text (e.g. images). Contextual search panel should not be displaying such characters as
+     * they get shown as [obj] character.
+     */
+    private static final String OBJ_CHARACTER = "\uFFFC";
+
     private static final float RESOLVED_SEARCH_TERM_SIDE_PADDING_DP = 40.f;
     private final int mSidePaddingPx;
 
@@ -106,9 +113,9 @@
      */
     public void setSearchContext(String selection, String start, String end) {
         mSelectionText.setPadding(0, 0, 0, 0);
-        mSelectionText.setText(selection);
-        mStartText.setText(start);
-        mEndText.setText(end);
+        mSelectionText.setText(sanitizeText(selection));
+        mStartText.setText(sanitizeText(start));
+        mEndText.setText(sanitizeText(end));
         mIsDirty = true;
     }
 
@@ -123,4 +130,9 @@
         mEndText.setText("");
         mIsDirty = true;
     }
+
+    private String sanitizeText(String text) {
+        if (text == null) return null;
+        return text.replace(OBJ_CHARACTER, " ");
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java
index db12da1..070c83b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelBase.java
@@ -33,11 +33,6 @@
     private static final float EXPANDED_PANEL_HEIGHT_PERCENTAGE = .7f;
 
     /**
-     * The height of the Toolbar in dps.
-     */
-    private static final float TOOLBAR_HEIGHT_DP = 56.f;
-
-    /**
      * The height of the Contextual Search Panel's Shadow in dps.
      */
     private static final float PANEL_SHADOW_HEIGHT_DP = 16.f;
@@ -128,6 +123,11 @@
     private static final float PROGRESS_BAR_VISIBILITY_THRESHOLD_DP = 10.f;
 
     /**
+     * The height of the Toolbar in dps.
+     */
+    private final float mToolbarHeight;
+
+    /**
      * The height of the Search Bar when the Panel is peeking, in dps.
      */
     private final float mSearchBarHeightPeeking;
@@ -191,9 +191,12 @@
 
         mPxToDp = 1.f / context.getResources().getDisplayMetrics().density;
 
+        mToolbarHeight = context.getResources().getDimension(
+                R.dimen.control_container_height) * mPxToDp;
+
         mSearchBarHeightPeeking = context.getResources().getDimension(
                 R.dimen.contextual_search_bar_height) * mPxToDp;
-        mSearchBarHeightMaximized = TOOLBAR_HEIGHT_DP + PANEL_SHADOW_HEIGHT_DP;
+        mSearchBarHeightMaximized = mToolbarHeight + PANEL_SHADOW_HEIGHT_DP;
         mSearchBarHeightExpanded =
                 Math.round((mSearchBarHeightPeeking + mSearchBarHeightMaximized) / 2.f);
         mSearchBarHeightPromo = SEARCH_BAR_HEIGHT_STATE_PROMO + PANEL_SHADOW_HEIGHT_DP;
@@ -266,12 +269,19 @@
     }
 
     /**
+     * @return The height of the Chrome toolbar in dp.
+     */
+    public float getToolbarHeight() {
+        return mToolbarHeight;
+    }
+
+    /**
      * @param y The y coordinate.
      * @return The Y coordinate relative the fullscreen height.
      */
     public float getFullscreenY(float y) {
         if (mIsToolbarShowing) {
-            y += TOOLBAR_HEIGHT_DP / mPxToDp;
+            y += mToolbarHeight / mPxToDp;
         }
         return y;
     }
@@ -307,7 +317,7 @@
         // here, there will be a "jump" when swiping the Search Panel around.
         // TODO(pedrosimonetti): Find better way to get the fullscreen height.
         if (mIsToolbarShowing) {
-            height += TOOLBAR_HEIGHT_DP;
+            height += mToolbarHeight;
         }
         return height;
     }
@@ -1162,7 +1172,7 @@
         offset = Math.min(offset, 0.f);
         // If visible, the Toolbar will be hidden. Therefore, we need to adjust
         // the offset to account for this difference.
-        if (mIsToolbarShowing) offset -= TOOLBAR_HEIGHT_DP;
+        if (mIsToolbarShowing) offset -= mToolbarHeight;
         // Make sure the offset is not greater than the expanded height, because
         // there's nothing to render below the Page.
         offset = Math.max(offset, -expandedHeight);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/OWNERS
new file mode 100644
index 0000000..812e8d9
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/OWNERS
@@ -0,0 +1 @@
+aurimas@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
index aeb178e7..231075b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
@@ -1143,10 +1143,16 @@
         updateSceneLayer(viewport, contentViewport, layerTitleCache, tabContentManager,
                 resourceManager, fullscreenManager);
 
+        float offsetPx = fullscreenManager != null ? fullscreenManager.getControlOffset() : 0.f;
+        float dpToPx = getContext().getResources().getDisplayMetrics().density;
+        float offsetDp = offsetPx / dpToPx;
+        float offsetOverride = getTopControlsOffset(offsetDp);
+        if (!Float.isNaN(offsetOverride)) offsetDp = offsetOverride;
+
         SceneLayer content = getSceneLayer();
         for (int i = 0; i < mSceneOverlays.size(); i++) {
             SceneOverlayLayer overlayLayer = mSceneOverlays.get(i).getUpdatedSceneOverlayTree(
-                    layerTitleCache, resourceManager, fullscreenManager);
+                    layerTitleCache, resourceManager, offsetDp);
 
             overlayLayer.setContentTree(content);
             content = overlayLayer;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java
index 7b211d1..d44cb1db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java
@@ -8,7 +8,6 @@
 import org.chromium.chrome.browser.compositor.layouts.components.VirtualView;
 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter;
 import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer;
-import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.ui.resources.ResourceManager;
 
@@ -23,12 +22,12 @@
      *
      * @param layerTitleCache A layer title cache.
      * @param resourceManager A resource manager.
-     * @param fullscreenManager A fullscreen manager.
+     * @param yOffset Current top controls offset in dp.
      * @return A {@link SceneOverlayLayer} that represents an scene overlay.
      * Or {@code null} if this {@link SceneOverlay} doesn't have a tree.
      */
     SceneOverlayLayer getUpdatedSceneOverlayTree(LayerTitleCache layerTitleCache,
-            ResourceManager resourceManager, ChromeFullscreenManager fullscreenManager);
+            ResourceManager resourceManager, float yOffset);
 
     /**
      * @return The {@link EventFilter} that processes events for this {@link SceneOverlay}.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
index 632fb07..cf0867b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
@@ -20,9 +20,6 @@
  * Centralizes UMA data collection for Contextual Search. All calls must be made from the UI thread.
  */
 public class ContextualSearchUma {
-    // An invalid value for the number of taps remaining for the promo.  Must be negative.
-    private static final int PROMO_TAPS_REMAINING_INVALID = -1;
-
     // Constants to use for the original selection gesture
     private static final boolean LONG_PRESS = false;
     private static final boolean TAP = true;
@@ -459,7 +456,7 @@
      *        before the first open of the panel, for all users that have ever opened the panel.
      */
     public static void logPromoTapsBeforeFirstOpen(int promoTaps) {
-        RecordHistogram.recordCountHistogram("Search.ContextualSearchPromosTapsBeforeFirstOpen",
+        RecordHistogram.recordCountHistogram("Search.ContextualSearchPromoTapsBeforeFirstOpen",
                 promoTaps);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/OWNERS
new file mode 100644
index 0000000..812e8d9
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/OWNERS
@@ -0,0 +1 @@
+aurimas@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
index d06d43f..a2da145 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -51,6 +51,13 @@
     }
 
     /**
+     * @return The activity that this delegate is associated with.
+     */
+    protected final Activity getActivity() {
+        return mActivity;
+    }
+
+    /**
      * Retrieve the best activity for the given intent. If a default activity is provided,
      * choose the default one. Otherwise, return the Intent picker if there are more than one
      * capable activities. If the intent is pdf type, return the platform pdf viewer if
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
index dbc956c..78a4c63 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -63,7 +63,10 @@
         this(new ExternalNavigationDelegateImpl(activity));
     }
 
-    @VisibleForTesting
+    /**
+     * Constructs a new instance of {@link ExternalNavigationHandler}, using the injected
+     * {@link ExternalNavigationDelegate}.
+     */
     public ExternalNavigationHandler(ExternalNavigationDelegate delegate) {
         mDelegate = delegate;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollector.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollector.java
index bcf16c6..16c7bf7f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollector.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollector.java
@@ -4,8 +4,11 @@
 
 package org.chromium.chrome.browser.feedback;
 
+import android.os.SystemClock;
+
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.profiles.Profile;
 
 import java.util.Collections;
@@ -26,21 +29,58 @@
      * FeedbackData contains the set of information that is to be included in a feedback report.
      */
     public static final class FeedbackData {
-        private final Map<Type, Result> mConnections;
+        /**
+         * The key for the data describing the timeout that was set as a maximum for collecting
+         * the connection data. This is to better understand the connection data.
+         * This string is user visible.
+         */
+        @VisibleForTesting
+        static final String CONNECTION_CHECK_TIMEOUT_MS = "Connection check timeout (ms)";
 
-        FeedbackData(Map<Type, Result> connections) {
+        /**
+         * The key for the data describing how long time from the connection check was started,
+         * until the data was collected. This is to better understand the connection data.
+         * This string is user visible.
+         */
+        @VisibleForTesting
+        static final String CONNECTION_CHECK_ELAPSED_MS = "Connection check elapsed (ms)";
+
+        private final Map<Type, Result> mConnections;
+        private final int mTimeoutMs;
+        private final long mElapsedTimeMs;
+
+        FeedbackData(Map<Type, Result> connections, int timeoutMs, long elapsedTimeMs) {
             mConnections = connections;
+            mTimeoutMs = timeoutMs;
+            mElapsedTimeMs = elapsedTimeMs;
         }
 
         /**
          * @return a {@link Map} with information about connection status for different connection
          * types.
          */
-        public Map<Type, Result> getConnections() {
+        @VisibleForTesting
+        Map<Type, Result> getConnections() {
             return Collections.unmodifiableMap(mConnections);
         }
 
         /**
+         * @return the timeout that was used for data collection.
+         */
+        @VisibleForTesting
+        int getTimeoutMs() {
+            return mTimeoutMs;
+        }
+
+        /**
+         * @return the time that was used from starting the check until data was gathered.
+         */
+        @VisibleForTesting
+        long getElapsedTimeMs() {
+            return mElapsedTimeMs;
+        }
+
+        /**
          * @return a {@link Map} with all the data fields for this feedback.
          */
         public Map<String, String> toMap() {
@@ -48,6 +88,8 @@
             for (Map.Entry<Type, Result> entry : mConnections.entrySet()) {
                 map.put(entry.getKey().name(), entry.getValue().name());
             }
+            map.put(CONNECTION_CHECK_TIMEOUT_MS, String.valueOf(mTimeoutMs));
+            map.put(CONNECTION_CHECK_ELAPSED_MS, String.valueOf(mElapsedTimeMs));
             return map;
         }
     }
@@ -65,6 +107,10 @@
 
     private static class ConnectivityCheckerFuture implements Future<FeedbackData> {
         private final Map<Type, Result> mResult = new EnumMap<Type, Result>(Type.class);
+        // These timing values are set to -1 to signify an error until they are correctly set
+        // when starting the checks and gathering the data.
+        private int mTimeoutMs = -1;
+        private long mStartCheckTimeMs = -1;
 
         private class SingleTypeTask implements ConnectivityChecker.ConnectivityCheckerCallback {
             private final Type mType;
@@ -140,7 +186,8 @@
                     result.put(type, Result.UNKNOWN);
                 }
             }
-            return new FeedbackData(result);
+            long elapsedTimeMs = SystemClock.elapsedRealtime() - mStartCheckTimeMs;
+            return new FeedbackData(result, mTimeoutMs, elapsedTimeMs);
         }
 
         @Override
@@ -152,6 +199,8 @@
          * Starts a separate connectivity check for each {@link Type}.
          */
         public void startChecks(Profile profile, int timeoutMs) {
+            mTimeoutMs = timeoutMs;
+            mStartCheckTimeMs = SystemClock.elapsedRealtime();
             for (Type t : Type.values()) {
                 SingleTypeTask task = new SingleTypeTask(t);
                 task.start(profile, timeoutMs);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedbackCollector.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedbackCollector.java
new file mode 100644
index 0000000..7327bd6
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedbackCollector.java
@@ -0,0 +1,124 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.feedback;
+
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import org.chromium.base.Log;
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
+import org.chromium.chrome.browser.profiles.Profile;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import javax.annotation.Nullable;
+
+/**
+ * A class which collects generic information about Chrome which is useful for all types of
+ * feedback, and provides it as a {@link Bundle}.
+ *
+ * Creating a {@link FeedbackCollector} initiates asynchronous operations for gathering feedback
+ * data, which may or not finish before the bundle is requested by calling {@link #getBundle()}.
+ *
+ * Interacting with the {@link FeedbackCollector} is only allowed on the main thread.
+ */
+public class FeedbackCollector {
+    private static final String TAG = "cr.feedback";
+
+    /**
+     * A user visible string describing the current URL.
+     */
+    private static final String URL_KEY = "URL";
+
+    /**
+     * A user visible string describing whether the data reduction proxy is enabled.
+     */
+    private static final String DATA_REDUCTION_PROXY_ENABLED_KEY = "Data reduction proxy enabled";
+
+    /**
+     * The default timeout for gathering data asynchronously.
+     */
+    private static final int DEFAULT_ASYNC_COLLECTION_TIMEOUT_MS = 1000;
+
+    private final Map<String, String> mData;
+    private final Profile mProfile;
+    private final String mUrl;
+    private final Future<ConnectivityCheckerCollector.FeedbackData> mConnectivityFuture;
+
+    /**
+     * Creates a {@link FeedbackCollector} and starts asynchronous operations to gather extra data.
+     * @param profile the current Profile.
+     * @param url The URL of the current tab to include in the feedback the user sends, if any.
+     *            This parameter may be null.
+     * @return the created {@link FeedbackCollector}.
+     */
+    public static FeedbackCollector create(Profile profile, @Nullable String url) {
+        ThreadUtils.assertOnUiThread();
+        return new FeedbackCollector(profile, url);
+    }
+
+    private FeedbackCollector(Profile profile, String url) {
+        mData = new HashMap<>();
+        mProfile = profile;
+        mUrl = url;
+        mConnectivityFuture = ConnectivityCheckerCollector.startChecks(
+                mProfile, DEFAULT_ASYNC_COLLECTION_TIMEOUT_MS);
+    }
+
+    /**
+     * Adds a key-value pair of data to be included in the feedback report. This data
+     * is user visible and should only contain single-line forms of data, not long Strings.
+     * @param key the user visible key.
+     * @param value the user visible value.
+     */
+    public void add(String key, String value) {
+        ThreadUtils.assertOnUiThread();
+        mData.put(key, value);
+    }
+
+    /**
+     * @return the collected data as a {@link Bundle}.
+     */
+    public Bundle getBundle() {
+        ThreadUtils.assertOnUiThread();
+        addUrl();
+        addConnectivityData();
+        addDataReductionProxyData();
+        return asBundle();
+    }
+
+    private void addUrl() {
+        if (!TextUtils.isEmpty(mUrl)) {
+            mData.put(URL_KEY, mUrl);
+        }
+    }
+
+    private void addConnectivityData() {
+        try {
+            Map<String, String> connectivityMap = mConnectivityFuture.get().toMap();
+            mData.putAll(connectivityMap);
+        } catch (InterruptedException | ExecutionException e) {
+            Log.w(TAG, "Failed to successfully get connectivity data.", e.getMessage());
+        }
+    }
+
+    private void addDataReductionProxyData() {
+        mData.put(DATA_REDUCTION_PROXY_ENABLED_KEY,
+                String.valueOf(
+                        DataReductionProxySettings.getInstance().isDataReductionProxyEnabled()));
+    }
+
+    private Bundle asBundle() {
+        Bundle bundle = new Bundle();
+        for (Map.Entry<String, String> entry : mData.entrySet()) {
+            bundle.putString(entry.getKey(), entry.getValue());
+        }
+        return bundle;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
index 8e73020..07b6dbd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
@@ -217,10 +217,8 @@
             return createGenericFirstRunIntent(activity, originalIntent, fromChromeIcon);
         }
 
-        // If Chrome isn't opened via the Chrome icon proceed directly to the intent handling.
-        if (!fromChromeIcon) return null;
-
-        return createGenericFirstRunIntent(activity, originalIntent, fromChromeIcon);
+        // Promo pages are removed, so there is nothing else to show in FRE.
+        return null;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/help/HelpAndFeedback.java b/chrome/android/java/src/org/chromium/chrome/browser/help/HelpAndFeedback.java
index 39a2b66..8952c1bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/help/HelpAndFeedback.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/help/HelpAndFeedback.java
@@ -18,6 +18,10 @@
 import org.chromium.chrome.browser.ChromiumApplication;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.UrlUtilities;
+import org.chromium.chrome.browser.feedback.FeedbackCollector;
+import org.chromium.chrome.browser.profiles.Profile;
+
+import javax.annotation.Nonnull;
 
 /**
  * Launches an activity that displays a relevant support page and has an option to provide feedback.
@@ -42,6 +46,18 @@
     }
 
     /**
+     * This method is deprecated and only exists to ensure it is possible to safely roll.
+     * Use {@link #show(Activity, String, Bitmap, FeedbackCollector)}
+     * instead.
+     * TODO(nyquist): Remove this method when only the new method is in use. See crbug.com/386395.
+     */
+    @Deprecated
+    public void show(Activity activity, String helpContext, Bitmap screenshot, String url) {
+        show(activity, helpContext, screenshot,
+                FeedbackCollector.create(Profile.getLastUsedProfile(), url));
+    }
+
+    /**
      * Starts an activity showing a help page for the specified context ID.
      *
      * @param activity The activity to use for starting the help activity and to take a
@@ -51,10 +67,10 @@
      * @param screenshot A screenshot of the current activity to include in the feedback the
      *                   user sends, if any. If null, this method will take a screenshot of the
      *                   activity (which will show a rendered page as black).
-     * @param url The URL of the current tab to include in the feedback the user sends, if any.
-     *            This parameter can be null.
+     * @param collector the {@link FeedbackCollector} to use for extra data. Must not be null.
      */
-    public void show(Activity activity, String helpContext, Bitmap screenshot, String url) {
+    public void show(Activity activity, String helpContext, Bitmap screenshot,
+            @Nonnull FeedbackCollector collector) {
         launchFallbackSupportUri(activity);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
index c33b904..ea4bde7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
@@ -4,7 +4,18 @@
 
 package org.chromium.chrome.browser.infobar;
 
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
+import android.os.Process;
+
+import org.chromium.chrome.browser.ContentSettingsType;
+import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.base.WindowAndroid.PermissionCallback;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * An infobar that presents the user with several buttons.
@@ -24,6 +35,14 @@
     /** Notified when one of the buttons is clicked. */
     private final InfoBarListeners.Confirm mConfirmListener;
 
+    private WindowAndroid mWindowAndroid;
+
+    /**
+     * The list of {@link ContentSettingsType}s being requested by this infobar.  Can be null or
+     * empty if none apply.
+     */
+    private int[] mContentSettings;
+
     public ConfirmInfoBar(InfoBarListeners.Confirm confirmListener, int iconDrawableId,
             Bitmap iconBitmap, String message, String linkText, String primaryButtonText,
             String secondaryButtonText) {
@@ -34,13 +53,106 @@
         mConfirmListener = confirmListener;
     }
 
+    /**
+     * Specifies the {@link ContentSettingsType}s that are controlled by this InfoBar.
+     *
+     * @param windowAndroid The WindowAndroid that will be used to check for the necessary
+     *                      permissions.
+     * @param contentSettings The list of {@link ContentSettingsType}s whose access is guarded
+     *                        by this InfoBar.
+     */
+    protected void setContentSettings(
+            WindowAndroid windowAndroid, int[] contentSettings) {
+        mWindowAndroid = windowAndroid;
+        mContentSettings = contentSettings;
+
+        assert windowAndroid != null
+                : "A WindowAndroid must be specified to request access to content settings";
+    }
+
     @Override
     public void createContent(InfoBarLayout layout) {
         layout.setButtons(mPrimaryButtonText, mSecondaryButtonText, mTertiaryButtonText);
     }
 
+    private static boolean hasPermission(Context context, String permission) {
+        return context.checkPermission(permission, Process.myPid(), Process.myUid())
+                != PackageManager.PERMISSION_DENIED;
+    }
+
+    private List<String> getPermissionsToRequest() {
+        Context context = getContext();
+        List<String> permissionsToRequest = new ArrayList<String>();
+        for (int i = 0; i < mContentSettings.length; i++) {
+            switch (mContentSettings[i]) {
+                case ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION:
+                    if (!hasPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)) {
+                        permissionsToRequest.add(Manifest.permission.ACCESS_FINE_LOCATION);
+                    }
+                    break;
+                case ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
+                    if (!hasPermission(context, Manifest.permission.CAMERA)) {
+                        permissionsToRequest.add(Manifest.permission.CAMERA);
+                    }
+                    break;
+                case ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
+                    if (!hasPermission(context, Manifest.permission.RECORD_AUDIO)) {
+                        permissionsToRequest.add(Manifest.permission.RECORD_AUDIO);
+                    }
+                    break;
+                default:
+                    // No associated Android permission, so just skip it.
+                    break;
+            }
+        }
+        return permissionsToRequest;
+    }
+
     @Override
-    public void onButtonClicked(boolean isPrimaryButton) {
+    public void onButtonClicked(final boolean isPrimaryButton) {
+        if (mWindowAndroid == null || mContentSettings == null
+                || !isPrimaryButton || getContext() == null) {
+            onButtonClickedInternal(isPrimaryButton);
+            return;
+        }
+
+        List<String> permissionsToRequest = getPermissionsToRequest();
+        if (permissionsToRequest.isEmpty()) {
+            onButtonClickedInternal(isPrimaryButton);
+            return;
+        }
+
+        PermissionCallback callback = new PermissionCallback() {
+            @Override
+            public void onRequestPermissionsResult(
+                    String[] permissions, int[] grantResults) {
+                boolean grantedAllPermissions = true;
+                for (int i = 0; i < grantResults.length; i++) {
+                    if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
+                        grantedAllPermissions = false;
+                        break;
+                    }
+                }
+
+                if (!grantedAllPermissions) {
+                    onCloseButtonClicked();
+                } else {
+                    onButtonClickedInternal(true);
+                }
+            }
+
+            @Override
+            public void onRequestPermissionAborted() {
+                onCloseButtonClicked();
+            }
+        };
+
+        mWindowAndroid.requestPermissions(
+                permissionsToRequest.toArray(new String[permissionsToRequest.size()]),
+                callback);
+    }
+
+    private void onButtonClickedInternal(boolean isPrimaryButton) {
         if (mConfirmListener != null) {
             mConfirmListener.onConfirmInfoBarButtonClicked(this, isPrimaryButton);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java
index d5d0ad1..d82b81c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java
@@ -8,6 +8,7 @@
 
 import org.chromium.base.CalledByNative;
 import org.chromium.chrome.browser.ResourceId;
+import org.chromium.ui.base.WindowAndroid;
 
 /**
  * Provides JNI methods for ConfirmInfoBars
@@ -24,22 +25,28 @@
 
     /**
      * Creates and begins the process for showing a ConfirmInfoBar.
+     * @param windowAndroid The owning window for the infobar.
      * @param enumeratedIconId ID corresponding to the icon that will be shown for the InfoBar.
      *                         The ID must have been mapped using the ResourceMapper class before
      *                         passing it to this function.
-     * @param iconBitmap Bitmap to use if there is no equivalent Java resource for enumeratedIconId.
+     * @param iconBitmap Bitmap to use if there is no equivalent Java resource for
+     *                   enumeratedIconId.
      * @param message Message to display to the user indicating what the InfoBar is for.
      * @param linkText Link text to display in addition to the message.
      * @param buttonOk String to display on the OK button.
      * @param buttonCancel String to display on the Cancel button.
+     * @param contentSettings The list of ContentSettingTypes being requested by this infobar.
      */
     @CalledByNative
-    InfoBar showConfirmInfoBar(int enumeratedIconId, Bitmap iconBitmap, String message,
-            String linkText, String buttonOk, String buttonCancel) {
+    InfoBar showConfirmInfoBar(WindowAndroid windowAndroid, int enumeratedIconId,
+            Bitmap iconBitmap, String message, String linkText, String buttonOk,
+            String buttonCancel, int[] contentSettings) {
         int drawableId = ResourceId.mapToDrawableId(enumeratedIconId);
 
         ConfirmInfoBar infoBar = new ConfirmInfoBar(
                 null, drawableId, iconBitmap, message, linkText, buttonOk, buttonCancel);
+        infoBar.setContentSettings(windowAndroid, contentSettings);
+
         return infoBar;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index 99f7f9d3..07cca22 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -254,7 +254,9 @@
 
     private static void configureStrictMode() {
         CommandLine commandLine = CommandLine.getInstance();
-        if ("eng".equals(Build.TYPE) || commandLine.hasSwitch(ChromeSwitches.STRICT_MODE)) {
+        if ("eng".equals(Build.TYPE)
+                || "userdebug".equals(Build.TYPE)
+                || commandLine.hasSwitch(ChromeSwitches.STRICT_MODE)) {
             StrictMode.enableDefaults();
             StrictMode.ThreadPolicy.Builder policy =
                     new StrictMode.ThreadPolicy.Builder(StrictMode.getThreadPolicy());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromeBrowserSyncAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java
similarity index 91%
rename from chrome/android/java/src/org/chromium/chrome/browser/sync/ChromeBrowserSyncAdapter.java
rename to chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java
index 61100976..09cc40e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromeBrowserSyncAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.sync;
+package org.chromium.chrome.browser.invalidation;
 
 import android.app.Application;
 import android.content.Context;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromeBrowserSyncAdapterService.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java
similarity index 92%
rename from chrome/android/java/src/org/chromium/chrome/browser/sync/ChromeBrowserSyncAdapterService.java
rename to chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java
index 17de259..e04fb64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromeBrowserSyncAdapterService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.sync;
+package org.chromium.chrome.browser.invalidation;
 
 import android.app.Application;
 import android.content.Context;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapter.java
similarity index 61%
rename from chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapter.java
rename to chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapter.java
index 83b9cd3..bb827bb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapter.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.sync;
+package org.chromium.chrome.browser.invalidation;
 
 import android.accounts.Account;
 import android.app.Application;
@@ -13,17 +13,15 @@
 import android.content.SyncResult;
 import android.os.Bundle;
 import android.os.Handler;
-import android.util.Log;
 
-import com.google.protos.ipc.invalidation.Types;
-
+import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.ProcessInitException;
-import org.chromium.chrome.browser.invalidation.InvalidationServiceFactory;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.components.invalidation.PendingInvalidation;
 import org.chromium.content.app.ContentApplication;
 import org.chromium.content.browser.BrowserStartupController;
 import org.chromium.sync.signin.ChromeSigninController;
@@ -32,21 +30,11 @@
 import java.util.concurrent.TimeUnit;
 
 /**
- * A sync adapter for Chromium.
+ * A Sync adapter that receives invalidations from {@link InvalidationClientService} and dispatches
+ * it to the native side with a caching layer in {@link DelayedInvalidationsController}.
  */
 public abstract class ChromiumSyncAdapter extends AbstractThreadedSyncAdapter {
-    private static final String TAG = "ChromiumSyncAdapter";
-
-    // TODO(nyquist) Make these fields package protected once downstream sync adapter tests are
-    // removed.
-    @VisibleForTesting
-    public static final String INVALIDATION_OBJECT_SOURCE_KEY = "objectSource";
-    @VisibleForTesting
-    public static final String INVALIDATION_OBJECT_ID_KEY = "objectId";
-    @VisibleForTesting
-    public static final String INVALIDATION_VERSION_KEY = "version";
-    @VisibleForTesting
-    public static final String INVALIDATION_PAYLOAD_KEY = "payload";
+    private static final String TAG = "cr.invalidation";
 
     private final Application mApplication;
     private final boolean mAsyncStartup;
@@ -61,7 +49,7 @@
 
     @Override
     public void onPerformSync(Account account, Bundle extras, String authority,
-                              ContentProviderClient provider, SyncResult syncResult) {
+            ContentProviderClient provider, SyncResult syncResult) {
         if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE)) {
             Account signedInAccount = ChromeSigninController.get(getContext()).getSignedInUser();
             if (account.equals(signedInAccount)) {
@@ -71,8 +59,11 @@
             }
             return;
         }
+        PendingInvalidation invalidation = new PendingInvalidation(extras);
 
-        if (!DelayedSyncController.getInstance().shouldPerformSync(getContext(), extras, account)) {
+        DelayedInvalidationsController controller = DelayedInvalidationsController.getInstance();
+        if (!controller.shouldNotifyInvalidation(extras)) {
+            controller.addPendingInvalidation(getContext(), account.name, invalidation);
             return;
         }
 
@@ -81,7 +72,7 @@
 
         // Configure the callback with all the data it needs.
         BrowserStartupController.StartupCallback callback =
-                getStartupCallback(mApplication, account, extras, syncResult, semaphore);
+                getStartupCallback(mApplication, account.name, invalidation, syncResult, semaphore);
         startBrowserProcess(callback, syncResult, semaphore);
 
         try {
@@ -92,14 +83,13 @@
                 syncResult.stats.numIoExceptions++;
             }
         } catch (InterruptedException e) {
-            Log.w(TAG, "Got InterruptedException when trying to request a sync.", e);
+            Log.w(TAG, "Got InterruptedException when trying to request an invalidation.", e);
             // Using numIoExceptions so Android will treat this as a soft error.
             syncResult.stats.numIoExceptions++;
         }
     }
 
-    private void startBrowserProcess(
-            final BrowserStartupController.StartupCallback callback,
+    private void startBrowserProcess(final BrowserStartupController.StartupCallback callback,
             final SyncResult syncResult, Semaphore semaphore) {
         try {
             ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@@ -110,8 +100,8 @@
                     if (mAsyncStartup) {
                         try {
                             BrowserStartupController.get(mApplication,
-                                    LibraryProcessType.PROCESS_BROWSER)
-                                            .startBrowserProcessesAsync(callback);
+                                                             LibraryProcessType.PROCESS_BROWSER)
+                                    .startBrowserProcessesAsync(callback);
                         } catch (ProcessInitException e) {
                             Log.e(TAG, "Unable to load native library.", e);
                             System.exit(-1);
@@ -123,7 +113,7 @@
             });
         } catch (RuntimeException e) {
             // It is still unknown why we ever experience this. See http://crbug.com/180044.
-            Log.w(TAG, "Got exception when trying to request a sync. Informing Android system.", e);
+            Log.w(TAG, "Got exception when trying to notify the invalidation.", e);
             // Using numIoExceptions so Android will treat this as a soft error.
             syncResult.stats.numIoExceptions++;
             semaphore.release();
@@ -148,40 +138,23 @@
         });
     }
 
-    private BrowserStartupController.StartupCallback getStartupCallback(
-            final Context context, final Account acct, Bundle extras,
+    private BrowserStartupController.StartupCallback getStartupCallback(final Context context,
+            final String account, final PendingInvalidation invalidation,
             final SyncResult syncResult, final Semaphore semaphore) {
-        final boolean syncAllTypes = extras.getString(INVALIDATION_OBJECT_ID_KEY) == null;
-        final int objectSource = syncAllTypes ? 0 : extras.getInt(INVALIDATION_OBJECT_SOURCE_KEY);
-        final String objectId = syncAllTypes ? "" : extras.getString(INVALIDATION_OBJECT_ID_KEY);
-        final long version = syncAllTypes ? 0 : extras.getLong(INVALIDATION_VERSION_KEY);
-        final String payload = syncAllTypes ? "" : extras.getString(INVALIDATION_PAYLOAD_KEY);
-
         return new BrowserStartupController.StartupCallback() {
             @Override
             public void onSuccess(boolean alreadyStarted) {
-                // Startup succeeded, so we can tickle the sync engine.
-                if (syncAllTypes) {
-                    Log.v(TAG, "Received sync tickle for all types.");
-                    requestSyncForAllTypes();
-                } else {
-                    // Invalidations persisted before objectSource was added should be assumed to be
-                    // for Sync objects. TODO(stepco): Remove this check once all persisted
-                    // invalidations can be expected to have the objectSource.
-                    int resolvedSource = objectSource;
-                    if (resolvedSource == 0) {
-                        resolvedSource = Types.ObjectSource.CHROME_SYNC;
-                    }
-                    Log.v(TAG, "Received sync tickle for " + resolvedSource + " " + objectId + ".");
-                    requestSync(resolvedSource, objectId, version, payload);
-                }
+                // Startup succeeded, so we can notify the invalidation.
+                notifyInvalidation(invalidation.mObjectSource, invalidation.mObjectId,
+                        invalidation.mVersion, invalidation.mPayload);
                 semaphore.release();
             }
 
             @Override
             public void onFailure() {
-                // The startup failed, so we reset the delayed sync state.
-                DelayedSyncController.getInstance().setDelayedSync(context, acct.name);
+                // The startup failed, so we defer the invalidation.
+                DelayedInvalidationsController.getInstance().addPendingInvalidation(
+                        context, account, invalidation);
                 // Using numIoExceptions so Android will treat this as a soft error.
                 syncResult.stats.numIoExceptions++;
                 semaphore.release();
@@ -190,14 +163,9 @@
     }
 
     @VisibleForTesting
-    public void requestSync(int objectSource, String objectId, long version, String payload) {
+    public void notifyInvalidation(
+            int objectSource, String objectId, long version, String payload) {
         InvalidationServiceFactory.getForProfile(Profile.getLastUsedProfile())
-                .requestSyncFromNativeChrome(objectSource, objectId, version, payload);
-    }
-
-    @VisibleForTesting
-    public void requestSyncForAllTypes() {
-        InvalidationServiceFactory.getForProfile(Profile.getLastUsedProfile())
-                .requestSyncFromNativeChromeForAllTypes();
+                .notifyInvalidationToNativeChrome(objectSource, objectId, version, payload);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterService.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapterService.java
similarity index 86%
rename from chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterService.java
rename to chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapterService.java
index 2e641e41..f90e930 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapterService.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.sync;
+package org.chromium.chrome.browser.invalidation;
 
 import android.app.Application;
 import android.app.Service;
@@ -31,6 +31,6 @@
         return getOrCreateSyncAdapter(getApplicationContext()).getSyncAdapterBinder();
     }
 
-    protected abstract ChromiumSyncAdapter createChromiumSyncAdapter(Context applicationContext,
-                                                                     Application application);
+    protected abstract ChromiumSyncAdapter createChromiumSyncAdapter(
+            Context applicationContext, Application application);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsController.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsController.java
new file mode 100644
index 0000000..e5d6668
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsController.java
@@ -0,0 +1,154 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.invalidation;
+
+import android.accounts.Account;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.components.invalidation.PendingInvalidation;
+import org.chromium.sync.AndroidSyncSettings;
+import org.chromium.sync.signin.AccountManagerHelper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A class for controlling whether an invalidation should be notified immediately, or should be
+ * delayed until Chrome comes to the foreground again.
+ */
+public class DelayedInvalidationsController {
+    private static final String TAG = Log.makeTag("invalidation");
+    private static final String DELAYED_ACCOUNT_NAME = "delayed_account";
+    private static final String DELAYED_INVALIDATIONS = "delayed_invalidations";
+
+    private static class LazyHolder {
+        private static final DelayedInvalidationsController INSTANCE =
+                new DelayedInvalidationsController();
+    }
+
+    public static DelayedInvalidationsController getInstance() {
+        return LazyHolder.INSTANCE;
+    }
+
+    @VisibleForTesting
+    DelayedInvalidationsController() {}
+
+    /**
+     * Notify any invalidations that were delayed while Chromium was backgrounded.
+     * @return whether there were any invalidations pending to be notified.
+     */
+    public boolean notifyPendingInvalidations(final Context context) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        String accountName = prefs.getString(DELAYED_ACCOUNT_NAME, null);
+        if (accountName == null) {
+            Log.d(TAG, "No pending invalidations.");
+            return false;
+        } else {
+            Log.d(TAG, "Handling pending invalidations.");
+            Account account = AccountManagerHelper.createAccountFromName(accountName);
+            List<Bundle> bundles = popPendingInvalidations(context);
+            notifyInvalidationsOnBackgroundThread(context, account, bundles);
+            return true;
+        }
+    }
+
+    /**
+     * Calls ContentResolver.requestSync() in a separate thread as it performs some blocking
+     * IO operations.
+     */
+    @VisibleForTesting
+    void notifyInvalidationsOnBackgroundThread(
+            final Context context, final Account account, final List<Bundle> bundles) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... unused) {
+                String contractAuthority = AndroidSyncSettings.getContractAuthority(context);
+                for (Bundle bundle : bundles) {
+                    ContentResolver.requestSync(account, contractAuthority, bundle);
+                }
+                return null;
+            }
+        }.execute();
+    }
+
+    /**
+     * Stores preferences to indicate that an invalidation has arrived, but dropped on the floor.
+     */
+    @VisibleForTesting
+    void addPendingInvalidation(Context context, String account, PendingInvalidation invalidation) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        String oldAccount = prefs.getString(DELAYED_ACCOUNT_NAME, null);
+        Set<String> invals = prefs.getStringSet(DELAYED_INVALIDATIONS, new HashSet<String>(1));
+        assert invals.isEmpty() || oldAccount != null;
+        if (oldAccount != null && !oldAccount.equals(account)) {
+            invals.clear();
+        }
+        SharedPreferences.Editor editor = prefs.edit();
+        editor.putString(DELAYED_ACCOUNT_NAME, account);
+        if (invalidation.mObjectSource == 0 || (oldAccount != null && invals.isEmpty())) {
+            editor.putStringSet(DELAYED_INVALIDATIONS, null);
+        } else {
+            invals.add(invalidation.encodeToString());
+            editor.putStringSet(DELAYED_INVALIDATIONS, invals);
+        }
+        editor.apply();
+    }
+
+    private List<Bundle> popPendingInvalidations(final Context context) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        assert prefs.contains(DELAYED_ACCOUNT_NAME);
+        Set<String> savedInvalidations = prefs.getStringSet(DELAYED_INVALIDATIONS, null);
+        clearPendingInvalidations(context);
+        // Absence of specific invalidations indicates invalidate all types.
+        if (savedInvalidations == null) return Arrays.asList(new Bundle());
+
+        List<Bundle> bundles = new ArrayList<Bundle>(savedInvalidations.size());
+        for (String invalidation : savedInvalidations) {
+            Bundle bundle = PendingInvalidation.decodeToBundle(invalidation);
+            if (bundle == null) {
+                Log.e(TAG, "Error parsing saved invalidation. Invalidating all.");
+                return Arrays.asList(new Bundle());
+            }
+            bundles.add(bundle);
+        }
+        return bundles;
+    }
+
+    /**
+     * If there are any pending invalidations, they will be cleared.
+     */
+    @VisibleForTesting
+    public void clearPendingInvalidations(Context context) {
+        SharedPreferences.Editor editor =
+                PreferenceManager.getDefaultSharedPreferences(context).edit();
+        editor.putString(DELAYED_ACCOUNT_NAME, null);
+        editor.putStringSet(DELAYED_INVALIDATIONS, null);
+        editor.apply();
+    }
+
+    @VisibleForTesting
+    boolean shouldNotifyInvalidation(Bundle extras) {
+        return isManualRequest(extras) || ApplicationStatus.hasVisibleActivities();
+    }
+
+    private static boolean isManualRequest(Bundle extras) {
+        if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) {
+            Log.d(TAG, "Manual sync requested.");
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/OWNERS
new file mode 100644
index 0000000..3f15c2d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/OWNERS
@@ -0,0 +1,3 @@
+nyquist@chromium.org
+yfriedman@chromium.org
+zea@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java b/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java
index 0dea87b7..f4acf6f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java
@@ -168,12 +168,21 @@
     }
 
     /**
-     * Sets that a "Show image" context menu request has been made.
+     * Records that a "Show image" context menu request has been made.
      */
     public void setLoFiShowImageRequested() {
         nativeSetLoFiShowImageRequested(mNativeDataReductionProxySettings);
     }
 
+    /**
+     * Counts the number of requests to reload the page with images from the Lo-Fi snackbar. If the
+     * user requests the page with images a certain number of times, then Lo-Fi is disabled for the
+     * session.
+     *  */
+    public void incrementLoFiUserRequestsForImages() {
+        nativeIncrementLoFiUserRequestsForImages(mNativeDataReductionProxySettings);
+    }
+
     /** Returns true if the SPDY proxy is managed by an administrator's policy. */
     public boolean isDataReductionProxyManaged() {
         return nativeIsDataReductionProxyManaged(mNativeDataReductionProxySettings);
@@ -252,6 +261,8 @@
             long nativeDataReductionProxySettingsAndroid);
     private native void nativeSetLoFiShowImageRequested(
             long nativeDataReductionProxySettingsAndroid);
+    private native void nativeIncrementLoFiUserRequestsForImages(
+            long nativeDataReductionProxySettingsAndroid);
     private native boolean nativeIsDataReductionProxyManaged(
             long nativeDataReductionProxySettingsAndroid);
     private native void nativeSetDataReductionProxyEnabled(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java
index cfbffe0..38ee2cf3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java
@@ -170,18 +170,18 @@
         if (emphasizeResponse.hasScheme()) {
             int colorId = nonEmphasizedColorId;
             if (!isInternalPage && emphasizeHttpsScheme) {
+                boolean strikeThroughScheme = false;
                 switch (securityLevel) {
                     case ConnectionSecurityHelperSecurityLevel.NONE:
                         colorId = nonEmphasizedColorId;
                         break;
                     case ConnectionSecurityHelperSecurityLevel.SECURITY_WARNING:
                         colorId = R.color.url_emphasis_start_scheme_security_warning;
+                        strikeThroughScheme = true;
                         break;
                     case ConnectionSecurityHelperSecurityLevel.SECURITY_ERROR:
                         colorId = R.color.url_emphasis_start_scheme_security_error;
-                        UrlEmphasisSecurityErrorSpan ss = new UrlEmphasisSecurityErrorSpan();
-                        url.setSpan(ss, startSchemeIndex, endSchemeIndex,
-                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                        strikeThroughScheme = true;
                         break;
                     case ConnectionSecurityHelperSecurityLevel.EV_SECURE:
                         colorId = R.color.url_emphasis_start_scheme_ev_secure;
@@ -192,6 +192,12 @@
                     default:
                         assert false;
                 }
+
+                if (strikeThroughScheme) {
+                    UrlEmphasisSecurityErrorSpan ss = new UrlEmphasisSecurityErrorSpan();
+                    url.setSpan(ss, startSchemeIndex, endSchemeIndex,
+                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
             }
             span = new UrlEmphasisColorSpan(resources.getColor(colorId));
             url.setSpan(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java
new file mode 100644
index 0000000..311a3369
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java
@@ -0,0 +1,100 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.preferences;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.UrlUtilities;
+import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
+import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations;
+import org.chromium.chrome.browser.widget.FloatLabelLayout;
+
+/**
+ * Provides the Java-UI for editing the homepage preference.
+ */
+public class HomepageEditor extends Fragment implements TextWatcher {
+    private HomepageManager mHomepageManager;
+    private EditText mHomepageUrlEdit;
+    private Button mSaveButton;
+    private Button mResetButton;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mHomepageManager = HomepageManager.getInstance(getActivity());
+        getActivity().setTitle(R.string.options_homepage_edit_title);
+        View v = inflater.inflate(R.layout.homepage_editor, container, false);
+
+        FloatLabelLayout homepageUrl = (FloatLabelLayout) v.findViewById(R.id.homepage_url);
+        homepageUrl.focusWithoutAnimation();
+
+        mHomepageUrlEdit = (EditText) v.findViewById(R.id.homepage_url_edit);
+        mHomepageUrlEdit.setText((mHomepageManager.getPrefHomepageUseDefaultUri()
+                ? PartnerBrowserCustomizations.getHomePageUrl()
+                : mHomepageManager.getPrefHomepageCustomUri()));
+        mHomepageUrlEdit.addTextChangedListener(this);
+
+        initializeSaveCancelResetButtons(v);
+        return v;
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+        mSaveButton.setEnabled(true);
+        mResetButton.setEnabled(true);
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+    }
+
+    private void initializeSaveCancelResetButtons(View v) {
+        mResetButton = (Button) v.findViewById(R.id.homepage_reset);
+        mResetButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mHomepageManager.setPrefHomepageUseDefaultUri(true);
+                getActivity().finish();
+            }
+        });
+        if (mHomepageManager.getPrefHomepageUseDefaultUri()) {
+            mResetButton.setEnabled(false);
+        }
+
+        mSaveButton = (Button) v.findViewById(R.id.homepage_save);
+        mSaveButton.setEnabled(false);
+        mSaveButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mHomepageManager.setPrefHomepageCustomUri(UrlUtilities.fixupUrl(
+                        mHomepageUrlEdit.getText().toString()));
+                mHomepageManager.setPrefHomepageUseDefaultUri(false);
+                getActivity().finish();
+            }
+        });
+
+        Button button = (Button) v.findViewById(R.id.homepage_cancel);
+        button.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                getActivity().finish();
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepagePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepagePreferences.java
index 310f78d..f1391eb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepagePreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepagePreferences.java
@@ -4,147 +4,56 @@
 
 package org.chromium.chrome.browser.preferences;
 
-import android.app.Fragment;
 import android.os.Bundle;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnFocusChangeListener;
-import android.view.ViewGroup;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.EditText;
-import android.widget.TextView;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceFragment;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.UrlUtilities;
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
 import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations;
-import org.chromium.chrome.browser.widget.ChromeSwitchCompat;
-import org.chromium.ui.UiUtils;
 
 /**
  * Fragment that allows the user to configure homepage related preferences.
  */
-public class HomepagePreferences extends Fragment {
-    private HomepageManager mHomepageManager;
-    private ChromeSwitchCompat mHomepageSwitch;
-    private TextView mHomepageSwitchLabel;
-    private String mCustomUriCache;
-    private EditText mCustomUriEditText;
-    private CheckBox mPartnerDefaultCheckbox;
+public class HomepagePreferences extends PreferenceFragment {
+    private static final String PREF_HOMEPAGE_SWITCH = "homepage_switch";
+    private static final String PREF_HOMEPAGE_EDIT = "homepage_edit";
 
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mHomepageManager = HomepageManager.getInstance(getActivity());
-    }
+    private HomepageManager mHomepageManager;
+    private ChromeSwitchPreference mHomepageSwitch;
+    private Preference mHomepageEdit;
 
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
+        mHomepageManager = HomepageManager.getInstance(getActivity());
         getActivity().setTitle(R.string.options_homepage_title);
-    }
+        addPreferencesFromResource(R.xml.homepage_preferences);
 
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        View rootView = inflater.inflate(R.layout.homepage_preferences, null);
-
-        initHomepageSwitch(rootView);
-        initCustomUriEditText(rootView);
-        initPartnerDefaultCheckbox(rootView);
-
-        updateUIState();
-
-        return rootView;
-    }
-
-    private void initHomepageSwitch(View rootView) {
-        mHomepageSwitch = (ChromeSwitchCompat) rootView.findViewById(R.id.homepage_switch);
-        mHomepageSwitchLabel = (TextView) rootView.findViewById(R.id.homepage_switch_label);
-
+        mHomepageSwitch = (ChromeSwitchPreference) findPreference(PREF_HOMEPAGE_SWITCH);
         boolean isHomepageEnabled = mHomepageManager.getPrefHomepageEnabled();
         mHomepageSwitch.setChecked(isHomepageEnabled);
-        setHomepageSwitchLabelText(isHomepageEnabled);
-
-        mHomepageSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener(){
+        mHomepageSwitch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
             @Override
-            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                mHomepageManager.setPrefHomepageEnabled(isChecked);
-                setHomepageSwitchLabelText(isChecked);
-                updateUIState();
+            public boolean onPreferenceChange(Preference preference, Object newValue) {
+                mHomepageManager.setPrefHomepageEnabled((boolean) newValue);
+                return true;
             }
         });
+
+        mHomepageEdit = findPreference(PREF_HOMEPAGE_EDIT);
+        updateCurrentHomepageUrl();
     }
-
-    private void setHomepageSwitchLabelText(boolean isChecked) {
-        if (isChecked) {
-            mHomepageSwitchLabel.setText(mHomepageSwitch.getTextOn());
-        } else {
-            mHomepageSwitchLabel.setText(mHomepageSwitch.getTextOff());
-        }
+    private void updateCurrentHomepageUrl() {
+        mHomepageEdit.setSummary((mHomepageManager.getPrefHomepageUseDefaultUri()
+                ? PartnerBrowserCustomizations.getHomePageUrl()
+                : mHomepageManager.getPrefHomepageCustomUri()));
     }
-
-    private void initCustomUriEditText(View rootView) {
-        mCustomUriCache = mHomepageManager.getPrefHomepageCustomUri();
-
-        mCustomUriEditText = (EditText) rootView.findViewById(R.id.custom_uri);
-        mCustomUriEditText.addTextChangedListener(new TextWatcher() {
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before, int count) {
-            }
-
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-            }
-
-            @Override
-            public void afterTextChanged(Editable s) {
-                if (mCustomUriEditText.isEnabled()) {
-                    mCustomUriCache = s.toString();
-                }
-            }
-        });
-        mCustomUriEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View view, boolean hasFocus) {
-                if (!hasFocus) UiUtils.hideKeyboard(view);
-            }
-        });
-    }
-
-    private void initPartnerDefaultCheckbox(View rootView) {
-        mPartnerDefaultCheckbox = (CheckBox) rootView.findViewById(R.id.default_checkbox);
-        mPartnerDefaultCheckbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-            @Override
-            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-                mHomepageManager.setPrefHomepageUseDefaultUri(isChecked);
-                updateUIState();
-            }
-        });
-    }
-
-    private void updateUIState() {
-        boolean isHomepageEnabled = mHomepageManager.getPrefHomepageEnabled();
-        boolean isHomepagePartnerEnabled =
-                mHomepageManager.getPrefHomepageUseDefaultUri();
-
-        mCustomUriEditText.setEnabled(false);
-        mCustomUriEditText.setText(isHomepagePartnerEnabled
-                ? PartnerBrowserCustomizations.getHomePageUrl() : mCustomUriCache);
-        mCustomUriEditText.setEnabled(isHomepageEnabled && !isHomepagePartnerEnabled);
-
-        mPartnerDefaultCheckbox.setChecked(isHomepagePartnerEnabled);
-        mPartnerDefaultCheckbox.setEnabled(isHomepageEnabled);
-    }
-
     @Override
-    public void onStop() {
-        super.onStop();
-        mHomepageManager.setPrefHomepageCustomUri(UrlUtilities.fixupUrl(mCustomUriCache));
+    public void onResume() {
+        super.onResume();
+        updateCurrentHomepageUrl();
     }
 
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreference.java
index cbcfad9..67ab354 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreference.java
@@ -14,7 +14,9 @@
 import android.widget.TextView;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.feedback.FeedbackCollector;
 import org.chromium.chrome.browser.help.HelpAndFeedback;
+import org.chromium.chrome.browser.profiles.Profile;
 
 /**
  * A preference that opens a HelpAndFeedback activity to learn more about the specified context.
@@ -34,8 +36,9 @@
 
     @Override
     protected void onClick() {
-        HelpAndFeedback.getInstance(getContext()).show(
-                (Activity) getContext(), getContext().getString(mHelpContext), null, null);
+        HelpAndFeedback.getInstance(getContext())
+                .show((Activity) getContext(), getContext().getString(mHelpContext), null,
+                        FeedbackCollector.create(Profile.getLastUsedProfile(), null));
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
index f6ebb28..7df76dd51 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
@@ -31,7 +31,9 @@
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.feedback.FeedbackCollector;
 import org.chromium.chrome.browser.help.HelpAndFeedback;
+import org.chromium.chrome.browser.profiles.Profile;
 
 /**
  * The Chrome settings activity.
@@ -254,8 +256,8 @@
             finish();
             return true;
         } else if (item.getItemId() == R.id.menu_id_help_general) {
-            HelpAndFeedback.getInstance(this).show(
-                    this, getString(R.string.help_context_settings), null, null);
+            HelpAndFeedback.getInstance(this).show(this, getString(R.string.help_context_settings),
+                    null, FeedbackCollector.create(Profile.getLastUsedProfile(), null));
             return true;
         }
         return super.onOptionsItemSelected(item);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardEditor.java
index 78da954..a01e4b07 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardEditor.java
@@ -86,7 +86,7 @@
 
         addSpinnerAdapters();
         addCardDataToEditFields();
-        hookupSaveCancelDeleteButtons(v);
+        initializeSaveCancelDeleteButtons(v);
         return v;
     }
 
@@ -139,12 +139,7 @@
     private void addCardDataToEditFields() {
         CreditCard card = PersonalDataManager.getInstance().getCreditCard(mGUID);
         if (card == null) {
-            // FloatLabelLayout animates showing the field label when its EditText is focused;
-            // to avoid this animation, manually set the name label to be visible, its EditText
-            // hint to null and request focus on its EditText field.
-            mNameLabel.getLabel().setVisibility(View.VISIBLE);
-            mNameText.setHint(null);
-            mNameText.requestFocus();
+            mNameLabel.focusWithoutAnimation();
             return;
         }
 
@@ -205,7 +200,7 @@
         }
     }
 
-    private void hookupSaveCancelDeleteButtons(View v) {
+    private void initializeSaveCancelDeleteButtons(View v) {
         Button button = (Button) v.findViewById(R.id.autofill_credit_card_delete);
         if ((mGUID == null) || (mGUID.compareTo("") == 0)) {
             // If this is a create, disable the delete button.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditor.java
index 35a2b2f..74555b7b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditor.java
@@ -92,7 +92,7 @@
 
         populateCountriesSpinner();
         createAndPopulateEditFields();
-        hookupSaveCancelDeleteButtons(v);
+        initializeSaveCancelDeleteButtons(v);
 
         return v;
     }
@@ -248,12 +248,7 @@
             mWidgetRoot.addView(fieldFloatLabel);
 
             if (firstField && autoFocusFirstField) {
-                // FloatLabelLayout animates showing the field label when the EditText is focused;
-                // to avoid this animation, manually set the label to be visible and the EditText
-                // hint to null and request focus on the EditText field.
-                fieldFloatLabel.getLabel().setVisibility(View.VISIBLE);
-                fieldEditText.setHint(null);
-                fieldEditText.requestFocus();
+                fieldFloatLabel.focusWithoutAnimation();
                 firstField = false;
             }
         }
@@ -300,7 +295,7 @@
         }
     }
 
-    private void hookupSaveCancelDeleteButtons(View v) {
+    private void initializeSaveCancelDeleteButtons(View v) {
         Button button = (Button) v.findViewById(R.id.autofill_profile_delete);
         if ((mGUID == null) || (mGUID.compareTo("") == 0)) {
             // If this is a create, disable the delete button.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
index 8191ea1..429c4ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
@@ -16,6 +16,7 @@
 import android.view.MenuItem;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.feedback.FeedbackCollector;
 import org.chromium.chrome.browser.help.HelpAndFeedback;
 import org.chromium.chrome.browser.preferences.ButtonPreference;
 import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
@@ -23,6 +24,7 @@
 import org.chromium.chrome.browser.preferences.NetworkPredictionOptions;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.Preferences;
+import org.chromium.chrome.browser.profiles.Profile;
 
 /**
  * Fragment to keep track of the all the privacy related preferences.
@@ -273,8 +275,9 @@
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         if (item.getItemId() == R.id.menu_id_help_privacy) {
-            HelpAndFeedback.getInstance(getActivity()).show(
-                    getActivity(), getString(R.string.help_context_privacy), null, null);
+            HelpAndFeedback.getInstance(getActivity())
+                    .show(getActivity(), getString(R.string.help_context_privacy), null,
+                            FeedbackCollector.create(Profile.getLastUsedProfile(), null));
             return true;
         }
         return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java
index 436d169..bb973d46e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java
@@ -25,6 +25,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
+import org.chromium.ui.UiUtils;
 
 /**
  * A utility class for the UI recording exceptions to the blocked list for site
@@ -115,7 +116,14 @@
                 .setView(view)
                 .setPositiveButton(R.string.website_settings_add_site_add_button, onClickListener)
                 .setNegativeButton(R.string.cancel, onClickListener)
-                .show();
+                .create();
+        alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
+            @Override
+            public void onShow(DialogInterface dialog) {
+                UiUtils.showKeyboard(input);
+            }
+        });
+        alertDialog.show();
         final Button okButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
         okButton.setEnabled(false);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/TranslatePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/TranslatePreferences.java
index 052db43..ad76a80 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/TranslatePreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/TranslatePreferences.java
@@ -16,11 +16,13 @@
 import android.widget.Toast;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.feedback.FeedbackCollector;
 import org.chromium.chrome.browser.help.HelpAndFeedback;
 import org.chromium.chrome.browser.preferences.ButtonPreference;
 import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
 import org.chromium.chrome.browser.preferences.ManagedPreferenceDelegate;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
+import org.chromium.chrome.browser.profiles.Profile;
 
 /**
  * Fragment to keep track of the translate preferences.
@@ -88,8 +90,9 @@
     public boolean onOptionsItemSelected(MenuItem item) {
         int itemId = item.getItemId();
         if (itemId == R.id.menu_id_translate_help) {
-            HelpAndFeedback.getInstance(getActivity()).show(
-                    getActivity(), getString(R.string.help_context_translate), null, null);
+            HelpAndFeedback.getInstance(getActivity())
+                    .show(getActivity(), getString(R.string.help_context_translate), null,
+                            FeedbackCollector.create(Profile.getLastUsedProfile(), null));
             return true;
         }
         return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreferences.java
index 2691e82..8508d14f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreferences.java
@@ -94,7 +94,10 @@
     private void getInfoForOrigins() {
         if (mFilter.showGeolocationSites(mCategoryFilter)
                 && !LocationSettings.getInstance().isSystemLocationSettingEnabled()) {
-            return;  // No need to fetch any data if we're not going to show it.
+            // No need to fetch any data if we're not going to show it, but we do need to update
+            // the global toggle to reflect updates in Android settings (e.g. Location).
+            resetList();
+            return;
         }
 
         WebsitePermissionsFetcher fetcher = new WebsitePermissionsFetcher(new ResultsPopulator());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandler.java
index ad01196..0d2b569 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandler.java
@@ -5,7 +5,7 @@
 package org.chromium.chrome.browser.prerender;
 
 import org.chromium.base.JNINamespace;
-import org.chromium.chrome.browser.ContentViewUtil;
+import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.content_public.browser.WebContents;
 
@@ -33,7 +33,7 @@
      */
     public WebContents addPrerender(Profile profile, String url, String referrer, int width,
             int height) {
-        WebContents webContents = ContentViewUtil.createWebContents(false, false);
+        WebContents webContents = WebContentsFactory.createWebContents(false, false);
         if (nativeAddPrerender(mNativeExternalPrerenderHandler, profile, webContents,
                 url, referrer, width, height)) {
             return webContents;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
index 0980a56..3b615a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
@@ -118,8 +118,6 @@
     private ArrayList<Preference> mAccountsListPreferences = new ArrayList<Preference>();
     private Preference mPrimaryAccountPreference;
 
-    private boolean mSaveInstanceStateWasCalled;
-
     private AccountManagementFragmentDelegate getDelegate() {
         return AccountManagementScreenHelper.getDelegate();
     }
@@ -159,12 +157,6 @@
         ProfileSyncService.get(getActivity()).removeSyncStateChangedListener(this);
     }
 
-    @Override
-    public void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        mSaveInstanceStateWasCalled = true;
-    }
-
     /**
      * Initiate fetching the user accounts data (images and the full name).
      * Fetched data will be sent to observers of ProfileDownloader.
@@ -226,8 +218,8 @@
             signOutSwitch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
                 @Override
                 public boolean onPreferenceChange(Preference preference, Object newValue) {
+                    if (!isVisible() || !isResumed()) return false;
                     if ((boolean) newValue) return true;
-                    if (mSaveInstanceStateWasCalled) return false;
 
                     if (ChromeSigninController.get(getActivity()).isSignedIn()
                             && getSignOutAllowedPreferenceValue(getActivity())) {
@@ -261,7 +253,7 @@
             addAccount.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                 @Override
                 public boolean onPreferenceClick(Preference preference) {
-                    if (mSaveInstanceStateWasCalled) return false;
+                    if (!isVisible() || !isResumed()) return false;
 
                     AccountManagementScreenHelper.logEvent(
                             ProfileAccountManagementMetrics.ADD_ACCOUNT,
@@ -295,7 +287,7 @@
             goIncognito.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                 @Override
                 public boolean onPreferenceClick(Preference preference) {
-                    if (mSaveInstanceStateWasCalled) return false;
+                    if (!isVisible() || !isResumed()) return false;
                     if (!PrefServiceBridge.getInstance().isIncognitoModeEnabled()) return false;
 
                     AccountManagementFragmentDelegate delegate = getDelegate();
@@ -401,7 +393,7 @@
                 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                     @Override
                     public boolean onPreferenceClick(Preference preference) {
-                        if (mSaveInstanceStateWasCalled) return false;
+                        if (!isVisible() || !isResumed()) return false;
 
                         AccountManagementScreenHelper.logEvent(
                                 ProfileAccountManagementMetrics.CLICK_PRIMARY_ACCOUNT,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/DelayedSyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/DelayedSyncController.java
deleted file mode 100644
index 8b896444..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/DelayedSyncController.java
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.sync;
-
-import android.accounts.Account;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.util.Log;
-
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.sync.AndroidSyncSettings;
-import org.chromium.sync.signin.AccountManagerHelper;
-
-/**
- * A class for controlling when a sync should be performed immediately, and when it should be
- * delayed until Chrome comes to the foreground again.
- */
-public class DelayedSyncController {
-    private static final String TAG = "DelayedSyncController";
-    private static final String DELAYED_ACCOUNT_NAME = "delayed_account";
-
-    private static class LazyHolder {
-        private static final DelayedSyncController INSTANCE = new DelayedSyncController();
-    }
-
-    public static DelayedSyncController getInstance() {
-        return LazyHolder.INSTANCE;
-    }
-
-    @VisibleForTesting
-    DelayedSyncController() {}
-
-    /**
-     * Resume any syncs that were delayed while Chromium was backgrounded.
-     */
-    public boolean resumeDelayedSyncs(final Context context) {
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
-        String accountName = prefs.getString(DELAYED_ACCOUNT_NAME, null);
-        if (accountName == null) {
-            Log.d(TAG, "No delayed sync.");
-            return false;
-        } else {
-            Log.d(TAG, "Handling delayed sync.");
-            Account account = AccountManagerHelper.createAccountFromName(accountName);
-            requestSyncOnBackgroundThread(context, account);
-            return true;
-        }
-    }
-
-    /**
-     * Calls ContentResolver.requestSync() in a separate thread as it performs some blocking
-     * IO operations.
-     */
-    @VisibleForTesting
-    void requestSyncOnBackgroundThread(final Context context, final Account account) {
-        new AsyncTask<Void, Void, Void>() {
-            @Override
-            protected Void doInBackground(Void... unused) {
-                String contractAuthority = AndroidSyncSettings.getContractAuthority(context);
-                ContentResolver.requestSync(account, contractAuthority, new Bundle());
-                return null;
-            }
-        }.execute();
-    }
-
-    /**
-     * Stores preferences to indicate that an invalidation has arrived, but dropped on the floor.
-     */
-    void setDelayedSync(Context ctx, String accountName) {
-        SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(ctx).edit();
-        editor.putString(DELAYED_ACCOUNT_NAME, accountName);
-        editor.apply();
-    }
-
-    /**
-     * If there is a delayed sync, it will be cleared.
-     */
-    @VisibleForTesting
-    void clearDelayedSyncs(Context context) {
-        setDelayedSync(context, null);
-    }
-
-    @VisibleForTesting
-    boolean shouldPerformSync(Context ctx, Bundle extras, Account account) {
-        boolean manualSync = isManualSync(extras);
-
-        if (manualSync || ApplicationStatus.hasVisibleActivities()) {
-            clearDelayedSyncs(ctx);
-            return true;
-        } else {
-            Log.d(TAG, "Delaying sync.");
-            setDelayedSync(ctx, account.name);
-            return false;
-        }
-    }
-
-    private static boolean isManualSync(Bundle extras) {
-        boolean manualSync = false;
-        if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) {
-            manualSync = true;
-            Log.d(TAG, "Manual sync requested.");
-        }
-        return manualSync;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
index bd0d9a3..dec9af64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
@@ -463,8 +463,8 @@
         return nativeHasSyncSetupCompleted(mNativeProfileSyncServiceAndroid);
     }
 
-    public boolean isStartSuppressed() {
-        return nativeIsStartSuppressed(mNativeProfileSyncServiceAndroid);
+    public boolean isSyncRequested() {
+        return nativeIsSyncRequested(mNativeProfileSyncServiceAndroid);
     }
 
     /**
@@ -671,7 +671,7 @@
             long nativeProfileSyncServiceAndroid, boolean inProgress);
     private native void nativeSetSyncSetupCompleted(long nativeProfileSyncServiceAndroid);
     private native boolean nativeHasSyncSetupCompleted(long nativeProfileSyncServiceAndroid);
-    private native boolean nativeIsStartSuppressed(long nativeProfileSyncServiceAndroid);
+    private native boolean nativeIsSyncRequested(long nativeProfileSyncServiceAndroid);
     private native boolean nativeHasKeepEverythingSynced(long nativeProfileSyncServiceAndroid);
     private native boolean nativeHasUnrecoverableError(long nativeProfileSyncServiceAndroid);
     private native boolean nativeIsPassphrasePrompted(long nativeProfileSyncServiceAndroid);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
index 3798dcb2..62ae896 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
@@ -198,9 +198,8 @@
     @Override
     public void syncStateChanged() {
         ThreadUtils.assertOnUiThread();
-        boolean isSyncActive = !mProfileSyncService.isStartSuppressed();
         // Make the Java state match the native state.
-        if (isSyncActive) {
+        if (mProfileSyncService.isSyncRequested()) {
             InvalidationController.get(mContext).start();
             AndroidSyncSettings.enableChromeSync(mContext);
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/BackgroundContentViewHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/BackgroundContentViewHelper.java
index e9c95a3f..fdb7c0f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/BackgroundContentViewHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/BackgroundContentViewHelper.java
@@ -14,9 +14,9 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.ChromeVersionInfo;
-import org.chromium.chrome.browser.ContentViewUtil;
 import org.chromium.chrome.browser.EmptyTabObserver;
 import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.components.web_contents_delegate_android.WebContentsDelegateAndroid;
 import org.chromium.content.browser.ContentView;
@@ -381,7 +381,7 @@
         mContentViewCore = new ContentViewCore(activity);
         ContentView cv = new ContentView(activity, mContentViewCore);
         mContentViewCore.initialize(cv, cv,
-                ContentViewUtil.createWebContents(mTab.isIncognito(), false), mWindowAndroid);
+                WebContentsFactory.createWebContents(mTab.isIncognito(), false), mWindowAndroid);
 
         // The renderer should be set with the height considering the top controls(non-fullscreen
         // mode).
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTabView.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTabView.java
new file mode 100644
index 0000000..f0cbcfb2
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/SadTabView.java
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tab;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.widget.ButtonCompat;
+
+/**
+ * View that handles orientation changes for Sad Tab / Crashed Renderer page.
+ */
+public class SadTabView extends ScrollView {
+
+    // Dimension (dp) at which reload button is dynamically sized and content centers
+    private static final int MAX_BUTTON_WIDTH_DP = 620;
+    private int mThresholdPx;
+    private float mDensity;
+
+    public SadTabView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mDensity = context.getResources().getDisplayMetrics().density;
+        mThresholdPx = (int) (mDensity * MAX_BUTTON_WIDTH_DP);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // This assumes that view's layout_width is set to match_parent.
+        assert MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        int height = MeasureSpec.getSize(heightMeasureSpec);
+
+        final ButtonCompat mReloadButton = (ButtonCompat) findViewById(R.id.sad_tab_reload_button);
+
+        final LinearLayout.LayoutParams mReloadButtonParams =
+                (LinearLayout.LayoutParams) mReloadButton.getLayoutParams();
+
+        if ((width > height || width > mThresholdPx) && mReloadButton.getWidth() <= width) {
+            // Orientation is landscape
+            mReloadButtonParams.width = LinearLayout.LayoutParams.WRAP_CONTENT;
+            mReloadButtonParams.gravity = Gravity.END;
+        } else {
+            // Orientation is portrait
+            mReloadButtonParams.width = LinearLayout.LayoutParams.MATCH_PARENT;
+            mReloadButtonParams.gravity = Gravity.FILL_HORIZONTAL;
+        }
+
+        mReloadButton.setLayoutParams(mReloadButtonParams);
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java
index c06de53..c0a5449 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java
@@ -34,7 +34,7 @@
          * @param id       The id to give the new tab.
          * @param index    The index for where to place the tab.
          */
-        void createFrozenTab(TabState state, int id, int index);
+        Tab createFrozenTab(TabState state, int id, int index);
 
         /**
          * Creates a tab around the native web contents pointer.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
index 0d208bb..5a67c376 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
@@ -25,7 +25,9 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.Tab;
 import org.chromium.chrome.browser.TabState;
+import org.chromium.chrome.browser.document.DocumentMetricIds;
 import org.chromium.chrome.browser.document.IncognitoNotificationManager;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
 import org.chromium.chrome.browser.tabmodel.TabList;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelJniBridge;
@@ -34,6 +36,7 @@
 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModelInfo.DocumentEntry;
 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModelInfo.DocumentList;
 import org.chromium.chrome.browser.util.MathUtils;
+import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 
 import java.io.File;
@@ -117,7 +120,7 @@
     private final StorageDelegate mStorageDelegate;
 
     /** Delegate that provides Tabs to the DocumentTabModel. */
-    private final TabDelegate mTabDelegate;
+    private final TabCreatorManager mTabCreatorManager;
 
     /** ID of a Tab whose state should be loaded immediately, if it belongs to this TabList. */
     private final int mPrioritizedTabId;
@@ -140,13 +143,13 @@
     /**
      * Construct a DocumentTabModelImpl.
      * @param activityDelegate Used to interact with DocumentActivities.
-     * @param tabDelegate Used to create/get Tabs.
+     * @param tabCreatorManager Used to create/get Tabs.
      * @param isIncognito Whether or not the TabList is managing incognito tabs.
      * @param prioritizedTabId ID of the tab to prioritize when loading.
      */
-    public DocumentTabModelImpl(ActivityDelegate activityDelegate, TabDelegate tabDelegate,
-            boolean isIncognito, int prioritizedTabId) {
-        this(activityDelegate, new StorageDelegate(), tabDelegate, isIncognito,
+    public DocumentTabModelImpl(ActivityDelegate activityDelegate,
+            TabCreatorManager tabCreatorManager, boolean isIncognito, int prioritizedTabId) {
+        this(activityDelegate, new StorageDelegate(), tabCreatorManager, isIncognito,
                 prioritizedTabId, ApplicationStatus.getApplicationContext());
     }
 
@@ -162,11 +165,12 @@
      * TODO(dfalcantara): Reduce visibility once DocumentMigrationHelper is upstreamed.
      */
     public DocumentTabModelImpl(ActivityDelegate activityDelegate, StorageDelegate storageDelegate,
-            TabDelegate tabDelegate, boolean isIncognito, int prioritizedTabId, Context context) {
+            TabCreatorManager tabCreatorManager, boolean isIncognito, int prioritizedTabId,
+            Context context) {
         super(isIncognito);
         mActivityDelegate = activityDelegate;
         mStorageDelegate = storageDelegate;
-        mTabDelegate = tabDelegate;
+        mTabCreatorManager = tabCreatorManager;
         mPrioritizedTabId = prioritizedTabId;
         mContext = context;
 
@@ -271,8 +275,8 @@
         int tabId = mTabIdList.get(index);
         List<WeakReference<Activity>> activities = ApplicationStatus.getRunningActivities();
         for (WeakReference<Activity> activityRef : activities) {
-            Tab tab = mTabDelegate.getActivityTab(
-                    isIncognito(), mActivityDelegate, activityRef.get());
+            Tab tab = getTabDelegate(isIncognito()).getActivityTab(
+                    mActivityDelegate, activityRef.get());
             int documentId = tab == null ? Tab.INVALID_TAB_ID : tab.getId();
             if (documentId == tabId) return tab;
         }
@@ -289,7 +293,8 @@
         // Create a frozen Tab if we are capable, or if the previous Tab is just a placeholder.
         if (entry.getTabState() != null && isNativeInitialized()
                 && (entry.placeholderTab == null || !entry.placeholderTab.isInitialized())) {
-            entry.placeholderTab = mTabDelegate.createFrozenTab(entry);
+            entry.placeholderTab = getTabDelegate(isIncognito()).createFrozenTab(
+                    entry.getTabState(), entry.tabId, TabModel.INVALID_TAB_INDEX);
             entry.placeholderTab.initializeNative();
         }
 
@@ -317,9 +322,12 @@
         Tab tab = getTabAt(index);
         for (TabModelObserver obs : mObservers) obs.willCloseTab(tab, false);
 
-        if (!tab.isIncognito()) tab.createHistoricalTab();
+        int tabId = tab.getId();
+        Entry entry = mEntryMap.get(tabId);
+        if (!isIncognito() && entry != null && entry.getTabState() != null) {
+            entry.getTabState().contentsState.createHistoricalTab();
+        }
 
-        int tabId = mTabIdList.get(index);
         mActivityDelegate.finishAndRemoveTask(isIncognito(), tabId);
         mTabIdList.remove(index);
         mEntryMap.remove(tabId);
@@ -342,14 +350,20 @@
     @Override
     protected Tab createTabWithWebContents(
             boolean isIncognito, WebContents webContents, int parentTabId) {
-        mTabDelegate.createTabWithWebContents(isIncognito, webContents, parentTabId);
-        return null;
+        // Tabs created along this pathway are currently only created via JNI, which includes
+        // session restore tabs.  Differs from TabModelImpl because we explicitly open tabs in the
+        // foreground -- opening tabs in affiliated mode is disallowed by ChromeLauncherActivity
+        // when a WebContents has already been created.
+        return getTabDelegate(isIncognito).createTabWithWebContents(
+                webContents, parentTabId, TabLaunchType.FROM_LONGPRESS_FOREGROUND,
+                DocumentMetricIds.STARTED_BY_CHROME_HOME_RECENT_TABS);
     }
 
     @Override
     protected Tab createNewTabForDevTools(String url) {
-        mTabDelegate.createTabForDevTools(url);
-        return null;
+        // TODO(dfalcantara): Move upwards once we delete ChromeShellTabModel.
+        return getTabDelegate(false).createNewTab(new LoadUrlParams(url),
+                TabModel.TabLaunchType.FROM_MENU_OR_OVERVIEW, null);
     }
 
     @Override
@@ -955,4 +969,8 @@
         }
         return false;
     }
+
+    private TabDelegate getTabDelegate(boolean incognito) {
+        return (TabDelegate) mTabCreatorManager.getTabCreator(incognito);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java
index a2ab80e..74f26e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelSelector.java
@@ -23,6 +23,7 @@
 import org.chromium.chrome.browser.document.DocumentUtils;
 import org.chromium.chrome.browser.document.PendingDocumentData;
 import org.chromium.chrome.browser.tabmodel.OffTheRecordTabModel.OffTheRecordTabModelDelegate;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorBase;
@@ -35,7 +36,7 @@
  */
 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class DocumentTabModelSelector extends TabModelSelectorBase
-        implements ActivityStateListener {
+        implements ActivityStateListener, TabCreatorManager {
     public static final String PREF_PACKAGE = "com.google.android.apps.chrome.document";
     public static final String PREF_IS_INCOGNITO_SELECTED = "is_incognito_selected";
 
@@ -52,7 +53,8 @@
     /**
      * Creates new Tabs.
      */
-    private final TabDelegate mTabDelegate;
+    private final TabDelegate mRegularTabDelegate;
+    private final TabDelegate mIncognitoTabDelegate;
 
     /**
      * TabModel that keeps track of regular tabs. This is always not null.
@@ -78,17 +80,19 @@
         sPrioritizedTabId = prioritizedTabId;
     }
 
-    public DocumentTabModelSelector(ActivityDelegate activityDelegate, TabDelegate tabDelegate) {
+    public DocumentTabModelSelector(ActivityDelegate activityDelegate,
+            TabDelegate regularTabDelegate, TabDelegate incognitoTabDelegate) {
         mActivityDelegate = activityDelegate;
-        mTabDelegate = tabDelegate;
+        mRegularTabDelegate = regularTabDelegate;
+        mIncognitoTabDelegate = incognitoTabDelegate;
 
         mRegularTabModel = new DocumentTabModelImpl(
-                activityDelegate, tabDelegate, false, sPrioritizedTabId);
+                activityDelegate, this, false, sPrioritizedTabId);
         mIncognitoTabModel = new OffTheRecordDocumentTabModel(new OffTheRecordTabModelDelegate() {
             @Override
             public TabModel createTabModel() {
                 DocumentTabModel incognitoModel = new DocumentTabModelImpl(
-                        mActivityDelegate, mTabDelegate, true, sPrioritizedTabId);
+                        mActivityDelegate, DocumentTabModelSelector.this, true, sPrioritizedTabId);
                 if (mRegularTabModel.isNativeInitialized()) {
                     incognitoModel.initializeNative();
                 }
@@ -113,6 +117,11 @@
         ApplicationStatus.registerStateListenerForAllActivities(this);
     }
 
+    @Override
+    public TabDelegate getTabCreator(boolean incognito) {
+        return incognito ? mIncognitoTabDelegate : mRegularTabDelegate;
+    }
+
     private void initializeTabIdCounter() {
         int biggestId = getLargestTaskIdFromRecents();
         biggestId = getMaxTabId(mRegularTabModel, biggestId);
@@ -168,7 +177,10 @@
 
         Activity parentActivity =
                 parent == null ? null : parent.getWindowAndroid().getActivity().get();
-        mTabDelegate.createTabInForeground(parentActivity, incognito, loadUrlParams, params);
+
+        TabDelegate delegate = getTabCreator(incognito);
+        Tab parentTab = delegate.getActivityTab(mActivityDelegate, parentActivity);
+        delegate.createNewTab(loadUrlParams, type, parentTab);
         return null;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
index 1bc89862..aae8306d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
@@ -7,51 +7,29 @@
 import android.app.Activity;
 
 import org.chromium.chrome.browser.Tab;
-import org.chromium.chrome.browser.document.PendingDocumentData;
-import org.chromium.chrome.browser.tabmodel.document.DocumentTabModel.Entry;
-import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.content_public.browser.WebContents;
 
 /**
  * Provides Tabs to a DocumentTabModel.
- * TODO(dfalcantara): Make this a TabCreatorManager.TabCreator subclass.
  */
-public interface TabDelegate {
+public interface TabDelegate extends TabCreator {
     /**
      * Returns the Tab for the given Activity.
-     * @param incognito Whether the Activity is supposed to hold an incognito Tab.
-     * @param delgate Sotres information about DocumentActivities.
+     * @param delgate Stores information about DocumentActivities.
      * @param activity Activity to grab the Tab of.
      * @return Tab for the DocumentActivity, if it is a valid DocumentActivity.  Null otherwise.
      */
-    Tab getActivityTab(boolean incognito, ActivityDelegate delgate, Activity activity);
+    Tab getActivityTab(ActivityDelegate activityDelegate, Activity activity);
 
     /**
-     * Opens a new Tab in the foreground.
-     * Assumed to be triggered by a window.open().
+     * Creates a Tab to host the given WebContents.
+     * @param webContents WebContents that has been pre-created.
+     * @param parentId ID of the parent Tab.
+     * @param type Launch type for the Tab.
+     * @param startedBy See {@link DocumentMetricIds}.
      */
-    void createTabInForeground(Activity parentActivity, boolean incognito,
-            LoadUrlParams loadUrlParams, PendingDocumentData documentParams);
-
-    /**
-     * Creates a frozen Tab for the Entry.  This Tab is not meant to be used or unfrozen -- it is
-     * only used as a placeholder until the real Tab can be created.
-     * @param entry Entry containing TabState.
-     * @return A frozen Tab.
-     */
-    Tab createFrozenTab(Entry entry);
-
-    /**
-     * Creates a new Activity for the pre-created WebContents.
-     * @param isIncognito Whether the Activity is supposed to hold an incognito Tab.
-     * @param webContents WebContents to use with the new Tab.
-     * @param parentTabId ID of the spawning Tab.
-     */
-    void createTabWithWebContents(boolean isIncognito, WebContents webContents, int parentTabId);
-
-    /**
-     * Creates a new Tab for a URL typed into DevTools.
-     * @param url URL to spawn a Tab for.
-     */
-    void createTabForDevTools(String url);
+    Tab createTabWithWebContents(
+            WebContents webContents, int parentId, TabLaunchType type, int startedBy);
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/FloatLabelLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/FloatLabelLayout.java
index f182417c..e6a2de40 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/FloatLabelLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/FloatLabelLayout.java
@@ -123,6 +123,17 @@
         super.addView(child, index, params);
     }
 
+    /**
+     * Focuses the EditText and makes the label visible without the normal
+     * animation that occurs on focus. This is particularly useful when
+     * auto-focusing the first field on a form.
+     */
+    public void focusWithoutAnimation() {
+        mEditText.setHint(null);
+        mLabel.setVisibility(View.VISIBLE);
+        mEditText.requestFocus();
+    }
+
     private void setEditText(EditText editText) {
         // If we already have an EditText, throw an exception
         if (mEditText != null) {
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 795e9d03..b4991e6a 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -137,6 +137,9 @@
       <message name="IDS_DELETE" desc="Label for a delete button. Used in multiple contexts. [CHAR-LIMIT=20]">
         Delete
       </message>
+      <message name="IDS_RESET" desc="Label for a button to reset information you are editing to a default.">
+        Reset
+      </message>
       <message name="IDS_TITLE" desc="Text indicating the title of a button or a textfield. Ued in multiple contexts. [CHAR-LIMIT=32]">
         Title
       </message>
@@ -301,6 +304,12 @@
       <message name="IDS_HOMEPAGE_DEFAULT_TITLE" desc="Label for checkbox to use the default homepage">
         Default
       </message>
+      <message name="IDS_OPTIONS_HOMEPAGE_EDIT_TITLE" desc="The title of the screen that allows users to change the URL that opens when they tap on the home page button in the omnibox.">
+        Edit home page
+      </message>
+      <message name="IDS_OPTIONS_HOMEPAGE_EDIT_LABEL" desc="The label for the edit text field that allows the user to change the URL that is opened when they tap on the home page button in the omnibox.">
+        Open this page
+      </message>
 
       <!-- Privacy preferences -->
       <message name="IDS_PREFS_PRIVACY" desc="Title for the Privacy preferences. [CHAR-LIMIT=32]">
@@ -1974,7 +1983,7 @@
       <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_MENU" desc="Content description for the settings menu button.">
         More options
       </message>
-      <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_SECURITY_LOCK" desc="Content description for the security lock icon that gives more site information when clicked.">
+      <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_SITE_INFO" desc="Content description for the page icon that gives more site information when clicked.  The icon can be a lock for secure pages, a magnifier for search result pages, or other icons representing the page state.">
         Site information
       </message>
       <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_MIC" desc="Content description for the voice search button.">
diff --git a/chrome/android/java_staging/AndroidManifest.xml b/chrome/android/java_staging/AndroidManifest.xml
index 17a0d0a..46a755f 100644
--- a/chrome/android/java_staging/AndroidManifest.xml
+++ b/chrome/android/java_staging/AndroidManifest.xml
@@ -16,7 +16,7 @@
     tools:ignore="MissingVersion">
     <!-- android:versionCode and android:versionName is set through gyp. See build/common.gypi -->
 
-    <uses-sdk android:minSdkVersion="{{min_sdk_version}}" android:targetSdkVersion="22" />
+    <uses-sdk android:minSdkVersion="{{min_sdk_version}}" android:targetSdkVersion="{{target_sdk_version}}" />
     <uses-feature android:glEsVersion="0x00020000" />
 
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
@@ -84,7 +84,8 @@
         android:label="@string/app_name"
         android:largeHeap="false"
         android:allowBackup="false"
-        android:supportsRtl="true">
+        android:supportsRtl="true"
+        {% block extra_application_attributes %}{% endblock %}>
 
         <!-- Samsung MultiWindow Support -->
         <meta-data android:name="com.samsung.android.sdk.multiwindow.enable"
@@ -372,8 +373,8 @@
                 android:resource="@xml/file_paths" />
         </provider>
 
-        <!-- Sync adapter for browser sync. -->
-        <service android:name="org.chromium.chrome.browser.sync.ChromeBrowserSyncAdapterService"
+        <!-- Sync adapter for browser invalidation. -->
+        <service android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService"
             android:exported="false">
             <intent-filter>
                 <action android:name="android.content.SyncAdapter" />
@@ -515,7 +516,7 @@
         <service android:name="org.chromium.chrome.browser.prerender.ChromePrerenderService"
             android:exported="true"
             tools:ignore="ExportedService" />
-        <service android:name="org.chromium.chrome.browser.customtabs.ChromeConnectionService"
+        <service android:name="org.chromium.chrome.browser.customtabs.CustomTabsConnectionService"
              android:exported="{{ 'true' if channel in ['dev', 'canary', 'default'] else 'false' }}"
              tools:ignore="ExportedService">
             <intent-filter>
@@ -589,4 +590,3 @@
         {% endblock %}
     </application>
 </manifest>
-
diff --git a/chrome/android/java_staging/proguard.flags b/chrome/android/java_staging/proguard.flags
index 24f472c58..2f24fe29 100644
--- a/chrome/android/java_staging/proguard.flags
+++ b/chrome/android/java_staging/proguard.flags
@@ -35,12 +35,14 @@
 -assumenosideeffects class * {
   @org.chromium.base.annotations.NoSideEffects <methods>;
 }
--assumenosideeffects class org.chromium.base.Log,
-                           com.google.android.apps.chrome.ILog {
+# Remove debug log calls but keep the functions themselves for use in tests.
+-assumenosideeffects class org.chromium.base.Log {
     public *** d(...);
     public *** v(...);
-    private *** debug(...);
-    private *** verbose(...);
+}
+-keep class org.chromium.base.Log {
+    public *** d(...);
+    public *** v(...);
 }
 
 # TODO(aurimas): figure out why we need to keep these classes.
@@ -120,3 +122,8 @@
 -keep class com.google.android.gms.cast.CastMediaControlIntent* {
   *;
 }
+
+# fling is used by Android WebView and a Chrome test.
+-keepclassmembers class org.chromium.content.browser.ContentViewCore {
+  public void fling(long, int, int, int, int);
+}
diff --git a/chrome/android/java_staging/res/layout-sw600dp/location_bar.xml b/chrome/android/java_staging/res/layout-sw600dp/location_bar.xml
index dcdcb8f..45ba3394 100644
--- a/chrome/android/java_staging/res/layout-sw600dp/location_bar.xml
+++ b/chrome/android/java_staging/res/layout-sw600dp/location_bar.xml
@@ -16,7 +16,7 @@
             android:layout_gravity="center_vertical"
             android:src="@drawable/ic_omnibox_page"
             android:scaleType="center"
-            android:contentDescription="@null"/>
+            android:contentDescription="@string/accessibility_toolbar_btn_site_info"/>
         <ImageButton android:id="@+id/security_button"
             style="@style/LocationBarButton"
             android:layout_height="match_parent"
@@ -25,7 +25,7 @@
             android:layout_gravity="center"
             android:alpha="0"
             android:visibility="invisible"
-            android:contentDescription="@string/accessibility_toolbar_btn_security_lock" />
+            android:contentDescription="@string/accessibility_toolbar_btn_site_info" />
     </FrameLayout>
     <include
         android:id="@+id/url_container"
diff --git a/chrome/android/java_staging/res/layout/add_bookmark.xml b/chrome/android/java_staging/res/layout/add_bookmark.xml
index 6d0157d..36e93bb 100644
--- a/chrome/android/java_staging/res/layout/add_bookmark.xml
+++ b/chrome/android/java_staging/res/layout/add_bookmark.xml
@@ -54,7 +54,7 @@
                 style="?android:attr/dropDownSpinnerStyle"
                 android:text="@string/loading_bookmark" />
         </LinearLayout>
-        <View style="@style/ButtonBarTopSpacer" />
+        <Space style="@style/ButtonBarTopSpacer" />
         <View style="@style/ButtonBarTopDivider" />
         <LinearLayout style="@style/ButtonBar" >
             <Button
diff --git a/chrome/android/java_staging/res/layout/custom_tabs_toolbar.xml b/chrome/android/java_staging/res/layout/custom_tabs_toolbar.xml
index 42b2ad2..5f117be 100644
--- a/chrome/android/java_staging/res/layout/custom_tabs_toolbar.xml
+++ b/chrome/android/java_staging/res/layout/custom_tabs_toolbar.xml
@@ -18,7 +18,7 @@
         android:layout_gravity="center_vertical"
         android:alpha="0"
         android:visibility="gone"
-        android:contentDescription="@string/accessibility_toolbar_btn_security_lock" />
+        android:contentDescription="@string/accessibility_toolbar_btn_site_info" />
     <FrameLayout
         android:id="@+id/url_info_container"
         android:background="@null"
diff --git a/chrome/android/java_staging/res/layout/location_bar.xml b/chrome/android/java_staging/res/layout/location_bar.xml
index 3141fee..cd410c3 100644
--- a/chrome/android/java_staging/res/layout/location_bar.xml
+++ b/chrome/android/java_staging/res/layout/location_bar.xml
@@ -23,7 +23,7 @@
             android:layout_height="match_parent"
             android:layout_gravity="center"
             android:scaleType="center"
-            android:contentDescription="@null"/>
+            android:contentDescription="@string/accessibility_toolbar_btn_site_info"/>
         <ImageButton android:id="@+id/security_button"
             style="@style/LocationBarButton"
             android:layout_height="match_parent"
@@ -32,7 +32,7 @@
             android:layout_gravity="center"
             android:alpha="0"
             android:visibility="invisible"
-            android:contentDescription="@string/accessibility_toolbar_btn_security_lock" />
+            android:contentDescription="@string/accessibility_toolbar_btn_site_info" />
     </FrameLayout>
     <include
         android:id="@+id/url_container"
diff --git a/chrome/android/java_staging/res/values-hdpi/dimens_staging.xml b/chrome/android/java_staging/res/values-hdpi/dimens_staging.xml
deleted file mode 100644
index ab9be249..0000000
--- a/chrome/android/java_staging/res/values-hdpi/dimens_staging.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<resources>
-    <!-- TabSwitcher -->
-    <dimen name="tabswitcher_border_frame_padding_left">5.333dp</dimen>
-    <dimen name="tabswitcher_border_frame_padding_top">49.333dp</dimen>
-</resources>
diff --git a/chrome/android/java_staging/res/values-sw600dp/dimens_staging.xml b/chrome/android/java_staging/res/values-sw600dp/dimens_staging.xml
deleted file mode 100644
index 262b9722..0000000
--- a/chrome/android/java_staging/res/values-sw600dp/dimens_staging.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<resources>
-    <!-- Tab Strip Dimensions -->
-    <dimen name="tab_strip_height">40dp</dimen>
-
-    <!-- Full Screen Dimensions -->
-    <dimen name="control_container_height">96dp</dimen>
-    <dimen name="custom_tabs_control_container_height">64dp</dimen>
-
-    <!-- The combined height of the tab strip and toolbar. -->
-    <dimen name="tab_strip_and_toolbar_height">96dp</dimen>
-
-    <dimen name="location_bar_url_text_size">18sp</dimen>
-    <dimen name="location_bar_icon_width">40dp</dimen>
-
-    <!-- Bookmarks widget dimensions -->
-    <dimen name="widget_thumbnail_height">104dp</dimen>
-    <dimen name="widget_column_width">130dp</dimen>
-
-    <!-- NTP dimensions -->
-    <dimen name="most_visited_spacing">16dp</dimen>
-    <dimen name="ntp_logo_height">180dp</dimen>
-
-    <!-- Recent tabs page -->
-    <dimen name="recent_tabs_visible_separator_padding">28dp</dimen>
-
-    <!-- Omnibox suggestion list -->
-    <dimen name="omnibox_suggestion_list_padding_top">8dp</dimen>
-    <dimen name="omnibox_suggestion_list_padding_bottom">8dp</dimen>
-</resources>
diff --git a/chrome/android/java_staging/res/values-xhdpi/dimens_staging.xml b/chrome/android/java_staging/res/values-xhdpi/dimens_staging.xml
deleted file mode 100644
index 3e27214..0000000
--- a/chrome/android/java_staging/res/values-xhdpi/dimens_staging.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<resources>
-    <!-- TabSwitcher -->
-    <dimen name="tabswitcher_border_frame_padding_left">5.5dp</dimen>
-    <dimen name="tabswitcher_border_frame_padding_top">49.5dp</dimen>
-</resources>
diff --git a/chrome/android/java_staging/res/values/colors_staging.xml b/chrome/android/java_staging/res/values/colors_staging.xml
deleted file mode 100644
index f748aef3..0000000
--- a/chrome/android/java_staging/res/values/colors_staging.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<resources>
-    <color name="text_highlight_color">#C6DAFC</color>
-
-    <!-- Theme colors. Also used for toolbar background -->
-    <color name="incognito_primary_color">#505050</color>
-
-    <!-- LocationBar colors -->
-    <color name="locationbar_light_hint_text">#80ffffff</color>
-    <color name="locationbar_light_selection_color">#cc5595fe</color>
-
-    <!-- Find in Page colors -->
-    <color name="find_result_bar_background_color">#bfffffff</color>
-    <color name="find_result_bar_background_border_color">#bf666666</color>
-    <color name="find_result_bar_result_color">#ffde43</color>
-    <color name="find_result_bar_result_border_color">#c9af35</color>
-    <color name="find_result_bar_active_color">#ff9632</color>
-    <color name="find_result_bar_active_border_color">#c37e3b</color>
-    <color name="find_in_page_query_color">#333333</color>
-    <color name="find_in_page_query_white_color">#ffffff</color>
-    <color name="find_in_page_results_status_color">#969696</color>
-    <color name="find_in_page_results_status_white_color">#7f7f7f</color>
-    <color name="find_in_page_failed_results_status_color">#db4437</color>
-
-    <!-- Tab Switcher Colors -->
-    <color name="tab_switcher_background">#14181C</color>
-    <color name="tab_back">#F1F1F1</color>
-    <color name="tab_back_incognito">#4F4F4F</color>
-
-    <!-- App Launch Colors -->
-    <color name="light_background_color">#FFFFFF</color>
-
-    <!-- NTP Colors. Used on the bookmarks and recent tabs pages. -->
-    <color name="ntp_bg">#fff</color>
-    <color name="ntp_bg_incognito">#222</color>
-    <color name="ntp_most_visited_text">#333</color>
-    <color name="ntp_most_visited_bg">#f2f2f2</color>
-    <color name="ntp_list_item_text">#333</color>
-    <color name="ntp_list_header_text">#333</color>
-    <color name="ntp_list_header_subtext">#969696</color>
-    <color name="ntp_list_header_subtext_active">#7cadff</color>
-
-    <!-- Reader mode colors -->
-    <color name="reader_mode_header_bg">#ff494949</color>
-
-    <!-- WebappActivity colors -->
-    <color name="webapp_url_bar_bg">#fafafa</color>
-    <color name="webapp_url_bar_separator">#e1e1e1</color>
-
-    <!-- Enhanced bookmark UI colors -->
-    <color name="enhanced_bookmark_detail_text">#212121</color>
-    <color name="enhanced_bookmark_detail_section">#7C7B79</color>
-    <color name="enhanced_bookmark_app_bar_shadow_color">#1D000000</color>
-    <color name="enhanced_bookmark_detail_dialog_shadow_color">#30000000</color>
-    <color name="enhanced_bookmark_selection_action_bar_background">#4F82F4</color>
-    <color name="enhanced_bookmark_drawer_selected_color">#4281F4</color>
-
-    <!-- Opt out promo -->
-    <color name="opt_out_text_color">#646464</color>
-</resources>
diff --git a/chrome/android/java_staging/res/values/dimens_staging.xml b/chrome/android/java_staging/res/values/dimens_staging.xml
deleted file mode 100644
index 6124cb11..0000000
--- a/chrome/android/java_staging/res/values/dimens_staging.xml
+++ /dev/null
@@ -1,156 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<resources>
-    <!-- Tab Strip Dimensions -->
-    <dimen name="tab_strip_height">0dp</dimen>
-
-    <!-- Full Screen Dimensions -->
-    <!-- Should match toolbar_height_no_shadow -->
-    <dimen name="control_container_height">56dp</dimen>
-    <dimen name="custom_tabs_control_container_height">56dp</dimen>
-    <dimen name="webapp_control_container_height">22dp</dimen>
-
-    <!-- The combined height of the tab strip and toolbar. -->
-    <dimen name="tab_strip_and_toolbar_height">56dp</dimen>
-
-    <!-- TabSwitcher - Size of the shift applied to tabs when stacked. -->
-    <dimen name="stacked_tab_visible_size">4dp</dimen>
-    <!-- TabSwitcher - Buffer space above the stack. -->
-    <dimen name="stack_buffer_height">5dp</dimen>
-    <!-- TabSwitcher - Buffer space on the side of the stack. -->
-    <dimen name="stack_buffer_width">5dp</dimen>
-    <!-- TabSwitcher - Minimum spacing between tabs. -->
-    <dimen name="min_spacing">120dp</dimen>
-    <!-- TabSwitcher - Maximum over scroll. -->
-    <dimen name="over_scroll">75dp</dimen>
-    <!-- TabSwitcher - Minimum scrolling distance to even out all the tabs. -->
-    <dimen name="even_out_scrolling">400dp</dimen>
-    <!-- TabSwitcher - The space between tabs in the toolbar swiping transition. -->
-    <dimen name="toolbar_swipe_space_between_tabs">30dp</dimen>
-    <!-- TabSwitcher - The minimum distance from the edge to commit a toolbar side swap. -->
-    <dimen name="toolbar_swipe_commit_distance">90dp</dimen>
-    <!-- TabSwitcher - Maximum amount to slide the tabs down or right in over scroll. -->
-    <dimen name="over_scroll_slide">10dp</dimen>
-
-    <!-- TabSwitcher -->
-    <dimen name="tabswitcher_border_frame_padding_left">6dp</dimen>
-    <dimen name="tabswitcher_border_frame_padding_top">50dp</dimen>
-    <dimen name="tabswitcher_border_frame_transparent_top">3dp</dimen>
-    <dimen name="tabswitcher_border_frame_transparent_side">2dp</dimen>
-
-    <!-- SelectBookmarkFolder - Default indent for bookmark folders in the selection dialog. -->
-    <dimen name="select_bookmark_folder_item_left">15dp</dimen>
-    <!-- SelectBookmarkFolder - Incremental indentation for nested bookmark folders in the
-         selection dialog. -->
-    <dimen name="select_bookmark_folder_item_inc_left">10dp</dimen>
-
-    <!-- Find in Page dimensions -->
-    <dimen name="find_result_bar_touch_width">68dp</dimen>
-    <dimen name="find_result_bar_draw_width">46dp</dimen>
-    <dimen name="find_result_bar_result_min_height">8px</dimen>
-    <dimen name="find_result_bar_active_min_height">16px</dimen>
-    <dimen name="find_result_bar_vertical_padding">8px</dimen>
-    <dimen name="find_result_bar_min_gap_between_stacks">3px</dimen>
-    <dimen name="find_result_bar_stacked_result_height">3px</dimen>
-    <dimen name="find_in_page_separator_width">1dp</dimen>
-    <dimen name="find_in_page_popup_width">375dp</dimen>
-    <dimen name="find_in_page_popup_height">60dp</dimen>
-    <dimen name="find_in_page_popup_margin_end">62dp</dimen>
-
-    <!-- Toolbar dimensions -->
-    <dimen name="toolbar_tab_count_text_size_1_digit">12dp</dimen>
-    <dimen name="toolbar_tab_count_text_size_2_digit">10dp</dimen>
-    <dimen name="toolbar_height_no_shadow">56dp</dimen>
-
-    <dimen name="location_bar_margin_top">5dp</dimen>
-    <dimen name="location_bar_margin_bottom">5dp</dimen>
-
-    <dimen name="toolbar_edge_padding">8dp</dimen>
-    <dimen name="location_bar_url_text_size">17sp</dimen>
-    <dimen name="location_bar_incognito_badge_padding">7dp</dimen>
-    <dimen name="omnibox_suggestion_height">60dp</dimen>
-    <dimen name="omnibox_suggestion_answer_height">72dp</dimen>
-    <dimen name="omnibox_suggestion_list_padding_top">0dp</dimen>
-    <dimen name="omnibox_suggestion_list_padding_bottom">0dp</dimen>
-    <dimen name="location_bar_icon_width">36dp</dimen>
-    <dimen name="tablet_toolbar_end_padding">6dp</dimen>
-
-    <!-- NTP dimensions -->
-    <dimen name="most_visited_spacing">16dp</dimen>
-    <dimen name="most_visited_tile_width">156dp</dimen>
-    <dimen name="most_visited_thumbnail_width">148dp</dimen>
-    <dimen name="most_visited_thumbnail_height">94dp</dimen>
-    <dimen name="most_visited_favicon_size">16dp</dimen>
-    <dimen name="most_visited_bg_corner_radius">2dp</dimen>
-    <!-- 250dp was chosen because it's smaller than the smallest dimension on the smallest device,
-         so we'll always have at least two columns of tiles (except in multiwindow with a narrow
-         window). -->
-    <dimen name="most_visited_two_column_min_width">250dp</dimen>
-    <!-- 450dp was chosen because it's greater than the width of the largest phone in portrait yet
-         less than the width of the smallest phone in landscape. So, we'll always have two columns
-         in portrait and three in landscape (except in atypical situations, like multiwindow). -->
-    <dimen name="most_visited_three_column_min_width">450dp</dimen>
-    <dimen name="icon_most_visited_layout_max_width">504dp</dimen>
-    <dimen name="icon_most_visited_layout_padding_top">16dp</dimen>
-    <dimen name="icon_most_visited_layout_no_logo_padding_top">28dp</dimen>
-    <dimen name="icon_most_visited_layout_bleed">8dp</dimen>
-    <dimen name="icon_most_visited_vertical_spacing">7dp</dimen>
-    <dimen name="icon_most_visited_min_horizontal_spacing">4dp</dimen>
-    <dimen name="icon_most_visited_max_horizontal_spacing">16dp</dimen>
-    <dimen name="icon_most_visited_tile_width">80dp</dimen>
-    <dimen name="icon_most_visited_icon_size">48dp</dimen>
-    <dimen name="ntp_logo_height">116dp</dimen>
-    <dimen name="ntp_list_item_padding">16dp</dimen>
-    <dimen name="ntp_list_item_min_height">48dp</dimen>
-    <dimen name="ntp_list_item_text_size">16sp</dimen>
-    <dimen name="ntp_list_item_favicon_size">16dp</dimen>
-    <dimen name="ntp_list_item_favicon_container_size">24dp</dimen>
-    <dimen name="ntp_shadow_height">9dp</dimen>
-
-    <!-- Bookmarks page -->
-    <dimen name="bookmark_folder_min_height">48dp</dimen>
-    <dimen name="bookmark_folder_text_size">16sp</dimen>
-
-    <!-- Recent tabs page -->
-    <dimen name="recent_tabs_visible_separator_padding">8dp</dimen>
-    <dimen name="recent_tabs_promo_padding">16dp</dimen>
-
-    <!-- Undo bar -->
-    <dimen name="undo_bar_height">48dp</dimen>
-    <dimen name="undo_bar_tablet_width">450dp</dimen>
-    <dimen name="undo_bar_tablet_margin">24dp</dimen>
-
-    <!-- Bookmarks widget dimensions -->
-    <dimen name="widget_thumbnail_height">94dp</dimen>
-    <dimen name="widget_horizontal_spacing">6dp</dimen>
-    <dimen name="widget_vertical_spacing">6dp</dimen>
-    <dimen name="widget_column_width">80dp</dimen>
-    <dimen name="widget_favicon_size">16dp</dimen>
-
-    <!-- Reader Mode dimensions -->
-    <dimen name="reader_mode_text_size">14sp</dimen>
-
-    <!-- Enhanced bookmarks dimensions -->
-    <dimen name="enhanced_bookmark_min_grid_width">135dp</dimen>
-    <dimen name="enhanced_bookmark_item_corner_radius">3dp</dimen>
-    <dimen name="enhanced_bookmark_item_popup_width">140dp</dimen>
-    <dimen name="enhanced_bookmark_item_half_space">4dp</dimen>
-    <dimen name="enhanced_bookmark_folder_item_left">16dp</dimen>
-    <dimen name="enhanced_bookmark_folder_item_icon_size">40dp</dimen>
-    <dimen name="enhanced_bookmark_detail_image_height">232dp</dimen>
-    <dimen name="enhanced_bookmark_minimum_dialog_size_tablet">500dp</dimen>
-    <dimen name="enhanced_bookmark_list_mode_background_margin">10dp</dimen>
-    <dimen name="enhanced_bookmark_drawer_drawable_padding">18dp</dimen>
-
-        <!-- Custom Tabs dimensions -->
-    <dimen name="custom_tabs_toolbar_maxWidth">60dp</dimen>
-    <dimen name="custom_tabs_toolbar_vertical_padding">16dp</dimen>
-    <dimen name="toolbar_icon_height">24dp</dimen>
-    <dimen name="min_toolbar_icon_side_padding">6dp</dimen>
-    <dimen name="custom_tabs_url_text_size">12sp</dimen>
-    <dimen name="custom_tabs_title_text_size">16sp</dimen>
-
-</resources>
diff --git a/chrome/android/java_staging/res/values/ids_staging.xml b/chrome/android/java_staging/res/values/ids_staging.xml
deleted file mode 100644
index fcc66eb9..0000000
--- a/chrome/android/java_staging/res/values/ids_staging.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<resources>
-    <item name="refine_view_id" type="id"/>
-    <item name="background_drawable" type="id"/>
-    <item name="foreground_drawable" type="id"/>
-
-    <item name="tabswitcher_single_drawable" type="id"/>
-    <item name="tabswitcher_multiple_drawable" type="id"/>
-
-    <item name="fre_pager" type="id"/>
-    <item name="eb_page" type="id"/>
-</resources>
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeMobileApplication.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeMobileApplication.java
index 0729a14a..613005d 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeMobileApplication.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeMobileApplication.java
@@ -54,6 +54,7 @@
 import org.chromium.chrome.browser.rlz.RevenueStats;
 import org.chromium.chrome.browser.services.GoogleServicesManager;
 import org.chromium.chrome.browser.share.ShareHelper;
+import org.chromium.chrome.browser.signin.AccountManagementFragmentDelegateImpl;
 import org.chromium.chrome.browser.smartcard.EmptyPKCS11AuthenticationManager;
 import org.chromium.chrome.browser.smartcard.PKCS11AuthenticationManager;
 import org.chromium.chrome.browser.sync.SyncController;
@@ -187,6 +188,8 @@
         // in the SyncController constructor.
         UniqueIdentificationGeneratorFactory.registerGenerator(SyncController.GENERATOR_ID,
                 new UuidBasedUniqueIdentificationGenerator(this, SESSIONS_UUID_PREF_KEY), false);
+
+        AccountManagementFragmentDelegateImpl.registerAccountManagementFragmentDelegate();
     }
 
     @Override
@@ -580,7 +583,7 @@
         if (sDocumentTabModelSelector == null) {
             sDocumentTabModelSelector = new DocumentTabModelSelector(
                     new ActivityDelegate(DocumentActivity.class, IncognitoDocumentActivity.class),
-                    new TabDelegateImpl());
+                    new TabDelegateImpl(false), new TabDelegateImpl(true));
         }
         return sDocumentTabModelSelector;
     }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java
index 9b9e7c59..dcc0aa7 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java
@@ -46,6 +46,7 @@
 import org.chromium.chrome.browser.dom_distiller.ReaderModeManager;
 import org.chromium.chrome.browser.enhanced_bookmarks.EnhancedBookmarksModel;
 import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkUtils;
+import org.chromium.chrome.browser.feedback.FeedbackCollector;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.help.HelpAndFeedback;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
@@ -55,7 +56,6 @@
 import org.chromium.chrome.browser.snackbar.LoFiBarPopupController;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable;
-import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
@@ -71,7 +71,7 @@
 import org.chromium.content_public.browser.readback_types.ReadbackResponse;
 import org.chromium.printing.PrintManagerDelegateImpl;
 import org.chromium.printing.PrintingController;
-import org.chromium.ui.base.DeviceFormFactor;
+import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
 
@@ -91,7 +91,7 @@
 
     private static final String TAG = "CompositorChromeActivity";
 
-    private WindowAndroid mWindowAndroid;
+    private ActivityWindowAndroid mWindowAndroid;
     private ChromeFullscreenManager mFullscreenManager;
     private CompositorViewHolder mCompositorViewHolder;
     private ContextualSearchManager mContextualSearchManager;
@@ -196,8 +196,7 @@
                 DeviceClassManager.enableSnapshots()));
         mCompositorViewHolder.onNativeLibraryReady(mWindowAndroid, getTabContentManager());
 
-        if (isContextualSearchAllowed() && ContextualSearchFieldTrial.isEnabled(this)
-                && !DeviceFormFactor.isTablet(this)) {
+        if (isContextualSearchAllowed() && ContextualSearchFieldTrial.isEnabled(this)) {
             mContextualSearchManager = new ContextualSearchManager(this, mWindowAndroid, this);
         }
 
@@ -331,6 +330,15 @@
         return mWindowAndroid.onActivityResult(requestCode, resultCode, intent);
     }
 
+    // @Override[ANDROID-M]
+    public void onRequestPermissionsResult(int requestCode, String[] permissions,
+            int[] grantResults) {
+        if (mWindowAndroid != null) {
+            mWindowAndroid.onRequestPermissionsResult(requestCode, permissions, grantResults);
+        }
+        //super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+    }
+
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
@@ -650,11 +658,13 @@
             final String helpContextId = HelpAndFeedback.getHelpContextIdFromUrl(
                     this, currentTab.getUrl(), getCurrentTabModel().isIncognito());
             final Activity mainActivity = this;
+            final FeedbackCollector collector =
+                    FeedbackCollector.create(currentTab.getProfile(), currentTab.getUrl());
             startTakingCompositorActivityScreenshot(new GetBitmapCallback() {
                 @Override
                 public void onFinishGetBitmap(Bitmap bitmap, int response) {
-                    HelpAndFeedback.getInstance(mainActivity).show(
-                            mainActivity, helpContextId, bitmap, currentTab.getUrl());
+                    HelpAndFeedback.getInstance(mainActivity)
+                            .show(mainActivity, helpContextId, bitmap, collector);
                     RecordUserAction.record("MobileMenuFeedback");
                 }
             });
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/DeferredStartupHandler.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/DeferredStartupHandler.java
index 35a4ae7..bd54eaa 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/DeferredStartupHandler.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/DeferredStartupHandler.java
@@ -20,7 +20,6 @@
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;
 import org.chromium.chrome.browser.share.ShareHelper;
-import org.chromium.chrome.browser.signin.AccountManagementFragmentDelegateImpl;
 
 /**
  * Handler for application level tasks to be completed on deferred startup.
@@ -99,8 +98,6 @@
         DownloadManagerService.getDownloadManagerService(application)
                 .clearPendingDownloadNotifications();
 
-        AccountManagementFragmentDelegateImpl.registerAccountManagementFragmentDelegate();
-
         application.initializeSharedClasses();
 
         ShareHelper.clearSharedScreenshots(application);
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java
index c26444d..f2ac162 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java
@@ -14,8 +14,8 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.invalidation.DelayedInvalidationsController;
 import org.chromium.chrome.browser.omaha.OmahaClient;
-import org.chromium.chrome.browser.sync.DelayedSyncController;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -74,7 +74,7 @@
                 context.startService(omahaIntent);
             }
 
-            DelayedSyncController.getInstance().resumeDelayedSyncs(context);
+            DelayedInvalidationsController.getInstance().notifyPendingInvalidations(context);
         }
     }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/appmenu/ChromeAppMenuPropertiesDelegate.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/appmenu/ChromeAppMenuPropertiesDelegate.java
index 93f45eb..4a7de61 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/appmenu/ChromeAppMenuPropertiesDelegate.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/appmenu/ChromeAppMenuPropertiesDelegate.java
@@ -90,9 +90,8 @@
 
                 mReloadMenuItem = menu.findItem(R.id.reload_menu_id);
                 mReloadMenuItem.setIcon(R.drawable.btn_reload_stop);
+                loadingStateChanged(currentTab.isLoading());
 
-                // Update the loading state of mReloadMenuItem.
-                if (currentTab.isLoading()) loadingStateChanged(true);
                 MenuItem bookmarkMenuItem = menu.findItem(R.id.bookmark_this_page_id);
                 bookmarkMenuItem.setEnabled(BookmarksBridge.isEditBookmarksEnabled(
                         mActivity.getActivityTab().getProfile().getOriginalProfile()));
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/phone/ContextualSearchLayout.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/phone/ContextualSearchLayout.java
index 8de83ecf..f4e3e90 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/phone/ContextualSearchLayout.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/phone/ContextualSearchLayout.java
@@ -33,12 +33,6 @@
  */
 public class ContextualSearchLayout extends ContextualSearchSupportedLayout {
     /**
-     * The height of the Toolbar in dps.
-     * TODO(pedrosimonetti): Get this value from the Toolbar code.
-     */
-    private static final float TOOLBAR_HEIGHT_DP = 56.f;
-
-    /**
      * The initial Y position of the touch event.
      */
     private float mInitialPanelTouchY;
@@ -79,7 +73,8 @@
 
     @Override
     public float getTopControlsOffset(float currentOffsetDp) {
-        return MathUtils.clamp(mBaseTab.getY(), -TOOLBAR_HEIGHT_DP, Math.min(currentOffsetDp, 0f));
+        return MathUtils.clamp(mBaseTab.getY(), -mSearchPanel.getToolbarHeight(),
+                Math.min(currentOffsetDp, 0f));
     }
 
     @Override
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
index cbca5f37..428ed7b 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -22,7 +22,6 @@
 import org.chromium.chrome.browser.compositor.overlays.SceneOverlay;
 import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer;
 import org.chromium.chrome.browser.compositor.scene_layer.TabStripSceneLayer;
-import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.ui.resources.ResourceManager;
@@ -118,11 +117,11 @@
 
     @Override
     public SceneOverlayLayer getUpdatedSceneOverlayTree(LayerTitleCache layerTitleCache,
-            ResourceManager resourceManager, ChromeFullscreenManager fullscreenManager) {
+            ResourceManager resourceManager, float yOffset) {
         assert mTabStripTreeProvider != null;
 
         mTabStripTreeProvider.pushAndUpdateStrip(this, layerTitleCache, resourceManager,
-                fullscreenManager, getActiveStripLayoutHelper().getStripLayoutTabsToRender());
+                getActiveStripLayoutHelper().getStripLayoutTabsToRender(), yOffset);
         return mTabStripTreeProvider;
     }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayer.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayer.java
index 617ccf1..01f4461 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayer.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayer.java
@@ -11,7 +11,6 @@
 import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutTab;
-import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.ui.resources.ResourceManager;
 
 /**
@@ -51,26 +50,25 @@
      * @param layoutHelper A layout helper for the tab strip.
      * @param layerTitleCache A layer title cache.
      * @param resourceManager A resource manager.
-     * @param fullscreenManager A fullscreen manager.
      * @param stripLayoutTabsToRender Array of strip layout tabs.
+     * @param yOffset Current top controls offset in dp.
      */
     public void pushAndUpdateStrip(StripLayoutHelperManager layoutHelper,
             LayerTitleCache layerTitleCache, ResourceManager resourceManager,
-            ChromeFullscreenManager fullscreenManager, StripLayoutTab[] stripLayoutTabsToRender) {
+            StripLayoutTab[] stripLayoutTabsToRender, float yOffset) {
         if (mNativePtr == 0) return;
 
         nativeBeginBuildingFrame(mNativePtr);
-        pushButtonsAndBackground(layoutHelper, resourceManager, fullscreenManager);
+        pushButtonsAndBackground(layoutHelper, resourceManager, yOffset);
         pushStripTabs(layoutHelper, layerTitleCache, resourceManager, stripLayoutTabsToRender);
         nativeFinishBuildingFrame(mNativePtr);
     }
 
     private void pushButtonsAndBackground(StripLayoutHelperManager layoutHelper,
-            ResourceManager resourceManager, ChromeFullscreenManager fullscreenManager) {
-        float yOffset = fullscreenManager != null ? fullscreenManager.getControlOffset() : 0.f;
-
+            ResourceManager resourceManager, float yOffset) {
         nativeUpdateTabStripLayer(mNativePtr, layoutHelper.getWidth() * mDpToPx,
-                layoutHelper.getHeight() * mDpToPx, yOffset, layoutHelper.getStripBrightness());
+                layoutHelper.getHeight() * mDpToPx, yOffset * mDpToPx,
+                layoutHelper.getStripBrightness());
 
         CompositorButton newTabButton = layoutHelper.getNewTabButton();
         CompositorButton modelSelectorButton = layoutHelper.getModelSelectorButton();
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
index 53a0dc04..e260c6f1 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -12,7 +12,6 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.components.variations.VariationsAssociatedData;
-import org.chromium.ui.base.DeviceFormFactor;
 
 import java.util.Arrays;
 import java.util.Locale;
@@ -27,8 +26,6 @@
     private static final String CONTEXTUAL_SEARCH_DISABLE_FOR_CJK = "disable_for_cjk";
     private static final String CONTEXTUAL_SEARCH_DISABLE_FOR_NON_ENGLISH =
             "disable_for_non_english";
-    private static final String CONTEXTUAL_SEARCH_DISABLE_SURROUNDINGS_OBSERVERS =
-            "disable_surroundings_observers";
     private static final String CONTEXTUAL_SEARCH_PROMO_ON_LONGPRESS_ONLY =
             "promo_on_longpress_only";
     static final String CONTEXTUAL_SEARCH_PROMO_ON_LIMITED_TAPS =
@@ -79,7 +76,7 @@
     }
 
     private static boolean detectEnabled(Context context) {
-        if (DeviceFormFactor.isTablet(context) || SysUtils.isLowEndDevice()) {
+        if (SysUtils.isLowEndDevice()) {
             return false;
         }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 5d4bdd3..162be11 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -21,8 +21,8 @@
 import org.chromium.base.SysUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.ContentViewUtil;
 import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchControl;
 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel.PanelState;
 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel.StateChangeReason;
@@ -943,7 +943,7 @@
         ContentView cv = new ContentView(mActivity, mSearchContentViewCore);
         // Creates an initially hidden WebContents which gets shown when the panel is opened.
         mSearchContentViewCore.initialize(cv, cv,
-                ContentViewUtil.createWebContents(false, true), mWindowAndroid);
+                WebContentsFactory.createWebContents(false, true), mWindowAndroid);
 
         // Transfers the ownership of the WebContents to the native ContextualSearchManager.
         nativeSetWebContents(mNativeContextualSearchManagerPtr, mSearchContentViewCore,
@@ -1338,6 +1338,11 @@
     }
 
     @Override
+    public void handleSelectionDismissal() {
+        hideContextualSearch(StateChangeReason.INVALID_SELECTION);
+    }
+
+    @Override
     public void handleSelectionModification(String selection, float x, float y) {
         if (mSearchPanelDelegate.isShowing()) {
             getContextualSearchControl().setCentralText(selection);
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
index 4ed4ea7..40dee706 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
@@ -170,7 +170,7 @@
                 shouldHandleSelection = true;
                 break;
             case SelectionEventType.SELECTION_CLEARED:
-                mHandler.onClearSelection();
+                mHandler.handleSelectionDismissal();
                 resetAllStates();
                 break;
             case SelectionEventType.SELECTION_DRAG_STARTED:
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionHandler.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionHandler.java
index 7bf5bee4..b1c44ca7 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionHandler.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionHandler.java
@@ -40,6 +40,11 @@
     public void handleSelectionModification(String selection, float x, float y);
 
     /**
+     * Handle a dismissal of the selection on the base page.
+     */
+    public void handleSelectionDismissal();
+
+    /**
      * Called when the selection is cleared.
      */
     public void onClearSelection();
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTab.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTab.java
index b3c5665f..8d00e5af 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTab.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTab.java
@@ -4,21 +4,29 @@
 
 package org.chromium.chrome.browser.customtabs;
 
+import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.os.TransactionTooLargeException;
 import android.text.TextUtils;
 import android.view.ContextMenu;
 import android.view.Menu;
 
 import com.google.android.apps.chrome.R;
 
+import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.CompositorChromeActivity;
-import org.chromium.chrome.browser.ContentViewUtil;
 import org.chromium.chrome.browser.EmptyTabObserver;
 import org.chromium.chrome.browser.Tab;
 import org.chromium.chrome.browser.UrlUtilities;
+import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
 import org.chromium.chrome.browser.contextmenu.ContextMenuParams;
 import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
 import org.chromium.chrome.browser.tab.ChromeTab;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.content_public.browser.LoadUrlParams;
@@ -29,42 +37,33 @@
  * A chrome tab that is only used as a custom tab.
  */
 public class CustomTab extends ChromeTab {
-    private static class LoadUrlTabObserver extends EmptyTabObserver {
-        private ChromeBrowserConnection mChromeBrowserConnection;
+    private static class CustomTabObserver extends EmptyTabObserver {
+        private CustomTabsConnection mCustomTabsConnection;
         private long mSessionId;
 
+        public CustomTabObserver(CustomTabsConnection customTabsConnection, long sessionId) {
+            mCustomTabsConnection = customTabsConnection;
+            mSessionId = sessionId;
+        }
+
         @Override
         public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
-            mChromeBrowserConnection.registerLaunch(mSessionId, params.getUrl());
-        }
-
-        public LoadUrlTabObserver(ChromeBrowserConnection chromeBrowserConnection, long sessionId) {
-            mChromeBrowserConnection = chromeBrowserConnection;
-            mSessionId = sessionId;
-        }
-    }
-
-    private static class CallbackTabObserver extends EmptyTabObserver {
-        private final ChromeBrowserConnection mChromeBrowserConnection;
-        private final long mSessionId;
-
-        public CallbackTabObserver(
-                ChromeBrowserConnection chromeBrowserConnection, long sessionId) {
-            mChromeBrowserConnection = chromeBrowserConnection;
-            mSessionId = sessionId;
+            mCustomTabsConnection.registerLaunch(mSessionId, params.getUrl());
         }
 
         @Override
         public void onPageLoadStarted(Tab tab, String url) {
-            mChromeBrowserConnection.notifyPageLoadStarted(mSessionId, url);
+            mCustomTabsConnection.notifyPageLoadStarted(mSessionId, url);
         }
 
         @Override
         public void onPageLoadFinished(Tab tab) {
-            mChromeBrowserConnection.notifyPageLoadFinished(mSessionId, tab.getUrl());
+            mCustomTabsConnection.notifyPageLoadFinished(mSessionId, tab.getUrl());
         }
     }
 
+    private ExternalNavigationHandler mNavigationHandler;
+    private CustomTabNavigationDelegate mNavigationDelegate;
     private TabChromeContextMenuItemDelegate
             mContextMenuDelegate = new TabChromeContextMenuItemDelegate() {
                 @Override
@@ -76,22 +75,44 @@
 
     /**
      * Construct an CustomTab. It might load a prerendered {@link WebContents} for the URL, if
-     * {@link ChromeConnectionService} has successfully warmed up for the url.
+     * {@link CustomTabsConnectionService} has successfully warmed up for the url.
      */
     public CustomTab(CompositorChromeActivity activity, WindowAndroid windowAndroid,
             long sessionId, String url, int parentTabId) {
         super(Tab.generateValidId(Tab.INVALID_TAB_ID), activity, false, windowAndroid,
                 TabLaunchType.FROM_EXTERNAL_APP, parentTabId, null, null);
-        ChromeBrowserConnection browserConnection =
-                ChromeBrowserConnection.getInstance(activity.getApplication());
-        WebContents webContents = browserConnection.takePrerenderedUrl(sessionId, url, null);
+        CustomTabsConnection customTabsConnection =
+                CustomTabsConnection.getInstance(activity.getApplication());
+        WebContents webContents = customTabsConnection.takePrerenderedUrl(sessionId, url, null);
         if (webContents == null) {
-            webContents = ContentViewUtil.createWebContents(isIncognito(), false);
+            webContents = WebContentsFactory.createWebContents(isIncognito(), false);
         }
         initialize(webContents, activity.getTabContentManager(), false);
         getView().requestFocus();
-        addObserver(new LoadUrlTabObserver(browserConnection, sessionId));
-        addObserver(new CallbackTabObserver(browserConnection, sessionId));
+        addObserver(new CustomTabObserver(customTabsConnection, sessionId));
+    }
+
+    @Override
+    protected InterceptNavigationDelegateImpl createInterceptNavigationDelegate() {
+        mNavigationDelegate = new CustomTabNavigationDelegate(mActivity);
+        mNavigationHandler = new ExternalNavigationHandler(mNavigationDelegate);
+        return new InterceptNavigationDelegateImpl(mNavigationHandler);
+    }
+
+    /**
+     * @return The {@link ExternalNavigationHandler} in this tab. For test purpose only.
+     */
+    @VisibleForTesting
+    ExternalNavigationHandler getExternalNavigationHandler() {
+        return mNavigationHandler;
+    }
+
+    /**
+     * @return The {@link CustomTabNavigationDelegate} in this tab. For test purpose only.
+     */
+    @VisibleForTesting
+    CustomTabNavigationDelegate getExternalNavigationDelegate() {
+        return mNavigationDelegate;
     }
 
     @Override
@@ -130,4 +151,84 @@
             }
         };
     }
+
+    /**
+     * A custom external navigation delegate that forbids the intent picker from showing up.
+     */
+    static class CustomTabNavigationDelegate extends ExternalNavigationDelegateImpl {
+        private static final String TAG = "cr.customtabs";
+        private boolean mHasActivityStarted;
+
+        /**
+         * Constructs a new instance of {@link CustomTabNavigationDelegate}.
+         */
+        public CustomTabNavigationDelegate(Activity activity) {
+            super(activity);
+        }
+
+        @Override
+        public void startActivity(Intent intent) {
+            super.startActivity(intent);
+            mHasActivityStarted = true;
+        }
+
+        @Override
+        public boolean startActivityIfNeeded(Intent intent) {
+            try {
+                if (resolveDefaultHandlerForIntent(intent)) {
+                    if (getActivity().startActivityIfNeeded(intent, -1)) {
+                        mHasActivityStarted = true;
+                        return true;
+                    } else {
+                        return false;
+                    }
+                } else {
+                    // If we failed to find the default handler of the intent, fall back to chrome.
+                    return false;
+                }
+            } catch (RuntimeException e) {
+                logTransactionTooLargeOrRethrow(e, intent);
+                return false;
+            }
+        }
+
+        /**
+         * Resolve the default external handler of an intent.
+         * @return Whether the default external handler is found: if chrome turns out to be the
+         *         default handler, this method will return false.
+         */
+        private boolean resolveDefaultHandlerForIntent(Intent intent) {
+            try {
+                ResolveInfo info = getActivity().getPackageManager().resolveActivity(intent, 0);
+                if (info != null) {
+                    final String chromePackage = getActivity().getPackageName();
+                    // If a default handler is found and it is not chrome itself, fire the intent.
+                    if (info.match != 0 && !chromePackage.equals(info.activityInfo.packageName)) {
+                        return true;
+                    }
+                }
+            } catch (RuntimeException e) {
+                logTransactionTooLargeOrRethrow(e, intent);
+            }
+            return false;
+        }
+
+        /**
+         * @return Whether an external activity has started to handle a url. For testing only.
+         */
+        @VisibleForTesting
+        public boolean hasExternalActivityStarted() {
+            return mHasActivityStarted;
+        }
+
+        private static void logTransactionTooLargeOrRethrow(RuntimeException e, Intent intent) {
+            // See http://crbug.com/369574.
+            if (e.getCause() != null && e.getCause() instanceof TransactionTooLargeException) {
+                Log.e(TAG, "Could not resolve Activity for intent " + intent.toString(), e);
+            } else {
+                throw e;
+            }
+        }
+    }
+
 }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 477e3492..64f3744 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -83,7 +83,7 @@
     @Override
     public void onStart() {
         super.onStart();
-        ChromeBrowserConnection.getInstance(getApplication())
+        CustomTabsConnection.getInstance(getApplication())
                 .keepAliveForSessionId(mIntentDataProvider.getSessionId(),
                         mIntentDataProvider.getKeepAliveServiceIntent());
     }
@@ -91,7 +91,7 @@
     @Override
     public void onStop() {
         super.onStop();
-        ChromeBrowserConnection.getInstance(getApplication())
+        CustomTabsConnection.getInstance(getApplication())
                 .dontKeepAliveForSessionId(mIntentDataProvider.getSessionId());
     }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
index 1d7a7e4..1d33ee6 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
@@ -43,8 +43,7 @@
 
             mReloadMenuItem = menu.findItem(R.id.reload_menu_id);
             mReloadMenuItem.setIcon(R.drawable.btn_reload_stop);
-            // Update the loading state of mReloadMenuItem.
-            if (currentTab.isLoading()) loadingStateChanged(true);
+            loadingStateChanged(currentTab.isLoading());
 
             // Add custom menu items. Make sure they are only added once.
             if (!mIsCustomEntryAdded) {
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 647f3a5..8e8e9f1 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -41,7 +41,7 @@
     /**
      * Extra used to match the session. This has to be included in the intent to open in
      * a custom tab. Can be -1 if there is no session id taken. Its value is a long returned
-     * by {@link IBrowserConnectionService#newSession}.
+     * by {@link ICustomTabsConnectionService#newSession}.
      */
     public static final String EXTRA_CUSTOM_TABS_SESSION_ID =
             "android.support.CUSTOM_TABS:session_id";
@@ -114,6 +114,7 @@
     private PendingIntent mActionButtonPendingIntent;
     private List<Pair<String, PendingIntent>> mMenuEntries = new ArrayList<>();
     private Bundle mAnimationBundle;
+    // OnFinished listener for PendingIntents. Used for testing only.
     private PendingIntent.OnFinished mOnFinished;
 
     /**
@@ -213,6 +214,15 @@
     }
 
     /**
+     * @return The {@link PendingIntent} that will be sent when the user clicks the action button.
+     *         For testing only.
+     */
+    @VisibleForTesting
+    public PendingIntent getActionButtonPendingIntentForTest() {
+        return mActionButtonPendingIntent;
+    }
+
+    /**
      * @return Titles of menu items that were passed from client app via intent.
      */
     public List<String> getMenuTitles() {
@@ -284,7 +294,7 @@
         Intent addedIntent = new Intent();
         addedIntent.setData(Uri.parse(url));
         try {
-            mActionButtonPendingIntent.send(context, 0, addedIntent);
+            mActionButtonPendingIntent.send(context, 0, addedIntent, mOnFinished, null);
         } catch (CanceledException e) {
             Log.e(TAG, "CanceledException while sending pending intent in custom tab");
         }
@@ -298,8 +308,12 @@
         return true;
     }
 
+    /**
+     * Set the callback object for {@link PendingIntent}s that are sent in this class. For testing
+     * purpose only.
+     */
     @VisibleForTesting
-    void setMenuSelectionOnFinishedForTesting(PendingIntent.OnFinished onFinished) {
+    void setPendingIntentOnFinishedForTesting(PendingIntent.OnFinished onFinished) {
         mOnFinished = onFinished;
     }
 }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeBrowserConnection.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
similarity index 91%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeBrowserConnection.java
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index 0857518c..ce0c5d48 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeBrowserConnection.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -20,6 +20,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.text.TextUtils;
@@ -31,6 +32,7 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.metrics.RecordHistogram;
@@ -49,9 +51,9 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * Implementation of the IBrowserConnectionService interface.
+ * Implementation of the ICustomTabsConnectionService interface.
  */
-class ChromeBrowserConnection extends IBrowserConnectionService.Stub {
+class CustomTabsConnection extends ICustomTabsConnectionService.Stub {
     private static final String TAG = Log.makeTag("ChromeConnection");
     private static final long RESULT_OK = 0;
     private static final long RESULT_ERROR = -1;
@@ -64,7 +66,7 @@
     private static final int PREDICTION_STATUS_COUNT = 3;
 
     private static final Object sConstructionLock = new Object();
-    private static ChromeBrowserConnection sInstance;
+    private static CustomTabsConnection sInstance;
 
     private static final class PrerenderedUrlParams {
         public final long mSessionId;
@@ -122,30 +124,30 @@
     }
 
     private final Object mLock;
-    private final SparseArray<IBrowserConnectionCallback> mUidToCallback;
+    private final SparseArray<ICustomTabsConnectionCallback> mUidToCallback;
     private final LongSparseArray<SessionParams> mSessionParams;
 
-    private ChromeBrowserConnection(Application application) {
+    private CustomTabsConnection(Application application) {
         super();
         mApplication = application;
         mWarmupHasBeenCalled = new AtomicBoolean();
         mLock = new Object();
-        mUidToCallback = new SparseArray<IBrowserConnectionCallback>();
+        mUidToCallback = new SparseArray<ICustomTabsConnectionCallback>();
         mSessionParams = new LongSparseArray<SessionParams>();
     }
 
     /**
-     * @return The unique instance of ChromeBrowserConnection.
+     * @return The unique instance of ChromeCustomTabsConnection.
      */
-    public static ChromeBrowserConnection getInstance(Application application) {
+    public static CustomTabsConnection getInstance(Application application) {
         synchronized (sConstructionLock) {
-            if (sInstance == null) sInstance = new ChromeBrowserConnection(application);
+            if (sInstance == null) sInstance = new CustomTabsConnection(application);
         }
         return sInstance;
     }
 
     @Override
-    public long finishSetup(IBrowserConnectionCallback callback) {
+    public long finishSetup(ICustomTabsConnectionCallback callback) {
         if (callback == null) return RESULT_ERROR;
         final int uid = Binder.getCallingUid();
         synchronized (mLock) {
@@ -172,7 +174,7 @@
     @Override
     public long warmup(long flags) {
         // Here and in mayLaunchUrl(), don't do expensive work for background applications.
-        if (!isUidForeground(Binder.getCallingUid())) return RESULT_ERROR;
+        if (!isUidForegroundOrSelf(Binder.getCallingUid())) return RESULT_ERROR;
         if (!mWarmupHasBeenCalled.compareAndSet(false, true)) return RESULT_OK;
         // The call is non-blocking and this must execute on the UI thread, post a task.
         ThreadUtils.postOnUiThread(new Runnable() {
@@ -230,7 +232,7 @@
         if (scheme != null && !scheme.equals("http") && !scheme.equals("https")) {
             return RESULT_ERROR;
         }
-        if (!isUidForeground(uid)) return RESULT_ERROR;
+        if (!isUidForegroundOrSelf(uid)) return RESULT_ERROR;
         synchronized (mLock) {
             SessionParams sessionParams = mSessionParams.get(sessionId);
             if (sessionParams == null || sessionParams.mUid != uid) return RESULT_ERROR;
@@ -318,7 +320,7 @@
         return null;
     }
 
-    private IBrowserConnectionCallback getCallbackForSessionIdAlreadyLocked(long sessionId) {
+    private ICustomTabsConnectionCallback getCallbackForSessionIdAlreadyLocked(long sessionId) {
         SessionParams sessionParams = mSessionParams.get(sessionId);
         if (sessionParams == null) return null;
         return mUidToCallback.get(sessionParams.mUid);
@@ -327,7 +329,7 @@
     /**
      * Notifies the application that a page load has started.
      *
-     * Delivers the {@link IBrowserConnectionCallback#onUserNavigationStarted}
+     * Delivers the {@link ICustomTabsConnectionCallback#onUserNavigationStarted}
      * callback to the aplication.
      *
      * @param sessionId The session ID.
@@ -336,7 +338,7 @@
      */
     boolean notifyPageLoadStarted(long sessionId, String url) {
         synchronized (mLock) {
-            IBrowserConnectionCallback cb = getCallbackForSessionIdAlreadyLocked(sessionId);
+            ICustomTabsConnectionCallback cb = getCallbackForSessionIdAlreadyLocked(sessionId);
             if (cb == null) return false;
             try {
                 cb.onUserNavigationStarted(sessionId, url, null);
@@ -350,7 +352,7 @@
     /**
      * Notifies the application that a page load has finished.
      *
-     * Delivers the {@link IBrowserConnectionCallback#onUserNavigationFinished}
+     * Delivers the {@link ICustomTabsConnectionCallback#onUserNavigationFinished}
      * callback to the aplication.
      *
      * @param sessionId The session ID.
@@ -359,7 +361,7 @@
      */
     boolean notifyPageLoadFinished(long sessionId, String url) {
         synchronized (mLock) {
-            IBrowserConnectionCallback cb = getCallbackForSessionIdAlreadyLocked(sessionId);
+            ICustomTabsConnectionCallback cb = getCallbackForSessionIdAlreadyLocked(sessionId);
             if (cb == null) return false;
             try {
                 cb.onUserNavigationFinished(sessionId, url, null);
@@ -438,9 +440,11 @@
     }
 
     /**
-     * @return true iff the UID is associated with a process having a foreground importance.
+     * @return true if the |uid| is associated with a process having a
+     * foreground importance, or self.
      */
-    private boolean isUidForeground(int uid) {
+    private boolean isUidForegroundOrSelf(int uid) {
+        if (uid == Process.myUid()) return true;
         ActivityManager am =
                 (ActivityManager) mApplication.getSystemService(Context.ACTIVITY_SERVICE);
         List<ActivityManager.RunningAppProcessInfo> running = am.getRunningAppProcesses();
@@ -453,6 +457,16 @@
     }
 
     /**
+     * {@link cleanupAlreadyLocked}, without holding mLock.
+     */
+    @VisibleForTesting
+    void cleanup(int uid) {
+        synchronized (mLock) {
+            cleanupAlreadyLocked(uid);
+        }
+    }
+
+    /**
      * Called when a remote client has died.
      */
     private void cleanupAlreadyLocked(int uid) {
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeConnectionService.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
similarity index 73%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeConnectionService.java
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
index 59bf8b2..12ed7ee 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeConnectionService.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
@@ -9,9 +9,9 @@
 import android.os.IBinder;
 
 /**
- * Chrome browser connection service, used by the embedded Chrome activities.
+ * Custom tabs connection service, used by the embedded Chrome activities.
  */
-public class ChromeConnectionService extends Service {
+public class CustomTabsConnectionService extends Service {
     @Override
     public void onCreate() {
         super.onCreate();
@@ -19,7 +19,7 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        return (IBinder) ChromeBrowserConnection.getInstance(getApplication());
+        return (IBinder) CustomTabsConnection.getInstance(getApplication());
     }
 
     @Override
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionCallback.aidl b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ICustomTabsConnectionCallback.aidl
similarity index 79%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionCallback.aidl
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ICustomTabsConnectionCallback.aidl
index dd52f15..45daf916 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionCallback.aidl
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ICustomTabsConnectionCallback.aidl
@@ -9,11 +9,11 @@
 /**
  * Interface for the client-provided callback on user navigation.
  */
-interface IBrowserConnectionCallback {
+interface ICustomTabsConnectionCallback {
     /**
      * To be called when a page navigation starts.
      *
-     * @param sessionId As returned by {@link IBrowserConnectionService#newSession}.
+     * @param sessionId As returned by {@link ICustomTabsConnectionService#newSession}.
      * @param url URL the user has navigated to.
      * @param extras Reserved for future use.
      */
@@ -22,7 +22,7 @@
     /**
      * To be called when a page navigation finishes.
      *
-     * @param sessionId As returned by {@link IBrowserConnectionService#newSession}.
+     * @param sessionId As returned by {@link ICustomTabsConnectionService#newSession}.
      * @param url URL the user has navigated to.
      * @param extras Reserved for future use.
      */
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionService.aidl b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ICustomTabsConnectionService.aidl
similarity index 95%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionService.aidl
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ICustomTabsConnectionService.aidl
index 647b366b..7254281 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionService.aidl
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ICustomTabsConnectionService.aidl
@@ -9,7 +9,7 @@
 /**
  * Interface for communicating between a browser background service and another application.
  */
-interface IBrowserConnectionService {
+interface ICustomTabsConnectionService {
     /**
      * Sets the callback triggered on an external navigation.
      *
@@ -21,7 +21,7 @@
      * @param callback Callback to be called, null if no callback is wanted.
      * @return 0 for success.
      */
-    long finishSetup(IBrowserConnectionCallback callback);
+    long finishSetup(ICustomTabsConnectionCallback callback);
 
     /**
      * Warms up the browser process.
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/common.aidl b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/common.aidl
index f3a0fc0..4229472a 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/common.aidl
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/common.aidl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file is needed to compile IBrowserConnectionService.aidl.
+// This file is needed to compile ICustomTabsConnectionService.aidl.
 
-interface org.chromium.chrome.browser.customtabs.IBrowserConnectionService;
-interface org.chromium.chrome.browser.customtabs.IBrowserConnectionCallback;
+interface org.chromium.chrome.browser.customtabs.ICustomTabsConnectionService;
+interface org.chromium.chrome.browser.customtabs.ICustomTabsConnectionCallback;
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentActivity.java
index 0651c6b0..0b352c4 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentActivity.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentActivity.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.document;
 
 import android.annotation.TargetApi;
-import android.app.Activity;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
@@ -156,30 +155,14 @@
             @Override
             public Tab openNewTab(LoadUrlParams loadUrlParams, TabLaunchType type, Tab parent,
                     boolean incognito) {
-                PendingDocumentData params = null;
-                if (loadUrlParams.getPostData() != null
-                        || loadUrlParams.getVerbatimHeaders() != null
-                        || loadUrlParams.getReferrer() != null) {
-                    params = new PendingDocumentData();
-                    params.postData = loadUrlParams.getPostData();
-                    params.extraHeaders = loadUrlParams.getVerbatimHeaders();
-                    params.referrer = loadUrlParams.getReferrer();
-                }
-
-                // Incognito never opens in the background.
-                int launchMode = type == TabLaunchType.FROM_LONGPRESS_BACKGROUND && !incognito
-                        ? ChromeLauncherActivity.LAUNCH_MODE_AFFILIATED
-                        : ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND;
-                Activity parentActivity =
-                        parent == null ? null : parent.getWindowAndroid().getActivity().get();
-                ChromeLauncherActivity.launchDocumentInstance(parentActivity, incognito,
-                        launchMode, loadUrlParams.getUrl(),
-                        DocumentMetricIds.STARTED_BY_WINDOW_OPEN,
-                        loadUrlParams.getTransitionType(), false, params);
-                return null;
+                // Triggered via open in new tab context menu on NTP.
+                return ChromeMobileApplication.getDocumentTabModelSelector().openNewTab(
+                        loadUrlParams, type, parent, incognito);
             }
         };
         setTabModelSelector(selector);
+        setTabCreators(ChromeMobileApplication.getDocumentTabModelSelector().getTabCreator(false),
+                ChromeMobileApplication.getDocumentTabModelSelector().getTabCreator(true));
 
         super.preInflationStartup();
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentMigrationHelper.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentMigrationHelper.java
index 07f2d62..aa371b7 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentMigrationHelper.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentMigrationHelper.java
@@ -42,6 +42,7 @@
 import org.chromium.chrome.browser.ntp.NativePageFactory;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
 import org.chromium.chrome.browser.tabmodel.TabPersistentStore;
 import org.chromium.chrome.browser.tabmodel.TabPersistentStore.OnTabStateReadCallback;
 import org.chromium.chrome.browser.tabmodel.document.ActivityDelegate;
@@ -122,6 +123,16 @@
         }
     }
 
+    private static class MigrationTabCreatorManager implements TabCreatorManager {
+        TabDelegateImpl mRegularTabCreator = new TabDelegateImpl(false);
+        TabDelegateImpl mIncognitoTabCreator = new TabDelegateImpl(true);
+
+        @Override
+        public TabDelegateImpl getTabCreator(boolean incognito) {
+            return incognito ? mIncognitoTabCreator : mRegularTabCreator;
+        }
+    }
+
     private static class MigrationTabModel extends DocumentTabModelImpl {
         private final SparseArray<String> mTitleList;
 
@@ -132,7 +143,7 @@
          */
         MigrationTabModel(MigrationActivityDelegate activityDelegate,
                 StorageDelegate storageDelegate) {
-            super(activityDelegate, storageDelegate, new TabDelegateImpl(), false,
+            super(activityDelegate, storageDelegate, new MigrationTabCreatorManager(), false,
                     Tab.INVALID_TAB_ID, ApplicationStatus.getApplicationContext());
             startTabStateLoad();
             mTitleList = new SparseArray<String>();
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java
index 7ae18bf..05bb9cf 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java
@@ -6,13 +6,11 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Rect;
-import android.util.LongSparseArray;
 
 import org.chromium.base.ObserverList.RewindableIterator;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.ChromeMobileApplication;
-import org.chromium.chrome.browser.ContentViewUtil;
 import org.chromium.chrome.browser.EmptyTabObserver;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.Tab;
@@ -20,6 +18,7 @@
 import org.chromium.chrome.browser.TabState;
 import org.chromium.chrome.browser.TabUma.TabCreationState;
 import org.chromium.chrome.browser.WarmupManager;
+import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
 import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
@@ -140,7 +139,7 @@
         if (!unfreeze && webContents == null) {
             webContents = WarmupManager.getInstance().hasPrerenderedUrl(url)
                     ? WarmupManager.getInstance().takePrerenderedWebContents()
-                    : ContentViewUtil.createWebContents(isIncognito(), false);
+                    : WebContentsFactory.createWebContents(isIncognito(), false);
         }
         initialize(webContents, tabContentManager, false);
         if (unfreeze) mDidRestoreState = unfreezeContents();
@@ -239,8 +238,6 @@
      */
     public class DocumentTabChromeWebContentsDelegateAndroidImpl
             extends TabChromeWebContentsDelegateAndroidImpl {
-        private final LongSparseArray<String> mContentsToUrlMapping = new LongSparseArray<String>();
-
         @Override
         public void webContentsCreated(WebContents sourceWebContents, long openerRenderFrameId,
                 String frameName, String targetUrl, WebContents newWebContents) {
@@ -248,31 +245,17 @@
             //                    WebContentsDelegateAndroidImpl.
             super.webContentsCreated(sourceWebContents, openerRenderFrameId, frameName,
                     targetUrl, newWebContents);
-            long nativeNewWebContents =
-                    ContentViewUtil.getNativeWebContentsFromWebContents(newWebContents);
-            mContentsToUrlMapping.put(nativeNewWebContents, targetUrl);
             DocumentWebContentsDelegate.getInstance().attachDelegate(newWebContents);
         }
 
         @Override
         public boolean addNewContents(WebContents sourceWebContents, WebContents webContents,
                 int disposition, Rect initialPosition, boolean userGesture) {
-            // TODO(dfalcantara): Set TabCreators on DocumentActivity, replace with super method.
             if (isClosing()) return false;
-            long nativeWebContents =
-                    ContentViewUtil.getNativeWebContentsFromWebContents(webContents);
-            String url = mContentsToUrlMapping.get(nativeWebContents);
-            if (url == null) url = "";
-            PendingDocumentData data = new PendingDocumentData();
-            data.webContents = webContents;
-            data.webContentsPaused = true;
-            ChromeLauncherActivity.launchDocumentInstance(
-                    getWindowAndroid().getActivity().get(), isIncognito(),
-                    ChromeLauncherActivity.LAUNCH_MODE_AFFILIATED, url,
-                    DocumentMetricIds.STARTED_BY_WINDOW_OPEN,
-                    PageTransition.AUTO_TOPLEVEL,
-                    false, data);
+            mActivity.getTabCreator(isIncognito()).createTabWithWebContents(
+                    webContents, getId(), TabLaunchType.FROM_LONGPRESS_FOREGROUND);
 
+            // Returns true because Tabs are created asynchronously.
             return true;
         }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/TabDelegateImpl.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/TabDelegateImpl.java
index a22b3133..2e18030 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/TabDelegateImpl.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/TabDelegateImpl.java
@@ -6,11 +6,13 @@
 
 import android.app.Activity;
 
+import org.chromium.chrome.browser.ChromeMobileApplication;
 import org.chromium.chrome.browser.Tab;
 import org.chromium.chrome.browser.TabState;
+import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.tab.ChromeTab;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.document.ActivityDelegate;
-import org.chromium.chrome.browser.tabmodel.document.DocumentTabModel.Entry;
 import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
@@ -21,47 +23,107 @@
  * TODO(dfalcantara): delete or refactor this after upstreaming.
  */
 public class TabDelegateImpl implements TabDelegate {
+    private boolean mIsIncognito;
+
+    /**
+     * Creates a TabDelegate.
+     * @param incognito Whether or not the TabDelegate handles the creation of incognito tabs.
+     */
+    public TabDelegateImpl(boolean incognito) {
+        mIsIncognito = incognito;
+    }
+
     @Override
-    public Tab getActivityTab(
-            boolean incognito, ActivityDelegate activityDelegate, Activity activity) {
+    public Tab getActivityTab(ActivityDelegate activityDelegate, Activity activity) {
         if (!(activity instanceof DocumentActivity)
-                || !activityDelegate.isValidActivity(incognito, activity.getIntent())) return null;
+                || !activityDelegate.isValidActivity(mIsIncognito, activity.getIntent())) {
+            return null;
+        }
         return ((DocumentActivity) activity).getActivityTab();
     }
 
+    /**
+     * Creates a frozen Tab.  This Tab is not meant to be used or unfrozen -- it is only used as a
+     * placeholder until the real Tab can be created.
+     * The index is ignored in DocumentMode because Android handles the ordering of Tabs.
+     */
     @Override
-    public void createTabInForeground(Activity parentActivity, boolean incognito,
-            LoadUrlParams loadUrlParams, PendingDocumentData documentParams) {
-        ChromeLauncherActivity.launchDocumentInstance(parentActivity, incognito,
-                ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND, loadUrlParams.getUrl(),
-                DocumentMetricIds.STARTED_BY_WINDOW_OPEN,
-                loadUrlParams.getTransitionType(), false, documentParams);
-    }
-
-    @Override
-    public Tab createFrozenTab(Entry entry) {
-        TabState state = entry.getTabState();
-        assert state != null;
-        return ChromeTab.createFrozenTabFromState(entry.tabId, null, state.isIncognito(), null,
+    public Tab createFrozenTab(TabState state, int id, int index) {
+        return ChromeTab.createFrozenTabFromState(id, null, state.isIncognito(), null,
                 Tab.INVALID_TAB_ID, state);
     }
 
     @Override
-    public void createTabWithWebContents(
-            boolean isIncognito, WebContents webContents, int parentTabId) {
-        PendingDocumentData data = new PendingDocumentData();
-        data.webContents = webContents;
-        ChromeLauncherActivity.launchDocumentInstance(
-                null, isIncognito, ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND, null,
-                DocumentMetricIds.STARTED_BY_CHROME_HOME_RECENT_TABS,
-                PageTransition.RELOAD, false, data);
+    public Tab createTabWithWebContents(
+            WebContents webContents, int parentId, TabLaunchType type) {
+        return createTabWithWebContents(
+                webContents, parentId, type, DocumentMetricIds.STARTED_BY_WINDOW_OPEN);
     }
 
     @Override
-    public void createTabForDevTools(String url) {
+    public Tab createTabWithWebContents(
+            WebContents webContents, int parentId, TabLaunchType type, int startedBy) {
+        // Tabs can't be launched in affiliated mode when a webcontents exists.
+        assert type != TabLaunchType.FROM_LONGPRESS_BACKGROUND;
+
+        // TODO(dfalcantara): Pipe information about paused WebContents from native.
+        PendingDocumentData data = new PendingDocumentData();
+        data.webContents = webContents;
+        data.webContentsPaused = startedBy != DocumentMetricIds.STARTED_BY_CHROME_HOME_RECENT_TABS;
+
+        String url = webContents.getUrl();
+        if (url == null) url = "";
+
+        // Determine information about the parent Activity.
+        Tab parentTab = parentId == Tab.INVALID_TAB_ID
+                ? null : ChromeMobileApplication.getDocumentTabModelSelector().getTabById(parentId);
+        Activity activity = getActivityFromTab(parentTab);
+
+        int pageTransition = startedBy == DocumentMetricIds.STARTED_BY_CHROME_HOME_RECENT_TABS
+                ? PageTransition.RELOAD : PageTransition.AUTO_TOPLEVEL;
+        ChromeLauncherActivity.launchDocumentInstance(activity, mIsIncognito,
+                ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND, url, startedBy, pageTransition,
+                false, data);
+
+        return null;
+    }
+
+    @Override
+    public Tab launchUrl(String url, TabLaunchType type) {
+        return createNewTab(new LoadUrlParams(url), type, null);
+    }
+
+    @Override
+    public Tab launchNTP() {
+        return launchUrl(UrlConstants.NTP_URL, TabLaunchType.FROM_MENU_OR_OVERVIEW);
+    }
+
+    @Override
+    public Tab createNewTab(LoadUrlParams loadUrlParams, TabLaunchType type, Tab parent) {
+        PendingDocumentData params = null;
+        if (loadUrlParams.getPostData() != null
+                || loadUrlParams.getVerbatimHeaders() != null
+                || loadUrlParams.getReferrer() != null) {
+            params = new PendingDocumentData();
+            params.postData = loadUrlParams.getPostData();
+            params.extraHeaders = loadUrlParams.getVerbatimHeaders();
+            params.referrer = loadUrlParams.getReferrer();
+        }
+
+        // TODO(dfalcantara): Is this really only triggered via NTP/Recent Tabs?
+        Activity parentActivity = getActivityFromTab(parent);
+        int launchMode = type == TabLaunchType.FROM_LONGPRESS_BACKGROUND && !mIsIncognito
+                ? ChromeLauncherActivity.LAUNCH_MODE_AFFILIATED
+                : ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND;
         ChromeLauncherActivity.launchDocumentInstance(
-                null, false, ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND, url,
+                parentActivity, mIsIncognito, launchMode, loadUrlParams.getUrl(),
                 DocumentMetricIds.STARTED_BY_CHROME_HOME_RECENT_TABS,
-                PageTransition.RELOAD, false, null);
+                PageTransition.RELOAD, false, params);
+        return null;
+    }
+
+    private Activity getActivityFromTab(Tab tab) {
+        return tab == null || tab.getWindowAndroid() == null
+                ? null : tab.getWindowAndroid().getActivity().get();
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModeButtonView.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModeButtonView.java
index fae8c40..53fb1fb823 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModeButtonView.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModeButtonView.java
@@ -71,12 +71,6 @@
         this.setClickable(true);
     }
 
-    // Expose dismiss to other classes in this package.
-    @Override
-    protected boolean dismiss(boolean horizontally) {
-        return super.dismiss(horizontally);
-    }
-
     @Override
     protected void onViewClicked() {
         mReaderModeButtonViewDelegate.onClick();
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
index 63bbc066..862462f8 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
@@ -11,8 +11,8 @@
 
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.chrome.browser.ContentViewUtil;
 import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
 import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable;
 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeEventFilter.ScrollDirection;
@@ -551,7 +551,9 @@
 
         if (mReaderModeButtonView != null
                 && (status != ReaderModeManager.POSSIBLE || !isReaderModeCurrentlyAllowed())) {
-            mReaderModeButtonView.dismiss(true);
+            // Unfortunately, dismiss() couldn't be used because it might attempt to remove a view
+            // while in onLayout, thus causing crash.
+            mReaderModeButtonView.removeFromParentView();
             mReaderModeButtonView = null;
             return;
         }
@@ -609,7 +611,7 @@
             Context context, WindowAndroid windowAndroid) {
         ContentViewCore cvc = new ContentViewCore(context);
         ContentView cv = new ContentView(context, cvc);
-        cvc.initialize(cv, cv, ContentViewUtil.createWebContents(false, true), windowAndroid);
+        cvc.initialize(cv, cv, WebContentsFactory.createWebContents(false, true), windowAndroid);
         cvc.setContentViewClient(new ContentViewClient() {
             @Override
             public void onOffsetsForFullscreenChanged(float topControlsOffsetYPix,
@@ -638,6 +640,10 @@
         mDistilledContentViewCore = createDistillerContentViewCore(
                 mReaderModeHost.getTab().getContentViewCore().getContext(),
                 mReaderModeHost.getTab().getWindowAndroid());
+
+        mergeNavigationHistory(mDistilledContentViewCore.getWebContents(),
+                mReaderModeHost.getTab().getWebContents());
+
         mDistilledContentObserver = new WebContentsObserver(
                 mDistilledContentViewCore.getWebContents()) {
             @Override
@@ -700,8 +706,6 @@
         mDistilledContentObserver = null;
 
         mDistilledContentViewCore.setContentViewClient(new ContentViewClient());
-        mergeNavigationHistory(mDistilledContentViewCore.getWebContents(),
-                mReaderModeHost.getTab().getWebContents());
         mReaderModeHost.getTab().swapContentViewCore(mDistilledContentViewCore, true,
                 mDidStartLoad, mDidFinishLoad);
         mDistilledContentViewCore.getContentViewClient().onOffsetsForFullscreenChanged(
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPage.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPage.java
index 39b4dc2..84035f2 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPage.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPage.java
@@ -15,8 +15,10 @@
 import org.chromium.chrome.browser.NativePage;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider;
+import org.chromium.chrome.browser.feedback.FeedbackCollector;
 import org.chromium.chrome.browser.help.HelpAndFeedback;
 import org.chromium.chrome.browser.ntp.IncognitoNewTabPageView.IncognitoNewTabPageManager;
+import org.chromium.chrome.browser.profiles.Profile;
 
 /**
  * Provides functionality when the user interacts with the Incognito NTP.
@@ -34,10 +36,9 @@
             new IncognitoNewTabPageManager() {
         @Override
         public void loadIncognitoLearnMore() {
-            HelpAndFeedback.getInstance(mActivity).show(
-                    mActivity,
-                    mActivity.getString(R.string.help_context_incognito_learn_more),
-                    null, null);
+            HelpAndFeedback.getInstance(mActivity).show(mActivity,
+                    mActivity.getString(R.string.help_context_incognito_learn_more), null,
+                    FeedbackCollector.create(Profile.getLastUsedProfile(), null));
         }
 
         @Override
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index ca8b5e6..a939e25 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -1751,6 +1751,7 @@
         Editable text = mUrlBar.getText();
 
         return mUrlBar.isCursorAtEndOfTypedText()
+                && !mUrlBar.isInBatchEditMode()
                 && BaseInputConnection.getComposingSpanEnd(text)
                         == BaseInputConnection.getComposingSpanStart(text);
     }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/UrlBar.java
index 142406f..7a8b652d 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/UrlBar.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -109,6 +109,8 @@
 
     private long mFirstFocusTimeMs;
 
+    private boolean mInBatchEditMode;
+
     /**
      * Implement this to get updates when the direction of the text in the URL bar changes.
      * E.g. If the user is typing a URL, then erases it and starts typing a query in Arabic,
@@ -272,6 +274,14 @@
     }
 
     /**
+     * @return Whether the URL is currently in batch edit mode triggered by an IME.  No external
+     *         text changes should be triggered while this is true.
+     */
+    public boolean isInBatchEditMode() {
+        return mInBatchEditMode;
+    }
+
+    /**
      * @return The user text without the autocomplete text.
      */
     public String getTextWithoutAutocomplete() {
@@ -292,7 +302,25 @@
     }
 
     @Override
+    public void onBeginBatchEdit() {
+        super.onBeginBatchEdit();
+        mInBatchEditMode = true;
+    }
+
+    @Override
+    public void onEndBatchEdit() {
+        super.onEndBatchEdit();
+        mInBatchEditMode = false;
+        validateSelection(getSelectionStart(), getSelectionEnd());
+    }
+
+    @Override
     protected void onSelectionChanged(int selStart, int selEnd) {
+        if (!mInBatchEditMode) validateSelection(selStart, selEnd);
+        super.onSelectionChanged(selStart, selEnd);
+    }
+
+    private void validateSelection(int selStart, int selEnd) {
         int spanStart = getText().getSpanStart(mAutocompleteSpan);
         int spanEnd = getText().getSpanEnd(mAutocompleteSpan);
         if (spanStart >= 0 && (spanStart != selStart || spanEnd != selEnd)) {
@@ -309,7 +337,6 @@
             // alone.  See crbug/273763 for more details.
             if (selEnd <= spanStart) getText().delete(spanStart, getText().length());
         }
-        super.onSelectionChanged(selStart, selEnd);
     }
 
     @Override
@@ -781,6 +808,7 @@
         }
     }
 
+    @VisibleForTesting
     InputConnectionWrapper mInputConnection = new InputConnectionWrapper(null, true) {
         private final char[] mTempSelectionChar = new char[1];
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java
index 53f3b28..51a8f30 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java
@@ -9,6 +9,7 @@
 import com.google.android.apps.chrome.R;
 
 import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.preferences.bandwidth.DataReductionProxyUma;
 
 /**
@@ -19,6 +20,7 @@
  * When the load images button is clicked, it will reload the page without Lo-Fi.
  */
 public class LoFiBarPopupController implements SnackbarManager.SnackbarController {
+    private static final int DEFAULT_LO_FI_SNACKBAR_SHOW_DURATION_MS = 6000;
     private final SnackbarManager mSnackbarManager;
     private final Context mContext;
     private Tab mTab;
@@ -41,7 +43,7 @@
         mSnackbarManager.showSnackbar(
                 null, mContext.getString(R.string.data_reduction_lo_fi_snackbar_message),
                 mContext.getString(R.string.data_reduction_lo_fi_snackbar_action),
-                tab.getId(), this);
+                tab.getId(), this, DEFAULT_LO_FI_SNACKBAR_SHOW_DURATION_MS);
         DataReductionProxyUma.dataReductionProxyLoFiUIAction(
                 DataReductionProxyUma.ACTION_LOAD_IMAGES_SNACKBAR_SHOWN);
     }
@@ -61,6 +63,7 @@
         mSnackbarManager.dismissSnackbar(false);
         mTab.stopLoading();
         mTab.reloadIgnoringCache();
+        DataReductionProxySettings.getInstance().incrementLoFiUserRequestsForImages();
         DataReductionProxyUma.dataReductionProxyLoFiUIAction(
                 DataReductionProxyUma.ACTION_LOAD_IMAGES_SNACKBAR_CLICKED);
     }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java
index 8e174630..ea10fec 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java
@@ -122,13 +122,30 @@
      */
     public void showSnackbar(String template, String description, String actionText,
             Object actionData, SnackbarController controller) {
-        mUIThreadHandler.removeCallbacks(mHideRunnable);
         int duration = sUndoBarShowDurationMs;
         // Duration for snackbars to show is different in normal mode and in accessibility mode.
         if (DeviceClassManager.isAccessibilityModeEnabled(mParent.getContext())) {
             duration = sAccessibilityUndoBarDurationMs;
         }
-        mUIThreadHandler.postDelayed(mHideRunnable, duration);
+        showSnackbar(template, description, actionText, actionData, controller, duration);
+    }
+
+    /**
+     * Shows a snackbar for the given timeout duration with description text and an action button.
+     * Allows overriding the default timeout of {@link #DEFAULT_SNACKBAR_SHOW_DURATION_MS} with
+     * a custom value.
+     * @param template Teamplate used to compose full description.
+     * @param description Text for description showing at start of snackbar.
+     * @param actionText Text for action button to show.
+     * @param actionData Data bound to this snackbar entry. Will be returned to listeners when
+     *                   action be clicked or snackbar be dismissed.
+     * @param controller Listener for this snackbar entry.
+     * @param timeoutMs The timeout to use in ms.
+     */
+    public void showSnackbar(String template, String description, String actionText,
+            Object actionData, SnackbarController controller, int timeoutMs) {
+        mUIThreadHandler.removeCallbacks(mHideRunnable);
+        mUIThreadHandler.postDelayed(mHideRunnable, timeoutMs);
 
         mStack.push(new SnackbarEntry(template, description, actionText, actionData, controller));
         if (mPopup == null) {
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ChromeTab.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ChromeTab.java
index 77dabcd..c37ae46 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ChromeTab.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ChromeTab.java
@@ -989,7 +989,7 @@
             mDownloadDelegate = new ChromeDownloadDelegate(mActivity,
                     mActivity.getTabModelSelector(), this);
             cvc.setDownloadDelegate(mDownloadDelegate);
-            setInterceptNavigationDelegate(new InterceptNavigationDelegateImpl());
+            setInterceptNavigationDelegate(createInterceptNavigationDelegate());
 
             if (mGestureStateListener == null) mGestureStateListener = createGestureStateListener();
             cvc.addGestureStateListener(mGestureStateListener);
@@ -1163,13 +1163,26 @@
         return mTabRedirectHandler;
     }
 
-    private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
+    /**
+     * Delegate that handles intercepting top-level navigation.
+     */
+    protected class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
         final ExternalNavigationHandler mExternalNavHandler;
         final AuthenticatorNavigationInterceptor mAuthenticatorHelper;
 
-        InterceptNavigationDelegateImpl() {
-            mExternalNavHandler = new ExternalNavigationHandler(mActivity);
+        /**
+         * Defualt constructor of {@link InterceptNavigationDelegateImpl}.
+         */
+        public InterceptNavigationDelegateImpl() {
+            this(new ExternalNavigationHandler(mActivity));
+        }
 
+        /**
+         * Constructs a new instance of {@link InterceptNavigationDelegateImpl} with the given
+         * {@link ExternalNavigationHandler}.
+         */
+        public InterceptNavigationDelegateImpl(ExternalNavigationHandler externalNavHandler) {
+            mExternalNavHandler = externalNavHandler;
             mAuthenticatorHelper = ((ChromeMobileApplication) getApplicationContext())
                     .createAuthenticatorNavigationInterceptor(ChromeTab.this);
         }
@@ -1318,6 +1331,15 @@
         return (InterceptNavigationDelegateImpl) super.getInterceptNavigationDelegate();
     }
 
+    /**
+     * Factory method for {@link InterceptNavigationDelegateImpl}. Meant to be overridden by
+     * subclasses.
+     * @return A new instance of {@link InterceptNavigationDelegateImpl}.
+     */
+    protected InterceptNavigationDelegateImpl createInterceptNavigationDelegate() {
+        return new InterceptNavigationDelegateImpl();
+    }
+
     @Override
     public void setClosing(boolean closing) {
         if (closing) mBackgroundContentViewHelper.recordTabClose();
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
index 80ca244..b45a45a 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
@@ -261,7 +261,7 @@
     }
 
     @Override
-    public void createFrozenTab(TabState state, int id, int index) {
+    public Tab createFrozenTab(TabState state, int id, int index) {
         ChromeTab tab = ChromeTab.createFrozenTabFromState(
                 id, mActivity, state.isIncognito(), mNativeWindow, state.parentId, state);
         boolean selectTab = mOrderController.willOpenInForeground(TabLaunchType.FROM_RESTORE,
@@ -269,6 +269,7 @@
         tab.initialize(null, mTabContentManager, !selectTab);
         assert state.isIncognito() == mIncognito;
         mTabModel.addTab(tab, index, TabLaunchType.FROM_RESTORE);
+        return tab;
     }
 
     /**
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
index 7f66fcf..518b96cc 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -28,6 +28,7 @@
 import com.google.android.apps.chrome.R;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ContextualMenuBar.ActionBarDelegate;
 import org.chromium.chrome.browser.CustomSelectionActionModeCallback;
 import org.chromium.chrome.browser.Tab;
@@ -93,6 +94,11 @@
     }
 
     @Override
+    protected int getToolbarHeightWithoutShadowResId() {
+        return R.dimen.custom_tabs_control_container_height;
+    }
+
+    @Override
     public void initialize(ToolbarDataProvider toolbarDataProvider,
             ToolbarTabController tabController, AppMenuButtonHelper appMenuButtonHelper) {
         super.initialize(toolbarDataProvider, tabController, appMenuButtonHelper);
@@ -141,6 +147,14 @@
         mCustomActionButton.setVisibility(VISIBLE);
     }
 
+    /**
+     * @return The custom action button. For test purpose only.
+     */
+    @VisibleForTesting
+    public ImageButton getCustomActionButtonForTest() {
+        return mCustomActionButton;
+    }
+
     @Override
     public ChromeTab getCurrentTab() {
         return ChromeTab.fromTab(getToolbarDataProvider().getTab());
@@ -175,7 +189,7 @@
     @Override
     protected void onNavigatedToDifferentPage() {
         super.onNavigatedToDifferentPage();
-        mTitleBar.setText("");
+        setTitleToPageTitle();
     }
 
     @Override
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
index b15333f..2c7ab90 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -65,7 +65,7 @@
     public ToolbarLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
         mToolbarHeightWithoutShadow = getResources().getDimensionPixelOffset(
-                R.dimen.toolbar_height_no_shadow);
+                getToolbarHeightWithoutShadowResId());
     }
 
     @Override
@@ -139,6 +139,13 @@
         return ((FrameLayout.LayoutParams) view.getLayoutParams());
     }
 
+    /**
+     * @return The resource id to be used while getting the toolbar height with no shadow.
+     */
+    protected int getToolbarHeightWithoutShadowResId() {
+        return R.dimen.toolbar_height_no_shadow;
+    }
+
     @Override
     public void initialize(ToolbarDataProvider toolbarDataProvider,
             ToolbarTabController tabController, AppMenuButtonHelper appMenuButtonHelper) {
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index adb8aab17..ab7a607 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -92,7 +92,7 @@
 
     private LocationBarPhone mPhoneLocationBar;
 
-    private View mToolbarButtonsContainer;
+    private ViewGroup mToolbarButtonsContainer;
     private ImageView mToggleTabStackButton;
     private NewTabButton mNewTabButton;
     private TintedImageButton mHomeButton;
@@ -231,26 +231,10 @@
     @Override
     public void onFinishInflate() {
         super.onFinishInflate();
-        Context context = getContext();
-
         mPhoneLocationBar = (LocationBarPhone) findViewById(R.id.location_bar);
 
-        mToolbarButtonsContainer = findViewById(R.id.toolbar_buttons);
+        mToolbarButtonsContainer = (ViewGroup) findViewById(R.id.toolbar_buttons);
 
-        mToggleTabStackButton = (ImageView) findViewById(R.id.tab_switcher_button);
-        mToggleTabStackButton.setClickable(false);
-
-        Resources resources = getResources();
-        mTabSwitcherButtonDrawable =
-                TabSwitcherDrawable.createTabSwitcherDrawable(resources, false);
-        mTabSwitcherButtonDrawableLight =
-                TabSwitcherDrawable.createTabSwitcherDrawable(resources, true);
-
-        mToggleTabStackButton.setVisibility(FeatureUtilities.isDocumentMode(getContext())
-                ? GONE : VISIBLE);
-        mToggleTabStackButton.setImageDrawable(mTabSwitcherButtonDrawable);
-
-        mNewTabButton = (NewTabButton) findViewById(R.id.new_tab_button);
         mHomeButton = (TintedImageButton) findViewById(R.id.home_button);
 
         mUrlBar = (TextView) findViewById(R.id.url_bar);
@@ -258,11 +242,9 @@
 
         mUrlActionsContainer = findViewById(R.id.url_action_container);
 
-        mTabSwitcherModeViews.add(mNewTabButton);
         mBrowsingModeViews.add(mPhoneLocationBar);
 
         mToolbarBackground = new ColorDrawable(getToolbarColorForVisualState(VisualState.NORMAL));
-
         mTabSwitcherAnimationBgOverlay =
                 new ColorDrawable(getToolbarColorForVisualState(VisualState.NORMAL));
 
@@ -277,22 +259,53 @@
 
         mMenuButton.setVisibility(shouldShowMenuButton() ? View.VISIBLE : View.GONE);
 
-        // Ensure that the new tab button will not draw over the toolbar buttons if the translated
-        // string is long.  Set a margin to the size of the toolbar button container for the new
-        // tab button.
-        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        Point screenSize = new Point();
-        wm.getDefaultDisplay().getSize(screenSize);
-
-        mToolbarButtonsContainer.measure(
-                MeasureSpec.makeMeasureSpec(screenSize.x, MeasureSpec.AT_MOST),
-                MeasureSpec.makeMeasureSpec(screenSize.y, MeasureSpec.AT_MOST));
-        ApiCompatibilityUtils.setMarginEnd(getFrameLayoutParams(mNewTabButton),
-                mToolbarButtonsContainer.getMeasuredWidth());
+        finishInflateForTabSwitchingResources();
 
         setWillNotDraw(false);
     }
 
+    private boolean isTabSwitchingEnabled() {
+        return !FeatureUtilities.isDocumentMode(getContext());
+    }
+
+    private void finishInflateForTabSwitchingResources() {
+        mToggleTabStackButton = (ImageView) findViewById(R.id.tab_switcher_button);
+        mNewTabButton = (NewTabButton) findViewById(R.id.new_tab_button);
+
+        if (!isTabSwitchingEnabled()) {
+            assert mToolbarButtonsContainer.indexOfChild(mToggleTabStackButton) >= 0;
+            mToolbarButtonsContainer.removeView(mToggleTabStackButton);
+            mToggleTabStackButton = null;
+            assert indexOfChild(mNewTabButton) >= 0;
+            removeView(mNewTabButton);
+            mNewTabButton = null;
+        } else {
+            mToggleTabStackButton.setClickable(false);
+            Resources resources = getResources();
+            mTabSwitcherButtonDrawable =
+                    TabSwitcherDrawable.createTabSwitcherDrawable(resources, false);
+            mTabSwitcherButtonDrawableLight =
+                    TabSwitcherDrawable.createTabSwitcherDrawable(resources, true);
+            mToggleTabStackButton.setImageDrawable(mTabSwitcherButtonDrawable);
+            mTabSwitcherModeViews.add(mNewTabButton);
+
+            // Ensure that the new tab button will not draw over the toolbar buttons if the
+            // translated string is long.  Set a margin to the size of the toolbar button container
+            // for the new tab button.
+            WindowManager wm = (WindowManager) getContext().getSystemService(
+                    Context.WINDOW_SERVICE);
+            Point screenSize = new Point();
+            wm.getDefaultDisplay().getSize(screenSize);
+
+            mToolbarButtonsContainer.measure(
+                    MeasureSpec.makeMeasureSpec(screenSize.x, MeasureSpec.AT_MOST),
+                    MeasureSpec.makeMeasureSpec(screenSize.y, MeasureSpec.AT_MOST));
+
+            ApiCompatibilityUtils.setMarginEnd(getFrameLayoutParams(mNewTabButton),
+                    mToolbarButtonsContainer.getMeasuredWidth());
+        }
+    }
+
     /**
      * Sets up click and key listeners once we have native library available to handle clicks.
      */
@@ -300,24 +313,27 @@
     public void onNativeLibraryReady() {
         super.onNativeLibraryReady();
         getLocationBar().onNativeLibraryReady();
-        mToggleTabStackButton.setOnClickListener(this);
-        mToggleTabStackButton.setOnLongClickListener(this);
-        mToggleTabStackButton.setOnKeyListener(new KeyboardNavigationListener() {
-            @Override
-            public View getNextFocusForward() {
-                if (mMenuButton != null && mMenuButton.isShown()) {
-                    return mMenuButton;
-                } else {
-                    return getCurrentTabView();
-                }
-            }
 
-            @Override
-            public View getNextFocusBackward() {
-                return findViewById(R.id.url_bar);
-            }
-        });
-        mNewTabButton.setOnClickListener(this);
+        if (isTabSwitchingEnabled()) {
+            mToggleTabStackButton.setOnClickListener(this);
+            mToggleTabStackButton.setOnLongClickListener(this);
+            mToggleTabStackButton.setOnKeyListener(new KeyboardNavigationListener() {
+                @Override
+                public View getNextFocusForward() {
+                    if (mMenuButton != null && mMenuButton.isShown()) {
+                        return mMenuButton;
+                    } else {
+                        return getCurrentTabView();
+                    }
+                }
+
+                @Override
+                public View getNextFocusBackward() {
+                    return findViewById(R.id.url_bar);
+                }
+            });
+            mNewTabButton.setOnClickListener(this);
+        }
         mHomeButton.setOnClickListener(this);
 
         mMenuButton.setOnKeyListener(new KeyboardNavigationListener() {
@@ -410,7 +426,7 @@
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
             boolean changed = layoutLocationBar(MeasureSpec.getSize(widthMeasureSpec));
-            setUrlFocusChangePercent(mUrlFocusChangePercent);
+            if (!mInTabSwitcherMode) setUrlFocusChangePercent(mUrlFocusChangePercent);
             if (!changed) return;
         } else {
             updateUnfocusedLocationBarLayoutParams();
@@ -673,6 +689,8 @@
     }
 
     private void updateUrlExpansionAnimation() {
+        if (mInTabSwitcherMode || isTabSwitcherAnimationRunning()) return;
+
         mLocationBarBackgroundOffset.setEmpty();
 
         FrameLayout.LayoutParams locationBarLayoutParams =
@@ -783,6 +801,7 @@
         if (!mUrlFocusChangeInProgress) {
             float searchBoxTranslationY =
                     mNtpSearchBoxTransformedBounds.top - mNtpSearchBoxOriginalBounds.top;
+            searchBoxTranslationY = Math.min(searchBoxTranslationY, 0);
             mToolbarButtonsContainer.setTranslationY(searchBoxTranslationY);
             mHomeButton.setTranslationY(searchBoxTranslationY);
         }
@@ -881,8 +900,8 @@
         // Draw the tab stack button and associated text.
         translateCanvasToView(this, mToolbarButtonsContainer, canvas);
 
-        if (mTabSwitcherAnimationTabStackDrawable != null
-                && mToggleTabStackButton.getVisibility() != View.GONE) {
+        if (mTabSwitcherAnimationTabStackDrawable != null && mToggleTabStackButton != null
+                && mUrlExpansionPercent != 1f) {
             // Draw the tab stack button image.
             canvas.save();
             translateCanvasToView(mToolbarButtonsContainer, mToggleTabStackButton, canvas);
@@ -905,7 +924,8 @@
         }
 
         // Draw the menu button if necessary.
-        if (mTabSwitcherAnimationMenuDrawable != null) {
+        if (mTabSwitcherAnimationMenuDrawable != null
+                && mUrlExpansionPercent != 1f) {
             mTabSwitcherAnimationMenuDrawable.setBounds(
                     mMenuButton.getPaddingLeft(), mMenuButton.getPaddingTop(),
                     mMenuButton.getWidth() - mMenuButton.getPaddingRight(),
@@ -1096,7 +1116,7 @@
 
     @Override
     public void onStateRestored() {
-        mToggleTabStackButton.setClickable(true);
+        if (mToggleTabStackButton != null) mToggleTabStackButton.setClickable(true);
     }
 
     @Override
@@ -1418,7 +1438,7 @@
         animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
         animators.add(animator);
 
-        if (mToggleTabStackButton.getVisibility() != GONE) {
+        if (mToggleTabStackButton != null) {
             animator = ObjectAnimator.ofFloat(
                     mToggleTabStackButton, TRANSLATION_X, toolbarButtonTranslationX);
             animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
@@ -1450,7 +1470,7 @@
         animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
         animators.add(animator);
 
-        if (mToggleTabStackButton.getVisibility() != GONE) {
+        if (mToggleTabStackButton != null) {
             animator = ObjectAnimator.ofFloat(mToggleTabStackButton, TRANSLATION_X, 0);
             animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
             animator.setStartDelay(URL_CLEAR_FOCUS_TABSTACK_DELAY_MS);
@@ -1577,8 +1597,9 @@
 
     @Override
     protected void updateTabCountVisuals(int numberOfTabs) {
+        if (mHomeButton != null) mHomeButton.setEnabled(true);
+
         if (mToggleTabStackButton == null) return;
-        mHomeButton.setEnabled(true);
 
         mToggleTabStackButton.setEnabled(numberOfTabs >= 1);
         mToggleTabStackButton.setContentDescription(
@@ -1626,7 +1647,7 @@
 
     @Override
     protected void onPrimaryColorChanged() {
-        if (!getToolbarDataProvider().isUsingBrandColor()) return;
+        if (!FeatureUtilities.isDocumentMode(getContext())) return;
 
         super.onPrimaryColorChanged();
         if (mBrandColorTransitionActive) mBrandColorTransitionAnimation.cancel();
@@ -1690,7 +1711,7 @@
             // Convert the previous NTP scroll percentage to URL focus percentage because that
             // will give a nicer transition animation from the expanded NTP omnibox to the
             // collapsed normal omnibox on other non-NTP pages.
-            if (previousNtpScrollPercent > 0f) {
+            if (!mInTabSwitcherMode && previousNtpScrollPercent > 0f) {
                 mUrlFocusChangePercent =
                         Math.max(previousNtpScrollPercent, mUrlFocusChangePercent);
                 triggerUrlFocusAnimation(false);
@@ -1830,8 +1851,10 @@
         getProgressBar().setProgressDrawable(
                 ApiCompatibilityUtils.getDrawable(getResources(), progressBarResource));
 
-        mToggleTabStackButton.setImageDrawable(mUseLightToolbarDrawables
-                ? mTabSwitcherButtonDrawableLight : mTabSwitcherButtonDrawable);
+        if (mToggleTabStackButton != null) {
+            mToggleTabStackButton.setImageDrawable(mUseLightToolbarDrawables
+                    ? mTabSwitcherButtonDrawableLight : mTabSwitcherButtonDrawable);
+        }
 
         ColorStateList dark = getResources().getColorStateList(R.color.dark_mode_tint);
         ColorStateList white = getResources().getColorStateList(R.color.light_mode_tint);
@@ -1856,7 +1879,8 @@
         CharSequence newTabContentDescription = getResources().getText(
                 isIncognito ? R.string.accessibility_toolbar_btn_new_incognito_tab :
                         R.string.accessibility_toolbar_btn_new_tab);
-        if (!newTabContentDescription.equals(mNewTabButton.getContentDescription())) {
+        if (mNewTabButton != null
+                && !newTabContentDescription.equals(mNewTabButton.getContentDescription())) {
             mNewTabButton.setContentDescription(newTabContentDescription);
         }
     }
diff --git a/chrome/android/javatests/AndroidManifest.xml b/chrome/android/javatests/AndroidManifest.xml
index 3b69261..300adda 100644
--- a/chrome/android/javatests/AndroidManifest.xml
+++ b/chrome/android/javatests/AndroidManifest.xml
@@ -27,6 +27,26 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="org.chromium.chrome.browser.customtabs.CustomTabExternalNavigationTest$DummyActivityForSpecialScheme"
+            android:exported="true" >
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:host="customtabtest" android:scheme="customtab" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="org.chromium.chrome.browser.customtabs.CustomTabExternalNavigationTest$DummyActivityForHttp"
+            android:exported="true" >
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:host="customtabtest.com" android:scheme="http" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="org.chromium.test.broker.OnDeviceInstrumentationBroker"
             android:exported="true"/>
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
index b544c3b5..adb34e92b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -6,8 +6,10 @@
 
 import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_TABLET;
 
-import android.test.FlakyTest;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Smoke;
+import android.text.TextUtils;
+import android.view.KeyEvent;
 
 import com.google.android.apps.chrome.R;
 
@@ -15,15 +17,21 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.base.test.util.UrlUtils;
+import org.chromium.chrome.browser.omnibox.LocationBarLayout;
+import org.chromium.chrome.browser.omnibox.UrlBar;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
 import org.chromium.chrome.test.util.ChromeTabUtils;
+import org.chromium.chrome.test.util.OmniboxTestUtils;
 import org.chromium.chrome.test.util.TestHttpServerClient;
+import org.chromium.chrome.test.util.browser.TabLoadObserver;
+import org.chromium.content.browser.test.util.CallbackHelper;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content.browser.test.util.JavaScriptUtils;
+import org.chromium.content.browser.test.util.KeyUtils;
 import org.chromium.content.browser.test.util.UiUtils;
 import org.chromium.net.test.util.TestWebServer;
 
@@ -33,6 +41,7 @@
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Navigate in UrlBar tests.
@@ -41,6 +50,80 @@
     private static final String HTTP_SCHEME = "http://";
     private static final String NEW_TAB_PAGE = "chrome-native://newtab/";
 
+    private void navigateAndObserve(final String startUrl, final String endUrl)
+            throws InterruptedException {
+        assertTrue(CriteriaHelper.pollForUIThreadCriteria(
+                new TabLoadObserver(getActivity().getActivityTab(), startUrl)));
+        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
+                assertNotNull("urlBar is null", urlBar);
+
+                return TextUtils.equals(expectedLocation(endUrl), urlBar.getText().toString())
+                        && TextUtils.equals(endUrl, getActivity().getActivityTab().getUrl());
+            }
+        }));
+    }
+
+    /**
+     * Types the passed text in the omnibox to trigger a navigation. You can pass a URL or a search
+     * term. This code triggers suggestions and prerendering; unless you are testing these
+     * features specifically, you should use loadUrl() which is less prone to flakyness.
+     * @param url The URL to navigate to.
+     * @return the URL in the omnibox.
+     * @throws InterruptedException
+     */
+    private String typeInOmniboxAndNavigate(final String url) throws InterruptedException {
+        final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
+        assertNotNull("urlBar is null", urlBar);
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                urlBar.requestFocus();
+                urlBar.setText(url);
+            }
+        });
+        final LocationBarLayout locationBar =
+                (LocationBarLayout) getActivity().findViewById(R.id.location_bar);
+        assertTrue("Omnibox Suggestions never shown.",
+                OmniboxTestUtils.waitForOmniboxSuggestions(locationBar));
+
+        Tab currentTab = getActivity().getActivityTab();
+        final CallbackHelper loadedCallback = new CallbackHelper();
+        final AtomicBoolean tabCrashReceived = new AtomicBoolean();
+        currentTab.addObserver(new EmptyTabObserver() {
+            @Override
+            public void onPageLoadFinished(Tab tab) {
+                loadedCallback.notifyCalled();
+                tab.removeObserver(this);
+            }
+
+            @Override
+            public void onCrash(Tab tab, boolean sadTabShown) {
+                tabCrashReceived.set(true);
+                tab.removeObserver(this);
+            }
+        });
+
+        // Loads the url.
+        KeyUtils.singleKeyEventView(getInstrumentation(), urlBar, KeyEvent.KEYCODE_ENTER);
+
+        boolean pageLoadReceived = true;
+        try {
+            loadedCallback.waitForCallback(0);
+        } catch (TimeoutException ex) {
+            pageLoadReceived = false;
+        }
+
+        assertTrue("Neither PAGE_LOAD_FINISHED nor a TAB_CRASHED event was received",
+                pageLoadReceived || tabCrashReceived.get());
+        getInstrumentation().waitForIdleSync();
+
+        // The URL has been set before the page notification was broadcast, so it is safe to access.
+        return urlBar.getText().toString();
+    }
+
     /**
      * @return the expected contents of the location bar after navigating to url.
      */
@@ -50,17 +133,15 @@
     }
 
     /**
-     * Verify Selection on the Location Bar
-     * Bug: crbug.com/413277
-     * @Smoke
-     * @MediumTest
-     * @Feature({"Navigation", "Main"})
+     * Verify Selection on the Location Bar.
      */
-    @FlakyTest
+    @Smoke
+    @MediumTest
+    @Feature({"Navigation", "Main"})
     public void testNavigate() throws InterruptedException {
         String url = TestHttpServerClient.getUrl("chrome/test/data/android/navigate/simple.html");
         String result = typeInOmniboxAndNavigate(url);
-        assertEquals(expectedLocation(url), result.trim());
+        assertEquals(expectedLocation(url), result);
     }
 
     @Restriction(RESTRICTION_TYPE_TABLET)
@@ -100,58 +181,57 @@
     @MediumTest
     @Feature({"Navigation"})
     public void testOpenAndNavigate() throws InterruptedException {
+        final String url =
+                TestHttpServerClient.getUrl("chrome/test/data/android/navigate/simple.html");
+        navigateAndObserve(url, url);
+
         final int tabCount = getActivity().getCurrentTabModel().getCount();
         ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
         UiUtils.settleDownUI(getInstrumentation());
 
         assertEquals("Wrong number of tabs",
                 tabCount + 1, getActivity().getCurrentTabModel().getCount());
-        String url = TestHttpServerClient.getUrl("chrome/test/data/android/navigate/simple.html");
         String result = typeInOmniboxAndNavigate(url);
         assertEquals(expectedLocation(url), result);
     }
 
     /**
      * Test Opening a link and verify that the desired page is loaded.
-     * Bug: crbug.com/171037
-     * @MediumTest
-     * @Feature({"Navigation"})
-    */
-    @FlakyTest
+     */
+    @MediumTest
+    @Feature({"Navigation"})
     public void testOpenLink() throws InterruptedException, TimeoutException {
-        String url = TestHttpServerClient.getUrl("chrome/test/data/android/google.html");
-        typeInOmniboxAndNavigate(url);
-        assertEquals(url, getActivity().getActivityTab().getUrl());
+        String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/google.html");
+        String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/about.html");
+
+        navigateAndObserve(url1, url1);
+        assertWaitForPageScaleFactorMatch(0.5f);
 
         Tab tab = getActivity().getActivityTab();
-        DOMUtils.clickNode(this, tab.getContentViewCore(), "aboutLink");
-        ChromeTabUtils.waitForTabPageLoaded(
-                tab, TestHttpServerClient.getUrl("chrome/test/data/android/about.html"));
 
-        String expectedUrl = TestHttpServerClient.getUrl("chrome/test/data/android/about.html");
-        assertEquals("Desired Link not open", expectedUrl,
-                getActivity().getActivityTab().getUrl());
+        DOMUtils.clickNode(this, tab.getContentViewCore(), "aboutLink");
+        ChromeTabUtils.waitForTabPageLoaded(tab, url2);
+        assertEquals("Desired Link not open", url2, getActivity().getActivityTab().getUrl());
     }
 
     /**
      * Test Opening a link and verify that TabObserver#onPageLoadStarted gives the old and new URL.
-     * Bug: crbug.com/171037
-     * @MediumTest
-     * @Feature({"Navigation"})
      */
-    @FlakyTest
+    @MediumTest
+    @Feature({"Navigation"})
     public void testTabObserverOnPageLoadStarted() throws InterruptedException, TimeoutException {
         final String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/google.html");
         final String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/about.html");
 
-        typeInOmniboxAndNavigate(url1);
-        assertEquals(url1, getActivity().getActivityTab().getUrl());
+        navigateAndObserve(url1, url1);
+        assertWaitForPageScaleFactorMatch(0.5f);
+
         TabObserver onPageLoadStartedObserver = new EmptyTabObserver() {
             @Override
-            public void onPageLoadStarted(Tab tab, String url) {
+            public void onPageLoadStarted(Tab tab, String newUrl) {
                 tab.removeObserver(this);
-                assertEquals(tab.getUrl(), url1);
-                assertEquals(url, url2);
+                assertEquals(url1, tab.getUrl());
+                assertEquals(url2, newUrl);
             }
         };
         Tab tab = getActivity().getActivityTab();
@@ -226,13 +306,10 @@
 
     /**
      * Test back and forward buttons.
-     *
-     * crbug.com/268463
-     * @Restriction(RESTRICTION_TYPE_TABLET)
-     * @MediumTest
-     * @Feature({"Navigation"})
      */
-    @FlakyTest
+    @Restriction(RESTRICTION_TYPE_TABLET)
+    @MediumTest
+    @Feature({"Navigation"})
     public void testNavigateBackAndForwardButtons() throws InterruptedException {
         final String[] urls = {
                 TestHttpServerClient.getUrl("chrome/test/data/android/navigate/one.html"),
@@ -241,7 +318,7 @@
         };
 
         for (String url : urls) {
-            typeInOmniboxAndNavigate(url);
+            navigateAndObserve(url, url);
         }
 
         final int repeats = 3;
@@ -272,18 +349,13 @@
         }
     }
 
-    /*
-     * Bug: crbug.com/413186
-     * @MediumTest
-     * @Feature({"Navigation"})
-     */
-    @FlakyTest
+    @MediumTest
+    @Feature({"Navigation"})
     public void testWindowOpenUrlSpoof() throws Exception {
         TestWebServer webServer = TestWebServer.start();
         try {
             // Make sure that we start with one tab.
             final TabModel model = getActivity().getTabModelSelector().getModel(false);
-            assertEquals("Invalid starting number of tabs", 1, model.getCount());
 
             final Semaphore urlServedSemaphore = new Semaphore(0);
             Runnable checkAction = new Runnable() {
@@ -301,14 +373,20 @@
             };
 
             // Mock out the test URL
-            final String mockedUrl = webServer.setResponseWithRunnableAction(
-                    "/mockme.html", "<html><body>Real</body></html>", null, checkAction);
+            final String mockedUrl = webServer.setResponseWithRunnableAction("/mockme.html",
+                    "<html>"
+                    + "  <head>"
+                    + "    <meta name=\"viewport\""
+                    + "        content=\"initial-scale=0.75,maximum-scale=0.75,user-scalable=no\">"
+                    + "  </head>"
+                    + "  <body>Real</body>"
+                    + "</html>", null, checkAction);
 
             // Navigate to the spoofable URL
             loadUrl(UrlUtils.encodeHtmlDataUri(
                       "<head>"
                     + "  <meta name=\"viewport\""
-                    + "      content=\"initial-scale=1,maximum-scale=1,user-scalable=no\">"
+                    + "      content=\"initial-scale=0.5,maximum-scale=0.5,user-scalable=no\">"
                     + "</head>"
                     + "<script>"
                     + "  function spoof() {"
@@ -318,24 +396,18 @@
                     + "    w.location = '" + mockedUrl + "'"
                     + "  }"
                     + "</script>"
-                    + "<a href='JavaScript:spoof()' id='link'>Go</a>"));
+                    + "<body id='body' onclick='spoof()'></body>"));
+            assertWaitForPageScaleFactorMatch(0.5f);
 
-            assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
-                @Override
-                public boolean isSatisfied() {
-                    return getActivity().getCurrentContentViewCore().getScale() == 1.f;
-                }
-            }));
-
-            // Click the 'Go' link
-            DOMUtils.clickNode(this, getActivity().getCurrentContentViewCore(), "link");
+            // Click the page, which triggers the URL load.
+            DOMUtils.clickNode(this, getActivity().getCurrentContentViewCore(), "body");
 
             // Wait for the proper URL to be served.
             assertTrue(urlServedSemaphore.tryAcquire(5, TimeUnit.SECONDS));
 
-            final Tab tab = TabModelUtils.getCurrentTab(model);
-
             // Wait for the url to change.
+            final Tab tab = TabModelUtils.getCurrentTab(model);
+            assertWaitForPageScaleFactorMatch(0.75f);
             assertTrue("Page url didn't change",
                     CriteriaHelper.pollForCriteria(new Criteria() {
                         @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index 00c577d7..946e5db 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -1092,7 +1092,7 @@
             @Override
             public void run() {
                 ContentViewCore view = getActivity().getActivityTab().getContentViewCore();
-                view.flingForTest(SystemClock.uptimeMillis(), 0, 0, 0, -2000);
+                view.fling(SystemClock.uptimeMillis(), 0, 0, 0, -2000);
             }
         });
         ChromeTabUtils.closeCurrentTab(getInstrumentation(), getActivity());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockResourcesForLayout.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockResourcesForLayout.java
index fe47318..f7aff80 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockResourcesForLayout.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockResourcesForLayout.java
@@ -71,6 +71,7 @@
         mBooleans.put(org.chromium.chrome.R.bool.compositor_tab_title_fake_bold_text, true);
         mStrings.put(R.string.tab_loading_default_title, "Loading...");
         mFloats.put(org.chromium.chrome.R.dimen.contextual_search_bar_height, 80.f);
+        mFloats.put(org.chromium.chrome.R.dimen.control_container_height, 56.0f);
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 77798c1..d90aeeae 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -4,30 +4,33 @@
 
 package org.chromium.chrome.browser.customtabs;
 
-import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.net.Uri;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Build;
 import android.os.Bundle;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.View;
+import android.widget.ImageButton;
 
 import com.google.android.apps.chrome.R;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.CompositorChromeActivity;
-import org.chromium.chrome.browser.DeferredStartupHandler;
 import org.chromium.chrome.browser.Tab;
-import org.chromium.chrome.browser.document.ChromeLauncherActivity;
+import org.chromium.chrome.browser.document.BrandColorUtils;
 import org.chromium.chrome.browser.document.DocumentActivity;
+import org.chromium.chrome.browser.toolbar.CustomTabToolbar;
 import org.chromium.chrome.browser.util.FeatureUtilities;
-import org.chromium.chrome.test.ChromeActivityTestCaseBase;
 import org.chromium.chrome.test.util.TestHttpServerClient;
 import org.chromium.chrome.test.util.browser.contextmenu.ContextMenuUtils;
 import org.chromium.content.browser.test.util.Criteria;
@@ -38,9 +41,9 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * Instrumentation tests for {@link CustomTabActivity}.
+ * Instrumentation tests for app menu, context menu, and toolbar of a {@link CustomTabActivity}.
  */
-public class CustomTabActivityTest extends ChromeActivityTestCaseBase<CustomTabActivity> {
+public class CustomTabActivityTest extends CustomTabActivityTestBase {
 
     /**
      * An empty {@link BroadcastReceiver} that exists only to make the PendingIntent to carry an
@@ -55,6 +58,8 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
+            // Note: even if this assertion fails, the test might still pass, because
+            // BroadcastReceiver is not treated as part of the instrumentation test.
             assertEquals(TEST_PAGE_COPY, intent.getDataString());
         }
     }
@@ -67,62 +72,17 @@
 
     private CustomTabActivity mActivity;
 
-    public CustomTabActivityTest() {
-        super(CustomTabActivity.class);
-    }
-
-    @Override
-    public void startMainActivity() throws InterruptedException {
-    }
-
     @Override
     protected void startActivityCompletely(Intent intent) {
-        Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonitor(
-                CustomTabActivity.class.getName(), null, false);
-        Activity activity = getInstrumentation().startActivitySync(intent);
-        assertNotNull("Main activity did not start", activity);
-        CustomTabActivity customTabActivity =
-                (CustomTabActivity) monitor.waitForActivityWithTimeout(
-                ACTIVITY_START_TIMEOUT_MS);
-        assertNotNull("CustomTabActivity did not start", customTabActivity);
-        setActivity(customTabActivity);
-        mActivity = customTabActivity;
-    }
-
-    private void startCustomTabActivityWithIntent(Intent intent) throws InterruptedException {
-        startActivityCompletely(intent);
-        assertTrue("Tab never selected/initialized.",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return getActivity().getActivityTab() != null;
-                    }
-                }));
-        Tab tab = getActivity().getActivityTab();
-
-        assertTrue("Deferred startup never completed",
-                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return DeferredStartupHandler.getInstance().isDeferredStartupComplete();
-                    }
-                }));
-
-        assertNotNull(tab);
-        assertNotNull(tab.getView());
+        super.startActivityCompletely(intent);
+        mActivity = getActivity();
     }
 
     /**
-     * Creates the simplest intent that is sufficient to let {@link ChromeLauncherActivity} launch
-     * the {@link CustomTabActivity}.
+     * @see CustomTabActivityTestBase#createMinimalCustomTabIntent(String)
      */
     private Intent createMinimalCustomTabIntent() {
-        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(TEST_PAGE));
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.setComponent(new ComponentName(getInstrumentation().getTargetContext(),
-                ChromeLauncherActivity.class));
-        intent.putExtra(CustomTabIntentDataProvider.EXTRA_CUSTOM_TABS_SESSION_ID, true);
-        return intent;
+        return createMinimalCustomTabIntent(TEST_PAGE);
     }
 
     /**
@@ -146,6 +106,29 @@
         return pi;
     }
 
+    private void addToolbarColorToIntent(Intent intent, int color) {
+        intent.putExtra(CustomTabIntentDataProvider.EXTRA_CUSTOM_TABS_TOOLBAR_COLOR, color);
+    }
+
+    /**
+     * Adds an action button to the custom tab toolbar.
+     * @return The {@link PendingIntent} that will be triggered when the action button is clicked.
+     */
+    private PendingIntent addActionButtonToIntent(Intent intent, Bitmap icon) {
+        Intent actionIntent = new Intent();
+        actionIntent.setClass(getInstrumentation().getContext(), DummyBroadcastReceiver.class);
+        actionIntent.setAction(TEST_ACTION);
+
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(CustomTabIntentDataProvider.KEY_CUSTOM_TABS_ICON, icon);
+        PendingIntent pi = PendingIntent.getBroadcast(getInstrumentation().getTargetContext(), 0,
+                actionIntent, 0);
+        bundle.putParcelable(CustomTabIntentDataProvider.KEY_CUSTOM_TABS_PENDING_INTENT, pi);
+
+        intent.putExtra(CustomTabIntentDataProvider.EXTRA_CUSTOM_TABS_ACTION_BUTTON_BUNDLE, bundle);
+        return pi;
+    }
+
     private void openAppMenuAndAssertMenuShown() throws InterruptedException {
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
@@ -162,6 +145,9 @@
         }));
     }
 
+    /**
+     * Test the entries in the context menu shown when long clicking an image.
+     */
     @SmallTest
     public void testContextMenuEntriesForImage() throws InterruptedException, TimeoutException {
         startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
@@ -175,6 +161,9 @@
         assertNotNull(menu.findItem(R.id.contextmenu_copy_image_url));
     }
 
+    /**
+     * Test the entries in the context menu shown when long clicking an link.
+     */
     @SmallTest
     public void testContextMenuEntriesForLink() throws InterruptedException, TimeoutException {
         startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
@@ -188,6 +177,9 @@
         assertNotNull(menu.findItem(R.id.contextmenu_save_link_as));
     }
 
+    /**
+     * Test the entries in the app menu.
+     */
     @SmallTest
     public void testCustomTabAppMenu() throws InterruptedException {
         Intent intent = createMinimalCustomTabIntent();
@@ -206,6 +198,10 @@
         assertNotNull(menu.findItem(R.id.open_in_chrome_id));
     }
 
+    /**
+     * Test whether the custom menu is correctly shown and clicking it sends the right
+     * {@link PendingIntent}.
+     */
     @SmallTest
     public void testCustomMenuEntry() throws InterruptedException {
         Intent intent = createMinimalCustomTabIntent();
@@ -213,7 +209,7 @@
         startCustomTabActivityWithIntent(intent);
 
         final OnFinishedForTest onFinished = new OnFinishedForTest(pi);
-        mActivity.getIntentDataProvider().setMenuSelectionOnFinishedForTesting(onFinished);
+        mActivity.getIntentDataProvider().setPendingIntentOnFinishedForTesting(onFinished);
 
         openAppMenuAndAssertMenuShown();
         ThreadUtils.runOnUiThread(new Runnable() {
@@ -234,6 +230,9 @@
         }));
     }
 
+    /**
+     * Test whether clicking "Open in Chrome" takes us to a chrome normal tab, loading the same url.
+     */
     @SmallTest
     public void testOpenInChrome() throws InterruptedException {
         startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
@@ -271,12 +270,113 @@
     }
 
     /**
+     * Test whether the color of the toolbar is correctly customized. For L or later releases,
+     * status bar color is also tested.
+     */
+    @SmallTest
+    public void testToolbarColor() throws InterruptedException {
+        Intent intent = createMinimalCustomTabIntent();
+        final int expectedColor = Color.RED;
+        addToolbarColorToIntent(intent, expectedColor);
+        startCustomTabActivityWithIntent(intent);
+
+        View toolbarView = getActivity().findViewById(R.id.toolbar);
+        assertTrue("A custom tab toolbar is never shown", toolbarView instanceof CustomTabToolbar);
+        CustomTabToolbar toolbar = (CustomTabToolbar) toolbarView;
+        assertEquals(expectedColor, toolbar.getBackground().getColor());
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
+            assertEquals(BrandColorUtils.computeStatusBarColor(expectedColor),
+                    getActivity().getWindow().getStatusBarColor());
+        }
+    }
+
+    /**
+     * Test if an action button is shown with correct image and size, and clicking it sends the
+     * correct {@link PendingIntent}.
+     */
+    @SmallTest
+    public void testActionButton() throws InterruptedException {
+        final int iconHeightDp = 48;
+        final int iconWidthDp = 96;
+        Resources testRes = getInstrumentation().getTargetContext().getResources();
+        float density = testRes.getDisplayMetrics().density;
+        Bitmap expectedIcon = Bitmap.createBitmap((int) (iconWidthDp * density),
+                (int) (iconHeightDp * density), Bitmap.Config.ARGB_8888);
+
+        Intent intent = createMinimalCustomTabIntent();
+        final PendingIntent pi = addActionButtonToIntent(intent, expectedIcon);
+        startCustomTabActivityWithIntent(intent);
+
+        final OnFinishedForTest onFinished = new OnFinishedForTest(pi);
+        mActivity.getIntentDataProvider().setPendingIntentOnFinishedForTesting(onFinished);
+
+        View toolbarView = getActivity().findViewById(R.id.toolbar);
+        assertTrue("A custom tab toolbar is never shown", toolbarView instanceof CustomTabToolbar);
+        CustomTabToolbar toolbar = (CustomTabToolbar) toolbarView;
+        final ImageButton actionButton = toolbar.getCustomActionButtonForTest();
+
+        assertNotNull(actionButton);
+        assertNotNull(actionButton.getDrawable());
+        assertTrue("Action button's background is not a BitmapDrawable.",
+                actionButton.getDrawable() instanceof BitmapDrawable);
+
+        assertTrue("Action button does not have the correct bitmap.",
+                expectedIcon.sameAs(((BitmapDrawable) actionButton.getDrawable()).getBitmap()));
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                actionButton.performClick();
+            }
+        });
+
+        assertTrue("Pending Intent was not sent.", CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return onFinished.isSent();
+            }
+        }));
+    }
+
+    /**
+     * Test the case that the action button should not be shown, given a bitmap with unacceptable
+     * height/width ratio.
+     */
+    @SmallTest
+    public void testActionButtonBadRatio() throws InterruptedException {
+        final int iconHeightDp = 20;
+        final int iconWidthDp = 60;
+        Resources testRes = getInstrumentation().getTargetContext().getResources();
+        float density = testRes.getDisplayMetrics().density;
+        Bitmap expectedIcon = Bitmap.createBitmap((int) (iconWidthDp * density),
+                (int) (iconHeightDp * density), Bitmap.Config.ARGB_8888);
+
+        Intent intent = createMinimalCustomTabIntent();
+        addActionButtonToIntent(intent, expectedIcon);
+        startCustomTabActivityWithIntent(intent);
+
+        View toolbarView = getActivity().findViewById(R.id.toolbar);
+        assertTrue("A custom tab toolbar is never shown", toolbarView instanceof CustomTabToolbar);
+        CustomTabToolbar toolbar = (CustomTabToolbar) toolbarView;
+        final ImageButton actionButton = toolbar.getCustomActionButtonForTest();
+
+        assertNotNull(actionButton);
+        assertTrue("Action button should not be shown",
+                View.VISIBLE != actionButton.getVisibility());
+
+        CustomTabIntentDataProvider dataProvider = mActivity.getIntentDataProvider();
+        assertNull(dataProvider.getActionButtonIcon());
+        assertNull(dataProvider.getActionButtonPendingIntentForTest());
+    }
+
+    /**
      * A helper class to monitor sending status of a {@link PendingIntent}.
      */
     private static class OnFinishedForTest implements PendingIntent.OnFinished {
 
         private PendingIntent mPi;
         private AtomicBoolean mIsSent = new AtomicBoolean();
+        private String mUri;
 
         /**
          * Create an instance of {@link OnFinishedForTest}, testing the given {@link PendingIntent}.
@@ -286,16 +386,20 @@
         }
 
         /**
-         * @return Whether {@link PendingIntent#send()} has been successfully triggered.
+         * @return Whether {@link PendingIntent#send()} has been successfully triggered and the sent
+         *         intent carries the correct Uri as data.
          */
         public boolean isSent() {
-            return mIsSent.get();
+            return mIsSent.get() && TEST_PAGE.equals(mUri);
         }
 
         @Override
         public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
                 String resultData, Bundle resultExtras) {
-            if (pendingIntent.equals(mPi)) mIsSent.set(true);
+            if (pendingIntent.equals(mPi)) {
+                mUri = intent.getDataString();
+                mIsSent.set(true);
+            }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestBase.java
new file mode 100644
index 0000000..70dd5c98
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestBase.java
@@ -0,0 +1,86 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.customtabs;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.net.Uri;
+
+import org.chromium.chrome.browser.DeferredStartupHandler;
+import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.document.ChromeLauncherActivity;
+import org.chromium.chrome.test.ChromeActivityTestCaseBase;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+
+/**
+ * Base class for all instrumentation tests that require a {@link CustomTabActivity}.
+ */
+public abstract class CustomTabActivityTestBase extends
+        ChromeActivityTestCaseBase<CustomTabActivity> {
+
+    public CustomTabActivityTestBase() {
+        super(CustomTabActivity.class);
+    }
+
+    @Override
+    public void startMainActivity() throws InterruptedException {
+    }
+
+    @Override
+    protected void startActivityCompletely(Intent intent) {
+        Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonitor(
+                CustomTabActivity.class.getName(), null, false);
+        Activity activity = getInstrumentation().startActivitySync(intent);
+        assertNotNull("Main activity did not start", activity);
+        CustomTabActivity customTabActivity =
+                (CustomTabActivity) monitor.waitForActivityWithTimeout(
+                ACTIVITY_START_TIMEOUT_MS);
+        assertNotNull("CustomTabActivity did not start", customTabActivity);
+        setActivity(customTabActivity);
+    }
+
+    /**
+     * Start a {@link CustomTabActivity} with given {@link Intent}, and wait till a tab is
+     * initialized.
+     */
+    protected void startCustomTabActivityWithIntent(Intent intent) throws InterruptedException {
+        startActivityCompletely(intent);
+        assertTrue("Tab never selected/initialized.",
+                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+                    @Override
+                    public boolean isSatisfied() {
+                        return getActivity().getActivityTab() != null;
+                    }
+                }));
+        Tab tab = getActivity().getActivityTab();
+
+        assertTrue("Deferred startup never completed",
+                CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+                    @Override
+                    public boolean isSatisfied() {
+                        return DeferredStartupHandler.getInstance().isDeferredStartupComplete();
+                    }
+                }));
+
+        assertNotNull(tab);
+        assertNotNull(tab.getView());
+    }
+
+    /**
+     * Creates the simplest intent that is sufficient to let {@link ChromeLauncherActivity} launch
+     * the {@link CustomTabActivity}.
+     */
+    protected Intent createMinimalCustomTabIntent(String url) {
+        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setComponent(new ComponentName(getInstrumentation().getTargetContext(),
+                ChromeLauncherActivity.class));
+        intent.putExtra(CustomTabIntentDataProvider.EXTRA_CUSTOM_TABS_SESSION_ID, -1);
+        return intent;
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java
new file mode 100644
index 0000000..2469057
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java
@@ -0,0 +1,89 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.customtabs;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.customtabs.CustomTab.CustomTabNavigationDelegate;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler.OverrideUrlLoadingResult;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationParams;
+
+/**
+ * Instrumentation test for external navigation handling in a {@link CustomTab}.
+ */
+public class CustomTabExternalNavigationTest extends CustomTabActivityTestBase {
+
+    /**
+     * A dummy activity that claims to handle "customtab://customtabtest".
+     */
+    public static class DummyActivityForSpecialScheme extends Activity {
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            finish();
+        }
+    }
+
+    /**
+     * A dummy activity that claims to handle "http://customtabtest.com".
+     */
+    public static class DummyActivityForHttp extends Activity {
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            finish();
+        }
+    }
+
+    private static final String TEST_URL = "about:blank";
+    private ExternalNavigationHandler mUrlHandler;
+    private CustomTabNavigationDelegate mNavigationDelegate;
+
+    @Override
+    public void startMainActivity() throws InterruptedException {
+        super.startMainActivity();
+        startCustomTabActivityWithIntent(createMinimalCustomTabIntent(TEST_URL));
+        Tab tab = getActivity().getActivityTab();
+        assertTrue("A custom tab is not present in the activity.", tab instanceof CustomTab);
+        CustomTab customTab = (CustomTab) tab;
+        mUrlHandler = customTab.getExternalNavigationHandler();
+        mNavigationDelegate = customTab.getExternalNavigationDelegate();
+    }
+
+    /**
+     * For urls with special schemes and hosts, and there is exactly one activity having a matching
+     * intent filter, the framework will make that activity the default handler of the special url.
+     * This test tests whether chrome is able to start the default external handler.
+     */
+    @SmallTest
+    public void testExternalActivityStartedForDefaultUrl() {
+        final String testUrl = "customtab://customtabtest/intent";
+        ExternalNavigationParams params = new ExternalNavigationParams.Builder(testUrl, false)
+                .build();
+        OverrideUrlLoadingResult result = mUrlHandler.shouldOverrideUrlLoading(params);
+        assertEquals(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT, result);
+        assertTrue("A dummy activity should have been started to handle the special url.",
+                mNavigationDelegate.hasExternalActivityStarted());
+    }
+
+    /**
+     * When loading a normal http url that chrome is able to handle, an intent picker should never
+     * be shown, even if other activities such as {@link DummyActivityForHttp} claim to handle it.
+     */
+    @SmallTest
+    public void testIntentPickerNotShownForNormalUrl() {
+        final String testUrl = "http://customtabtest.com";
+        ExternalNavigationParams params = new ExternalNavigationParams.Builder(testUrl, false)
+                .build();
+        OverrideUrlLoadingResult result = mUrlHandler.shouldOverrideUrlLoading(params);
+        assertEquals(OverrideUrlLoadingResult.NO_OVERRIDE, result);
+        assertFalse("External activities should not be started to handle the url",
+                mNavigationDelegate.hasExternalActivityStarted());
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java
new file mode 100644
index 0000000..bb5be6db
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java
@@ -0,0 +1,138 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.customtabs;
+
+import android.app.Application;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Process;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/** Tests for CustomTabsConnection. */
+public class CustomTabsConnectionTest extends InstrumentationTestCase {
+    private CustomTabsConnection mCustomTabsConnection;
+    private static final String URL = "http://www.google.com";
+    private static final String INVALID_SCHEME_URL = "intent://www.google.com";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Context context = getInstrumentation().getTargetContext().getApplicationContext();
+        mCustomTabsConnection = CustomTabsConnection.getInstance((Application) context);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mCustomTabsConnection.cleanup(Process.myUid());
+    }
+
+    /**
+     * Tests that we can register the callback. Registering null returns an
+     * error code, and multiple registrations are not allowed.
+     */
+    @SmallTest
+    public void testFinishSetup() {
+        assertTrue("It should not be possible to set a null callback.",
+                mCustomTabsConnection.finishSetup(null) != 0);
+        ICustomTabsConnectionCallback cb = new ICustomTabsConnectionCallback.Stub() {
+            @Override
+            public void onUserNavigationStarted(long sessionId, String url, Bundle extras) {}
+            @Override
+            public void onUserNavigationFinished(long sessionId, String url, Bundle extras) {}
+            @Override
+            public IBinder asBinder() {
+                return this;
+            }
+        };
+        assertEquals(0, mCustomTabsConnection.finishSetup(cb));
+        assertTrue("It should not be possible to set the callback twice.",
+                mCustomTabsConnection.finishSetup(cb) != 0);
+    }
+
+    /**
+     * Tests that {@link CustomTabsConnection#warmup(long)} succeeds and can
+     * be issued multiple times.
+     */
+    @SmallTest
+    public void testCanWarmup() {
+        assertEquals(0, mCustomTabsConnection.warmup(0));
+        // Can call it several times.
+        assertEquals(0, mCustomTabsConnection.warmup(0));
+    }
+
+    /**
+     * Tests that the session ID is positive, multiple sessions can be created,
+     * and {@link CustomTabsConnection#newSession()} doesn't always return
+     * the same session ID.
+     */
+    @SmallTest
+    public void testNewSession() {
+        long sessionId = mCustomTabsConnection.newSession();
+        assertTrue("Session IDs should be strictly positive.", sessionId > 0);
+        assertTrue("Session IDs should be unique.",
+                mCustomTabsConnection.newSession() != sessionId);
+    }
+
+    /**
+     * Calls warmup() and mayLaunchUrl(), checks for the expected result
+     * (success or failure) and returns the result code.
+     */
+    private long assertWarmupAndMayLaunchUrl(long id, String url, boolean shouldSucceed) {
+        mCustomTabsConnection.warmup(0);
+        long sessionId = id == 0 ? mCustomTabsConnection.newSession() : id;
+        mCustomTabsConnection.mayLaunchUrl(sessionId, url, null, null);
+        long result = mCustomTabsConnection.mayLaunchUrl(sessionId, url, null, null);
+        if (shouldSucceed) {
+            assertEquals(sessionId, result);
+        } else {
+            assertTrue("The result should be negative to signal failure.", result < 0);
+        }
+        return result;
+    }
+
+    /**
+     * Tests that
+     * {@link CustomTabsConnection#mayLaunchUrl(long, String, Bundle, List<Bundle>)}
+     * returns an error when called with an invalid session ID.
+     */
+    @SmallTest
+    public void testNoMayLaunchUrlWithInvalidSessionId() {
+        assertWarmupAndMayLaunchUrl(42, URL, false);
+        assertWarmupAndMayLaunchUrl(-1, URL, false);
+    }
+
+    /**
+     * Tests that
+     * {@link CustomTabsConnection#mayLaunchUrl(long, String, Bundle, List<Bundle>)}
+     * rejects invalid URL schemes.
+     */
+    @SmallTest
+    public void testNoMayLaunchUrlWithInvalidScheme() {
+        assertWarmupAndMayLaunchUrl(0, INVALID_SCHEME_URL, false);
+    }
+
+    /**
+     * Tests that
+     * {@link CustomTabsConnection#mayLaunchUrl(long, String, Bundle, List<Bundle>)}
+     * succeeds.
+     */
+    @SmallTest
+    public void testMayLaunchUrl() {
+        assertWarmupAndMayLaunchUrl(0, URL, true);
+    }
+
+    /**
+     * Tests that session IDs are forgotten properly.
+     */
+    @SmallTest
+    public void testForgetsSessionId() {
+        long sessionId = assertWarmupAndMayLaunchUrl(0, URL, true);
+        mCustomTabsConnection.cleanup(Process.myUid());
+        assertWarmupAndMayLaunchUrl(sessionId, URL, false);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
index 2c9741f..68d523b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
@@ -51,6 +51,7 @@
 import org.chromium.content.browser.test.util.CallbackHelper;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content.browser.test.util.TouchCommon;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.base.PageTransition;
@@ -69,6 +70,7 @@
 @MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP)
 @DisableInTabbedMode
 public class DocumentModeTest extends MultiActivityTestBase {
+    private static final float FLOAT_EPSILON = 0.001f;
 
     private static final int ACTIVITY_START_TIMEOUT = 1000;
     private static final String URL_1 = "data:text/html;charset=utf-8,Page%201";
@@ -76,11 +78,48 @@
     private static final String URL_3 = "data:text/html;charset=utf-8,Page%203";
     private static final String URL_4 = "data:text/html;charset=utf-8,Page%204";
 
-    private static final String HTML_LINK = "<html><head><meta "
-            + "name='viewport' content='width=device-width initial-scale=0.5, maximum-scale=0.5'>"
-            + "<style>body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}"
-            + "</style></head><body><a href='data:text/html;charset=utf-8,white' target='_blank'>"
-            + "<div></div></a></body></html>";
+    private static final String LANDING_PAGE = UrlUtils.encodeHtmlDataUri(
+            "<html>"
+            + "  <head>"
+            + "    <meta name='viewport' content='width=device-width "
+            + "        initial-scale=1.0, maximum-scale=1.0'>"
+            + "    <style>"
+            + "        body {margin: 0em;} div {width: 100%; height: 100%; background: #ff00ff;}"
+            + "    </style>"
+            + "  </head>"
+            + "  <body>Second page</body>"
+            + "</html>");
+    private static final float LANDING_PAGE_SCALE = 1.0f;
+
+    // Defines one gigantic link spanning the whole page that creates a new window.
+    private static final String HREF_LINK = UrlUtils.encodeHtmlDataUri(
+            "<html>"
+            + "  <head>"
+            + "    <meta name='viewport'"
+            + "        content='width=device-width initial-scale=0.5, maximum-scale=0.5'>"
+            + "    <style>"
+            + "      body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}"
+            + "    </style>"
+            + "  </head>"
+            + "  <body>"
+            + "    <a href='" + LANDING_PAGE + "' target='_blank'><div></div></a>"
+            + "  </body>"
+            + "</html>");
+
+    // Clicking the body triggers a window.open() call.
+    private static final String ONCLICK_LINK = UrlUtils.encodeHtmlDataUri(
+            "<html>"
+            + "  <head>"
+            + "    <meta name='viewport'"
+            + "        content='width=device-width initial-scale=0.5, maximum-scale=0.5'>"
+            + "    <style>"
+            + "      body {margin: 0em;} div {width: 100%; height: 100%; background: #011684;}"
+            + "    </style>"
+            + "  </head>"
+            + "  <body id='body'>"
+            + "    <div onclick='window.open(\"" + LANDING_PAGE + "\")'></div></a>"
+            + "  </body>"
+            + "</html>");
     private static final float HTML_SCALE = 0.5f;
 
     private boolean mInitializationCompleted;
@@ -764,7 +803,7 @@
      */
     @MediumTest
     public void testIncognitoOpensInForegroundViaLinkContextMenu() throws Exception {
-        launchLinkDocument();
+        launchTestPageDocument(HREF_LINK);
 
         // Save the current tab info.
         final DocumentActivity regularActivity =
@@ -818,11 +857,60 @@
     }
 
     /**
+     * Tests that tabs opened via window.open() load properly.
+     */
+    @MediumTest
+    public void testWindowOpen() throws Exception {
+        launchTestPageDocument(ONCLICK_LINK);
+
+        final DocumentActivity firstActivity =
+                (DocumentActivity) ApplicationStatus.getLastTrackedFocusedActivity();
+
+        // Save the current tab ID.
+        final DocumentTabModelSelector selector =
+                ChromeMobileApplication.getDocumentTabModelSelector();
+        final TabModel tabModel = selector.getModel(false);
+        final int firstTabId = selector.getCurrentTabId();
+        final int firstTabIndex = tabModel.index();
+
+        // Do a plain click to make the link open in a new foreground Document via a window.open().
+        Runnable fgTrigger = new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    DOMUtils.clickNode(null, firstActivity.getCurrentContentViewCore(), "body");
+                } catch (Exception e) {
+
+                }
+            }
+        };
+
+        // The WebContents gets paused because of the window.open.  Checking that the page scale
+        // factor is set correctly both checks that the page loaded and that the WebContents was
+        // when the new Activity starts.
+        ChromeActivity secondActivity = (ChromeActivity) ActivityUtils.waitForActivity(
+                getInstrumentation(), DocumentActivity.class, fgTrigger);
+        assertWaitForPageScaleFactorMatch(secondActivity, LANDING_PAGE_SCALE);
+
+        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                if (2 != tabModel.getCount()) return false;
+                if (firstTabIndex == tabModel.index()) return false;
+                if (firstTabId == selector.getCurrentTabId()) return false;
+                return true;
+            }
+        }));
+        MoreAsserts.assertNotEqual(
+                firstActivity, ApplicationStatus.getLastTrackedFocusedActivity());
+    }
+
+    /**
      * Tests that tab ID is properly set when tabs change.
      */
     @MediumTest
     public void testLastTabIdUpdates() throws Exception {
-        launchLinkDocument();
+        launchTestPageDocument(HREF_LINK);
 
         final DocumentActivity firstActivity =
                 (DocumentActivity) ApplicationStatus.getLastTrackedFocusedActivity();
@@ -866,7 +954,7 @@
     @Restriction(RESTRICTION_TYPE_LOW_END_DEVICE)
     @MediumTest
     public void testNewTabLoadLowEnd() throws Exception {
-        launchLinkDocument();
+        launchTestPageDocument(HREF_LINK);
 
         final CallbackHelper tabCreatedCallback = new CallbackHelper();
         final CallbackHelper tabLoadStartedCallback = new CallbackHelper();
@@ -908,7 +996,7 @@
     @Restriction(RESTRICTION_TYPE_LOW_END_DEVICE)
     @MediumTest
     public void testNewTabRenderersLowEnd() throws Exception {
-        launchLinkDocument();
+        launchTestPageDocument(HREF_LINK);
 
         // Ignore any side effects that the first background tab might produce.
         openLinkInBackgroundTab();
@@ -1010,19 +1098,25 @@
     }
 
     /**
-     * Launches DocumentActivity with the special URL suitable for openLinkInBackgroundTab()
-     * invocations.
+     * Launches DocumentActivity with a page that can be used to create a second page.
      */
-    private void launchLinkDocument() throws Exception {
-        // Load HTML that defines one gigantic link spanning the whole page.
-        launchViaLaunchDocumentInstance(false, UrlUtils.encodeHtmlDataUri(HTML_LINK));
+    private void launchTestPageDocument(String link) throws Exception {
+        launchViaLaunchDocumentInstance(false, link);
         final DocumentActivity activity =
                 (DocumentActivity) ApplicationStatus.getLastTrackedFocusedActivity();
+        assertWaitForPageScaleFactorMatch(activity, HTML_SCALE);
+    }
+
+    // TODO(dfalcantara): Combine this one and ChromeActivityTestCaseBase's.
+    private void assertWaitForPageScaleFactorMatch(
+            final ChromeActivity activity, final float expectedScale) throws Exception {
         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                return Float.compare(
-                        activity.getCurrentContentViewCore().getScale(), HTML_SCALE) == 0;
+                if (activity.getCurrentContentViewCore() == null) return false;
+
+                return Math.abs(activity.getCurrentContentViewCore().getScale() - expectedScale)
+                        < FLOAT_EPSILON;
             }
         }));
     }
@@ -1082,7 +1176,7 @@
         activity.getActivityTab().removeObserver(observer);
 
         // Select the "open in new tab" option to open a tab in the background.
-        ActivityUtils.waitForActivity(getInstrumentation(),
+        ChromeActivity newActivity = ActivityUtils.waitForActivity(getInstrumentation(),
                 incognito ? IncognitoDocumentActivity.class : DocumentActivity.class,
                 new Runnable() {
                     @Override
@@ -1097,6 +1191,7 @@
                     }
                 }
         );
+        assertWaitForPageScaleFactorMatch(newActivity, LANDING_PAGE_SCALE);
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java
new file mode 100644
index 0000000..d707bdd
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java
@@ -0,0 +1,143 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.invalidation;
+
+import android.accounts.Account;
+import android.app.Application;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.CommandLine;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.test.ChromeActivityTestCaseBase;
+import org.chromium.components.invalidation.PendingInvalidation;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.sync.AndroidSyncSettings;
+import org.chromium.sync.signin.AccountManagerHelper;
+
+/**
+ * Tests for ChromeBrowserSyncAdapter.
+ *
+ * TODO(nyquist) Remove this class when Chrome sync starts up the same way as the testshell.
+ */
+public class ChromeBrowserSyncAdapterTest extends ChromeActivityTestCaseBase<ChromeActivity> {
+    private static final Account TEST_ACCOUNT =
+            AccountManagerHelper.createAccountFromName("test@gmail.com");
+    private static final long WAIT_FOR_LAUNCHER_MS = 10 * 1000;
+    private static final long POLL_INTERVAL_MS = 100;
+
+    private TestChromeSyncAdapter mSyncAdapter;
+
+    public ChromeBrowserSyncAdapterTest() {
+        super(ChromeActivity.class);
+    }
+
+    private static void sendChromeToBackground(Context context) throws InterruptedException {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        context.startActivity(intent);
+
+        assertTrue("Activity should have been sent to background",
+                CriteriaHelper.pollForCriteria(new Criteria() {
+                    @Override
+                    public boolean isSatisfied() {
+                        return !ApplicationStatus.hasVisibleActivities();
+                    }
+                }, WAIT_FOR_LAUNCHER_MS, POLL_INTERVAL_MS));
+    }
+
+    private void performSyncWithBundle(Bundle bundle) {
+        mSyncAdapter.onPerformSync(TEST_ACCOUNT, bundle,
+                AndroidSyncSettings.getContractAuthority(getActivity()), null, new SyncResult());
+    }
+
+    private static class TestChromeSyncAdapter extends ChromiumSyncAdapter {
+        private boolean mInvalidationRequested;
+        private boolean mInvalidationRequestedForAllTypes;
+        private int mObjectSource;
+        private String mObjectId;
+        private long mVersion;
+        private String mPayload;
+
+        public TestChromeSyncAdapter(Context context, Application application) {
+            super(context, application);
+        }
+
+        @Override
+        protected boolean useAsyncStartup() {
+            return false;
+        }
+
+        @Override
+        public void notifyInvalidation(
+                int objectSource, String objectId, long version, String payload) {
+            mObjectSource = objectSource;
+            mObjectId = objectId;
+            mVersion = version;
+            mPayload = payload;
+            if (objectSource == 0) {
+                mInvalidationRequestedForAllTypes = true;
+            } else {
+                mInvalidationRequested = true;
+            }
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mSyncAdapter = new TestChromeSyncAdapter(
+                getInstrumentation().getTargetContext(), getActivity().getApplication());
+    }
+
+    @Override
+    public void startMainActivity() throws InterruptedException {
+        startMainActivityOnBlankPage();
+    }
+
+    @MediumTest
+    @Feature({"Sync", "Invalidation"})
+    public void testRequestInvalidationForAllTypes() {
+        performSyncWithBundle(new Bundle());
+        assertTrue(mSyncAdapter.mInvalidationRequestedForAllTypes);
+        assertFalse(mSyncAdapter.mInvalidationRequested);
+        assertTrue(CommandLine.isInitialized());
+    }
+
+    @MediumTest
+    @Feature({"Sync", "Invalidation"})
+    public void testRequestSpecificInvalidation() {
+        String objectId = "objectid_value";
+        int objectSource = 65;
+        long version = 42L;
+        String payload = "payload_value";
+
+        performSyncWithBundle(
+                PendingInvalidation.createBundle(objectId, objectSource, version, payload));
+
+        assertFalse(mSyncAdapter.mInvalidationRequestedForAllTypes);
+        assertTrue(mSyncAdapter.mInvalidationRequested);
+        assertEquals(objectSource, mSyncAdapter.mObjectSource);
+        assertEquals(objectId, mSyncAdapter.mObjectId);
+        assertEquals(version, mSyncAdapter.mVersion);
+        assertEquals(payload, mSyncAdapter.mPayload);
+        assertTrue(CommandLine.isInitialized());
+    }
+
+    @MediumTest
+    @Feature({"Sync", "Invalidation"})
+    public void testInvalidationsHeldWhenChromeInBackground() throws InterruptedException {
+        sendChromeToBackground(getActivity());
+        performSyncWithBundle(new Bundle());
+        assertFalse(mSyncAdapter.mInvalidationRequestedForAllTypes);
+        assertFalse(mSyncAdapter.mInvalidationRequested);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
index e9a4133..a8f2312 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
@@ -264,6 +264,43 @@
 
     @SmallTest
     @Feature({"Omnibox"})
+    public void testSelectionChangesIgnoredInBatchMode() throws InterruptedException {
+        startMainActivityOnBlankPage();
+        stubLocationBarAutocomplete();
+        final UrlBar urlBar = getUrlBar();
+        OmniboxTestUtils.toggleUrlBarFocus(urlBar, true);
+
+        setTextAndVerifyNoAutocomplete(urlBar, "test");
+        setAutocomplete(urlBar, "test", "ing is fun");
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                urlBar.beginBatchEdit();
+            }
+        });
+        // Ensure the autocomplete is not modified if in batch mode.
+        AutocompleteState state = setSelection(urlBar, 1, 1);
+        assertTrue(state.hasAutocomplete);
+        assertEquals("test", state.textWithoutAutocomplete);
+        assertEquals("testing is fun", state.textWithAutocomplete);
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                urlBar.endBatchEdit();
+            }
+        });
+
+        // Ensure that after batch mode has ended that the autocomplete is cleared due to the
+        // invalid selection range.
+        state = getAutocompleteState(urlBar, null);
+        assertFalse(state.hasAutocomplete);
+        assertEquals("test", state.textWithoutAutocomplete);
+        assertEquals("test", state.textWithAutocomplete);
+    }
+
+    @SmallTest
+    @Feature({"Omnibox"})
     public void testAutocompleteUpdatedOnDefocus() throws InterruptedException {
         startMainActivityOnBlankPage();
         stubLocationBarAutocomplete();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
index 1bcbd91..311227f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
@@ -9,7 +9,7 @@
 import android.preference.PreferenceManager;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
-import android.widget.CheckBox;
+import android.widget.Button;
 import android.widget.Checkable;
 import android.widget.EditText;
 
@@ -21,6 +21,7 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.preferences.HomepageEditor;
 import org.chromium.chrome.browser.preferences.HomepagePreferences;
 import org.chromium.chrome.browser.preferences.Preferences;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
@@ -108,7 +109,7 @@
         Preferences homepagePreferenceActivity =
                 startPreferences(HomepagePreferences.class.getName());
         ChromeSwitchCompat homepageSwitch =
-                (ChromeSwitchCompat) homepagePreferenceActivity.findViewById(R.id.homepage_switch);
+                (ChromeSwitchCompat) homepagePreferenceActivity.findViewById(R.id.switch_widget);
         assertNotNull(homepageSwitch);
         TouchCommon.singleClickView(homepageSwitch);
         waitForCheckedState(homepageSwitch, false);
@@ -127,7 +128,7 @@
         // Enable homepage.
         homepagePreferenceActivity = startPreferences(HomepagePreferences.class.getName());
         homepageSwitch =
-                (ChromeSwitchCompat) homepagePreferenceActivity.findViewById(R.id.homepage_switch);
+                (ChromeSwitchCompat) homepagePreferenceActivity.findViewById(R.id.switch_widget);
         assertNotNull(homepageSwitch);
         TouchCommon.singleClickView(homepageSwitch);
         waitForCheckedState(homepageSwitch, true);
@@ -156,29 +157,32 @@
 
     /**
      * Custom homepage URI should be fixed (e.g., "chrome.com" -> "http://chrome.com/")
-     * on exiting Homepage settings page.
+     * when the URI is saved from the home page edit screen.
      */
     @MediumTest
     @Feature({"Homepage"})
     public void testPreferenceCustomUriFixup() throws InterruptedException {
-        // Change homepage custom URI on homepage settings.
-        final Preferences homepagePreferenceActivity =
-                startPreferences(HomepagePreferences.class.getName());
-        CheckBox checkBox =
-                (CheckBox) homepagePreferenceActivity.findViewById(R.id.default_checkbox);
-        assertTrue(checkBox.isChecked());
-        TouchCommon.singleClickView(checkBox);
-        TouchCommon.singleClickView(homepagePreferenceActivity.findViewById(R.id.custom_uri));
+        // Change home page custom URI on hompage edit screen.
+        final Preferences editHomepagePreferenceActivity =
+                startPreferences(HomepageEditor.class.getName());
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                ((EditText) homepagePreferenceActivity.findViewById(R.id.custom_uri))
+                ((EditText) editHomepagePreferenceActivity.findViewById(R.id.homepage_url_edit))
                         .setText("chrome.com");
             }
         });
-        homepagePreferenceActivity.finish();
+        Button saveButton =
+                (Button) editHomepagePreferenceActivity.findViewById(R.id.homepage_save);
+        TouchCommon.singleClickView(saveButton);
 
-        UiUtils.settleDownUI(getInstrumentation());
+        CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return editHomepagePreferenceActivity.isDestroyed();
+            }
+        });
+
         assertEquals("http://chrome.com/", HomepageManager.getHomepageUri(getActivity()));
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ChromeBrowserSyncAdapterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ChromeBrowserSyncAdapterTest.java
deleted file mode 100644
index c56a6bc..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ChromeBrowserSyncAdapterTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.sync;
-
-import android.accounts.Account;
-import android.app.Application;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SyncResult;
-import android.os.Bundle;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.CommandLine;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.test.ChromeActivityTestCaseBase;
-import org.chromium.content.browser.test.util.Criteria;
-import org.chromium.content.browser.test.util.CriteriaHelper;
-import org.chromium.sync.AndroidSyncSettings;
-import org.chromium.sync.signin.AccountManagerHelper;
-
-/**
- * Tests for ChromeBrowserSyncAdapter.
- *
- * TODO(nyquist) Remove this class when Chrome sync starts up the same way as the testshell.
- */
-public class ChromeBrowserSyncAdapterTest extends ChromeActivityTestCaseBase<ChromeActivity> {
-
-    private static final Account TEST_ACCOUNT =
-            AccountManagerHelper.createAccountFromName("test@gmail.com");
-    private static final long WAIT_FOR_LAUNCHER_MS = 10 * 1000;
-    private static final long POLL_INTERVAL_MS = 100;
-
-    private TestChromeSyncAdapter mSyncAdapter;
-
-    public ChromeBrowserSyncAdapterTest() {
-        super(ChromeActivity.class);
-    }
-
-    private static void sendChromeToBackground(Context context) throws InterruptedException {
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.addCategory(Intent.CATEGORY_HOME);
-        context.startActivity(intent);
-
-        assertTrue("Activity should have been sent to background",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return !ApplicationStatus.hasVisibleActivities();
-                    }
-                }, WAIT_FOR_LAUNCHER_MS, POLL_INTERVAL_MS));
-    }
-
-
-    private static class TestChromeSyncAdapter extends ChromiumSyncAdapter {
-        private boolean mSyncRequested;
-        private boolean mSyncRequestedForAllTypes;
-        private int mObjectSource;
-        private String mObjectId;
-        private long mVersion;
-        private String mPayload;
-
-        public TestChromeSyncAdapter(Context context, Application application) {
-            super(context, application);
-        }
-
-        @Override
-        protected boolean useAsyncStartup() {
-            return false;
-        }
-
-        @Override
-        public void requestSync(int objectSource, String objectId, long version, String payload) {
-            mObjectSource = objectSource;
-            mObjectId = objectId;
-            mVersion = version;
-            mPayload = payload;
-            mSyncRequested = true;
-        }
-
-        @Override
-        public void requestSyncForAllTypes() {
-            mSyncRequestedForAllTypes = true;
-        }
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mSyncAdapter = new TestChromeSyncAdapter(getInstrumentation().getTargetContext(),
-                getActivity().getApplication());
-    }
-
-    @Override
-    public void startMainActivity() throws InterruptedException {
-        startMainActivityOnBlankPage();
-    }
-
-    @MediumTest
-    @Feature({"Sync"})
-    public void testRequestSyncNoInvalidationData() {
-        SyncResult syncResult = new SyncResult();
-        mSyncAdapter.onPerformSync(TEST_ACCOUNT, new Bundle(),
-                AndroidSyncSettings.getContractAuthority(getActivity()), null, syncResult);
-        assertTrue(mSyncAdapter.mSyncRequestedForAllTypes);
-        assertFalse(mSyncAdapter.mSyncRequested);
-        assertTrue(CommandLine.isInitialized());
-    }
-
-    @MediumTest
-    @Feature({"Sync"})
-    public void testRequestSyncSpecificDataType() {
-        SyncResult syncResult = new SyncResult();
-        Bundle extras = new Bundle();
-        extras.putInt(ChromiumSyncAdapter.INVALIDATION_OBJECT_SOURCE_KEY, 65);
-        extras.putString(ChromiumSyncAdapter.INVALIDATION_OBJECT_ID_KEY, "objectid_value");
-        extras.putLong(ChromiumSyncAdapter.INVALIDATION_VERSION_KEY, 42);
-        extras.putString(ChromiumSyncAdapter.INVALIDATION_PAYLOAD_KEY, "payload_value");
-        mSyncAdapter.onPerformSync(TEST_ACCOUNT, extras,
-                AndroidSyncSettings.getContractAuthority(getActivity()), null, syncResult);
-        assertFalse(mSyncAdapter.mSyncRequestedForAllTypes);
-        assertTrue(mSyncAdapter.mSyncRequested);
-        assertEquals(65, mSyncAdapter.mObjectSource);
-        assertEquals("objectid_value", mSyncAdapter.mObjectId);
-        assertEquals(42, mSyncAdapter.mVersion);
-        assertEquals("payload_value", mSyncAdapter.mPayload);
-        assertTrue(CommandLine.isInitialized());
-    }
-
-    @MediumTest
-    @Feature({"Sync"})
-    public void testRequestSyncWhenChromeInBackground() throws InterruptedException {
-        sendChromeToBackground(getActivity());
-        SyncResult syncResult = new SyncResult();
-        mSyncAdapter.onPerformSync(TEST_ACCOUNT, new Bundle(),
-                AndroidSyncSettings.getContractAuthority(getActivity()), null, syncResult);
-        assertFalse(mSyncAdapter.mSyncRequestedForAllTypes);
-        assertFalse(mSyncAdapter.mSyncRequested);
-    }
-}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java
index 22312e1..f1a0515 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.toolbar;
 
 import android.graphics.Color;
-import android.test.FlakyTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.TextUtils;
 
@@ -33,6 +32,7 @@
 
     private ToolbarPhone mToolbar;
     private ToolbarDataProvider mToolbarDataProvider;
+    private int mDefaultColor;
 
     private static String getUrlWithBrandColor(String brandColor) {
         String brandColorMetaTag = TextUtils.isEmpty(brandColor)
@@ -54,39 +54,33 @@
     }
 
     private void checkForBrandColor(final int brandColor) {
-        checkNoColorTransition();
+        try {
+            assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+                @Override
+                public boolean isSatisfied() {
+                    if (mToolbarDataProvider.getPrimaryColor() != brandColor) return false;
+                    return mToolbarDataProvider.getPrimaryColor()
+                            == mToolbar.getBackgroundDrawable().getColor();
+                }
+            }));
+        } catch (InterruptedException e) {
+            fail();
+        }
         ThreadUtils.postOnUiThread(new Runnable() {
             @Override
             public void run() {
-                assertEquals("The data provider doesn't contain the right color",
-                        brandColor, mToolbarDataProvider.getPrimaryColor());
-                assertEquals("The toolbar view doesn't contain the right color",
-                        brandColor, mToolbar.getBackgroundDrawable().getColor());
                 assertEquals("The overlay drawable doesn't contain the right color",
                         brandColor, mToolbar.getOverlayDrawable().getColor());
             }
         });
     }
 
-    private void checkNoColorTransition() {
-        try {
-            CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
-                @Override
-                public boolean isSatisfied() {
-                    return mToolbarDataProvider.getPrimaryColor()
-                            == mToolbar.getBackgroundDrawable().getColor();
-                }
-            });
-        } catch (InterruptedException e) {
-            fail();
-        }
-    }
-
     @Override
     protected void startMainActivityWithURL(String url) throws InterruptedException {
         super.startMainActivityWithURL(url);
         mToolbar = (ToolbarPhone) getActivity().findViewById(R.id.toolbar);
         mToolbarDataProvider = mToolbar.getToolbarDataProvider();
+        mDefaultColor = getActivity().getResources().getColor(R.color.default_primary_color);
     }
 
     /**
@@ -96,7 +90,7 @@
     @Feature({"Omnibox"})
     public void testNoBrandColor() throws InterruptedException {
         startMainActivityWithURL(getUrlWithBrandColor(""));
-        checkForBrandColor(getActivity().getResources().getColor(R.color.default_primary_color));
+        checkForBrandColor(mDefaultColor);
     }
 
     /**
@@ -128,12 +122,9 @@
 
     /**
      * Test for checking navigating to new brand color updates correctly.
-     *
-     * Bug: http://crbug.com/474414
-     * @SmallTest
-     * @Feature({"Omnibox"})
      */
-    @FlakyTest
+    @SmallTest
+    @Feature({"Omnibox"})
     public void testNavigatingToNewBrandColor() throws InterruptedException {
         startMainActivityWithURL(getUrlWithBrandColor(BRAND_COLOR_1));
         checkForBrandColor(Color.parseColor(BRAND_COLOR_1));
@@ -142,12 +133,39 @@
     }
 
     /**
-     * Test for interstitial page loads resetting brand color.
-     * http://crbug.com/497866
-     * @SmallTest
-     * @Feature({"Omnibox"})
+     * Test for checking navigating to a brand color site from a site with no brand color and then
+     * back again.
      */
-    @FlakyTest
+    @SmallTest
+    @Feature({"Omnibox"})
+    public void testNavigatingToBrandColorAndBack() throws InterruptedException {
+        startMainActivityWithURL("about:blank");
+        checkForBrandColor(mDefaultColor);
+        loadUrl(getUrlWithBrandColor(BRAND_COLOR_1));
+        checkForBrandColor(Color.parseColor(BRAND_COLOR_1));
+        loadUrl("about:blank");
+        checkForBrandColor(mDefaultColor);
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().onBackPressed();
+            }
+        });
+        checkForBrandColor(Color.parseColor(BRAND_COLOR_1));
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().onBackPressed();
+            }
+        });
+        checkForBrandColor(mDefaultColor);
+    }
+
+    /**
+     * Test for interstitial page loads resetting brand color.
+     */
+    @SmallTest
+    @Feature({"Omnibox"})
     public void testBrandColorInterstitial() throws InterruptedException {
         final String brandColorUrl = getUrlWithBrandColor(BRAND_COLOR_1);
         startMainActivityWithURL(brandColorUrl);
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/UrlUtilitiesTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/UrlUtilitiesTest.java
index acf79698..0254f820 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/UrlUtilitiesTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/UrlUtilitiesTest.java
@@ -142,6 +142,12 @@
                 + "TEST_AUTHENTICATOR;category=android.intent.category."
                 + "BROWSABLE;S.inputData=cancelled;end"));
 
+        // null does not have a valid intent scheme.
+        assertFalse(UrlUtilities.validateIntentUrl(null));
+        // The empty string does not have a valid intent scheme.
+        assertFalse(UrlUtilities.validateIntentUrl(""));
+        // A whitespace string does not have a valid intent scheme.
+        assertFalse(UrlUtilities.validateIntentUrl(" "));
         // Junk after end.
         assertFalse(UrlUtilities.validateIntentUrl(
                 "intent://10010#Intent;scheme=tel;action=com.google.android.apps."
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/autofill/AutofillTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/autofill/AutofillTest.java
index c360ad13..b1447bd 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/autofill/AutofillTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/autofill/AutofillTest.java
@@ -45,13 +45,13 @@
         waitForActiveShellToBeDoneLoading();
 
         mMockAutofillCallback = new MockAutofillCallback();
-        mWindowAndroid = new ActivityWindowAndroid(activity);
         final ViewAndroidDelegate viewDelegate =
                 activity.getActiveContentViewCore().getViewAndroidDelegate();
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
+                mWindowAndroid = new ActivityWindowAndroid(activity);
                 mAutofillPopup = new AutofillPopup(activity, viewDelegate, mMockAutofillCallback);
                 mAutofillPopup.filterAndShow(new AutofillSuggestion[0], false);
                 mAutofillPopup.setAnchorRect(50, 500, 500, 50);
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollectorTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollectorTest.java
index f5860c1..0bf2b72 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollectorTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollectorTest.java
@@ -68,6 +68,8 @@
                     fail("Failed to recognize type " + re.getKey());
             }
         }
+        assertTrue("The elapsed time should be non-negative.", feedback.getElapsedTimeMs() >= 0);
+        assertEquals("The timeout value is wrong.", TIMEOUT_MS, feedback.getTimeoutMs());
     }
 
     @MediumTest
@@ -110,6 +112,8 @@
                     fail("Failed to recognize type " + re.getKey());
             }
         }
+        assertTrue("The elapsed time should be non-negative.", feedback.getElapsedTimeMs() >= 0);
+        assertEquals("The timeout value is wrong.", TIMEOUT_MS, feedback.getTimeoutMs());
     }
 
     @SmallTest
@@ -120,10 +124,10 @@
         connectionMap.put(Type.SYSTEM_HTTP, Result.UNKNOWN);
         connectionMap.put(Type.SYSTEM_HTTPS, Result.CONNECTED);
 
-        FeedbackData feedback = new FeedbackData(connectionMap);
+        FeedbackData feedback = new FeedbackData(connectionMap, 42, 21);
         Map<String, String> map = feedback.toMap();
 
-        assertEquals("Should have 4 entries.", 4, map.size());
+        assertEquals("Should have 6 entries.", 6, map.size());
         assertTrue(map.containsKey("CHROME_HTTP"));
         assertEquals("NOT_CONNECTED", map.get("CHROME_HTTP"));
         assertTrue(map.containsKey("CHROME_HTTPS"));
@@ -132,6 +136,10 @@
         assertEquals("UNKNOWN", map.get("SYSTEM_HTTP"));
         assertTrue(map.containsKey("SYSTEM_HTTPS"));
         assertEquals("CONNECTED", map.get("SYSTEM_HTTPS"));
+        assertTrue(map.containsKey(FeedbackData.CONNECTION_CHECK_TIMEOUT_MS));
+        assertEquals("42", map.get(FeedbackData.CONNECTION_CHECK_TIMEOUT_MS));
+        assertTrue(map.containsKey(FeedbackData.CONNECTION_CHECK_ELAPSED_MS));
+        assertEquals("21", map.get(FeedbackData.CONNECTION_CHECK_ELAPSED_MS));
     }
 
     private static FeedbackData getResult(
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/infobar/InfoBarTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
index 1622226..5bdc8162 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
@@ -12,7 +12,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
-import org.chromium.chrome.browser.ContentViewUtil;
+import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.location.LocationSettingsTestUtil;
 import org.chromium.chrome.shell.ChromeShellTestBase;
 import org.chromium.chrome.test.util.InfoBarTestAnimationListener;
@@ -160,7 +160,7 @@
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                WebContents newContents = ContentViewUtil.createWebContents(false, false);
+                WebContents newContents = WebContentsFactory.createWebContents(false, false);
                 getActivity().getActiveTab().swapWebContents(newContents, false, false);
             }
         });
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
index 2989bfd..34ab8d2 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
@@ -7,7 +7,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.UrlUtils;
-import org.chromium.chrome.browser.ContentViewUtil;
+import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.shell.ChromeShellTestBase;
 import org.chromium.content.browser.ContentView;
 import org.chromium.content.browser.ContentViewCore;
@@ -73,7 +73,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                WebContents webContents = ContentViewUtil.createWebContents(false, false);
+                WebContents webContents = WebContentsFactory.createWebContents(false, false);
                 WindowAndroid windowAndroid = new ActivityWindowAndroid(getActivity());
 
                 ContentViewCore contentViewCore = new ContentViewCore(getActivity());
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapterTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapterTest.java
new file mode 100644
index 0000000..69575f1
--- /dev/null
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/invalidation/ChromiumSyncAdapterTest.java
@@ -0,0 +1,124 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.invalidation;
+
+import android.accounts.Account;
+import android.app.Application;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.chromium.base.CommandLine;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.shell.ChromeShellTestBase;
+import org.chromium.components.invalidation.PendingInvalidation;
+import org.chromium.sync.AndroidSyncSettings;
+import org.chromium.sync.signin.AccountManagerHelper;
+
+/**
+ * Tests for ChromiumSyncAdapter.
+ */
+public class ChromiumSyncAdapterTest extends ChromeShellTestBase {
+    private static final Account TEST_ACCOUNT =
+            AccountManagerHelper.createAccountFromName("test@gmail.com");
+
+    private TestChromiumSyncAdapter mSyncAdapter;
+
+    private static class TestChromiumSyncAdapter extends ChromiumSyncAdapter {
+        private boolean mInvalidated;
+        private boolean mInvalidatedAllTypes;
+        private int mObjectSource;
+        private String mObjectId;
+        private long mVersion;
+        private String mPayload;
+
+        public TestChromiumSyncAdapter(Context context, Application application) {
+            super(context, application);
+        }
+
+        @Override
+        protected boolean useAsyncStartup() {
+            return true;
+        }
+
+        @Override
+        public void notifyInvalidation(
+                int objectSource, String objectId, long version, String payload) {
+            mObjectSource = objectSource;
+            mObjectId = objectId;
+            mVersion = version;
+            mPayload = payload;
+            if (objectId == null) {
+                mInvalidatedAllTypes = true;
+            } else {
+                mInvalidated = true;
+            }
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        launchChromeShellWithBlankPage();
+        mSyncAdapter = new TestChromiumSyncAdapter(
+                getInstrumentation().getTargetContext(), getActivity().getApplication());
+    }
+
+    private void performSyncWithBundle(Bundle bundle) {
+        mSyncAdapter.onPerformSync(TEST_ACCOUNT, bundle,
+                AndroidSyncSettings.getContractAuthority(getActivity()), null, new SyncResult());
+    }
+
+    @MediumTest
+    @Feature({"Sync"})
+    public void testRequestSyncNoInvalidationData() {
+        performSyncWithBundle(new Bundle());
+        assertTrue(mSyncAdapter.mInvalidatedAllTypes);
+        assertFalse(mSyncAdapter.mInvalidated);
+        assertTrue(CommandLine.isInitialized());
+    }
+
+    @MediumTest
+    @Feature({"Sync"})
+    public void testRequestSyncSpecificDataType() {
+        String objectId = "objectid_value";
+        int objectSource = 61;
+        long version = 42L;
+        String payload = "payload_value";
+
+        performSyncWithBundle(
+                PendingInvalidation.createBundle(objectId, objectSource, version, payload));
+
+        assertFalse(mSyncAdapter.mInvalidatedAllTypes);
+        assertTrue(mSyncAdapter.mInvalidated);
+        assertEquals(objectSource, mSyncAdapter.mObjectSource);
+        assertEquals(objectId, mSyncAdapter.mObjectId);
+        assertEquals(version, mSyncAdapter.mVersion);
+        assertEquals(payload, mSyncAdapter.mPayload);
+        assertTrue(CommandLine.isInitialized());
+    }
+
+    @MediumTest
+    @Feature({"Sync"})
+    public void testRequestSyncWhenChromeInBackground() throws InterruptedException {
+        DelayedInvalidationsControllerTest.sendChromeToBackground(getActivity());
+        performSyncWithBundle(new Bundle());
+        assertFalse(mSyncAdapter.mInvalidatedAllTypes);
+        assertFalse(mSyncAdapter.mInvalidated);
+        assertTrue(CommandLine.isInitialized());
+    }
+
+    @MediumTest
+    @Feature({"Sync"})
+    public void testRequestInitializeSync() throws InterruptedException {
+        Bundle extras = new Bundle();
+        extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
+        performSyncWithBundle(extras);
+        assertFalse(mSyncAdapter.mInvalidatedAllTypes);
+        assertFalse(mSyncAdapter.mInvalidated);
+    }
+}
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsControllerTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsControllerTest.java
new file mode 100644
index 0000000..0245fec8
--- /dev/null
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsControllerTest.java
@@ -0,0 +1,188 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.invalidation;
+
+import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.shell.ChromeShellTestBase;
+import org.chromium.components.invalidation.PendingInvalidation;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+
+import java.util.List;
+
+/**
+ * Tests for DelayedInvalidationsController.
+ */
+public class DelayedInvalidationsControllerTest extends ChromeShellTestBase {
+    private static final String TEST_ACCOUNT = "something@gmail.com";
+    private static final long WAIT_FOR_LAUNCHER_MS = scaleTimeout(10 * 1000);
+    private static final long POLL_INTERVAL_MS = 100;
+
+    private static final String OBJECT_ID = "object_id";
+    private static final int OBJECT_SRC = 4;
+    private static final long VERSION = 1L;
+    private static final String PAYLOAD = "payload";
+
+    private static final String OBJECT_ID_2 = "object_id_2";
+    private static final int OBJECT_SRC_2 = 5;
+    private static final long VERSION_2 = 2L;
+    private static final String PAYLOAD_2 = "payload_2";
+
+    private MockDelayedInvalidationsController mController;
+
+    /**
+     * Mocks {@link DelayedInvalidationsController} for testing.
+     * It intercepts access to the Android Sync Adapter.
+     */
+    private static class MockDelayedInvalidationsController extends DelayedInvalidationsController {
+        private boolean mInvalidated = false;
+        private List<Bundle> mBundles = null;
+
+        private MockDelayedInvalidationsController() {}
+
+        @Override
+        void notifyInvalidationsOnBackgroundThread(
+                Context context, Account account, List<Bundle> bundles) {
+            mInvalidated = true;
+            mBundles = bundles;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mController = new MockDelayedInvalidationsController();
+        launchChromeShellWithBlankPage();
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testManualSyncRequestsShouldAlwaysTriggerSync() throws InterruptedException {
+        // Sync should trigger for manual requests when Chrome is in the foreground.
+        assertTrue(isActivityResumed());
+        Bundle extras = new Bundle();
+        extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+        assertTrue(mController.shouldNotifyInvalidation(extras));
+
+        // Sync should trigger for manual requests when Chrome is in the background.
+        sendChromeToBackground(getActivity());
+        extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+        assertTrue(mController.shouldNotifyInvalidation(extras));
+    }
+
+    @SmallTest
+    @Feature({"Sync", "Invalidation"})
+    public void testInvalidationsTriggeredWhenChromeIsInForeground() {
+        assertTrue(isActivityResumed());
+        assertTrue(mController.shouldNotifyInvalidation(new Bundle()));
+    }
+
+    @SmallTest
+    @Feature({"Sync", "Invalidation"})
+    public void testInvalidationsReceivedWhenChromeIsInBackgroundIsDelayed()
+            throws InterruptedException {
+        sendChromeToBackground(getActivity());
+        assertFalse(mController.shouldNotifyInvalidation(new Bundle()));
+    }
+
+    @SmallTest
+    @Feature({"Sync", "Invalidation"})
+    public void testOnlySpecificInvalidationsTriggeredOnResume() throws InterruptedException {
+        // First make sure there are no pending invalidations.
+        mController.clearPendingInvalidations(getActivity());
+        assertFalse(mController.notifyPendingInvalidations(getActivity()));
+        assertFalse(mController.mInvalidated);
+
+        // Create some invalidations.
+        PendingInvalidation firstInv =
+                new PendingInvalidation(OBJECT_ID, OBJECT_SRC, VERSION, PAYLOAD);
+        PendingInvalidation secondInv =
+                new PendingInvalidation(OBJECT_ID_2, OBJECT_SRC_2, VERSION_2, PAYLOAD_2);
+
+        // Can't invalidate while Chrome is in the background.
+        sendChromeToBackground(getActivity());
+        assertFalse(mController.shouldNotifyInvalidation(new Bundle()));
+
+        // Add multiple pending invalidations.
+        mController.addPendingInvalidation(getActivity(), TEST_ACCOUNT, firstInv);
+        mController.addPendingInvalidation(getActivity(), TEST_ACCOUNT, secondInv);
+
+        // Make sure there are pending invalidations.
+        assertTrue(mController.notifyPendingInvalidations(getActivity()));
+        assertTrue(mController.mInvalidated);
+
+        // Ensure only specific invalidations are being notified.
+        assertEquals(2, mController.mBundles.size());
+        PendingInvalidation parsedInv1 = new PendingInvalidation(mController.mBundles.get(0));
+        PendingInvalidation parsedInv2 = new PendingInvalidation(mController.mBundles.get(1));
+        assertTrue(firstInv.equals(parsedInv1) ^ firstInv.equals(parsedInv2));
+        assertTrue(secondInv.equals(parsedInv1) ^ secondInv.equals(parsedInv2));
+    }
+
+    @SmallTest
+    @Feature({"Sync", "Invalidation"})
+    public void testAllInvalidationsTriggeredOnResume() throws InterruptedException {
+        // First make sure there are no pending invalidations.
+        mController.clearPendingInvalidations(getActivity());
+        assertFalse(mController.notifyPendingInvalidations(getActivity()));
+        assertFalse(mController.mInvalidated);
+
+        // Create some invalidations.
+        PendingInvalidation firstInv =
+                new PendingInvalidation(OBJECT_ID, OBJECT_SRC, VERSION, PAYLOAD);
+        PendingInvalidation secondInv =
+                new PendingInvalidation(OBJECT_ID_2, OBJECT_SRC_2, VERSION_2, PAYLOAD_2);
+        PendingInvalidation allInvalidations = new PendingInvalidation(new Bundle());
+        assertEquals(allInvalidations.mObjectSource, 0);
+
+        // Can't invalidate while Chrome is in the background.
+        sendChromeToBackground(getActivity());
+        assertFalse(mController.shouldNotifyInvalidation(new Bundle()));
+
+        // Add multiple pending invalidations.
+        mController.addPendingInvalidation(getActivity(), TEST_ACCOUNT, firstInv);
+        mController.addPendingInvalidation(getActivity(), TEST_ACCOUNT, allInvalidations);
+        mController.addPendingInvalidation(getActivity(), TEST_ACCOUNT, secondInv);
+
+        // Make sure there are pending invalidations.
+        assertTrue(mController.notifyPendingInvalidations(getActivity()));
+        assertTrue(mController.mInvalidated);
+
+        // As Invalidation for all ids has been received, it will supersede all other invalidations.
+        assertEquals(1, mController.mBundles.size());
+        assertEquals(allInvalidations, new PendingInvalidation(mController.mBundles.get(0)));
+    }
+
+    @VisibleForTesting
+    static void sendChromeToBackground(Activity activity) throws InterruptedException {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        activity.startActivity(intent);
+
+        assertTrue(
+                "Activity should have been resumed", CriteriaHelper.pollForCriteria(new Criteria() {
+                    @Override
+                    public boolean isSatisfied() {
+                        return !isActivityResumed();
+                    }
+                }, WAIT_FOR_LAUNCHER_MS, POLL_INTERVAL_MS));
+    }
+
+    private static boolean isActivityResumed() {
+        return ApplicationStatus.hasVisibleActivities();
+    }
+}
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java
index 46a1613..8efbdff 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java
@@ -10,6 +10,7 @@
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
 
+import org.chromium.base.CommandLine;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
@@ -18,30 +19,27 @@
 import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer.UrlEmphasisSpan;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.ssl.ConnectionSecurityHelperSecurityLevel;
-import org.chromium.chrome.shell.ChromeShellActivity;
-import org.chromium.chrome.shell.ChromeShellTab;
-import org.chromium.chrome.shell.ChromeShellTestBase;
+import org.chromium.content.browser.test.NativeLibraryTestBase;
 
 /**
  * Unit tests for OmniboxUrlEmphasizer that ensure various types of URLs are
  * emphasized and colored correctly.
  */
-public class OmniboxUrlEmphasizerTest extends ChromeShellTestBase {
-    private ChromeShellActivity mActivity;
+public class OmniboxUrlEmphasizerTest extends NativeLibraryTestBase {
     private Profile mProfile;
     private Resources mResources;
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mActivity = launchChromeShellWithBlankPage();
-        assertTrue(waitForActiveShellToBeDoneLoading());
+        CommandLine.init(null);
+        loadNativeLibraryAndInitBrowserProcess();
+
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                ChromeShellTab tab = mActivity.getActiveTab();
-                mProfile = tab.getProfile();
-                mResources = mActivity.getResources();
+                mProfile = Profile.getLastUsedProfile().getOriginalProfile();
+                mResources = getInstrumentation().getTargetContext().getResources();
             }
         });
     }
@@ -203,12 +201,13 @@
                 ConnectionSecurityHelperSecurityLevel.SECURITY_WARNING, false, true, true);
         EmphasizedUrlSpanHelper[] spans = EmphasizedUrlSpanHelper.getSpansForEmphasizedUrl(url);
 
-        assertEquals("Unexpected number of spans:", 3, spans.length);
-        spans[0].assertIsColoredSpan("https", 0,
+        assertEquals("Unexpected number of spans:", 4, spans.length);
+        spans[0].assertIsStrikethroughSpan("https", 0);
+        spans[1].assertIsColoredSpan("https", 0,
                 mResources.getColor(R.color.url_emphasis_start_scheme_security_warning));
-        spans[1].assertIsColoredSpan("://", 5,
+        spans[2].assertIsColoredSpan("://", 5,
                 mResources.getColor(R.color.url_emphasis_non_emphasized_text));
-        spans[2].assertIsColoredSpan("www.dodgysite.com", 8,
+        spans[3].assertIsColoredSpan("www.dodgysite.com", 8,
                 mResources.getColor(R.color.url_emphasis_domain_and_registry));
     }
 
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterTest.java
deleted file mode 100644
index a79a14e5..0000000
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.sync;
-
-import android.accounts.Account;
-import android.app.Application;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.SyncResult;
-import android.os.Bundle;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import com.google.protos.ipc.invalidation.Types;
-
-import org.chromium.base.CommandLine;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.shell.ChromeShellTestBase;
-import org.chromium.sync.AndroidSyncSettings;
-import org.chromium.sync.signin.AccountManagerHelper;
-
-/**
- * Tests for ChromiumSyncAdapter.
- */
-public class ChromiumSyncAdapterTest extends ChromeShellTestBase {
-
-    private static final Account TEST_ACCOUNT =
-            AccountManagerHelper.createAccountFromName("test@gmail.com");
-
-    private TestChromiumSyncAdapter mSyncAdapter;
-
-    private static class TestChromiumSyncAdapter extends ChromiumSyncAdapter {
-        private boolean mSyncRequested;
-        private boolean mSyncRequestedForAllTypes;
-        private int mObjectSource;
-        private String mObjectId;
-        private long mVersion;
-        private String mPayload;
-
-        public TestChromiumSyncAdapter(Context context, Application application) {
-            super(context, application);
-        }
-
-        @Override
-        protected boolean useAsyncStartup() {
-            return true;
-        }
-
-        @Override
-        public void requestSync(int objectSource, String objectId, long version, String payload) {
-            mObjectSource = objectSource;
-            mObjectId = objectId;
-            mVersion = version;
-            mPayload = payload;
-            mSyncRequested = true;
-        }
-
-        @Override
-        public void requestSyncForAllTypes() {
-            mSyncRequestedForAllTypes = true;
-        }
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        launchChromeShellWithBlankPage();
-        mSyncAdapter = new TestChromiumSyncAdapter(getInstrumentation().getTargetContext(),
-                getActivity().getApplication());
-    }
-
-    public void performSyncWithBundle(Bundle bundle) {
-        mSyncAdapter.onPerformSync(TEST_ACCOUNT, bundle,
-                AndroidSyncSettings.getContractAuthority(getActivity()),
-                null, new SyncResult());
-    }
-
-    @MediumTest
-    @Feature({"Sync"})
-    public void testRequestSyncNoInvalidationData() {
-        performSyncWithBundle(new Bundle());
-        assertTrue(mSyncAdapter.mSyncRequestedForAllTypes);
-        assertFalse(mSyncAdapter.mSyncRequested);
-        assertTrue(CommandLine.isInitialized());
-    }
-
-    private void testRequestSyncSpecificDataType(boolean withObjectSource) {
-        Bundle extras = new Bundle();
-        if (withObjectSource) {
-            extras.putInt(ChromiumSyncAdapter.INVALIDATION_OBJECT_SOURCE_KEY, 61);
-        }
-        extras.putString(ChromiumSyncAdapter.INVALIDATION_OBJECT_ID_KEY, "objectid_value");
-        extras.putLong(ChromiumSyncAdapter.INVALIDATION_VERSION_KEY, 42);
-        extras.putString(ChromiumSyncAdapter.INVALIDATION_PAYLOAD_KEY, "payload_value");
-
-        performSyncWithBundle(extras);
-
-        assertFalse(mSyncAdapter.mSyncRequestedForAllTypes);
-        assertTrue(mSyncAdapter.mSyncRequested);
-        if (withObjectSource) {
-            assertEquals(61, mSyncAdapter.mObjectSource);
-        } else {
-            assertEquals(Types.ObjectSource.CHROME_SYNC, mSyncAdapter.mObjectSource);
-        }
-        assertEquals("objectid_value", mSyncAdapter.mObjectId);
-        assertEquals(42, mSyncAdapter.mVersion);
-        assertEquals("payload_value", mSyncAdapter.mPayload);
-        assertTrue(CommandLine.isInitialized());
-    }
-
-    @MediumTest
-    @Feature({"Sync"})
-    public void testRequestSyncSpecificDataType() {
-        testRequestSyncSpecificDataType(true /* withObjectSource */);
-    }
-
-    @MediumTest
-    @Feature({"Sync"})
-    public void testRequestSyncSpecificDataType_withoutObjectSource() {
-        testRequestSyncSpecificDataType(false /* withObjectSource */);
-    }
-
-    @MediumTest
-    @Feature({"Sync"})
-    public void testRequestSyncWhenChromeInBackground() throws InterruptedException {
-        DelayedSyncControllerTest.sendChromeToBackground(getActivity());
-        performSyncWithBundle(new Bundle());
-        assertFalse(mSyncAdapter.mSyncRequestedForAllTypes);
-        assertFalse(mSyncAdapter.mSyncRequested);
-        assertTrue(CommandLine.isInitialized());
-    }
-
-    @MediumTest
-    @Feature({"Sync"})
-    public void testRequestInitializeSync() throws InterruptedException {
-        Bundle extras = new Bundle();
-        extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
-        performSyncWithBundle(extras);
-        assertFalse(mSyncAdapter.mSyncRequestedForAllTypes);
-        assertFalse(mSyncAdapter.mSyncRequested);
-    }
-}
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/sync/DelayedSyncControllerTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/sync/DelayedSyncControllerTest.java
deleted file mode 100644
index d08621a..0000000
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/sync/DelayedSyncControllerTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.sync;
-
-import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
-
-import android.accounts.Account;
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.shell.ChromeShellTestBase;
-import org.chromium.content.browser.test.util.Criteria;
-import org.chromium.content.browser.test.util.CriteriaHelper;
-import org.chromium.sync.signin.AccountManagerHelper;
-
-public class DelayedSyncControllerTest extends ChromeShellTestBase {
-    private static final Account TEST_ACCOUNT =
-            AccountManagerHelper.createAccountFromName("something@gmail.com");
-    private static final long WAIT_FOR_LAUNCHER_MS = scaleTimeout(10 * 1000);
-    private static final long POLL_INTERVAL_MS = 100;
-    private TestDelayedSyncController mController;
-
-    private static class TestDelayedSyncController extends DelayedSyncController {
-        private boolean mSyncRequested;
-
-        private TestDelayedSyncController() {}
-
-        @Override
-        void requestSyncOnBackgroundThread(Context context, Account account) {
-            mSyncRequested = true;
-        }
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mController = new TestDelayedSyncController();
-        launchChromeShellWithBlankPage();
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testManualSyncRequestsShouldAlwaysTriggerSync() throws InterruptedException {
-        // Sync should trigger for manual requests when Chrome is in the foreground.
-        assertTrue(isActivityResumed());
-        Bundle extras = new Bundle();
-        extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
-        assertTrue(mController.shouldPerformSync(getActivity(), extras, TEST_ACCOUNT));
-
-        // Sync should trigger for manual requests when Chrome is in the background.
-        sendChromeToBackground(getActivity());
-        extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
-        assertTrue(mController.shouldPerformSync(getActivity(), extras, TEST_ACCOUNT));
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testSyncRequestsShouldTriggerSyncWhenChromeIsInForeground() {
-        assertTrue(isActivityResumed());
-        Bundle extras = new Bundle();
-        assertTrue(mController.shouldPerformSync(getActivity(), extras, TEST_ACCOUNT));
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testSyncRequestsWhenChromeIsInBackgroundShouldBeDelayed()
-            throws InterruptedException {
-        sendChromeToBackground(getActivity());
-        Bundle extras = new Bundle();
-        assertFalse(mController.shouldPerformSync(getActivity(), extras, TEST_ACCOUNT));
-    }
-
-    @SmallTest
-    @Feature({"Sync"})
-    public void testDelayedSyncRequestsShouldBeTriggeredOnResume() throws InterruptedException {
-        // First make sure there are no delayed syncs.
-        mController.clearDelayedSyncs(getActivity());
-        assertFalse(mController.resumeDelayedSyncs(getActivity()));
-        assertFalse(mController.mSyncRequested);
-
-        // Trying to perform sync when Chrome is in the background should create a delayed sync.
-        sendChromeToBackground(getActivity());
-        Bundle extras = new Bundle();
-        assertFalse(mController.shouldPerformSync(getActivity(), extras, TEST_ACCOUNT));
-
-        // Make sure the delayed sync can be resumed.
-        assertTrue(mController.resumeDelayedSyncs(getActivity()));
-        assertTrue(mController.mSyncRequested);
-    }
-
-    @VisibleForTesting
-    static void sendChromeToBackground(Activity activity) throws InterruptedException {
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.addCategory(Intent.CATEGORY_HOME);
-        activity.startActivity(intent);
-
-        assertTrue("Activity should have been resumed",
-                CriteriaHelper.pollForCriteria(new Criteria() {
-                    @Override
-                    public boolean isSatisfied() {
-                        return !isActivityResumed();
-                    }
-                }, WAIT_FOR_LAUNCHER_MS, POLL_INTERVAL_MS));
-    }
-
-    private static boolean isActivityResumed() {
-        return ApplicationStatus.hasVisibleActivities();
-    }
-}
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
index c0f3261..5b61ea1 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
@@ -55,10 +55,11 @@
         }
 
         @Override
-        public void createFrozenTab(TabState state, int id, int index) {
+        public Tab createFrozenTab(TabState state, int id, int index) {
             if (created.size() == 0) idOfFirstCreatedTab = id;
             created.put(id, state);
             notifyCalled();
+            return null;
         }
 
         @Override
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImplTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImplTest.java
index a9d28b07..5e96d3c 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImplTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImplTest.java
@@ -18,8 +18,8 @@
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.test.util.browser.tabmodel.document.MockActivityDelegate;
+import org.chromium.chrome.test.util.browser.tabmodel.document.MockDocumentTabCreatorManager;
 import org.chromium.chrome.test.util.browser.tabmodel.document.MockStorageDelegate;
-import org.chromium.chrome.test.util.browser.tabmodel.document.MockTabDelegate;
 import org.chromium.chrome.test.util.browser.tabmodel.document.TestInitializationObserver;
 import org.chromium.content.browser.test.NativeLibraryTestBase;
 
@@ -78,7 +78,7 @@
 
     private MockActivityDelegate mActivityDelegate;
     private MockStorageDelegate mStorageDelegate;
-    private MockTabDelegate mTabDelegate;
+    private MockDocumentTabCreatorManager mTabCreatorManager;
     private DocumentTabModel mTabModel;
     private AdvancedMockContext mContext;
 
@@ -89,7 +89,7 @@
         loadNativeLibraryAndInitBrowserProcess();
 
         mActivityDelegate = new MockActivityDelegate();
-        mTabDelegate = new MockTabDelegate();
+        mTabCreatorManager = new MockDocumentTabCreatorManager();
         mContext = new AdvancedMockContext(getInstrumentation().getTargetContext());
         mStorageDelegate = new MockStorageDelegate(mContext.getCacheDir());
     }
@@ -112,8 +112,8 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                mTabModel = new DocumentTabModelImpl(
-                        mActivityDelegate, mStorageDelegate, mTabDelegate, false, 1010, mContext);
+                mTabModel = new DocumentTabModelImpl(mActivityDelegate, mStorageDelegate,
+                        mTabCreatorManager, false, 1010, mContext);
                 mTabModel.startTabStateLoad();
             }
         });
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModelTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModelTest.java
index 82f91dc..9a21a3868 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModelTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/document/OffTheRecordDocumentTabModelTest.java
@@ -16,8 +16,8 @@
 import org.chromium.chrome.browser.tabmodel.OffTheRecordTabModel.OffTheRecordTabModelDelegate;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.test.util.browser.tabmodel.document.MockActivityDelegate;
+import org.chromium.chrome.test.util.browser.tabmodel.document.MockDocumentTabCreatorManager;
 import org.chromium.chrome.test.util.browser.tabmodel.document.MockStorageDelegate;
-import org.chromium.chrome.test.util.browser.tabmodel.document.MockTabDelegate;
 import org.chromium.chrome.test.util.browser.tabmodel.document.TestInitializationObserver;
 import org.chromium.content.browser.test.NativeLibraryTestBase;
 
@@ -31,7 +31,7 @@
 public class OffTheRecordDocumentTabModelTest extends NativeLibraryTestBase {
     private MockActivityDelegate mActivityDelegate;
     private MockStorageDelegate mStorageDelegate;
-    private MockTabDelegate mTabDelegate;
+    private MockDocumentTabCreatorManager mTabCreatorManager;
 
     private OffTheRecordDocumentTabModel mTabModel;
     private Profile mProfile;
@@ -48,7 +48,7 @@
         mContext = getInstrumentation().getTargetContext();
         mStorageDelegate = new MockStorageDelegate(mContext.getCacheDir());
         mActivityDelegate = new MockActivityDelegate();
-        mTabDelegate = new MockTabDelegate();
+        mTabCreatorManager = new MockDocumentTabCreatorManager();
     }
 
     private void createTabModel() {
@@ -57,8 +57,8 @@
 
             @Override
             public TabModel createTabModel() {
-                mModel = new DocumentTabModelImpl(mActivityDelegate, mStorageDelegate, mTabDelegate,
-                        true, Tab.INVALID_TAB_ID, mContext);
+                mModel = new DocumentTabModelImpl(mActivityDelegate, mStorageDelegate,
+                        mTabCreatorManager, true, Tab.INVALID_TAB_ID, mContext);
                 return mModel;
             }
 
diff --git a/chrome/android/shell/java/AndroidManifest.xml.jinja2 b/chrome/android/shell/java/AndroidManifest.xml.jinja2
index 2ad635dbf..d1a7c82 100644
--- a/chrome/android/shell/java/AndroidManifest.xml.jinja2
+++ b/chrome/android/shell/java/AndroidManifest.xml.jinja2
@@ -184,9 +184,9 @@
                 android:resource="@xml/file_paths" />
         </provider>
 
-        <!-- Sync adapter for browser sync. -->
+        <!-- Sync adapter for browser invalidation. -->
         <service android:exported="false"
-                 android:name="org.chromium.chrome.shell.sync.ChromeShellSyncAdapterService">
+                 android:name="org.chromium.chrome.shell.invalidation.ChromeShellSyncAdapterService">
             <intent-filter>
                 <action android:name="android.content.SyncAdapter" />
             </intent-filter>
diff --git a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
index 3b451ab4..28fa149 100644
--- a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
+++ b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
@@ -47,8 +47,8 @@
 import org.chromium.chrome.browser.sync.SyncController;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.shell.sync.AccountChooserFragment;
-import org.chromium.chrome.shell.sync.SignoutFragment;
+import org.chromium.chrome.shell.signin.AccountChooserFragment;
+import org.chromium.chrome.shell.signin.SignoutFragment;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
 import org.chromium.components.service_tab_launcher.ServiceTabLauncher;
 import org.chromium.content.app.ContentApplication;
@@ -88,7 +88,7 @@
                 }
             };
 
-    private WindowAndroid mWindow;
+    private ActivityWindowAndroid mWindow;
     private TabManager mTabManager;
     private ChromeShellToolbar mToolbar;
     private DevToolsServer mDevToolsServer;
diff --git a/chrome/android/shell/java/src/org/chromium/chrome/shell/sync/ChromeShellSyncAdapter.java b/chrome/android/shell/java/src/org/chromium/chrome/shell/invalidation/ChromeShellSyncAdapter.java
similarity index 81%
rename from chrome/android/shell/java/src/org/chromium/chrome/shell/sync/ChromeShellSyncAdapter.java
rename to chrome/android/shell/java/src/org/chromium/chrome/shell/invalidation/ChromeShellSyncAdapter.java
index 3c559eb3..7e962325 100644
--- a/chrome/android/shell/java/src/org/chromium/chrome/shell/sync/ChromeShellSyncAdapter.java
+++ b/chrome/android/shell/java/src/org/chromium/chrome/shell/invalidation/ChromeShellSyncAdapter.java
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.shell.sync;
+package org.chromium.chrome.shell.invalidation;
 
 import android.app.Application;
 import android.content.Context;
 
-import org.chromium.chrome.browser.sync.ChromiumSyncAdapter;
+import org.chromium.chrome.browser.invalidation.ChromiumSyncAdapter;
 
 public class ChromeShellSyncAdapter extends ChromiumSyncAdapter {
     public ChromeShellSyncAdapter(Context appContext, Application application) {
diff --git a/chrome/android/shell/java/src/org/chromium/chrome/shell/sync/ChromeShellSyncAdapterService.java b/chrome/android/shell/java/src/org/chromium/chrome/shell/invalidation/ChromeShellSyncAdapterService.java
similarity index 72%
rename from chrome/android/shell/java/src/org/chromium/chrome/shell/sync/ChromeShellSyncAdapterService.java
rename to chrome/android/shell/java/src/org/chromium/chrome/shell/invalidation/ChromeShellSyncAdapterService.java
index c57e543..70e010e 100644
--- a/chrome/android/shell/java/src/org/chromium/chrome/shell/sync/ChromeShellSyncAdapterService.java
+++ b/chrome/android/shell/java/src/org/chromium/chrome/shell/invalidation/ChromeShellSyncAdapterService.java
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.shell.sync;
+package org.chromium.chrome.shell.invalidation;
 
 import android.app.Application;
 import android.content.Context;
 
-import org.chromium.chrome.browser.sync.ChromiumSyncAdapter;
-import org.chromium.chrome.browser.sync.ChromiumSyncAdapterService;
+import org.chromium.chrome.browser.invalidation.ChromiumSyncAdapter;
+import org.chromium.chrome.browser.invalidation.ChromiumSyncAdapterService;
 
 public class ChromeShellSyncAdapterService extends ChromiumSyncAdapterService {
     @Override
diff --git a/chrome/android/shell/java/src/org/chromium/chrome/shell/sync/AccountChooserFragment.java b/chrome/android/shell/java/src/org/chromium/chrome/shell/signin/AccountChooserFragment.java
similarity index 92%
rename from chrome/android/shell/java/src/org/chromium/chrome/shell/sync/AccountChooserFragment.java
rename to chrome/android/shell/java/src/org/chromium/chrome/shell/signin/AccountChooserFragment.java
index 1eab46a9..40a2530a6 100644
--- a/chrome/android/shell/java/src/org/chromium/chrome/shell/sync/AccountChooserFragment.java
+++ b/chrome/android/shell/java/src/org/chromium/chrome/shell/signin/AccountChooserFragment.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.shell.sync;
+package org.chromium.chrome.shell.signin;
 
 import android.app.Dialog;
 import android.app.DialogFragment;
@@ -21,9 +21,8 @@
  *
  * It lists the available Google accounts on the device and makes the user choose one.
  */
-public class AccountChooserFragment extends DialogFragment
-        implements DialogInterface.OnClickListener {
-
+public class AccountChooserFragment
+        extends DialogFragment implements DialogInterface.OnClickListener {
     private String[] mAccounts;
     private int mSelectedAccount;
 
diff --git a/chrome/android/shell/java/src/org/chromium/chrome/shell/sync/SignoutFragment.java b/chrome/android/shell/java/src/org/chromium/chrome/shell/signin/SignoutFragment.java
similarity index 96%
rename from chrome/android/shell/java/src/org/chromium/chrome/shell/sync/SignoutFragment.java
rename to chrome/android/shell/java/src/org/chromium/chrome/shell/signin/SignoutFragment.java
index e352f55..aff3c40 100644
--- a/chrome/android/shell/java/src/org/chromium/chrome/shell/sync/SignoutFragment.java
+++ b/chrome/android/shell/java/src/org/chromium/chrome/shell/signin/SignoutFragment.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.shell.sync;
+package org.chromium.chrome.shell.signin;
 
 import android.app.Dialog;
 import android.app.DialogFragment;
diff --git a/chrome/android/sync_shell/java/AndroidManifest.xml.jinja2 b/chrome/android/sync_shell/java/AndroidManifest.xml.jinja2
index a773460..82abdd7 100644
--- a/chrome/android/sync_shell/java/AndroidManifest.xml.jinja2
+++ b/chrome/android/sync_shell/java/AndroidManifest.xml.jinja2
@@ -136,9 +136,9 @@
                   android:authorities="org.chromium.chrome.sync_shell"
                   android:exported="true" />
 
-        <!-- Sync adapter for browser sync. -->
+        <!-- Sync adapter for browser invalidation. -->
         <service android:exported="false"
-                 android:name="org.chromium.chrome.shell.sync.ChromeShellSyncAdapterService">
+                 android:name="org.chromium.chrome.shell.invalidation.ChromeShellSyncAdapterService">
             <intent-filter>
                 <action android:name="android.content.SyncAdapter" />
             </intent-filter>
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java
new file mode 100644
index 0000000..0cbbe9c
--- /dev/null
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java
@@ -0,0 +1,168 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.sync;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Pair;
+
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.sync.internal_api.pub.base.ModelType;
+import org.chromium.sync.protocol.AutofillProfileSpecifics;
+import org.chromium.sync.protocol.AutofillSpecifics;
+import org.chromium.sync.protocol.EntitySpecifics;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test suite for the autofill sync data type.
+ */
+public class AutofillTest extends SyncTestBase {
+    private static final String TAG = "AutofillTest";
+
+    private static final String AUTOFILL_TYPE = "Autofill";
+
+    private static final String STREET = "1600 Amphitheatre Pkwy";
+    private static final String CITY = "Mountain View";
+    private static final String STATE = "CA";
+    private static final String ZIP = "94043";
+
+    // A container to store autofill information for data verification.
+    private static class Autofill {
+        public final String id;
+        public final String street;
+        public final String city;
+        public final String state;
+        public final String zip;
+
+        public Autofill(String id, String street, String city, String state, String zip) {
+            this.id = id;
+            this.street = street;
+            this.city = city;
+            this.state = state;
+            this.zip = zip;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setupTestAccountAndSignInToSync(CLIENT_ID);
+        // Make sure the initial state is clean.
+        assertClientAutofillCount(0);
+        assertServerAutofillCountWithName(0, STREET);
+    }
+
+    // Test syncing a autofill from server to client.
+    @LargeTest
+    @Feature({"Sync"})
+    public void testDownloadAutofill() throws Exception {
+        addServerAutofillProfile(STREET, CITY, STATE, ZIP);
+        assertServerAutofillCountWithName(1, STREET);
+        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
+
+        // Verify data synced to client.
+        List<Autofill> autofills = getClientAutofillProfiles();
+        assertEquals("Only the injected autofill should exist on the client.",
+                1, autofills.size());
+        Autofill autofill = autofills.get(0);
+        assertEquals("The wrong street was found for the address.", STREET, autofill.street);
+        assertEquals("The wrong city was found for the autofill.", CITY, autofill.city);
+        assertEquals("The wrong state was found for the autofill.", STATE, autofill.state);
+        assertEquals("The wrong zip was found for the autofill.", ZIP, autofill.zip);
+    }
+
+    // Test syncing a autofill deletion from server to client.
+    @LargeTest
+    @Feature({"Sync"})
+    public void testDownloadDeletedAutofill() throws Exception {
+        // Add the entity to test deleting.
+        addServerAutofillProfile(STREET, CITY, STATE, ZIP);
+        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
+        assertServerAutofillCountWithName(1, STREET);
+        assertClientAutofillCount(1);
+
+        // Delete on server, sync, and verify deleted locally.
+        Autofill autofill = getClientAutofillProfiles().get(0);
+        mFakeServerHelper.deleteEntity(autofill.id);
+        waitForServerAutofillCountWithName(0, STREET);
+        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
+        waitForClientAutofillCount(0);
+    }
+
+    private void addServerAutofillProfile(String street, String city, String state, String zip) {
+        EntitySpecifics specifics = new EntitySpecifics();
+        specifics.autofill = new AutofillSpecifics();
+        AutofillProfileSpecifics profile = new AutofillProfileSpecifics();
+        profile.addressHomeLine1 = street;
+        profile.addressHomeCity = city;
+        profile.addressHomeState = state;
+        profile.addressHomeZip = zip;
+        specifics.autofill.profile = profile;
+        mFakeServerHelper.injectUniqueClientEntity(street /* name */, specifics);
+    }
+
+    private List<Autofill> getClientAutofillProfiles() throws JSONException {
+        List<Pair<String, JSONObject>> entities = SyncTestUtil.getLocalData(
+                mContext, AUTOFILL_TYPE);
+        List<Autofill> autofills = new ArrayList<Autofill>(entities.size());
+        for (Pair<String, JSONObject> entity : entities) {
+            String id = entity.first;
+            JSONObject profile = entity.second.getJSONObject("profile");
+            String street = profile.getString("address_home_line1");
+            String city = profile.getString("address_home_city");
+            String state = profile.getString("address_home_state");
+            String zip = profile.getString("address_home_zip");
+            autofills.add(new Autofill(id, street, city, state, zip));
+        }
+        return autofills;
+    }
+
+    private void assertClientAutofillCount(int count) throws JSONException {
+        assertEquals("There should be " + count + " local autofill entities.",
+                count, SyncTestUtil.getLocalData(mContext, AUTOFILL_TYPE).size());
+    }
+
+    private void assertServerAutofillCountWithName(int count, String name) {
+        assertTrue("Expected " + count + " server autofills with name " + name + ".",
+                mFakeServerHelper.verifyEntityCountByTypeAndName(
+                        count, ModelType.AUTOFILL, name));
+    }
+
+    private void waitForClientAutofillCount(final int count) throws InterruptedException {
+        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                try {
+                    return SyncTestUtil.getLocalData(mContext, AUTOFILL_TYPE).size() == count;
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }, SyncTestUtil.UI_TIMEOUT_MS, SyncTestUtil.CHECK_INTERVAL_MS);
+        assertTrue("Expected " + count + " local autofill entities.", success);
+    }
+
+    private void waitForServerAutofillCountWithName(final int count, final String name)
+            throws InterruptedException {
+        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                try {
+                    return mFakeServerHelper.verifyEntityCountByTypeAndName(
+                            count, ModelType.AUTOFILL, name);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }, SyncTestUtil.UI_TIMEOUT_MS, SyncTestUtil.CHECK_INTERVAL_MS);
+        assertTrue("Expected " + count + " server autofills with name " + name + ".", success);
+    }
+}
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 68553fb4..eb3ba7e1 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -931,16 +931,16 @@
       <if expr="is_win">
         <if expr="use_titlecase">
           <message name="IDS_SRT_MENU_ITEM" desc="In Title Case: Text for the Chrome menu option replacing Update required.">
-            Chromium Behaving Strangely?
+            Chromium Has Detected Unusual Behavior
           </message>
         </if>
         <if expr="not use_titlecase">
           <message name="IDS_SRT_MENU_ITEM" desc="Text for the Chrome menu option replacing Update required.">
-            Chromium behaving strangely?
+            Chromium has detected unusual behavior
           </message>
         </if>
         <message name="IDS_SRT_BUBBLE_TITLE" desc="Text for the title of the software removal tool bubble view.">
-            Chromium behaving strangely?
+            Chromium has detected unusual behavior
         </message>
       </if>
       <!-- Sync/sign-in error messages -->
diff --git a/chrome/app/client_util.cc b/chrome/app/client_util.cc
index 87b8163..66f651d 100644
--- a/chrome/app/client_util.cc
+++ b/chrome/app/client_util.cc
@@ -325,6 +325,11 @@
         }
       }
     }
+  } else {
+    // Set non-browser processes up to be killed by the system after the browser
+    // goes away. The browser uses the default shutdown order, which is 0x280.
+    // This gets rid of most of those unsighly sad tabs on logout and shutdown.
+    ::SetProcessShutdownParameters(0x281, SHUTDOWN_NORETRY);
   }
 }
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 8571c75..96dfdfd3 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5971,12 +5971,6 @@
       <message name="IDS_FLAGS_ACCELERATED_FIXED_ROOT_BACKGROUND_DESCRIPTION" desc="Description for the flag to all fixed root backgrounds to be put in separate, composited layers.">
         If this option is enabled, and if the body is styled with background-attachment:fixed, the background will have its own compositied layer.
       </message>
-      <message name="IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_NAME" desc="Name of the 'Enable deferred image decoding' lab.">
-        Enable deferred image decoding.
-      </message>
-      <message name="IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_DESCRIPTION" desc="Description for the flag to defer image decoding in WebKit.">
-        Defer image decoding operations in WebKit until painting.
-      </message>
       <message name="IDS_FLAGS_ENABLE_QUIC_NAME" desc="Title for the flag to enable QUIC.">
         Experimental QUIC protocol.
       </message>
@@ -6473,11 +6467,20 @@
           Use Data Saver with bypass warnings. The proxy must be enabled in settings for this flag to take effect.
         </message>
       </if>
-      <message name="IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_LO_FI_NAME" desc="An about::flags experiment title to enable/disable Data Saver Lo-Fi">
-         Enable Data Saver Lo-Fi mode
+      <message name="IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_NAME" desc="An about::flags experiment title to enable/disable Data Saver Lo-Fi">
+         Data Saver Lo-Fi mode
       </message>
-      <message name="IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_LO_FI_DESCRIPTION" desc="Describes an about::flags experiment to enable/disable Data Saver Lo-Fi">
-         Puts the Data Saver in Lo-Fi mode when enabled.
+      <message name="IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_DESCRIPTION" desc="Describes an about::flags experiment to enable/disable Data Saver Lo-Fi">
+         Forces Data Saver Lo-Fi mode to be always enabled, enabled only on cellular connections, or disabled. Data Saver must be enabled for Lo-Fi mode to be used.
+      </message>
+      <message name="IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_ALWAYS_ON" desc="Option for IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_LO_FI_NAME to enable Lo-Fi always on">
+         Always on
+      </message>
+      <message name="IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_CELLULAR_ONLY" desc="Option for IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_LO_FI_NAME to enable Lo-Fi only on celluar connections">
+         Cellular only
+      </message>
+      <message name="IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_DISABLED" desc="Option for IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_LO_FI_NAME to disable Lo-Fi">
+         Disable
       </message>
       <message name="IDS_FLAGS_DATA_REDUCTION_PROXY_RESET_SAVINGS_NAME" desc="Title in about::flags to clear data savings obtained with data reduction proxy when Chrome restarts">
          Clear data savings on startup
@@ -6511,16 +6514,16 @@
           If enabled, the renderer delegates compositing to the browser, merging both compositing passes.
         </message>
       </if>
-      <message name="IDS_FLAGS_ONE_COPY_NAME" desc="Name of about:flags option for one-copy rasterizer.">
-        Enable one-copy rasterizer
+      <message name="IDS_FLAGS_DISABLE_ONE_COPY_NAME" desc="Name of about:flags option for one-copy rasterizer.">
+        Disable one-copy rasterizer
       </message>
-      <message name="IDS_FLAGS_ONE_COPY_DESCRIPTION" desc="Description of about:flags option for one-copy rasterizer.">
-        If enabled, raster threads write to GPU memory.
+      <message name="IDS_FLAGS_DISABLE_ONE_COPY_DESCRIPTION" desc="Description of about:flags option for one-copy rasterizer.">
+        If disabled, raster threads won't write to GPU memory.
       </message>
-      <message name="IDS_FLAGS_ZERO_COPY_NAME" desc="Name of about:flags option for zero-copy rasterizer.">
+      <message name="IDS_FLAGS_ENABLE_ZERO_COPY_NAME" desc="Name of about:flags option for zero-copy rasterizer.">
         Enable zero-copy rasterizer
       </message>
-      <message name="IDS_FLAGS_ZERO_COPY_DESCRIPTION" desc="Description of about:flags option for zero-copy rasterizer.">
+      <message name="IDS_FLAGS_ENABLE_ZERO_COPY_DESCRIPTION" desc="Description of about:flags option for zero-copy rasterizer.">
         If enabled, raster threads write directly to GPU memory associated with tiles.
       </message>
       <message name="IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_NAME" desc="">
@@ -6768,6 +6771,12 @@
       <message name="IDS_FLAGS_DISABLE_THREADED_SCROLLING_DESCRIPTION" desc="Description for the flag to disable threaded scrolling.">
         Disabled threaded handling of scroll-related input events, forcing all such scroll events to be handled on the main thread. Note that this can dramatically hurt scrolling performance of most websites and is intended for testing purposes only.
       </message>
+      <message name="IDS_FLAGS_INVERT_VIEWPORT_SCROLL_ORDER_NAME" desc="Title for the flag to enable the viewport scroll order experiment.">
+        Invert Viewport Scroll Order.
+      </message>
+      <message name="IDS_FLAGS_INVERT_VIEWPORT_SCROLL_ORDER_DESCRIPTION" desc="Description for the flag to enable the viewport scroll order experiment.">
+        Enables flipped viewport scroll order in some situations. Namely, during a pinch-zoom, the visual viewport should be scrolled first, then the layout viewport.
+      </message>
       <message name="IDS_FLAGS_BLEEDING_RENDERER_NAME" desc="Name of the 'Stacked Tabs' lab.">
         Bleeding Edge Renderer Paths - LIKELY TO CRASH YOUR BROWSER
       </message>
@@ -6912,6 +6921,12 @@
         <message name="IDS_FLAGS_APP_INFO_DIALOG_DESCRIPTION" desc="Description of flag to enable or disable the toolkit-views App Info dialog on Mac.">
           Makes the Toolkit-Views based App Info dialog accessible from chrome://apps or chrome://extensions in place of the native extension permissions dialog, or the details link (which is a link to the Web Store).
         </message>
+        <message name="IDS_FLAGS_MAC_VIEWS_NATIVE_APP_WINDOWS_NAME" desc="Name of the flag to enable or disable toolkit-views Chrome App windows on Mac.">
+          Toolkit-Views App Windows.
+        </message>
+        <message name="IDS_FLAGS_MAC_VIEWS_NATIVE_APP_WINDOWS_DESCRIPTION" desc="Description of flag to enable or disable toolkit-views Chrome App windows on Mac.">
+          Controls whether to use Toolkit-Views based Chrome App windows.
+        </message>
       </if>
 
       <!-- Crashes -->
@@ -7297,9 +7312,6 @@
       <message name="IDS_ADD_TO_SHELF_INFOBAR_ADD_BUTTON" desc="Text displayed on the button to allow users to add to the site to their shelf">
         Add
       </message>
-      <message name="IDS_ADD_TO_SHELF_INFOBAR_NEVER_BUTTON" desc="Text displayed on the button to prevent the add to shelf infobar from ever being displayed for this site">
-        Never for this site
-      </message>
 
       <!-- about:system strings -->
       <if expr="not is_android">
@@ -8480,16 +8492,18 @@
       </message>
 
       <!-- SRT bubble messages -->
-      <message name="IDS_SRT_BUBBLE_DOWNLOAD_BUTTON_TEXT" desc="Download button of the software removal tool bubble">
-        Get the Software Removal Tool
+      <message name="IDS_SRT_BUBBLE_DOWNLOAD_BUTTON_TEXT" desc="Download button of the Chrome Cleanup Tool bubble">
+        Get the Chrome Cleanup Tool
       </message>
-      <message name="IDS_SRT_BUBBLE_RUN_BUTTON_TEXT" desc="Run button of the software removal tool bubble">
-        Run the Software Removal Tool
+      <message name="IDS_SRT_BUBBLE_DISMISS" desc="Dismiss button text of the Chrome Cleanup Tool bubble">
+        Dismiss
       </message>
-      <message name="IDS_SRT_BUBBLE_TEXT" desc="Text for the software removal tool bubble view full description.">
-          For example, causing crashes, unusual startup pages or toolbars, unexpected ads you can't get rid of, or otherwise changing your browsing experience? You may be able to fix the problem by running the Software Removal Tool.
+      <message name="IDS_SRT_BUBBLE_RUN_BUTTON_TEXT" desc="Run button of the Chrome Cleanup Tool bubble">
+        Run Chrome Cleanup Tool
       </message>
-
+      <message name="IDS_SRT_BUBBLE_TEXT" desc="Text for the Chrome Cleanup Tool bubble view full description.">
+          Is Chrome crashing, showing unusual startup pages, toolbars, or unexpected ads you can't get rid of, or otherwise changing your browsing experience? You may be able to fix the problem by running the Chrome Cleanup Tool.
+      </message>
       <!-- Upgrade bubble messages -->
       <message name="IDS_REENABLE_UPDATES" desc="Text for the button the user clicks to re-enable automatic updates.">
         Enable autoupdate
@@ -8842,6 +8856,18 @@
         <message name="IDS_PRINT_PREVIEW_INVITE_TEXT" desc="Message to show when the user has pending printer-sharing invitation.">
           &lt;strong&gt;<ph name="SENDER">$1</ph>&lt;/strong&gt; wants to share a printer &lt;strong&gt;<ph name="PRINTER_NAME">$2</ph>&lt;/strong&gt; with you.
         </message>
+        <message name="IDS_PRINT_PREVIEW_BUTTON_SELECT" desc="Label for a button in a dialog asking a user to confirm selection of a printer in print preview UI. The printer gets selected if the user clicks the button.">
+          Select
+        </message>
+        <message name="IDS_PRINT_PREVIEW_BUTTON_GO_BACK" desc="Label for a button in a dialog asking a user to confirm selection of a printer in print preview UI. Clicking the button will cancel printer selection, close the dialog and go back to the list of printers available for selection.">
+          Back
+        </message>
+        <message name="IDS_PRINT_PREVIEW_RESOLVE_EXTENSION_USB_PERMISSION_MESSAGE" desc="Warning shown to the user when they attempt to select a USB printer supported by an extension, but for which the extension doesn't yet have access permission. The user is warned that selecting the printer would grant the extension access to the USB device and asked to confirm or cancel the selection. The extension name will be shown in the paragraph immediately bellow this message.">
+          By selecting this printer, you are giving the following extension the permission to access your printer:
+        </message>
+        <message name="IDS_PRINT_PREVIEW_RESOLVE_EXTENSION_USB_ERROR_MESSAGE" desc="Message shown to the user when they attempt to select a USB pinter supported by an extension, but for which the extension does not yet have access permission. The message is shown if the user grants the extension access to the USB device (by confirming printer selection), but the extension is not able to retrieve information about the printer, and an error is reported. The message contains a placeholder for the name of the extension.">
+          <ph name="EXTENSION_NAME">$1<ex>Print app</ex></ph> could not communicate with this printer. Make sure the printer is plugged in and try again.
+        </message>
       </if>
 
       <!-- Load State -->
@@ -9027,6 +9053,12 @@
       <message name="IDS_ERRORPAGES_BUTTON_RELOAD" desc="Label for the button on an error page to reload the page">
         Reload
       </message>
+      <message name="IDS_ERRORPAGES_BUTTON_SHOW_CACHED_COPY" desc="Label for the button on an error page to show Google cached copy">
+        Show cached copy
+      </message>
+      <message name="IDS_ERRORPAGES_BUTTON_SHOW_CACHED_PAGE" desc="Label for the button on an error page to show Google cached page for ">
+        Show cached page
+      </message>
       <message name="IDS_ERRORPAGES_BUTTON_SHOW_SAVED_COPY" desc="Label for the button on an error page to show a saved entry from the cache">
         Show saved copy
       </message>
@@ -10020,9 +10052,9 @@
         Connect
       </message>
 
-      <!-- Strings for the certificate selection dialog triggered by platformKeys -->
+      <!-- Strings for the certificate selection dialog triggered by chrome.platformKeys -->
       <message name="IDS_PLATFORM_KEYS_SELECT_CERT_DIALOG_TEXT" desc="The text in the dialog that prompts the user to select a certificate when an extension requests certificates through the platformKeys API.">
-        Extension '<ph name="EXTENSION_NAME">$1<ex>Better OpenVPN App</ex></ph>' has requested a certificate. Selecting a certificate will grant the extension the ability to use this identity with servers now and in the future. You should only select a certificate if you trust the extension.
+        <ph name="EXTENSION_NAME">$1<ex>My OpenVPN App</ex></ph> wants permanent access to a certificate to authenticate itself on your behalf.
       </message>
 
       <!-- Misc strings for SSL UI -->
@@ -10713,8 +10745,8 @@
         <message name="IDS_OPTIONS_CLOUD_PRINT_CONNECTOR_ENABLING_BUTTON" desc="The label of the cloud connector configure button while it is being set up.">
           Enabling...
         </message>
-        <message name="IDS_OPTIONS_SAFEBROWSING_ENABLEPROTECTION" desc="The label of the 'Enable phishing and malware protection' checkbox">
-          Enable phishing and malware protection
+        <message name="IDS_OPTIONS_SAFEBROWSING_ENABLEPROTECTION" desc="The label of the 'Protect you and your device from dangerous sites' checkbox">
+          Protect you and your device from dangerous sites
         </message>
         <message name="IDS_OPTIONS_SAFEBROWSING_ENABLE_EXTENDED_REPORTING" desc="Checkbox label: should Chrome upload information about suspicious downloads and websites to Safe Browsing">
           Automatically report details of possible security incidents to Google
@@ -10908,7 +10940,7 @@
       <message name="IDS_OPTIONS_HOMEPAGE_TITLE" desc="The title of the home page overlay" formatter_data="android_java">
         Home page
       </message>
-      <message name="IDS_OPTIONS_STARTUP_PAGES_PLACEHOLDER" desc="The placeholder text in the custom startup urls dialog" formatter_data="android_java">
+      <message name="IDS_OPTIONS_STARTUP_PAGES_PLACEHOLDER" desc="The placeholder text in the custom startup urls dialog">
         Enter URL...
       </message>
 
@@ -15616,7 +15648,6 @@
           Your printer is ready.
         </message>
       </if>
-
     </messages>
   </release>
 </grit>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 2fe3701..9c2093899 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -854,16 +854,16 @@
       <if expr="is_win">
         <if expr="use_titlecase">
           <message name="IDS_SRT_MENU_ITEM" desc="In Title Case: Text for the Chrome menu option replacing Update required.">
-            Chrome Behaving Strangely?
+            Chrome Has Detected Unusual Behavior
           </message>
         </if>
         <if expr="not use_titlecase">
           <message name="IDS_SRT_MENU_ITEM" desc="Text for the Chrome menu option replacing Update required.">
-            Chrome behaving strangely?
+            Chrome has detected unusual behavior
           </message>
         </if>
         <message name="IDS_SRT_BUBBLE_TITLE" desc="Text for the title of the software removal tool bubble view.">
-            Chrome behaving strangely?
+            Chrome has detected unusual behavior
         </message>
       </if>
       <!-- Sync/sign-in error messages -->
diff --git a/chrome/app/nibs/Toolbar.xib b/chrome/app/nibs/Toolbar.xib
index cde4f53..b5e7b9a8 100644
--- a/chrome/app/nibs/Toolbar.xib
+++ b/chrome/app/nibs/Toolbar.xib
@@ -105,7 +105,7 @@
 						<bool key="NSEnabled">YES</bool>
 						<object class="NSButtonCell" key="NSCell" id="760046712">
 							<int key="NSCellFlags">67108864</int>
-							<int key="NSCellFlags2">134250496</int>
+							<int key="NSCellFlags2">134217728</int>
 							<string key="NSContents"/>
 							<object class="NSFont" key="NSSupport" id="64724822">
 								<string key="NSName">LucidaGrande</string>
@@ -133,7 +133,7 @@
 						<bool key="NSEnabled">YES</bool>
 						<object class="NSButtonCell" key="NSCell" id="386107000">
 							<int key="NSCellFlags">67108864</int>
-							<int key="NSCellFlags2">134250496</int>
+							<int key="NSCellFlags2">134217728</int>
 							<string key="NSContents"/>
 							<reference key="NSSupport" ref="64724822"/>
 							<reference key="NSControlView" ref="458854861"/>
@@ -157,7 +157,7 @@
 						<bool key="NSEnabled">YES</bool>
 						<object class="NSButtonCell" key="NSCell" id="3781855">
 							<int key="NSCellFlags">-2080374784</int>
-							<int key="NSCellFlags2">134250496</int>
+							<int key="NSCellFlags2">134217728</int>
 							<string key="NSContents"/>
 							<reference key="NSSupport" ref="64724822"/>
 							<reference key="NSControlView" ref="781044416"/>
@@ -181,7 +181,7 @@
 						<bool key="NSEnabled">YES</bool>
 						<object class="NSButtonCell" key="NSCell" id="697431051">
 							<int key="NSCellFlags">-2080374784</int>
-							<int key="NSCellFlags2">134250496</int>
+							<int key="NSCellFlags2">134217728</int>
 							<string key="NSContents"/>
 							<reference key="NSSupport" ref="64724822"/>
 							<reference key="NSControlView" ref="634265909"/>
@@ -204,7 +204,7 @@
 						<bool key="NSEnabled">YES</bool>
 						<object class="NSButtonCell" key="NSCell" id="204555298">
 							<int key="NSCellFlags">67108864</int>
-							<int key="NSCellFlags2">134250496</int>
+							<int key="NSCellFlags2">134217728</int>
 							<string key="NSContents"/>
 							<reference key="NSSupport" ref="64724822"/>
 							<reference key="NSControlView" ref="602421009"/>
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp
index 13c3ead..ae278a90 100644
--- a/chrome/app/settings_chromium_strings.grdp
+++ b/chrome/app/settings_chromium_strings.grdp
@@ -1,6 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- Settings-specific Chromium strings (included from chromium_strings.grd). -->
 <grit-part>
+  <!-- Privacy Page -->
+  <message name="IDS_SETTINGS_IMPROVE_BROWSING_EXPERIENCE" desc="The text in the options panel that describes how we use web services to improve browsing experience.">
+    Chromium may use <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>web services<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph> to improve your browsing experience. You may optionally disable these services at any time.
+  </message>
+
   <!-- Sync Page -->
   <message name="IDS_SETTINGS_SYNC_DATA_ENCRYPTED_TEXT" desc="Text alerting the user that synced data is encrypted.">
     For added security, Chromium will encrypt your data.
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp
index c03e904..d1e15ad 100644
--- a/chrome/app/settings_google_chrome_strings.grdp
+++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -1,6 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- Settings-specific Google Chrome strings (included from google_chrome_strings.grd). -->
 <grit-part>
+  <!-- Privacy Page -->
+  <message name="IDS_SETTINGS_IMPROVE_BROWSING_EXPERIENCE" desc="The text in the options panel that describes how we use web services to improve browsing experience.">
+    Google Chrome may use <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>web services<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph> to improve your browsing experience. You may optionally disable these services at any time.
+  </message>
+
   <!-- Sync Page -->
   <message name="IDS_SETTINGS_SYNC_DATA_ENCRYPTED_TEXT" desc="Text alerting the user that synced data is encrypted.">
     For added security, Google Chrome will encrypt your data.
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 7271871..ffea13b 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -122,6 +122,47 @@
     Network Details
   </message>
 
+  <!-- Privacy Page -->
+  <message name="IDS_SETTINGS_PRIVACY_PAGE_TITLE" desc="Name of the settings page which allows users to modify privacy and security settings.">
+    Privacy &amp; Security
+  </message>
+  <message name="IDS_SETTINGS_LINKDOCTOR_PREF" desc="The documentation string of the 'Use Link Doctor' preference to help with navigation errors.">
+    Use a web service to help resolve navigation errors
+  </message>
+  <message name="IDS_SETTINGS_SUGGEST_PREF" desc="The documentation string of the 'Use Suggest' preference">
+    Use a prediction service to help complete searches and URLs typed in the address bar or the app launcher search box
+  </message>
+  <message name="IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESCRIPTION" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions.  Actions include DNS prefetching, TCP and SSL preconnection, and prerendering of webpages.">
+    Prefetch resources to load pages more quickly
+  </message>
+  <message name="IDS_SETTINGS_SAFEBROWSING_ENABLEPROTECTION" desc="The label of the 'Enable phishing and malware protection' checkbox">
+    Enable phishing and malware protection
+  </message>
+  <message name="IDS_SETTINGS_SAFEBROWSING_ENABLE_EXTENDED_REPORTING" desc="Checkbox label: should Chrome upload information about suspicious downloads and websites to Safe Browsing">
+    Automatically report details of possible security incidents to Google
+  </message>
+  <message name="IDS_SETTINGS_SPELLING_PREF" desc="The documentation string of the 'Use Spelling' preference">
+    Use a web service to help resolve spelling errors
+  </message>
+  <message name="IDS_SETTINGS_ENABLE_LOGGING" desc="The label of the checkbox to enable/disable crash and user metrics logging">
+    Automatically send usage statistics and crash reports to Google
+  </message>
+  <message name="IDS_SETTINGS_ENABLE_DO_NOT_TRACK" desc="The label of the checkbox to enable/disable sending the 'Do Not track' header">
+    Send a "Do Not Track" request with your browsing traffic
+  </message>
+  <message name="IDS_SETTINGS_ENABLE_CONTENT_PROTECTION_ATTESTATION" desc="description label for verified access about premium contents">
+    Enable Verified Access
+  </message>
+  <message name="IDS_SETTINGS_WAKE_ON_WIFI_DESCRIPTION" desc="In the settings tab, the text next to the checkbox for enabling quickly reconnecting to known Wi-Fi SSIDs.">
+    Keep Wi-Fi on during sleep
+  </message>
+  <message name="IDS_SETTINGS_SITE_SETTINGS" desc="Text for site settings button in Privacy options">
+    Site settings
+  </message>
+  <message name="IDS_SETTINGS_CLEAR_DATA" desc="Text for clear browsing data button in Privacy options">
+    Clear browsing data
+  </message>
+
   <!-- Search Page -->
   <message name="IDS_SETTINGS_SEARCH_PAGE_TITLE" desc="Name of the settings page which displays search engine preferences.">
     Search
diff --git a/chrome/app_shim/chrome_main_app_mode_mac.mm b/chrome/app_shim/chrome_main_app_mode_mac.mm
index ca3d271..98630a6 100644
--- a/chrome/app_shim/chrome_main_app_mode_mac.mm
+++ b/chrome/app_shim/chrome_main_app_mode_mac.mm
@@ -211,10 +211,8 @@
 void AppShimController::CreateChannelAndSendLaunchApp(
     const base::FilePath& socket_path) {
   IPC::ChannelHandle handle(socket_path.value());
-  channel_ = IPC::ChannelProxy::Create(handle,
-                                       IPC::Channel::MODE_NAMED_CLIENT,
-                                       this,
-                                       g_io_thread->message_loop_proxy().get());
+  channel_ = IPC::ChannelProxy::Create(handle, IPC::Channel::MODE_NAMED_CLIENT,
+                                       this, g_io_thread->task_runner().get());
 
   bool launched_by_chrome = base::CommandLine::ForCurrentProcess()->HasSwitch(
       app_mode::kLaunchedByChromeProcessId);
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 30127a3a..fbc6552d 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -19,6 +19,11 @@
   import("//build/config/linux/pkg_config.gni")
 }
 
+declare_args() {
+  # 'Ok Google' hotwording is enabled.
+  enable_hotwording = true
+}
+
 about_credits_file = "$target_gen_dir/about_credits.html"
 additional_modules_list_file =
     "$root_gen_dir/chrome/browser/internal/additional_modules_list.txt"
@@ -452,6 +457,10 @@
     }
   }
 
+  if (enable_hotwording) {
+    defines += [ "ENABLE_HOTWORDING" ]
+  }
+
   if (is_linux) {
     deps += [
       "//device/media_transfer_protocol",
@@ -612,6 +621,7 @@
     deps += [
       "//components/feedback",
       "//device/core",
+      "//device/devices_app:lib",
       "//device/usb",
     ]
   }
@@ -645,6 +655,7 @@
 
     if (use_seccomp_bpf) {
       defines += [ "USE_SECCOMP_BPF" ]
+      deps += [ "//sandbox/linux:seccomp_bpf" ]
     }
   }
 
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 4f7ac97..5375c12 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -104,6 +104,7 @@
   "+courgette",
   "+device/bluetooth",
   "+device/core",
+  "+device/devices_app",
   "+device/hid",
   "+device/usb",
   "+device/media_transfer_protocol",
@@ -176,9 +177,9 @@
   # header-only types, and some selected common code.
   "-third_party/WebKit",
   "+third_party/WebKit/public/platform/WebReferrerPolicy.h",
-  "+third_party/WebKit/public/platform/WebScreenOrientationLockType.h",
   "+third_party/WebKit/public/platform/modules/app_banner/WebAppBannerPromptReply.h",
   "+third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h",
+  "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
   "+third_party/WebKit/public/web/WebCache.h",
   "+third_party/WebKit/public/web/WebContextMenuData.h",
   "+third_party/WebKit/public/web/WebFindOptions.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 393fd9b..3eb8d98f 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -215,6 +215,20 @@
         switches::kMarkNonSecureAs, switches::kMarkNonSecureAsDubious}
 };
 
+const Experiment::Choice kDataReductionProxyLoFiChoices[] = {
+    { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
+    { IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_ALWAYS_ON,
+        data_reduction_proxy::switches::kDataReductionProxyLoFi,
+        data_reduction_proxy::switches::kDataReductionProxyLoFiValueAlwaysOn},
+    { IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_CELLULAR_ONLY,
+        data_reduction_proxy::switches::kDataReductionProxyLoFi,
+        data_reduction_proxy::switches::
+            kDataReductionProxyLoFiValueCellularOnly},
+    { IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_DISABLED,
+        data_reduction_proxy::switches::kDataReductionProxyLoFi,
+        data_reduction_proxy::switches::kDataReductionProxyLoFiValueDisabled}
+};
+
 const Experiment::Choice kShowSavedCopyChoices[] = {
   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
   { IDS_FLAGS_ENABLE_SHOW_SAVED_COPY_PRIMARY,
@@ -517,1916 +531,1480 @@
 //
 // When adding a new choice, add it to the end of the list.
 const Experiment kExperiments[] = {
-  {
-    "ignore-gpu-blacklist",
-    IDS_FLAGS_IGNORE_GPU_BLACKLIST_NAME,
-    IDS_FLAGS_IGNORE_GPU_BLACKLIST_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kIgnoreGpuBlacklist)
-  },
+    {"ignore-gpu-blacklist",
+     IDS_FLAGS_IGNORE_GPU_BLACKLIST_NAME,
+     IDS_FLAGS_IGNORE_GPU_BLACKLIST_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kIgnoreGpuBlacklist)},
 #if defined(OS_WIN)
-  {
-    "disable-direct-write",
-    IDS_FLAGS_DISABLE_DIRECT_WRITE_NAME,
-    IDS_FLAGS_DISABLE_DIRECT_WRITE_DESCRIPTION,
-    kOsWin,
-    SINGLE_VALUE_TYPE(switches::kDisableDirectWrite)
-  },
+    {"disable-direct-write",
+     IDS_FLAGS_DISABLE_DIRECT_WRITE_NAME,
+     IDS_FLAGS_DISABLE_DIRECT_WRITE_DESCRIPTION,
+     kOsWin,
+     SINGLE_VALUE_TYPE(switches::kDisableDirectWrite)},
 #endif
-  {
-    "enable-experimental-canvas-features",
-    IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_NAME,
-    IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableExperimentalCanvasFeatures)
-  },
-  {
-    "disable-accelerated-2d-canvas",
-    IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_NAME,
-    IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kDisableAccelerated2dCanvas)
-  },
-  {
-    "enable-display-list-2d-canvas",
-    IDS_FLAGS_ENABLE_DISPLAY_LIST_2D_CANVAS_NAME,
-    IDS_FLAGS_ENABLE_DISPLAY_LIST_2D_CANVAS_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDisplayList2dCanvas,
-                              switches::kDisableDisplayList2dCanvas)
-  },
-  {
-    "composited-layer-borders",
-    IDS_FLAGS_COMPOSITED_LAYER_BORDERS,
-    IDS_FLAGS_COMPOSITED_LAYER_BORDERS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(cc::switches::kShowCompositedLayerBorders)
-  },
-  {
-    "show-fps-counter",
-    IDS_FLAGS_SHOW_FPS_COUNTER,
-    IDS_FLAGS_SHOW_FPS_COUNTER_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(cc::switches::kShowFPSCounter)
-  },
-  {
-    "disable-webgl",
-    IDS_FLAGS_DISABLE_WEBGL_NAME,
-    IDS_FLAGS_DISABLE_WEBGL_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kDisableExperimentalWebGL)
-  },
-  {
-    "disable-webrtc",
-    IDS_FLAGS_DISABLE_WEBRTC_NAME,
-    IDS_FLAGS_DISABLE_WEBRTC_DESCRIPTION,
-    kOsAndroid,
+    {"enable-experimental-canvas-features",
+     IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_NAME,
+     IDS_FLAGS_ENABLE_EXPERIMENTAL_CANVAS_FEATURES_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableExperimentalCanvasFeatures)},
+    {"disable-accelerated-2d-canvas",
+     IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_NAME,
+     IDS_FLAGS_DISABLE_ACCELERATED_2D_CANVAS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kDisableAccelerated2dCanvas)},
+    {"enable-display-list-2d-canvas",
+     IDS_FLAGS_ENABLE_DISPLAY_LIST_2D_CANVAS_NAME,
+     IDS_FLAGS_ENABLE_DISPLAY_LIST_2D_CANVAS_DESCRIPTION,
+     kOsAll,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDisplayList2dCanvas,
+                               switches::kDisableDisplayList2dCanvas)},
+    {"composited-layer-borders",
+     IDS_FLAGS_COMPOSITED_LAYER_BORDERS,
+     IDS_FLAGS_COMPOSITED_LAYER_BORDERS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(cc::switches::kShowCompositedLayerBorders)},
+    {"show-fps-counter",
+     IDS_FLAGS_SHOW_FPS_COUNTER,
+     IDS_FLAGS_SHOW_FPS_COUNTER_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(cc::switches::kShowFPSCounter)},
+    {"disable-webgl",
+     IDS_FLAGS_DISABLE_WEBGL_NAME,
+     IDS_FLAGS_DISABLE_WEBGL_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kDisableExperimentalWebGL)},
+    {"disable-webrtc",
+     IDS_FLAGS_DISABLE_WEBRTC_NAME,
+     IDS_FLAGS_DISABLE_WEBRTC_DESCRIPTION,
+     kOsAndroid,
 #if defined(OS_ANDROID)
-    SINGLE_VALUE_TYPE(switches::kDisableWebRTC)
+     SINGLE_VALUE_TYPE(switches::kDisableWebRTC)
 #else
-    SINGLE_VALUE_TYPE("")
+     SINGLE_VALUE_TYPE("")
 #endif
-  },
+    },
 #if defined(ENABLE_WEBRTC)
-  {
-    "disable-webrtc-hw-decoding",
-    IDS_FLAGS_DISABLE_WEBRTC_HW_DECODING_NAME,
-    IDS_FLAGS_DISABLE_WEBRTC_HW_DECODING_DESCRIPTION,
-    kOsAndroid | kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kDisableWebRtcHWDecoding)
-  },
-  {
-    "disable-webrtc-hw-encoding",
-    IDS_FLAGS_DISABLE_WEBRTC_HW_ENCODING_NAME,
-    IDS_FLAGS_DISABLE_WEBRTC_HW_ENCODING_DESCRIPTION,
-    kOsAndroid | kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kDisableWebRtcHWEncoding)
-  },
-  {
-    "enable-webrtc-stun-origin",
-    IDS_FLAGS_ENABLE_WEBRTC_STUN_ORIGIN_NAME,
-    IDS_FLAGS_ENABLE_WEBRTC_STUN_ORIGIN_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableWebRtcStunOrigin)
-  },
+    {"disable-webrtc-hw-decoding",
+     IDS_FLAGS_DISABLE_WEBRTC_HW_DECODING_NAME,
+     IDS_FLAGS_DISABLE_WEBRTC_HW_DECODING_DESCRIPTION,
+     kOsAndroid | kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kDisableWebRtcHWDecoding)},
+    {"disable-webrtc-hw-encoding",
+     IDS_FLAGS_DISABLE_WEBRTC_HW_ENCODING_NAME,
+     IDS_FLAGS_DISABLE_WEBRTC_HW_ENCODING_DESCRIPTION,
+     kOsAndroid | kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kDisableWebRtcHWEncoding)},
+    {"enable-webrtc-stun-origin",
+     IDS_FLAGS_ENABLE_WEBRTC_STUN_ORIGIN_NAME,
+     IDS_FLAGS_ENABLE_WEBRTC_STUN_ORIGIN_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableWebRtcStunOrigin)},
 #endif
 #if defined(OS_ANDROID)
-  {
-    "disable-webaudio",
-    IDS_FLAGS_DISABLE_WEBAUDIO_NAME,
-    IDS_FLAGS_DISABLE_WEBAUDIO_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kDisableWebAudio)
-  },
+    {"disable-webaudio",
+     IDS_FLAGS_DISABLE_WEBAUDIO_NAME,
+     IDS_FLAGS_DISABLE_WEBAUDIO_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kDisableWebAudio)},
 #endif
   // Native client is compiled out when DISABLE_NACL is defined.
 #if !defined(DISABLE_NACL)
-  {
-    "enable-nacl",  // FLAGS:RECORD_UMA
-    IDS_FLAGS_ENABLE_NACL_NAME,
-    IDS_FLAGS_ENABLE_NACL_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableNaCl)
-  },
-  {
-    "enable-nacl-debug",  // FLAGS:RECORD_UMA
-    IDS_FLAGS_ENABLE_NACL_DEBUG_NAME,
-    IDS_FLAGS_ENABLE_NACL_DEBUG_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kEnableNaClDebug)
-  },
-  {
-    "nacl-debug-mask",  // FLAGS:RECORD_UMA
-    IDS_FLAGS_NACL_DEBUG_MASK_NAME,
-    IDS_FLAGS_NACL_DEBUG_MASK_DESCRIPTION,
-    kOsDesktop,
-    MULTI_VALUE_TYPE(kNaClDebugMaskChoices)
-  },
+    {"enable-nacl",  // FLAGS:RECORD_UMA
+     IDS_FLAGS_ENABLE_NACL_NAME,
+     IDS_FLAGS_ENABLE_NACL_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableNaCl)},
+    {"enable-nacl-debug",  // FLAGS:RECORD_UMA
+     IDS_FLAGS_ENABLE_NACL_DEBUG_NAME,
+     IDS_FLAGS_ENABLE_NACL_DEBUG_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kEnableNaClDebug)},
+    {"nacl-debug-mask",  // FLAGS:RECORD_UMA
+     IDS_FLAGS_NACL_DEBUG_MASK_NAME,
+     IDS_FLAGS_NACL_DEBUG_MASK_DESCRIPTION,
+     kOsDesktop,
+     MULTI_VALUE_TYPE(kNaClDebugMaskChoices)},
 #endif
 #if defined(ENABLE_EXTENSIONS)
-  {
-    "extension-apis",  // FLAGS:RECORD_UMA
-    IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_NAME,
-    IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(extensions::switches::kEnableExperimentalExtensionApis)
-  },
-  {
-    "extensions-on-chrome-urls",
-    IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_NAME,
-    IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(extensions::switches::kExtensionsOnChromeURLs)
-  },
+    {"extension-apis",  // FLAGS:RECORD_UMA
+     IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_NAME,
+     IDS_FLAGS_EXPERIMENTAL_EXTENSION_APIS_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(extensions::switches::kEnableExperimentalExtensionApis)},
+    {"extensions-on-chrome-urls",
+     IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_NAME,
+     IDS_FLAGS_EXTENSIONS_ON_CHROME_URLS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(extensions::switches::kExtensionsOnChromeURLs)},
 #endif
-  {
-    "enable-fast-unload",
-    IDS_FLAGS_ENABLE_FAST_UNLOAD_NAME,
-    IDS_FLAGS_ENABLE_FAST_UNLOAD_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableFastUnload)
-  },
+    {"enable-fast-unload",
+     IDS_FLAGS_ENABLE_FAST_UNLOAD_NAME,
+     IDS_FLAGS_ENABLE_FAST_UNLOAD_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableFastUnload)},
 #if defined(ENABLE_EXTENSIONS)
-  {
-    "enable-app-window-controls",
-    IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_NAME,
-    IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(extensions::switches::kEnableAppWindowControls)
-  },
+    {"enable-app-window-controls",
+     IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_NAME,
+     IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(extensions::switches::kEnableAppWindowControls)},
 #endif
-  {
-    "disable-hyperlink-auditing",
-    IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_NAME,
-    IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kNoPings)
-  },
+    {"disable-hyperlink-auditing",
+     IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_NAME,
+     IDS_FLAGS_DISABLE_HYPERLINK_AUDITING_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kNoPings)},
 #if defined(OS_ANDROID)
-  {
-    "contextual-search",
-    IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH,
-    IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH_DESCRIPTION,
-    kOsAndroid,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableContextualSearch,
-                              switches::kDisableContextualSearch)
-  },
+    {"contextual-search",
+     IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH,
+     IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH_DESCRIPTION,
+     kOsAndroid,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableContextualSearch,
+                               switches::kDisableContextualSearch)},
 #endif
-  {
-    "show-autofill-type-predictions",
-    IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_NAME,
-    IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(autofill::switches::kShowAutofillTypePredictions)
-  },
-  {
-    "enable-smooth-scrolling",  // FLAGS:RECORD_UMA
-    IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_NAME,
-    IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_DESCRIPTION,
-    // Can't expose the switch unless the code is compiled in.
-    // On by default for the Mac (different implementation in WebKit).
-    kOsLinux | kOsWin,
-    SINGLE_VALUE_TYPE(switches::kEnableSmoothScrolling)
-  },
+    {"show-autofill-type-predictions",
+     IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_NAME,
+     IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(autofill::switches::kShowAutofillTypePredictions)},
+    {"enable-smooth-scrolling",  // FLAGS:RECORD_UMA
+     IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_NAME,
+     IDS_FLAGS_ENABLE_SMOOTH_SCROLLING_DESCRIPTION,
+     // Can't expose the switch unless the code is compiled in.
+     // On by default for the Mac (different implementation in WebKit).
+     kOsLinux | kOsWin,
+     SINGLE_VALUE_TYPE(switches::kEnableSmoothScrolling)},
 #if defined(USE_AURA) || defined(OS_LINUX)
-  {
-    "overlay-scrollbars",
-    IDS_FLAGS_ENABLE_OVERLAY_SCROLLBARS_NAME,
-    IDS_FLAGS_ENABLE_OVERLAY_SCROLLBARS_DESCRIPTION,
-    // Uses the system preference on Mac (a different implementation).
-    // On Android, this is always enabled.
-    kOsLinux | kOsCrOS | kOsWin,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOverlayScrollbar,
-                              switches::kDisableOverlayScrollbar)
-  },
+    {"overlay-scrollbars",
+     IDS_FLAGS_ENABLE_OVERLAY_SCROLLBARS_NAME,
+     IDS_FLAGS_ENABLE_OVERLAY_SCROLLBARS_DESCRIPTION,
+     // Uses the system preference on Mac (a different implementation).
+     // On Android, this is always enabled.
+     kOsLinux | kOsCrOS | kOsWin,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOverlayScrollbar,
+                               switches::kDisableOverlayScrollbar)},
 #endif
-  {
-    "enable-panels",
-    IDS_FLAGS_ENABLE_PANELS_NAME,
-    IDS_FLAGS_ENABLE_PANELS_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kEnablePanels)
-  },
-  {
-    // See http://crbug.com/120416 for how to remove this flag.
-    "save-page-as-mhtml",  // FLAGS:RECORD_UMA
-    IDS_FLAGS_SAVE_PAGE_AS_MHTML_NAME,
-    IDS_FLAGS_SAVE_PAGE_AS_MHTML_DESCRIPTION,
-    kOsMac | kOsWin | kOsLinux,
-    SINGLE_VALUE_TYPE(switches::kSavePageAsMHTML)
-  },
-  {
-    "enable-quic",
-    IDS_FLAGS_ENABLE_QUIC_NAME,
-    IDS_FLAGS_ENABLE_QUIC_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableQuic,
-                              switches::kDisableQuic)
-  },
-  {
-    "disable-media-source",
-    IDS_FLAGS_DISABLE_MEDIA_SOURCE_NAME,
-    IDS_FLAGS_DISABLE_MEDIA_SOURCE_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kDisableMediaSource)
-  },
-  {
-    "disable-encrypted-media",
-    IDS_FLAGS_DISABLE_ENCRYPTED_MEDIA_NAME,
-    IDS_FLAGS_DISABLE_ENCRYPTED_MEDIA_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kDisableEncryptedMedia)
-  },
-  {
-    "disable-prefixed-encrypted-media",
-    IDS_FLAGS_DISABLE_PREFIXED_ENCRYPTED_MEDIA_NAME,
-    IDS_FLAGS_DISABLE_PREFIXED_ENCRYPTED_MEDIA_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kDisablePrefixedEncryptedMedia)
-  },
+    {"enable-panels",
+     IDS_FLAGS_ENABLE_PANELS_NAME,
+     IDS_FLAGS_ENABLE_PANELS_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kEnablePanels)},
+    {// See http://crbug.com/120416 for how to remove this flag.
+     "save-page-as-mhtml",  // FLAGS:RECORD_UMA
+     IDS_FLAGS_SAVE_PAGE_AS_MHTML_NAME,
+     IDS_FLAGS_SAVE_PAGE_AS_MHTML_DESCRIPTION,
+     kOsMac | kOsWin | kOsLinux,
+     SINGLE_VALUE_TYPE(switches::kSavePageAsMHTML)},
+    {"enable-quic",
+     IDS_FLAGS_ENABLE_QUIC_NAME,
+     IDS_FLAGS_ENABLE_QUIC_DESCRIPTION,
+     kOsAll,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableQuic, switches::kDisableQuic)},
+    {"disable-media-source",
+     IDS_FLAGS_DISABLE_MEDIA_SOURCE_NAME,
+     IDS_FLAGS_DISABLE_MEDIA_SOURCE_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kDisableMediaSource)},
+    {"disable-encrypted-media",
+     IDS_FLAGS_DISABLE_ENCRYPTED_MEDIA_NAME,
+     IDS_FLAGS_DISABLE_ENCRYPTED_MEDIA_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kDisableEncryptedMedia)},
+    {"disable-prefixed-encrypted-media",
+     IDS_FLAGS_DISABLE_PREFIXED_ENCRYPTED_MEDIA_NAME,
+     IDS_FLAGS_DISABLE_PREFIXED_ENCRYPTED_MEDIA_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kDisablePrefixedEncryptedMedia)},
 #if defined(OS_ANDROID)
-  {
-    "disable-infobar-for-protected-media-identifier",
-    IDS_FLAGS_DISABLE_INFOBAR_FOR_PROTECTED_MEDIA_IDENTIFIER_NAME,
-    IDS_FLAGS_DISABLE_INFOBAR_FOR_PROTECTED_MEDIA_IDENTIFIER_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kDisableInfobarForProtectedMediaIdentifier)
-  },
+    {"disable-infobar-for-protected-media-identifier",
+     IDS_FLAGS_DISABLE_INFOBAR_FOR_PROTECTED_MEDIA_IDENTIFIER_NAME,
+     IDS_FLAGS_DISABLE_INFOBAR_FOR_PROTECTED_MEDIA_IDENTIFIER_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kDisableInfobarForProtectedMediaIdentifier)},
 #endif  // defined(OS_ANDROID)
-  {
-    "disable-javascript-harmony-shipping",
-    IDS_FLAGS_DISABLE_JAVASCRIPT_HARMONY_SHIPPING_NAME,
-    IDS_FLAGS_DISABLE_JAVASCRIPT_HARMONY_SHIPPING_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kDisableJavaScriptHarmonyShipping)
-  },
-  {
-    "enable-javascript-harmony",
-    IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_NAME,
-    IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kJavaScriptHarmony)
-  },
-  {
-    "disable-software-rasterizer",
-    IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_NAME,
-    IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_DESCRIPTION,
+    {"disable-javascript-harmony-shipping",
+     IDS_FLAGS_DISABLE_JAVASCRIPT_HARMONY_SHIPPING_NAME,
+     IDS_FLAGS_DISABLE_JAVASCRIPT_HARMONY_SHIPPING_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kDisableJavaScriptHarmonyShipping)},
+    {"enable-javascript-harmony",
+     IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_NAME,
+     IDS_FLAGS_ENABLE_JAVASCRIPT_HARMONY_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kJavaScriptHarmony)},
+    {"disable-software-rasterizer",
+     IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_NAME,
+     IDS_FLAGS_DISABLE_SOFTWARE_RASTERIZER_DESCRIPTION,
 #if defined(ENABLE_SWIFTSHADER)
-    kOsAll,
+     kOsAll,
 #else
-    0,
+     0,
 #endif
-    SINGLE_VALUE_TYPE(switches::kDisableSoftwareRasterizer)
-  },
-  {
-    "enable-gpu-rasterization",
-    IDS_FLAGS_ENABLE_GPU_RASTERIZATION_NAME,
-    IDS_FLAGS_ENABLE_GPU_RASTERIZATION_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kEnableGpuRasterizationChoices)
-  },
-  {
-    "gpu-rasterization-msaa-sample-count",
-    IDS_FLAGS_GPU_RASTERIZATION_MSAA_SAMPLE_COUNT_NAME,
-    IDS_FLAGS_GPU_RASTERIZATION_MSAA_SAMPLE_COUNT_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kGpuRasterizationMSAASampleCountChoices)
-  },
-  {
-    "enable-slimming-paint",
-    IDS_FLAGS_ENABLE_SLIMMING_PAINT_NAME,
-    IDS_FLAGS_ENABLE_SLIMMING_PAINT_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableSlimmingPaint)
-  },
-  {
-    "enable-experimental-web-platform-features",
-    IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_NAME,
-    IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableExperimentalWebPlatformFeatures)
-  },
-  {
-    "enable-web-bluetooth",
-    IDS_FLAGS_WEB_BLUETOOTH_NAME,
-    IDS_FLAGS_WEB_BLUETOOTH_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableWebBluetooth)
-  },
-  {
-    "enable-devtools-experiments",
-    IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_NAME,
-    IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kEnableDevToolsExperiments)
-  },
-  {
-    "silent-debugger-extension-api",
-    IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_NAME,
-    IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kSilentDebuggerExtensionAPI)
-  },
+     SINGLE_VALUE_TYPE(switches::kDisableSoftwareRasterizer)},
+    {"enable-gpu-rasterization",
+     IDS_FLAGS_ENABLE_GPU_RASTERIZATION_NAME,
+     IDS_FLAGS_ENABLE_GPU_RASTERIZATION_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kEnableGpuRasterizationChoices)},
+    {"gpu-rasterization-msaa-sample-count",
+     IDS_FLAGS_GPU_RASTERIZATION_MSAA_SAMPLE_COUNT_NAME,
+     IDS_FLAGS_GPU_RASTERIZATION_MSAA_SAMPLE_COUNT_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kGpuRasterizationMSAASampleCountChoices)},
+    {"enable-slimming-paint",
+     IDS_FLAGS_ENABLE_SLIMMING_PAINT_NAME,
+     IDS_FLAGS_ENABLE_SLIMMING_PAINT_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableSlimmingPaint)},
+    {"enable-experimental-web-platform-features",
+     IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_NAME,
+     IDS_FLAGS_EXPERIMENTAL_WEB_PLATFORM_FEATURES_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableExperimentalWebPlatformFeatures)},
+    {"enable-web-bluetooth",
+     IDS_FLAGS_WEB_BLUETOOTH_NAME,
+     IDS_FLAGS_WEB_BLUETOOTH_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableWebBluetooth)},
+    {"enable-devtools-experiments",
+     IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_NAME,
+     IDS_FLAGS_ENABLE_DEVTOOLS_EXPERIMENTS_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kEnableDevToolsExperiments)},
+    {"silent-debugger-extension-api",
+     IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_NAME,
+     IDS_FLAGS_SILENT_DEBUGGER_EXTENSION_API_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kSilentDebuggerExtensionAPI)},
 #if defined(ENABLE_SPELLCHECK)
-  {
-    "spellcheck-autocorrect",
-    IDS_FLAGS_SPELLCHECK_AUTOCORRECT,
-    IDS_FLAGS_SPELLCHECK_AUTOCORRECT_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kEnableSpellingAutoCorrect)
-  },
+    {"spellcheck-autocorrect",
+     IDS_FLAGS_SPELLCHECK_AUTOCORRECT,
+     IDS_FLAGS_SPELLCHECK_AUTOCORRECT_DESCRIPTION,
+     kOsWin | kOsLinux | kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kEnableSpellingAutoCorrect)},
 #endif
-  {
-    "enable-scroll-prediction",
-    IDS_FLAGS_ENABLE_SCROLL_PREDICTION_NAME,
-    IDS_FLAGS_ENABLE_SCROLL_PREDICTION_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kEnableScrollPrediction)
-  },
+    {"enable-scroll-prediction",
+     IDS_FLAGS_ENABLE_SCROLL_PREDICTION_NAME,
+     IDS_FLAGS_ENABLE_SCROLL_PREDICTION_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kEnableScrollPrediction)},
 #if defined(ENABLE_TOPCHROME_MD)
-  {
-    "top-chrome-md",
-    IDS_FLAGS_TOP_CHROME_MD,
-    IDS_FLAGS_TOP_CHROME_MD_DESCRIPTION,
-    kOsWin | kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(
-    switches::kTopChromeMDEnabled,
-    switches::kTopChromeMDDisabled)
-  },
+    {"top-chrome-md",
+     IDS_FLAGS_TOP_CHROME_MD,
+     IDS_FLAGS_TOP_CHROME_MD_DESCRIPTION,
+     kOsWin | kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kTopChromeMDEnabled,
+                               switches::kTopChromeMDDisabled)},
 #endif
-  {
-    "touch-events",
-    IDS_TOUCH_EVENTS_NAME,
-    IDS_TOUCH_EVENTS_DESCRIPTION,
-    kOsDesktop,
-    MULTI_VALUE_TYPE(kTouchEventsChoices)
-  },
-  {
-    "disable-touch-adjustment",
-    IDS_DISABLE_TOUCH_ADJUSTMENT_NAME,
-    IDS_DISABLE_TOUCH_ADJUSTMENT_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS | kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kDisableTouchAdjustment)
-  },
+    {"touch-events",
+     IDS_TOUCH_EVENTS_NAME,
+     IDS_TOUCH_EVENTS_DESCRIPTION,
+     kOsDesktop,
+     MULTI_VALUE_TYPE(kTouchEventsChoices)},
+    {"disable-touch-adjustment",
+     IDS_DISABLE_TOUCH_ADJUSTMENT_NAME,
+     IDS_DISABLE_TOUCH_ADJUSTMENT_DESCRIPTION,
+     kOsWin | kOsLinux | kOsCrOS | kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kDisableTouchAdjustment)},
 #if defined(OS_CHROMEOS)
-  {
-    "network-portal-notification",
-    IDS_FLAGS_NETWORK_PORTAL_NOTIFICATION_NAME,
-    IDS_FLAGS_NETWORK_PORTAL_NOTIFICATION_DESCRIPTION,
-    kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(
-        chromeos::switches::kEnableNetworkPortalNotification,
-        chromeos::switches::kDisableNetworkPortalNotification)
-  },
+    {"network-portal-notification",
+     IDS_FLAGS_NETWORK_PORTAL_NOTIFICATION_NAME,
+     IDS_FLAGS_NETWORK_PORTAL_NOTIFICATION_DESCRIPTION,
+     kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(
+         chromeos::switches::kEnableNetworkPortalNotification,
+         chromeos::switches::kDisableNetworkPortalNotification)},
 #endif
-  {
-    "enable-download-resumption",
-    IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_NAME,
-    IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kEnableDownloadResumption)
-  },
-  {
-    "enable-download-notification",
-    IDS_FLAGS_ENABLE_DOWNLOAD_NOTIFICATION_NAME,
-    IDS_FLAGS_ENABLE_DOWNLOAD_NOTIFICATION_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kEnableDownloadNotification)
-  },
+    {"enable-download-resumption",
+     IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_NAME,
+     IDS_FLAGS_ENABLE_DOWNLOAD_RESUMPTION_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kEnableDownloadResumption)},
+    {"enable-download-notification",
+     IDS_FLAGS_ENABLE_DOWNLOAD_NOTIFICATION_NAME,
+     IDS_FLAGS_ENABLE_DOWNLOAD_NOTIFICATION_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kEnableDownloadNotification)},
 #if defined(ENABLE_PLUGINS)
-  {
-    "allow-nacl-socket-api",
-    IDS_FLAGS_ALLOW_NACL_SOCKET_API_NAME,
-    IDS_FLAGS_ALLOW_NACL_SOCKET_API_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE_AND_VALUE(switches::kAllowNaClSocketAPI, "*")
-  },
+    {"allow-nacl-socket-api",
+     IDS_FLAGS_ALLOW_NACL_SOCKET_API_NAME,
+     IDS_FLAGS_ALLOW_NACL_SOCKET_API_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE_AND_VALUE(switches::kAllowNaClSocketAPI, "*")},
 #endif
 #if defined(OS_CHROMEOS)
-  {
-    "allow-touchpad-three-finger-click",
-    IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_NAME,
-    IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kEnableTouchpadThreeFingerClick)
-  },
-  {
-    "ash-enable-unified-desktop",
-    IDS_FLAGS_ASH_ENABLE_UNIFIED_DESKTOP_NAME,
-    IDS_FLAGS_ASH_ENABLE_UNIFIED_DESKTOP_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshEnableUnifiedDesktop)
-  },
-  {
-    "disable-easy-unlock",
-    IDS_FLAGS_DISABLE_EASY_UNLOCK_NAME,
-    IDS_FLAGS_DISABLE_EASY_UNLOCK_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(proximity_auth::switches::kDisableEasyUnlock)
-  },
-  {
-    "enable-easy-unlock-proximity-detection",
-    IDS_FLAGS_ENABLE_EASY_UNLOCK_PROXIMITY_DETECTION_NAME,
-    IDS_FLAGS_ENABLE_EASY_UNLOCK_PROXIMITY_DETECTION_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(proximity_auth::switches::kEnableProximityDetection)
-  },
-  {
-    "enable-easy-unlock-bluetooth-low-energy-detection",
-    IDS_FLAGS_ENABLE_EASY_UNLOCK_BLUETOOTH_LOW_ENERGY_DISCOVERY_NAME,
-    IDS_FLAGS_ENABLE_EASY_UNLOCK_BLUETOOTH_LOW_ENERGY_DISCOVERY_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(
-        proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)
-  },
+    {"allow-touchpad-three-finger-click",
+     IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_NAME,
+     IDS_FLAGS_ALLOW_TOUCHPAD_THREE_FINGER_CLICK_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kEnableTouchpadThreeFingerClick)},
+    {"ash-enable-unified-desktop",
+     IDS_FLAGS_ASH_ENABLE_UNIFIED_DESKTOP_NAME,
+     IDS_FLAGS_ASH_ENABLE_UNIFIED_DESKTOP_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(ash::switches::kAshEnableUnifiedDesktop)},
+    {"disable-easy-unlock",
+     IDS_FLAGS_DISABLE_EASY_UNLOCK_NAME,
+     IDS_FLAGS_DISABLE_EASY_UNLOCK_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(proximity_auth::switches::kDisableEasyUnlock)},
+    {"enable-easy-unlock-proximity-detection",
+     IDS_FLAGS_ENABLE_EASY_UNLOCK_PROXIMITY_DETECTION_NAME,
+     IDS_FLAGS_ENABLE_EASY_UNLOCK_PROXIMITY_DETECTION_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(proximity_auth::switches::kEnableProximityDetection)},
+    {"enable-easy-unlock-bluetooth-low-energy-detection",
+     IDS_FLAGS_ENABLE_EASY_UNLOCK_BLUETOOTH_LOW_ENERGY_DISCOVERY_NAME,
+     IDS_FLAGS_ENABLE_EASY_UNLOCK_BLUETOOTH_LOW_ENERGY_DISCOVERY_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(
+         proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)},
 #endif
 #if defined(USE_ASH)
-  {
-    "disable-minimize-on-second-launcher-item-click",
-    IDS_FLAGS_DISABLE_MINIMIZE_ON_SECOND_LAUNCHER_ITEM_CLICK_NAME,
-    IDS_FLAGS_DISABLE_MINIMIZE_ON_SECOND_LAUNCHER_ITEM_CLICK_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kDisableMinimizeOnSecondLauncherItemClick)
-  },
-  {
-    "show-touch-hud",
-    IDS_FLAGS_SHOW_TOUCH_HUD_NAME,
-    IDS_FLAGS_SHOW_TOUCH_HUD_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(ash::switches::kAshTouchHud)
-  },
-  {
-    "enable-pinch",
-    IDS_FLAGS_ENABLE_PINCH_SCALE_NAME,
-    IDS_FLAGS_ENABLE_PINCH_SCALE_DESCRIPTION,
-    kOsLinux | kOsWin | kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePinch, switches::kDisablePinch),
-  },
+    {"disable-minimize-on-second-launcher-item-click",
+     IDS_FLAGS_DISABLE_MINIMIZE_ON_SECOND_LAUNCHER_ITEM_CLICK_NAME,
+     IDS_FLAGS_DISABLE_MINIMIZE_ON_SECOND_LAUNCHER_ITEM_CLICK_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kDisableMinimizeOnSecondLauncherItemClick)},
+    {"show-touch-hud",
+     IDS_FLAGS_SHOW_TOUCH_HUD_NAME,
+     IDS_FLAGS_SHOW_TOUCH_HUD_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(ash::switches::kAshTouchHud)},
+    {
+     "enable-pinch",
+     IDS_FLAGS_ENABLE_PINCH_SCALE_NAME,
+     IDS_FLAGS_ENABLE_PINCH_SCALE_DESCRIPTION,
+     kOsLinux | kOsWin | kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePinch, switches::kDisablePinch),
+    },
 #endif  // defined(USE_ASH)
-  {
-    "enable-viewport-meta",
-    IDS_FLAGS_ENABLE_VIEWPORT_META_NAME,
-    IDS_FLAGS_ENABLE_VIEWPORT_META_DESCRIPTION,
-    kOsLinux | kOsWin | kOsCrOS | kOsMac,
-    SINGLE_VALUE_TYPE(switches::kEnableViewportMeta),
-  },
+    {
+     "enable-viewport-meta",
+     IDS_FLAGS_ENABLE_VIEWPORT_META_NAME,
+     IDS_FLAGS_ENABLE_VIEWPORT_META_DESCRIPTION,
+     kOsLinux | kOsWin | kOsCrOS | kOsMac,
+     SINGLE_VALUE_TYPE(switches::kEnableViewportMeta),
+    },
 #if defined(OS_CHROMEOS)
-  {
-    "disable-boot-animation",
-    IDS_FLAGS_DISABLE_BOOT_ANIMATION,
-    IDS_FLAGS_DISABLE_BOOT_ANIMATION_DESCRIPTION,
-    kOsCrOSOwnerOnly,
-    SINGLE_VALUE_TYPE(chromeos::switches::kDisableBootAnimation),
-  },
-  {
-    "enable-video-player-chromecast-support",
-    IDS_FLAGS_ENABLE_VIDEO_PLAYER_CHROMECAST_SUPPORT_NAME,
-    IDS_FLAGS_ENABLE_VIDEO_PLAYER_CHROMECAST_SUPPORT_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kEnableVideoPlayerChromecastSupport)
-  },
-  {
-    "disable-office-editing-component-app",
-    IDS_FLAGS_DISABLE_OFFICE_EDITING_COMPONENT_APP_NAME,
-    IDS_FLAGS_DISABLE_OFFICE_EDITING_COMPONENT_APP_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kDisableOfficeEditingComponentApp),
-  },
-  {
-    "disable-display-color-calibration",
-    IDS_FLAGS_DISABLE_DISPLAY_COLOR_CALIBRATION_NAME,
-    IDS_FLAGS_DISABLE_DISPLAY_COLOR_CALIBRATION_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(ui::switches::kDisableDisplayColorCalibration),
-  },
-  {
-    "ash-disable-screen-orientation-lock",
-    IDS_FLAGS_ASH_DISABLE_SCREEN_ORIENTATION_LOCK_NAME,
-    IDS_FLAGS_ASH_DISABLE_SCREEN_ORIENTATION_LOCK_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshDisableScreenOrientationLock),
-  },
+    {
+     "disable-boot-animation",
+     IDS_FLAGS_DISABLE_BOOT_ANIMATION,
+     IDS_FLAGS_DISABLE_BOOT_ANIMATION_DESCRIPTION,
+     kOsCrOSOwnerOnly,
+     SINGLE_VALUE_TYPE(chromeos::switches::kDisableBootAnimation),
+    },
+    {"enable-video-player-chromecast-support",
+     IDS_FLAGS_ENABLE_VIDEO_PLAYER_CHROMECAST_SUPPORT_NAME,
+     IDS_FLAGS_ENABLE_VIDEO_PLAYER_CHROMECAST_SUPPORT_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(
+         chromeos::switches::kEnableVideoPlayerChromecastSupport)},
+    {
+     "disable-office-editing-component-app",
+     IDS_FLAGS_DISABLE_OFFICE_EDITING_COMPONENT_APP_NAME,
+     IDS_FLAGS_DISABLE_OFFICE_EDITING_COMPONENT_APP_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kDisableOfficeEditingComponentApp),
+    },
+    {
+     "disable-display-color-calibration",
+     IDS_FLAGS_DISABLE_DISPLAY_COLOR_CALIBRATION_NAME,
+     IDS_FLAGS_DISABLE_DISPLAY_COLOR_CALIBRATION_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(ui::switches::kDisableDisplayColorCalibration),
+    },
+    {
+     "ash-disable-screen-orientation-lock",
+     IDS_FLAGS_ASH_DISABLE_SCREEN_ORIENTATION_LOCK_NAME,
+     IDS_FLAGS_ASH_DISABLE_SCREEN_ORIENTATION_LOCK_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(ash::switches::kAshDisableScreenOrientationLock),
+    },
 #endif  // defined(OS_CHROMEOS)
-  { "disable-accelerated-video-decode",
-    IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_NAME,
-    IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_DESCRIPTION,
-    kOsMac | kOsWin | kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kDisableAcceleratedVideoDecode),
-  },
+    {
+     "disable-accelerated-video-decode",
+     IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_NAME,
+     IDS_FLAGS_DISABLE_ACCELERATED_VIDEO_DECODE_DESCRIPTION,
+     kOsMac | kOsWin | kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kDisableAcceleratedVideoDecode),
+    },
 #if defined(USE_ASH)
-  {
-    "ash-debug-shortcuts",
-    IDS_FLAGS_DEBUG_SHORTCUTS_NAME,
-    IDS_FLAGS_DEBUG_SHORTCUTS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(ash::switches::kAshDebugShortcuts),
-  },
-  {
-    "ash-disable-maximize-mode-window-backdrop",
-    IDS_FLAGS_ASH_DISABLE_MAXIMIZE_MODE_WINDOW_BACKDROP_NAME,
-    IDS_FLAGS_ASH_DISABLE_MAXIMIZE_MODE_WINDOW_BACKDROP_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshDisableMaximizeModeWindowBackdrop),
-  },
-  { "ash-enable-touch-view-testing",
-    IDS_FLAGS_ASH_ENABLE_TOUCH_VIEW_TESTING_NAME,
-    IDS_FLAGS_ASH_ENABLE_TOUCH_VIEW_TESTING_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshEnableTouchViewTesting),
-  },
-  {
-    "disable-touch-feedback",
-    IDS_FLAGS_DISABLE_TOUCH_FEEDBACK_NAME,
-    IDS_FLAGS_DISABLE_TOUCH_FEEDBACK_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kDisableTouchFeedback),
-  },
-  { "ash-enable-mirrored-screen",
-    IDS_FLAGS_ASH_ENABLE_MIRRORED_SCREEN_NAME,
-    IDS_FLAGS_ASH_ENABLE_MIRRORED_SCREEN_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshEnableMirroredScreen),
-  },
-  {
-    "ash-enable-screen-rotation-animations",
-    IDS_FLAGS_ASH_ENABLE_SCREEN_ROTATION_ANIMATION_NAME,
-    IDS_FLAGS_ASH_ENABLE_SCREEN_ROTATION_ANIMATION_DESCRIPTION,
-    kOsCrOS,
-    MULTI_VALUE_TYPE(kAshScreenRotationAnimationChoices)
-  },
-  {
-    "ash-stable-overview-order",
-    IDS_FLAGS_ASH_STABLE_OVERVIEW_ORDER_NAME,
-    IDS_FLAGS_ASH_STABLE_OVERVIEW_ORDER_DESCRIPTION,
-    kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(ash::switches::kAshEnableStableOverviewOrder,
-                              ash::switches::kAshDisableStableOverviewOrder),
-  },
+    {
+     "ash-debug-shortcuts",
+     IDS_FLAGS_DEBUG_SHORTCUTS_NAME,
+     IDS_FLAGS_DEBUG_SHORTCUTS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(ash::switches::kAshDebugShortcuts),
+    },
+    {
+     "ash-disable-maximize-mode-window-backdrop",
+     IDS_FLAGS_ASH_DISABLE_MAXIMIZE_MODE_WINDOW_BACKDROP_NAME,
+     IDS_FLAGS_ASH_DISABLE_MAXIMIZE_MODE_WINDOW_BACKDROP_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(ash::switches::kAshDisableMaximizeModeWindowBackdrop),
+    },
+    {
+     "ash-enable-touch-view-testing",
+     IDS_FLAGS_ASH_ENABLE_TOUCH_VIEW_TESTING_NAME,
+     IDS_FLAGS_ASH_ENABLE_TOUCH_VIEW_TESTING_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(ash::switches::kAshEnableTouchViewTesting),
+    },
+    {
+     "disable-touch-feedback",
+     IDS_FLAGS_DISABLE_TOUCH_FEEDBACK_NAME,
+     IDS_FLAGS_DISABLE_TOUCH_FEEDBACK_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kDisableTouchFeedback),
+    },
+    {
+     "ash-enable-mirrored-screen",
+     IDS_FLAGS_ASH_ENABLE_MIRRORED_SCREEN_NAME,
+     IDS_FLAGS_ASH_ENABLE_MIRRORED_SCREEN_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(ash::switches::kAshEnableMirroredScreen),
+    },
+    {"ash-enable-screen-rotation-animations",
+     IDS_FLAGS_ASH_ENABLE_SCREEN_ROTATION_ANIMATION_NAME,
+     IDS_FLAGS_ASH_ENABLE_SCREEN_ROTATION_ANIMATION_DESCRIPTION,
+     kOsCrOS,
+     MULTI_VALUE_TYPE(kAshScreenRotationAnimationChoices)},
+    {
+     "ash-stable-overview-order",
+     IDS_FLAGS_ASH_STABLE_OVERVIEW_ORDER_NAME,
+     IDS_FLAGS_ASH_STABLE_OVERVIEW_ORDER_DESCRIPTION,
+     kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(ash::switches::kAshEnableStableOverviewOrder,
+                               ash::switches::kAshDisableStableOverviewOrder),
+    },
 #endif  // defined(USE_ASH)
 #if defined(OS_CHROMEOS)
-  {
-    "disable-cloud-import",
-    IDS_FLAGS_DISABLE_CLOUD_IMPORT,
-    IDS_FLAGS_DISABLE_CLOUD_IMPORT_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kDisableCloudImport)
-  },
-  {
-    "enable-request-tablet-site",
-    IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_NAME,
-    IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kEnableRequestTabletSite)
-  },
+    {"disable-cloud-import",
+     IDS_FLAGS_DISABLE_CLOUD_IMPORT,
+     IDS_FLAGS_DISABLE_CLOUD_IMPORT_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kDisableCloudImport)},
+    {"enable-request-tablet-site",
+     IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_NAME,
+     IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kEnableRequestTabletSite)},
 #endif
-  {
-    "debug-packed-apps",
-    IDS_FLAGS_DEBUG_PACKED_APP_NAME,
-    IDS_FLAGS_DEBUG_PACKED_APP_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kDebugPackedApps)
-  },
-  {
-    "enable-password-generation",
-    IDS_FLAGS_ENABLE_PASSWORD_GENERATION_NAME,
-    IDS_FLAGS_ENABLE_PASSWORD_GENERATION_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS | kOsMac | kOsAndroid,
-    ENABLE_DISABLE_VALUE_TYPE(autofill::switches::kEnablePasswordGeneration,
-                              autofill::switches::kDisablePasswordGeneration)
-  },
-  {
-    "enable-automatic-password-saving",
-    IDS_FLAGS_ENABLE_AUTOMATIC_PASSWORD_SAVING_NAME,
-    IDS_FLAGS_ENABLE_AUTOMATIC_PASSWORD_SAVING_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(
-        password_manager::switches::kEnableAutomaticPasswordSaving)
-  },
-  {
-    "password-manager-reauthentication",
-    IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_NAME,
-    IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_DESCRIPTION,
-    kOsMac | kOsWin,
-    SINGLE_VALUE_TYPE(switches::kDisablePasswordManagerReauthentication)
-  },
-  {
-    "enable-password-force-saving",
-    IDS_FLAGS_ENABLE_PASSWORD_FORCE_SAVING_NAME,
-    IDS_FLAGS_ENABLE_PASSWORD_FORCE_SAVING_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(
-        password_manager::switches::kEnablePasswordForceSaving)
-  },
-  {
-    "enable-password-link",
-    IDS_FLAGS_PASSWORD_MANAGER_LINK_NAME,
-    IDS_FLAGS_PASSWORD_MANAGER_LINK_DESCRIPTION,
-    kOsAndroid | kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE(
-        password_manager::switches::kEnablePasswordLink,
-        password_manager::switches::kDisablePasswordLink)
-  },
-  {
-    "enable-affiliation-based-matching",
-    IDS_FLAGS_ENABLE_AFFILIATION_BASED_MATCHING_NAME,
-    IDS_FLAGS_ENABLE_AFFILIATION_BASED_MATCHING_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS | kOsMac | kOsAndroid,
-    ENABLE_DISABLE_VALUE_TYPE(
-        password_manager::switches::kEnableAffiliationBasedMatching,
-        password_manager::switches::kDisableAffiliationBasedMatching)
-  },
-  {
-    "enable-deferred-image-decoding",
-    IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_NAME,
-    IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_DESCRIPTION,
-    kOsMac | kOsLinux | kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kEnableDeferredImageDecoding)
-  },
-  {
-    "wallet-service-use-sandbox",
-    IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_NAME,
-    IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_DESCRIPTION,
-    kOsAndroid | kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
-        autofill::switches::kWalletServiceUseSandbox, "1",
-        autofill::switches::kWalletServiceUseSandbox, "0")
-  },
+    {"debug-packed-apps",
+     IDS_FLAGS_DEBUG_PACKED_APP_NAME,
+     IDS_FLAGS_DEBUG_PACKED_APP_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kDebugPackedApps)},
+    {"enable-password-generation",
+     IDS_FLAGS_ENABLE_PASSWORD_GENERATION_NAME,
+     IDS_FLAGS_ENABLE_PASSWORD_GENERATION_DESCRIPTION,
+     kOsWin | kOsLinux | kOsCrOS | kOsMac | kOsAndroid,
+     ENABLE_DISABLE_VALUE_TYPE(autofill::switches::kEnablePasswordGeneration,
+                               autofill::switches::kDisablePasswordGeneration)},
+    {"enable-automatic-password-saving",
+     IDS_FLAGS_ENABLE_AUTOMATIC_PASSWORD_SAVING_NAME,
+     IDS_FLAGS_ENABLE_AUTOMATIC_PASSWORD_SAVING_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(
+         password_manager::switches::kEnableAutomaticPasswordSaving)},
+    {"password-manager-reauthentication",
+     IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_NAME,
+     IDS_FLAGS_PASSWORD_MANAGER_REAUTHENTICATION_DESCRIPTION,
+     kOsMac | kOsWin,
+     SINGLE_VALUE_TYPE(switches::kDisablePasswordManagerReauthentication)},
+    {"enable-password-force-saving",
+     IDS_FLAGS_ENABLE_PASSWORD_FORCE_SAVING_NAME,
+     IDS_FLAGS_ENABLE_PASSWORD_FORCE_SAVING_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(password_manager::switches::kEnablePasswordForceSaving)},
+    {"enable-password-link",
+     IDS_FLAGS_PASSWORD_MANAGER_LINK_NAME,
+     IDS_FLAGS_PASSWORD_MANAGER_LINK_DESCRIPTION,
+     kOsAndroid | kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(
+         password_manager::switches::kEnablePasswordLink,
+         password_manager::switches::kDisablePasswordLink)},
+    {"enable-affiliation-based-matching",
+     IDS_FLAGS_ENABLE_AFFILIATION_BASED_MATCHING_NAME,
+     IDS_FLAGS_ENABLE_AFFILIATION_BASED_MATCHING_DESCRIPTION,
+     kOsWin | kOsLinux | kOsCrOS | kOsMac | kOsAndroid,
+     ENABLE_DISABLE_VALUE_TYPE(
+         password_manager::switches::kEnableAffiliationBasedMatching,
+         password_manager::switches::kDisableAffiliationBasedMatching)},
+    {"wallet-service-use-sandbox",
+     IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_NAME,
+     IDS_FLAGS_WALLET_SERVICE_USE_SANDBOX_DESCRIPTION,
+     kOsAndroid | kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
+         autofill::switches::kWalletServiceUseSandbox,
+         "1",
+         autofill::switches::kWalletServiceUseSandbox,
+         "0")},
 #if defined(USE_AURA)
-  {
-    "overscroll-history-navigation",
-    IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_NAME,
-    IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kOverscrollHistoryNavigationChoices)
-  },
+    {"overscroll-history-navigation",
+     IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_NAME,
+     IDS_FLAGS_OVERSCROLL_HISTORY_NAVIGATION_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kOverscrollHistoryNavigationChoices)},
 #endif
-  {
-    "scroll-end-effect",
-    IDS_FLAGS_SCROLL_END_EFFECT_NAME,
-    IDS_FLAGS_SCROLL_END_EFFECT_DESCRIPTION,
-    kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
-        switches::kScrollEndEffect, "1",
-        switches::kScrollEndEffect, "0")
-  },
-  {
-    "enable-icon-ntp",
-    IDS_FLAGS_ENABLE_ICON_NTP_NAME,
-    IDS_FLAGS_ENABLE_ICON_NTP_DESCRIPTION,
-    kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableIconNtp,
-                              switches::kDisableIconNtp)
-  },
-  {
-    "enable-touch-drag-drop",
-    IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_NAME,
-    IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_DESCRIPTION,
-    kOsWin | kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchDragDrop,
-                              switches::kDisableTouchDragDrop)
-  },
-  {
-    "enable-touch-editing",
-    IDS_FLAGS_ENABLE_TOUCH_EDITING_NAME,
-    IDS_FLAGS_ENABLE_TOUCH_EDITING_DESCRIPTION,
-    kOsCrOS | kOsWin | kOsLinux,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchEditing,
-                              switches::kDisableTouchEditing)
-  },
-  {
-      "touch-selection-strategy",
-      IDS_FLAGS_TOUCH_SELECTION_STRATEGY_NAME,
-      IDS_FLAGS_TOUCH_SELECTION_STRATEGY_DESCRIPTION,
-      kOsAndroid,   // TODO(mfomitchev): Add CrOS/Win/Linux support soon.
-      MULTI_VALUE_TYPE(kTouchTextSelectionStrategyChoices)
-  },
-  {
-    "enable-stale-while-revalidate",
-    IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_NAME,
-    IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableStaleWhileRevalidate)
-  },
-  {
-    "enable-suggestions-service",
-    IDS_FLAGS_ENABLE_SUGGESTIONS_SERVICE_NAME,
-    IDS_FLAGS_ENABLE_SUGGESTIONS_SERVICE_DESCRIPTION,
-    kOsAndroid | kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSuggestionsService,
-                              switches::kDisableSuggestionsService)
-  },
-  {
-    "enable-supervised-user-managed-bookmarks-folder",
-    IDS_FLAGS_ENABLE_SUPERVISED_USER_MANAGED_BOOKMARKS_FOLDER_NAME,
-    IDS_FLAGS_ENABLE_SUPERVISED_USER_MANAGED_BOOKMARKS_FOLDER_DESCRIPTION,
-    kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kEnableSupervisedUserManagedBookmarksFolder)
-  },
+    {"scroll-end-effect",
+     IDS_FLAGS_SCROLL_END_EFFECT_NAME,
+     IDS_FLAGS_SCROLL_END_EFFECT_DESCRIPTION,
+     kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(switches::kScrollEndEffect,
+                                         "1",
+                                         switches::kScrollEndEffect,
+                                         "0")},
+    {"enable-icon-ntp",
+     IDS_FLAGS_ENABLE_ICON_NTP_NAME,
+     IDS_FLAGS_ENABLE_ICON_NTP_DESCRIPTION,
+     kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableIconNtp,
+                               switches::kDisableIconNtp)},
+    {"enable-touch-drag-drop",
+     IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_NAME,
+     IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_DESCRIPTION,
+     kOsWin | kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchDragDrop,
+                               switches::kDisableTouchDragDrop)},
+    {"enable-touch-editing",
+     IDS_FLAGS_ENABLE_TOUCH_EDITING_NAME,
+     IDS_FLAGS_ENABLE_TOUCH_EDITING_DESCRIPTION,
+     kOsCrOS | kOsWin | kOsLinux,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTouchEditing,
+                               switches::kDisableTouchEditing)},
+    {"touch-selection-strategy",
+     IDS_FLAGS_TOUCH_SELECTION_STRATEGY_NAME,
+     IDS_FLAGS_TOUCH_SELECTION_STRATEGY_DESCRIPTION,
+     kOsAndroid,  // TODO(mfomitchev): Add CrOS/Win/Linux support soon.
+     MULTI_VALUE_TYPE(kTouchTextSelectionStrategyChoices)},
+    {"enable-stale-while-revalidate",
+     IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_NAME,
+     IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableStaleWhileRevalidate)},
+    {"enable-suggestions-service",
+     IDS_FLAGS_ENABLE_SUGGESTIONS_SERVICE_NAME,
+     IDS_FLAGS_ENABLE_SUGGESTIONS_SERVICE_DESCRIPTION,
+     kOsAndroid | kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSuggestionsService,
+                               switches::kDisableSuggestionsService)},
+    {"enable-supervised-user-managed-bookmarks-folder",
+     IDS_FLAGS_ENABLE_SUPERVISED_USER_MANAGED_BOOKMARKS_FOLDER_NAME,
+     IDS_FLAGS_ENABLE_SUPERVISED_USER_MANAGED_BOOKMARKS_FOLDER_DESCRIPTION,
+     kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kEnableSupervisedUserManagedBookmarksFolder)},
 #if defined(ENABLE_APP_LIST)
-  {
-    "enable-sync-app-list",
-    IDS_FLAGS_ENABLE_SYNC_APP_LIST_NAME,
-    IDS_FLAGS_ENABLE_SYNC_APP_LIST_DESCRIPTION,
-    kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE(app_list::switches::kEnableSyncAppList,
-                              app_list::switches::kDisableSyncAppList)
-  },
+    {"enable-sync-app-list",
+     IDS_FLAGS_ENABLE_SYNC_APP_LIST_NAME,
+     IDS_FLAGS_ENABLE_SYNC_APP_LIST_DESCRIPTION,
+     kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(app_list::switches::kEnableSyncAppList,
+                               app_list::switches::kDisableSyncAppList)},
 #endif
 #if defined(OS_MACOSX)
-  {
-    "enable-avfoundation",
-    IDS_FLAGS_ENABLE_AVFOUNDATION_NAME,
-    IDS_FLAGS_ENABLE_AVFOUNDATION_DESCRIPTION,
-    kOsMac,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAVFoundation,
-                              switches::kForceQTKit)
-  },
+    {"enable-avfoundation",
+     IDS_FLAGS_ENABLE_AVFOUNDATION_NAME,
+     IDS_FLAGS_ENABLE_AVFOUNDATION_DESCRIPTION,
+     kOsMac,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAVFoundation,
+                               switches::kForceQTKit)},
 #endif
-  {
-    "lcd-text-aa",
-    IDS_FLAGS_LCD_TEXT_NAME,
-    IDS_FLAGS_LCD_TEXT_DESCRIPTION,
-    kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableLCDText,
-                              switches::kDisableLCDText)
-  },
+    {"lcd-text-aa",
+     IDS_FLAGS_LCD_TEXT_NAME,
+     IDS_FLAGS_LCD_TEXT_DESCRIPTION,
+     kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableLCDText,
+                               switches::kDisableLCDText)},
 #if defined(OS_ANDROID) || defined(OS_MACOSX)
-  {
-    "delegated-renderer",
-    IDS_FLAGS_DELEGATED_RENDERER_NAME,
-    IDS_FLAGS_DELEGATED_RENDERER_DESCRIPTION,
-    kOsAndroid,  // TODO(ccameron) Add mac support soon.
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDelegatedRenderer,
-                              switches::kDisableDelegatedRenderer)
-  },
+    {"delegated-renderer",
+     IDS_FLAGS_DELEGATED_RENDERER_NAME,
+     IDS_FLAGS_DELEGATED_RENDERER_DESCRIPTION,
+     kOsAndroid,  // TODO(ccameron) Add mac support soon.
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDelegatedRenderer,
+                               switches::kDisableDelegatedRenderer)},
 #endif
-  {
-    "enable-offer-store-unmasked-wallet-cards",
-    IDS_FLAGS_ENABLE_OFFER_STORE_UNMASKED_WALLET_CARDS,
-    IDS_FLAGS_ENABLE_OFFER_STORE_UNMASKED_WALLET_CARDS_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE(
-        autofill::switches::kEnableOfferStoreUnmaskedWalletCards,
-        autofill::switches::kDisableOfferStoreUnmaskedWalletCards)
-  },
-  {
-    "enable-offline-auto-reload",
-    IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_NAME,
-    IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOfflineAutoReload,
-                              switches::kDisableOfflineAutoReload)
-  },
-  {
-    "enable-offline-auto-reload-visible-only",
-    IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_VISIBLE_ONLY_NAME,
-    IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_VISIBLE_ONLY_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOfflineAutoReloadVisibleOnly,
-                              switches::kDisableOfflineAutoReloadVisibleOnly)
-  },
-  {
-    "show-saved-copy",
-    IDS_FLAGS_SHOW_SAVED_COPY_NAME,
-    IDS_FLAGS_SHOW_SAVED_COPY_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kShowSavedCopyChoices)
-  },
-  {
-    "default-tile-width",
-    IDS_FLAGS_DEFAULT_TILE_WIDTH_NAME,
-    IDS_FLAGS_DEFAULT_TILE_WIDTH_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kDefaultTileWidthChoices)
-  },
-  {
-    "default-tile-height",
-    IDS_FLAGS_DEFAULT_TILE_HEIGHT_NAME,
-    IDS_FLAGS_DEFAULT_TILE_HEIGHT_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kDefaultTileHeightChoices)
-  },
+    {"enable-offer-store-unmasked-wallet-cards",
+     IDS_FLAGS_ENABLE_OFFER_STORE_UNMASKED_WALLET_CARDS,
+     IDS_FLAGS_ENABLE_OFFER_STORE_UNMASKED_WALLET_CARDS_DESCRIPTION,
+     kOsAll,
+     ENABLE_DISABLE_VALUE_TYPE(
+         autofill::switches::kEnableOfferStoreUnmaskedWalletCards,
+         autofill::switches::kDisableOfferStoreUnmaskedWalletCards)},
+    {"enable-offline-auto-reload",
+     IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_NAME,
+     IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_DESCRIPTION,
+     kOsAll,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOfflineAutoReload,
+                               switches::kDisableOfflineAutoReload)},
+    {"enable-offline-auto-reload-visible-only",
+     IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_VISIBLE_ONLY_NAME,
+     IDS_FLAGS_ENABLE_OFFLINE_AUTO_RELOAD_VISIBLE_ONLY_DESCRIPTION,
+     kOsAll,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOfflineAutoReloadVisibleOnly,
+                               switches::kDisableOfflineAutoReloadVisibleOnly)},
+    {"show-saved-copy",
+     IDS_FLAGS_SHOW_SAVED_COPY_NAME,
+     IDS_FLAGS_SHOW_SAVED_COPY_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kShowSavedCopyChoices)},
+    {"default-tile-width",
+     IDS_FLAGS_DEFAULT_TILE_WIDTH_NAME,
+     IDS_FLAGS_DEFAULT_TILE_WIDTH_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kDefaultTileWidthChoices)},
+    {"default-tile-height",
+     IDS_FLAGS_DEFAULT_TILE_HEIGHT_NAME,
+     IDS_FLAGS_DEFAULT_TILE_HEIGHT_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kDefaultTileHeightChoices)},
 #if defined(OS_ANDROID)
-  {
-    "disable-gesture-requirement-for-media-playback",
-    IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_NAME,
-    IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kDisableGestureRequirementForMediaPlayback)
-  },
+    {"disable-gesture-requirement-for-media-playback",
+     IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_NAME,
+     IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kDisableGestureRequirementForMediaPlayback)},
 #endif
 #if defined(OS_CHROMEOS)
-  {
-    "enable-virtual-keyboard",
-    IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_NAME,
-    IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(keyboard::switches::kEnableVirtualKeyboard)
-  },
-  {
-    "enable-virtual-keyboard-overscroll",
-    IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_OVERSCROLL_NAME,
-    IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_OVERSCROLL_DESCRIPTION,
-    kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(
-        keyboard::switches::kEnableVirtualKeyboardOverscroll,
-        keyboard::switches::kDisableVirtualKeyboardOverscroll)
-  },
-  {
-    "enable-swipe-selection",
-    IDS_FLAGS_ENABLE_SWIPE_SELECTION_NAME,
-    IDS_FLAGS_ENABLE_SWIPE_SELECTION_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(keyboard::switches::kEnableSwipeSelection)
-  },
-  {
-    "enable-input-view",
-    IDS_FLAGS_ENABLE_INPUT_VIEW_NAME,
-    IDS_FLAGS_ENABLE_INPUT_VIEW_DESCRIPTION,
-    kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(keyboard::switches::kEnableInputView,
-                              keyboard::switches::kDisableInputView)
-  },
-  {
-    "disable-new-korean-ime",
-    IDS_FLAGS_DISABLE_NEW_KOREAN_IME_NAME,
-    IDS_FLAGS_DISABLE_NEW_KOREAN_IME_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kDisableNewKoreanIme)
-  },
-  {
-    "disable-new-md-input-view",
-    IDS_FLAGS_DISABLE_NEW_MD_INPUT_VIEW_NAME,
-    IDS_FLAGS_DISABLE_NEW_MD_INPUT_VIEW_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(keyboard::switches::kDisableNewMDInputView)
-  },
-  {
-    "enable-physical-keyboard-autocorrect",
-    IDS_FLAGS_ENABLE_PHYSICAL_KEYBOARD_AUTOCORRECT_NAME,
-    IDS_FLAGS_ENABLE_PHYSICAL_KEYBOARD_AUTOCORRECT_DESCRIPTION,
-    kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(
-        chromeos::switches::kEnablePhysicalKeyboardAutocorrect,
-        chromeos::switches::kDisablePhysicalKeyboardAutocorrect)
-  },
-  {
-    "disable-voice-input",
-    IDS_FLAGS_DISABLE_VOICE_INPUT_NAME,
-    IDS_FLAGS_DISABLE_VOICE_INPUT_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(keyboard::switches::kDisableVoiceInput)
-  },
-  {
-    "enable-experimental-input-view-features",
-    IDS_FLAGS_ENABLE_EXPERIMENTAL_INPUT_VIEW_FEATURES_NAME,
-    IDS_FLAGS_ENABLE_EXPERIMENTAL_INPUT_VIEW_FEATURES_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(keyboard::switches::kEnableExperimentalInputViewFeatures)
-  },
-  {
-    "floating-virtual-keyboard",
-    IDS_FLAGS_FLOATING_VIRTUAL_KEYBOARD_NAME,
-    IDS_FLAGS_FLOATING_VIRTUAL_KEYBOARD_DESCRIPTION,
-    kOsCrOS,
-    MULTI_VALUE_TYPE(kFloatingVirtualKeyboardChoices)
-  },
-  {
-    "smart-virtual-keyboard",
-    IDS_FLAGS_SMART_VIRTUAL_KEYBOARD_NAME,
-    IDS_FLAGS_SMART_VIRTUAL_KEYBOARD_DESCRIPTION,
-    kOsCrOS,
-    MULTI_VALUE_TYPE(kSmartVirtualKeyboardChoices)
-  },
-  {
-    "gesture-typing",
-    IDS_FLAGS_GESTURE_TYPING_NAME,
-    IDS_FLAGS_GESTURE_TYPING_DESCRIPTION,
-    kOsCrOS,
-    MULTI_VALUE_TYPE(kGestureTypingChoices)
-  },
-  {
-    "gesture-editing",
-    IDS_FLAGS_GESTURE_EDITING_NAME,
-    IDS_FLAGS_GESTURE_EDITING_DESCRIPTION,
-    kOsCrOS,
-    MULTI_VALUE_TYPE(kGestureEditingChoices)
-  },
-  {
-    "enable-fullscreen-app-list",
-    IDS_FLAGS_FULLSCREEN_APP_LIST_NAME,
-    IDS_FLAGS_FULLSCREEN_APP_LIST_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshEnableFullscreenAppList)
-  },
+    {"enable-virtual-keyboard",
+     IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_NAME,
+     IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(keyboard::switches::kEnableVirtualKeyboard)},
+    {"enable-virtual-keyboard-overscroll",
+     IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_OVERSCROLL_NAME,
+     IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_OVERSCROLL_DESCRIPTION,
+     kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(
+         keyboard::switches::kEnableVirtualKeyboardOverscroll,
+         keyboard::switches::kDisableVirtualKeyboardOverscroll)},
+    {"enable-swipe-selection",
+     IDS_FLAGS_ENABLE_SWIPE_SELECTION_NAME,
+     IDS_FLAGS_ENABLE_SWIPE_SELECTION_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(keyboard::switches::kEnableSwipeSelection)},
+    {"enable-input-view",
+     IDS_FLAGS_ENABLE_INPUT_VIEW_NAME,
+     IDS_FLAGS_ENABLE_INPUT_VIEW_DESCRIPTION,
+     kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(keyboard::switches::kEnableInputView,
+                               keyboard::switches::kDisableInputView)},
+    {"disable-new-korean-ime",
+     IDS_FLAGS_DISABLE_NEW_KOREAN_IME_NAME,
+     IDS_FLAGS_DISABLE_NEW_KOREAN_IME_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kDisableNewKoreanIme)},
+    {"disable-new-md-input-view",
+     IDS_FLAGS_DISABLE_NEW_MD_INPUT_VIEW_NAME,
+     IDS_FLAGS_DISABLE_NEW_MD_INPUT_VIEW_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(keyboard::switches::kDisableNewMDInputView)},
+    {"enable-physical-keyboard-autocorrect",
+     IDS_FLAGS_ENABLE_PHYSICAL_KEYBOARD_AUTOCORRECT_NAME,
+     IDS_FLAGS_ENABLE_PHYSICAL_KEYBOARD_AUTOCORRECT_DESCRIPTION,
+     kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(
+         chromeos::switches::kEnablePhysicalKeyboardAutocorrect,
+         chromeos::switches::kDisablePhysicalKeyboardAutocorrect)},
+    {"disable-voice-input",
+     IDS_FLAGS_DISABLE_VOICE_INPUT_NAME,
+     IDS_FLAGS_DISABLE_VOICE_INPUT_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(keyboard::switches::kDisableVoiceInput)},
+    {"enable-experimental-input-view-features",
+     IDS_FLAGS_ENABLE_EXPERIMENTAL_INPUT_VIEW_FEATURES_NAME,
+     IDS_FLAGS_ENABLE_EXPERIMENTAL_INPUT_VIEW_FEATURES_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(
+         keyboard::switches::kEnableExperimentalInputViewFeatures)},
+    {"floating-virtual-keyboard",
+     IDS_FLAGS_FLOATING_VIRTUAL_KEYBOARD_NAME,
+     IDS_FLAGS_FLOATING_VIRTUAL_KEYBOARD_DESCRIPTION,
+     kOsCrOS,
+     MULTI_VALUE_TYPE(kFloatingVirtualKeyboardChoices)},
+    {"smart-virtual-keyboard",
+     IDS_FLAGS_SMART_VIRTUAL_KEYBOARD_NAME,
+     IDS_FLAGS_SMART_VIRTUAL_KEYBOARD_DESCRIPTION,
+     kOsCrOS,
+     MULTI_VALUE_TYPE(kSmartVirtualKeyboardChoices)},
+    {"gesture-typing",
+     IDS_FLAGS_GESTURE_TYPING_NAME,
+     IDS_FLAGS_GESTURE_TYPING_DESCRIPTION,
+     kOsCrOS,
+     MULTI_VALUE_TYPE(kGestureTypingChoices)},
+    {"gesture-editing",
+     IDS_FLAGS_GESTURE_EDITING_NAME,
+     IDS_FLAGS_GESTURE_EDITING_DESCRIPTION,
+     kOsCrOS,
+     MULTI_VALUE_TYPE(kGestureEditingChoices)},
+    {"enable-fullscreen-app-list",
+     IDS_FLAGS_FULLSCREEN_APP_LIST_NAME,
+     IDS_FLAGS_FULLSCREEN_APP_LIST_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(ash::switches::kAshEnableFullscreenAppList)},
 #endif
-  {
-    "enable-simple-cache-backend",
-    IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_NAME,
-    IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_DESCRIPTION,
-    kOsWin | kOsMac | kOsLinux | kOsCrOS,
-    MULTI_VALUE_TYPE(kSimpleCacheBackendChoices)
-  },
-  {
-    "enable-tcp-fast-open",
-    IDS_FLAGS_ENABLE_TCP_FAST_OPEN_NAME,
-    IDS_FLAGS_ENABLE_TCP_FAST_OPEN_DESCRIPTION,
-    kOsLinux | kOsCrOS | kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableTcpFastOpen)
-  },
+    {"enable-simple-cache-backend",
+     IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_NAME,
+     IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_DESCRIPTION,
+     kOsWin | kOsMac | kOsLinux | kOsCrOS,
+     MULTI_VALUE_TYPE(kSimpleCacheBackendChoices)},
+    {"enable-tcp-fast-open",
+     IDS_FLAGS_ENABLE_TCP_FAST_OPEN_NAME,
+     IDS_FLAGS_ENABLE_TCP_FAST_OPEN_DESCRIPTION,
+     kOsLinux | kOsCrOS | kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kEnableTcpFastOpen)},
 #if defined(ENABLE_SERVICE_DISCOVERY)
-  {
-    "device-discovery-notifications",
-    IDS_FLAGS_DEVICE_DISCOVERY_NOTIFICATIONS_NAME,
-    IDS_FLAGS_DEVICE_DISCOVERY_NOTIFICATIONS_DESCRIPTION,
-    kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDeviceDiscoveryNotifications,
-                              switches::kDisableDeviceDiscoveryNotifications)
-  },
-  {
-    "enable-print-preview-register-promos",
-    IDS_FLAGS_ENABLE_PRINT_PREVIEW_REGISTER_PROMOS_NAME,
-    IDS_FLAGS_ENABLE_PRINT_PREVIEW_REGISTER_PROMOS_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kEnablePrintPreviewRegisterPromos)
-  },
+    {"device-discovery-notifications",
+     IDS_FLAGS_DEVICE_DISCOVERY_NOTIFICATIONS_NAME,
+     IDS_FLAGS_DEVICE_DISCOVERY_NOTIFICATIONS_DESCRIPTION,
+     kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDeviceDiscoveryNotifications,
+                               switches::kDisableDeviceDiscoveryNotifications)},
+    {"enable-print-preview-register-promos",
+     IDS_FLAGS_ENABLE_PRINT_PREVIEW_REGISTER_PROMOS_NAME,
+     IDS_FLAGS_ENABLE_PRINT_PREVIEW_REGISTER_PROMOS_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kEnablePrintPreviewRegisterPromos)},
 #endif  // ENABLE_SERVICE_DISCOVERY
 #if defined(OS_WIN)
-  {
-    "enable-cloud-print-xps",
-    IDS_FLAGS_ENABLE_CLOUD_PRINT_XPS_NAME,
-    IDS_FLAGS_ENABLE_CLOUD_PRINT_XPS_DESCRIPTION,
-    kOsWin,
-    SINGLE_VALUE_TYPE(switches::kEnableCloudPrintXps)
-  },
+    {"enable-cloud-print-xps",
+     IDS_FLAGS_ENABLE_CLOUD_PRINT_XPS_NAME,
+     IDS_FLAGS_ENABLE_CLOUD_PRINT_XPS_DESCRIPTION,
+     kOsWin,
+     SINGLE_VALUE_TYPE(switches::kEnableCloudPrintXps)},
 #endif
 #if defined(USE_AURA)
-  {
-    "tab-capture-upscale-quality",
-    IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_NAME,
-    IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kTabCaptureUpscaleQualityChoices)
-  },
-  {
-    "tab-capture-downscale-quality",
-    IDS_FLAGS_TAB_CAPTURE_DOWNSCALE_QUALITY_NAME,
-    IDS_FLAGS_TAB_CAPTURE_DOWNSCALE_QUALITY_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kTabCaptureDownscaleQualityChoices)
-  },
+    {"tab-capture-upscale-quality",
+     IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_NAME,
+     IDS_FLAGS_TAB_CAPTURE_UPSCALE_QUALITY_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kTabCaptureUpscaleQualityChoices)},
+    {"tab-capture-downscale-quality",
+     IDS_FLAGS_TAB_CAPTURE_DOWNSCALE_QUALITY_NAME,
+     IDS_FLAGS_TAB_CAPTURE_DOWNSCALE_QUALITY_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kTabCaptureDownscaleQualityChoices)},
 #endif
 #if defined(TOOLKIT_VIEWS)
-  {
-    "disable-hide-inactive-stacked-tab-close-buttons",
-    IDS_FLAGS_DISABLE_HIDE_INACTIVE_STACKED_TAB_CLOSE_BUTTONS_NAME,
-    IDS_FLAGS_DISABLE_HIDE_INACTIVE_STACKED_TAB_CLOSE_BUTTONS_DESCRIPTION,
-    kOsCrOS | kOsWin | kOsLinux,
-    SINGLE_VALUE_TYPE(switches::kDisableHideInactiveStackedTabCloseButtons)
-  },
+    {"disable-hide-inactive-stacked-tab-close-buttons",
+     IDS_FLAGS_DISABLE_HIDE_INACTIVE_STACKED_TAB_CLOSE_BUTTONS_NAME,
+     IDS_FLAGS_DISABLE_HIDE_INACTIVE_STACKED_TAB_CLOSE_BUTTONS_DESCRIPTION,
+     kOsCrOS | kOsWin | kOsLinux,
+     SINGLE_VALUE_TYPE(switches::kDisableHideInactiveStackedTabCloseButtons)},
 #endif
 #if defined(ENABLE_SPELLCHECK)
-  {
-    "enable-spelling-feedback-field-trial",
-    IDS_FLAGS_ENABLE_SPELLING_FEEDBACK_FIELD_TRIAL_NAME,
-    IDS_FLAGS_ENABLE_SPELLING_FEEDBACK_FIELD_TRIAL_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableSpellingFeedbackFieldTrial)
-  },
+    {"enable-spelling-feedback-field-trial",
+     IDS_FLAGS_ENABLE_SPELLING_FEEDBACK_FIELD_TRIAL_NAME,
+     IDS_FLAGS_ENABLE_SPELLING_FEEDBACK_FIELD_TRIAL_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableSpellingFeedbackFieldTrial)},
 #endif
-  {
-    "enable-webgl-draft-extensions",
-    IDS_FLAGS_ENABLE_WEBGL_DRAFT_EXTENSIONS_NAME,
-    IDS_FLAGS_ENABLE_WEBGL_DRAFT_EXTENSIONS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableWebGLDraftExtensions)
-  },
-  {
-    "enable-new-profile-management",
-    IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_NAME,
-    IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_DESCRIPTION,
-    kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableNewProfileManagement,
-                              switches::kDisableNewProfileManagement)
-  },
-  {
-    "enable-account-consistency",
-    IDS_FLAGS_ENABLE_ACCOUNT_CONSISTENCY_NAME,
-    IDS_FLAGS_ENABLE_ACCOUNT_CONSISTENCY_DESCRIPTION,
-    kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAccountConsistency,
-                              switches::kDisableAccountConsistency)
-  },
-  {
-    "enable-iframe-based-signin",
-    IDS_FLAGS_ENABLE_IFRAME_BASED_SIGNIN_NAME,
-    IDS_FLAGS_ENABLE_IFRAME_BASED_SIGNIN_DESCRIPTION,
-    kOsMac | kOsWin | kOsLinux,
-    SINGLE_VALUE_TYPE(switches::kEnableIframeBasedSignin)
-  },
-  {
-    "enable-google-profile-info",
-    IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_NAME,
-    IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_DESCRIPTION,
-    kOsMac | kOsWin | kOsLinux,
-    SINGLE_VALUE_TYPE(switches::kGoogleProfileInfo)
-  },
-  {
-    "reset-app-list-install-state",
-    IDS_FLAGS_RESET_APP_LIST_INSTALL_STATE_NAME,
-    IDS_FLAGS_RESET_APP_LIST_INSTALL_STATE_DESCRIPTION,
-    kOsMac | kOsWin | kOsLinux,
-    SINGLE_VALUE_TYPE(switches::kResetAppListInstallState)
-  },
+    {"enable-webgl-draft-extensions",
+     IDS_FLAGS_ENABLE_WEBGL_DRAFT_EXTENSIONS_NAME,
+     IDS_FLAGS_ENABLE_WEBGL_DRAFT_EXTENSIONS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableWebGLDraftExtensions)},
+    {"enable-new-profile-management",
+     IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_NAME,
+     IDS_FLAGS_ENABLE_NEW_PROFILE_MANAGEMENT_DESCRIPTION,
+     kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableNewProfileManagement,
+                               switches::kDisableNewProfileManagement)},
+    {"enable-account-consistency",
+     IDS_FLAGS_ENABLE_ACCOUNT_CONSISTENCY_NAME,
+     IDS_FLAGS_ENABLE_ACCOUNT_CONSISTENCY_DESCRIPTION,
+     kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAccountConsistency,
+                               switches::kDisableAccountConsistency)},
+    {"enable-iframe-based-signin",
+     IDS_FLAGS_ENABLE_IFRAME_BASED_SIGNIN_NAME,
+     IDS_FLAGS_ENABLE_IFRAME_BASED_SIGNIN_DESCRIPTION,
+     kOsMac | kOsWin | kOsLinux,
+     SINGLE_VALUE_TYPE(switches::kEnableIframeBasedSignin)},
+    {"enable-google-profile-info",
+     IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_NAME,
+     IDS_FLAGS_ENABLE_GOOGLE_PROFILE_INFO_DESCRIPTION,
+     kOsMac | kOsWin | kOsLinux,
+     SINGLE_VALUE_TYPE(switches::kGoogleProfileInfo)},
+    {"reset-app-list-install-state",
+     IDS_FLAGS_RESET_APP_LIST_INSTALL_STATE_NAME,
+     IDS_FLAGS_RESET_APP_LIST_INSTALL_STATE_DESCRIPTION,
+     kOsMac | kOsWin | kOsLinux,
+     SINGLE_VALUE_TYPE(switches::kResetAppListInstallState)},
 #if defined(ENABLE_APP_LIST)
 #if defined(OS_LINUX)
-  {
-    // This is compiled out on non-Linux platforms because otherwise it would be
-    // visible on Win/Mac/CrOS but not on Linux GTK, which would be confusing.
-    // TODO(mgiuca): Remove the #if when Aura is the default on Linux.
-    "enable-app-list",
-    IDS_FLAGS_ENABLE_APP_LIST_NAME,
-    IDS_FLAGS_ENABLE_APP_LIST_DESCRIPTION,
-    kOsLinux,
-    SINGLE_VALUE_TYPE(switches::kEnableAppList)
-  },
+    {// This is compiled out on non-Linux platforms because otherwise it would
+     // be
+     // visible on Win/Mac/CrOS but not on Linux GTK, which would be confusing.
+     // TODO(mgiuca): Remove the #if when Aura is the default on Linux.
+     "enable-app-list",
+     IDS_FLAGS_ENABLE_APP_LIST_NAME,
+     IDS_FLAGS_ENABLE_APP_LIST_DESCRIPTION,
+     kOsLinux,
+     SINGLE_VALUE_TYPE(switches::kEnableAppList)},
 #endif
 #if defined(ENABLE_EXTENSIONS)
-  {
-    "enable-surface-worker",
-    IDS_FLAGS_ENABLE_SURFACE_WORKER_NAME,
-    IDS_FLAGS_ENABLE_SURFACE_WORKER_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(extensions::switches::kEnableSurfaceWorker)
-  },
+    {"enable-surface-worker",
+     IDS_FLAGS_ENABLE_SURFACE_WORKER_NAME,
+     IDS_FLAGS_ENABLE_SURFACE_WORKER_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(extensions::switches::kEnableSurfaceWorker)},
 #endif
-  {
-    "disable-drive-apps-in-app-list",
-    IDS_FLAGS_DISABLE_DRIVE_APPS_IN_APP_LIST_NAME,
-    IDS_FLAGS_DISABLE_DRIVE_APPS_IN_APP_LIST_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(app_list::switches::kDisableDriveAppsInAppList)
-  },
+    {"disable-drive-apps-in-app-list",
+     IDS_FLAGS_DISABLE_DRIVE_APPS_IN_APP_LIST_NAME,
+     IDS_FLAGS_DISABLE_DRIVE_APPS_IN_APP_LIST_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(app_list::switches::kDisableDriveAppsInAppList)},
 #endif
 #if defined(OS_ANDROID)
-  {
-    "enable-accessibility-tab-switcher",
-    IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_NAME,
-    IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableAccessibilityTabSwitcher)
-  },
-  {
-    // TODO(dmazzoni): remove this flag when native android accessibility
-    // ships in the stable channel. http://crbug.com/356775
-    "enable-accessibility-script-injection",
-    IDS_FLAGS_ENABLE_ACCESSIBILITY_SCRIPT_INJECTION_NAME,
-    IDS_FLAGS_ENABLE_ACCESSIBILITY_SCRIPT_INJECTION_DESCRIPTION,
-    kOsAndroid,
-    // Java-only switch: ContentSwitches.ENABLE_ACCESSIBILITY_SCRIPT_INJECTION.
-    SINGLE_VALUE_TYPE("enable-accessibility-script-injection")
-  },
+    {"enable-accessibility-tab-switcher",
+     IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_NAME,
+     IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kEnableAccessibilityTabSwitcher)},
+    {// TODO(dmazzoni): remove this flag when native android accessibility
+     // ships in the stable channel. http://crbug.com/356775
+     "enable-accessibility-script-injection",
+     IDS_FLAGS_ENABLE_ACCESSIBILITY_SCRIPT_INJECTION_NAME,
+     IDS_FLAGS_ENABLE_ACCESSIBILITY_SCRIPT_INJECTION_DESCRIPTION,
+     kOsAndroid,
+     // Java-only switch: ContentSwitches.ENABLE_ACCESSIBILITY_SCRIPT_INJECTION.
+     SINGLE_VALUE_TYPE("enable-accessibility-script-injection")},
 #endif
-  {
-    "enable-one-copy",
-    IDS_FLAGS_ONE_COPY_NAME,
-    IDS_FLAGS_ONE_COPY_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableOneCopy,
-                              switches::kDisableOneCopy)
-  },
-  {
-    "enable-zero-copy",
-    IDS_FLAGS_ZERO_COPY_NAME,
-    IDS_FLAGS_ZERO_COPY_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableZeroCopy)
-  },
+    {"disable-one-copy",
+     IDS_FLAGS_DISABLE_ONE_COPY_NAME,
+     IDS_FLAGS_DISABLE_ONE_COPY_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kDisableOneCopy)},
+    {"enable-zero-copy",
+     IDS_FLAGS_ENABLE_ZERO_COPY_NAME,
+     IDS_FLAGS_ENABLE_ZERO_COPY_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableZeroCopy)},
 #if defined(OS_CHROMEOS)
-  {
-    "enable-first-run-ui-transitions",
-    IDS_FLAGS_ENABLE_FIRST_RUN_UI_TRANSITIONS_NAME,
-    IDS_FLAGS_ENABLE_FIRST_RUN_UI_TRANSITIONS_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kEnableFirstRunUITransitions)
-  },
+    {"enable-first-run-ui-transitions",
+     IDS_FLAGS_ENABLE_FIRST_RUN_UI_TRANSITIONS_NAME,
+     IDS_FLAGS_ENABLE_FIRST_RUN_UI_TRANSITIONS_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kEnableFirstRunUITransitions)},
 #endif
-  {
-    "disable-new-bookmark-apps",
-    IDS_FLAGS_NEW_BOOKMARK_APPS_NAME,
-    IDS_FLAGS_NEW_BOOKMARK_APPS_DESCRIPTION,
-    kOsWin | kOsCrOS | kOsLinux | kOsMac,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableNewBookmarkApps,
-                              switches::kDisableNewBookmarkApps)
-  },
+    {"disable-new-bookmark-apps",
+     IDS_FLAGS_NEW_BOOKMARK_APPS_NAME,
+     IDS_FLAGS_NEW_BOOKMARK_APPS_DESCRIPTION,
+     kOsWin | kOsCrOS | kOsLinux | kOsMac,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableNewBookmarkApps,
+                               switches::kDisableNewBookmarkApps)},
 #if defined(OS_MACOSX)
-  {
-    "disable-hosted-app-shim-creation",
-    IDS_FLAGS_DISABLE_HOSTED_APP_SHIM_CREATION_NAME,
-    IDS_FLAGS_DISABLE_HOSTED_APP_SHIM_CREATION_DESCRIPTION,
-    kOsMac,
-    SINGLE_VALUE_TYPE(switches::kDisableHostedAppShimCreation)
-  },
-  {
-    "enable-hosted-app-quit-notification",
-    IDS_FLAGS_ENABLE_HOSTED_APP_QUIT_NOTIFICATION_NAME,
-    IDS_FLAGS_ENABLE_HOSTED_APP_QUIT_NOTIFICATION_DESCRIPTION,
-    kOsMac,
-    SINGLE_VALUE_TYPE(switches::kHostedAppQuitNotification)
-  },
+    {"disable-hosted-app-shim-creation",
+     IDS_FLAGS_DISABLE_HOSTED_APP_SHIM_CREATION_NAME,
+     IDS_FLAGS_DISABLE_HOSTED_APP_SHIM_CREATION_DESCRIPTION,
+     kOsMac,
+     SINGLE_VALUE_TYPE(switches::kDisableHostedAppShimCreation)},
+    {"enable-hosted-app-quit-notification",
+     IDS_FLAGS_ENABLE_HOSTED_APP_QUIT_NOTIFICATION_NAME,
+     IDS_FLAGS_ENABLE_HOSTED_APP_QUIT_NOTIFICATION_DESCRIPTION,
+     kOsMac,
+     SINGLE_VALUE_TYPE(switches::kHostedAppQuitNotification)},
 #endif
-  {
-    "enable-ephemeral-apps-in-webstore",
-    IDS_FLAGS_ENABLE_EPHEMERAL_APPS_IN_WEBSTORE_NAME,
-    IDS_FLAGS_ENABLE_EPHEMERAL_APPS_IN_WEBSTORE_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableEphemeralAppsInWebstore)
-  },
-  {
-    "enable-linkable-ephemeral-apps",
-    IDS_FLAGS_ENABLE_LINKABLE_EPHEMERAL_APPS_NAME,
-    IDS_FLAGS_ENABLE_LINKABLE_EPHEMERAL_APPS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableLinkableEphemeralApps)
-  },
-  {
-    "enable-service-worker-sync",
-    IDS_FLAGS_ENABLE_SERVICE_WORKER_SYNC_NAME,
-    IDS_FLAGS_ENABLE_SERVICE_WORKER_SYNC_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableServiceWorkerSync)
-  },
+    {"enable-ephemeral-apps-in-webstore",
+     IDS_FLAGS_ENABLE_EPHEMERAL_APPS_IN_WEBSTORE_NAME,
+     IDS_FLAGS_ENABLE_EPHEMERAL_APPS_IN_WEBSTORE_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableEphemeralAppsInWebstore)},
+    {"enable-linkable-ephemeral-apps",
+     IDS_FLAGS_ENABLE_LINKABLE_EPHEMERAL_APPS_NAME,
+     IDS_FLAGS_ENABLE_LINKABLE_EPHEMERAL_APPS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableLinkableEphemeralApps)},
+    {"enable-service-worker-sync",
+     IDS_FLAGS_ENABLE_SERVICE_WORKER_SYNC_NAME,
+     IDS_FLAGS_ENABLE_SERVICE_WORKER_SYNC_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableServiceWorkerSync)},
 #if defined(OS_ANDROID)
-  {
-    "disable-click-delay",
-    IDS_FLAGS_DISABLE_CLICK_DELAY_NAME,
-    IDS_FLAGS_DISABLE_CLICK_DELAY_DESCRIPTION,
-    kOsAndroid,
-    // Java-only switch: CommandLine.DISABLE_CLICK_DELAY
-    SINGLE_VALUE_TYPE("disable-click-delay")
-  },
-  {
-    "disable-pull-to-refresh-effect",
-    IDS_FLAGS_DISABLE_PULL_TO_REFRESH_EFFECT_NAME,
-    IDS_FLAGS_DISABLE_PULL_TO_REFRESH_EFFECT_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kDisablePullToRefreshEffect)
-  },
+    {"disable-click-delay",
+     IDS_FLAGS_DISABLE_CLICK_DELAY_NAME,
+     IDS_FLAGS_DISABLE_CLICK_DELAY_DESCRIPTION,
+     kOsAndroid,
+     // Java-only switch: CommandLine.DISABLE_CLICK_DELAY
+     SINGLE_VALUE_TYPE("disable-click-delay")},
+    {"disable-pull-to-refresh-effect",
+     IDS_FLAGS_DISABLE_PULL_TO_REFRESH_EFFECT_NAME,
+     IDS_FLAGS_DISABLE_PULL_TO_REFRESH_EFFECT_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kDisablePullToRefreshEffect)},
 #endif
 #if defined(OS_MACOSX)
-  {
-    "enable-translate-new-ux",
-    IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_NAME,
-    IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_DESCRIPTION,
-    kOsMac,
-    SINGLE_VALUE_TYPE(switches::kEnableTranslateNewUX)
-  },
+    {"enable-translate-new-ux",
+     IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_NAME,
+     IDS_FLAGS_ENABLE_TRANSLATE_NEW_UX_DESCRIPTION,
+     kOsMac,
+     SINGLE_VALUE_TYPE(switches::kEnableTranslateNewUX)},
 #endif
 #if defined(TOOLKIT_VIEWS)
-  {
-    "disable-views-rect-based-targeting",  // FLAGS:RECORD_UMA
-    IDS_FLAGS_DISABLE_VIEWS_RECT_BASED_TARGETING_NAME,
-    IDS_FLAGS_DISABLE_VIEWS_RECT_BASED_TARGETING_DESCRIPTION,
-    kOsCrOS | kOsWin | kOsLinux,
-    SINGLE_VALUE_TYPE(views::switches::kDisableViewsRectBasedTargeting)
-  },
-  {
-    "enable-link-disambiguation-popup",
-    IDS_FLAGS_ENABLE_LINK_DISAMBIGUATION_POPUP_NAME,
-    IDS_FLAGS_ENABLE_LINK_DISAMBIGUATION_POPUP_DESCRIPTION,
-    kOsCrOS | kOsWin,
-    SINGLE_VALUE_TYPE(switches::kEnableLinkDisambiguationPopup)
-  },
+    {"disable-views-rect-based-targeting",  // FLAGS:RECORD_UMA
+     IDS_FLAGS_DISABLE_VIEWS_RECT_BASED_TARGETING_NAME,
+     IDS_FLAGS_DISABLE_VIEWS_RECT_BASED_TARGETING_DESCRIPTION,
+     kOsCrOS | kOsWin | kOsLinux,
+     SINGLE_VALUE_TYPE(views::switches::kDisableViewsRectBasedTargeting)},
+    {"enable-link-disambiguation-popup",
+     IDS_FLAGS_ENABLE_LINK_DISAMBIGUATION_POPUP_NAME,
+     IDS_FLAGS_ENABLE_LINK_DISAMBIGUATION_POPUP_DESCRIPTION,
+     kOsCrOS | kOsWin,
+     SINGLE_VALUE_TYPE(switches::kEnableLinkDisambiguationPopup)},
 #endif
 #if defined(ENABLE_EXTENSIONS)
-  {
-    "enable-apps-show-on-first-paint",
-    IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_NAME,
-    IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(extensions::switches::kEnableAppsShowOnFirstPaint)
-  },
+    {"enable-apps-show-on-first-paint",
+     IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_NAME,
+     IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(extensions::switches::kEnableAppsShowOnFirstPaint)},
 #endif
-  {
-    "enhanced-bookmarks-experiment",
-    IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_NAME,
-    IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_DESCRIPTION,
-    kOsDesktop | kOsAndroid,
-    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
-        switches::kEnhancedBookmarksExperiment, "1",
-        switches::kEnhancedBookmarksExperiment, "0")
-  },
+    {"enhanced-bookmarks-experiment",
+     IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_NAME,
+     IDS_FLAGS_ENABLE_ENHANCED_BOOKMARKS_DESCRIPTION,
+     kOsDesktop | kOsAndroid,
+     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(switches::kEnhancedBookmarksExperiment,
+                                         "1",
+                                         switches::kEnhancedBookmarksExperiment,
+                                         "0")},
 #if defined(OS_ANDROID)
-  {
-    "enable-zero-suggest-experiment",
-    IDS_FLAGS_ZERO_SUGGEST_EXPERIMENT_NAME,
-    IDS_FLAGS_ZERO_SUGGEST_EXPERIMENT_DESCRIPTION,
-    kOsAndroid,
-    MULTI_VALUE_TYPE(kZeroSuggestExperimentsChoices)
-  },
-  {
-    "reader-mode-heuristics",
-    IDS_FLAGS_READER_MODE_HEURISTICS_NAME,
-    IDS_FLAGS_READER_MODE_HEURISTICS_DESCRIPTION,
-    kOsAndroid,
-    MULTI_VALUE_TYPE(kReaderModeHeuristicsChoices)
-  },
-  {
-    "enable-reader-mode-toolbar-icon",
-    IDS_FLAGS_READER_MODE_EXPERIMENT_NAME,
-    IDS_FLAGS_READER_MODE_EXPERIMENT_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableReaderModeToolbarIcon)
-  },
-  {
-    "enable-dom-distiller-button-animation",
-    IDS_FLAGS_READER_MODE_BUTTON_ANIMATION,
-    IDS_FLAGS_READER_MODE_BUTTON_ANIMATION_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableDomDistillerButtonAnimation)
-  },
+    {"enable-zero-suggest-experiment",
+     IDS_FLAGS_ZERO_SUGGEST_EXPERIMENT_NAME,
+     IDS_FLAGS_ZERO_SUGGEST_EXPERIMENT_DESCRIPTION,
+     kOsAndroid,
+     MULTI_VALUE_TYPE(kZeroSuggestExperimentsChoices)},
+    {"reader-mode-heuristics",
+     IDS_FLAGS_READER_MODE_HEURISTICS_NAME,
+     IDS_FLAGS_READER_MODE_HEURISTICS_DESCRIPTION,
+     kOsAndroid,
+     MULTI_VALUE_TYPE(kReaderModeHeuristicsChoices)},
+    {"enable-reader-mode-toolbar-icon",
+     IDS_FLAGS_READER_MODE_EXPERIMENT_NAME,
+     IDS_FLAGS_READER_MODE_EXPERIMENT_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kEnableReaderModeToolbarIcon)},
+    {"enable-dom-distiller-button-animation",
+     IDS_FLAGS_READER_MODE_BUTTON_ANIMATION,
+     IDS_FLAGS_READER_MODE_BUTTON_ANIMATION_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kEnableDomDistillerButtonAnimation)},
 #endif
-  {
-    "num-raster-threads",
-    IDS_FLAGS_NUM_RASTER_THREADS_NAME,
-    IDS_FLAGS_NUM_RASTER_THREADS_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kNumRasterThreadsChoices)
-  },
-  {
-    "enable-single-click-autofill",
-    IDS_FLAGS_ENABLE_SINGLE_CLICK_AUTOFILL_NAME,
-    IDS_FLAGS_ENABLE_SINGLE_CLICK_AUTOFILL_DESCRIPTION,
-    kOsCrOS | kOsMac | kOsWin | kOsLinux | kOsAndroid,
-    ENABLE_DISABLE_VALUE_TYPE(
-        autofill::switches::kEnableSingleClickAutofill,
-        autofill::switches::kDisableSingleClickAutofill)
-  },
-  {
-    "enable-permissions-bubbles",
-    IDS_FLAGS_ENABLE_PERMISSIONS_BUBBLES_NAME,
-    IDS_FLAGS_ENABLE_PERMISSIONS_BUBBLES_DESCRIPTION,
-    kOsCrOS | kOsMac | kOsWin | kOsLinux,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePermissionsBubbles,
-                              switches::kDisablePermissionsBubbles)
-  },
-  {
-    "enable-site-engagement-service",
-    IDS_FLAGS_ENABLE_SITE_ENGAGEMENT_SERVICE_NAME,
-    IDS_FLAGS_ENABLE_SITE_ENGAGEMENT_SERVICE_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSiteEngagementService,
-                              switches::kDisableSiteEngagementService)
-  },
-  {
-    "enable-session-crashed-bubble",
-    IDS_FLAGS_ENABLE_SESSION_CRASHED_BUBBLE_NAME,
-    IDS_FLAGS_ENABLE_SESSION_CRASHED_BUBBLE_DESCRIPTION,
-    kOsWin | kOsLinux,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSessionCrashedBubble,
-                              switches::kDisableSessionCrashedBubble)
-  },
-  {
-    "enable-pdf-material-ui",
-    IDS_FLAGS_PDF_MATERIAL_UI_NAME,
-    IDS_FLAGS_PDF_MATERIAL_UI_DESCRIPTION,
-    kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePdfMaterialUI,
-                              switches::kDisablePdfMaterialUI)
-  },
-  {
-    "disable-cast-streaming-hw-encoding",
-    IDS_FLAGS_DISABLE_CAST_STREAMING_HW_ENCODING_NAME,
-    IDS_FLAGS_DISABLE_CAST_STREAMING_HW_ENCODING_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kDisableCastStreamingHWEncoding)
-  },
+    {"num-raster-threads",
+     IDS_FLAGS_NUM_RASTER_THREADS_NAME,
+     IDS_FLAGS_NUM_RASTER_THREADS_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kNumRasterThreadsChoices)},
+    {"enable-single-click-autofill",
+     IDS_FLAGS_ENABLE_SINGLE_CLICK_AUTOFILL_NAME,
+     IDS_FLAGS_ENABLE_SINGLE_CLICK_AUTOFILL_DESCRIPTION,
+     kOsCrOS | kOsMac | kOsWin | kOsLinux | kOsAndroid,
+     ENABLE_DISABLE_VALUE_TYPE(
+         autofill::switches::kEnableSingleClickAutofill,
+         autofill::switches::kDisableSingleClickAutofill)},
+    {"enable-permissions-bubbles",
+     IDS_FLAGS_ENABLE_PERMISSIONS_BUBBLES_NAME,
+     IDS_FLAGS_ENABLE_PERMISSIONS_BUBBLES_DESCRIPTION,
+     kOsCrOS | kOsMac | kOsWin | kOsLinux,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePermissionsBubbles,
+                               switches::kDisablePermissionsBubbles)},
+    {"enable-site-engagement-service",
+     IDS_FLAGS_ENABLE_SITE_ENGAGEMENT_SERVICE_NAME,
+     IDS_FLAGS_ENABLE_SITE_ENGAGEMENT_SERVICE_DESCRIPTION,
+     kOsAll,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSiteEngagementService,
+                               switches::kDisableSiteEngagementService)},
+    {"enable-session-crashed-bubble",
+     IDS_FLAGS_ENABLE_SESSION_CRASHED_BUBBLE_NAME,
+     IDS_FLAGS_ENABLE_SESSION_CRASHED_BUBBLE_DESCRIPTION,
+     kOsWin | kOsLinux,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSessionCrashedBubble,
+                               switches::kDisableSessionCrashedBubble)},
+    {"enable-pdf-material-ui",
+     IDS_FLAGS_PDF_MATERIAL_UI_NAME,
+     IDS_FLAGS_PDF_MATERIAL_UI_DESCRIPTION,
+     kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnablePdfMaterialUI,
+                               switches::kDisablePdfMaterialUI)},
+    {"disable-cast-streaming-hw-encoding",
+     IDS_FLAGS_DISABLE_CAST_STREAMING_HW_ENCODING_NAME,
+     IDS_FLAGS_DISABLE_CAST_STREAMING_HW_ENCODING_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kDisableCastStreamingHWEncoding)},
 #if defined(OS_ANDROID)
-  {
-    "disable-cast",
-    IDS_FLAGS_DISABLE_CAST_NAME,
-    IDS_FLAGS_DISABLE_CAST_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kDisableCast)
-  },
-  {
-    "prefetch-search-results",
-    IDS_FLAGS_PREFETCH_SEARCH_RESULTS_NAME,
-    IDS_FLAGS_PREFETCH_SEARCH_RESULTS_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kPrefetchSearchResults)
-  },
+    {"disable-cast",
+     IDS_FLAGS_DISABLE_CAST_NAME,
+     IDS_FLAGS_DISABLE_CAST_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kDisableCast)},
+    {"prefetch-search-results",
+     IDS_FLAGS_PREFETCH_SEARCH_RESULTS_NAME,
+     IDS_FLAGS_PREFETCH_SEARCH_RESULTS_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kPrefetchSearchResults)},
 #endif
 #if defined(ENABLE_APP_LIST)
-  {
-    "enable-experimental-app-list",
-    IDS_FLAGS_ENABLE_EXPERIMENTAL_APP_LIST_NAME,
-    IDS_FLAGS_ENABLE_EXPERIMENTAL_APP_LIST_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(app_list::switches::kEnableExperimentalAppList,
-                              app_list::switches::kDisableExperimentalAppList)
-  },
-  {
-    "enable-centered-app-list",
-    IDS_FLAGS_ENABLE_CENTERED_APP_LIST_NAME,
-    IDS_FLAGS_ENABLE_CENTERED_APP_LIST_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS,
-    SINGLE_VALUE_TYPE(app_list::switches::kEnableCenteredAppList)
-  },
-  {
-    "enable-new-app-list-mixer",
-    IDS_FLAGS_ENABLE_NEW_APP_LIST_MIXER_NAME,
-    IDS_FLAGS_ENABLE_NEW_APP_LIST_MIXER_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS | kOsMac,
-    ENABLE_DISABLE_VALUE_TYPE(app_list::switches::kEnableNewAppListMixer,
-                              app_list::switches::kDisableNewAppListMixer)
-  },
+    {"enable-experimental-app-list",
+     IDS_FLAGS_ENABLE_EXPERIMENTAL_APP_LIST_NAME,
+     IDS_FLAGS_ENABLE_EXPERIMENTAL_APP_LIST_DESCRIPTION,
+     kOsWin | kOsLinux | kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(
+         app_list::switches::kEnableExperimentalAppList,
+         app_list::switches::kDisableExperimentalAppList)},
+    {"enable-centered-app-list",
+     IDS_FLAGS_ENABLE_CENTERED_APP_LIST_NAME,
+     IDS_FLAGS_ENABLE_CENTERED_APP_LIST_DESCRIPTION,
+     kOsWin | kOsLinux | kOsCrOS,
+     SINGLE_VALUE_TYPE(app_list::switches::kEnableCenteredAppList)},
+    {"enable-new-app-list-mixer",
+     IDS_FLAGS_ENABLE_NEW_APP_LIST_MIXER_NAME,
+     IDS_FLAGS_ENABLE_NEW_APP_LIST_MIXER_DESCRIPTION,
+     kOsWin | kOsLinux | kOsCrOS | kOsMac,
+     ENABLE_DISABLE_VALUE_TYPE(app_list::switches::kEnableNewAppListMixer,
+                               app_list::switches::kDisableNewAppListMixer)},
 #endif
-  {
-    "disable-threaded-scrolling",
-    IDS_FLAGS_DISABLE_THREADED_SCROLLING_NAME,
-    IDS_FLAGS_DISABLE_THREADED_SCROLLING_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS | kOsAndroid | kOsMac,
-    SINGLE_VALUE_TYPE(switches::kDisableThreadedScrolling)
-  },
-  {
-    "bleeding-edge-renderer-mode",
-    IDS_FLAGS_BLEEDING_RENDERER_NAME,
-    IDS_FLAGS_BLEEDING_RENDERER_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableBleedingEdgeRenderingFastPaths)
-  },
-  {
-    "enable-settings-window",
-    IDS_FLAGS_ENABLE_SETTINGS_WINDOW_NAME,
-    IDS_FLAGS_ENABLE_SETTINGS_WINDOW_DESCRIPTION,
-    kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSettingsWindow,
-                              switches::kDisableSettingsWindow)
-  },
+    {"disable-threaded-scrolling",
+     IDS_FLAGS_DISABLE_THREADED_SCROLLING_NAME,
+     IDS_FLAGS_DISABLE_THREADED_SCROLLING_DESCRIPTION,
+     kOsWin | kOsLinux | kOsCrOS | kOsAndroid | kOsMac,
+     SINGLE_VALUE_TYPE(switches::kDisableThreadedScrolling)},
+    {"invert-viewport-scroll-order",
+     IDS_FLAGS_INVERT_VIEWPORT_SCROLL_ORDER_NAME,
+     IDS_FLAGS_INVERT_VIEWPORT_SCROLL_ORDER_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kInvertViewportScrollOrder)},
+    {"bleeding-edge-renderer-mode",
+     IDS_FLAGS_BLEEDING_RENDERER_NAME,
+     IDS_FLAGS_BLEEDING_RENDERER_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kEnableBleedingEdgeRenderingFastPaths)},
+    {"enable-settings-window",
+     IDS_FLAGS_ENABLE_SETTINGS_WINDOW_NAME,
+     IDS_FLAGS_ENABLE_SETTINGS_WINDOW_DESCRIPTION,
+     kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSettingsWindow,
+                               switches::kDisableSettingsWindow)},
 #if defined(OS_ANDROID)
-  {
-    "enable-instant-search-clicks",
-    IDS_FLAGS_ENABLE_INSTANT_SEARCH_CLICKS_NAME,
-    IDS_FLAGS_ENABLE_INSTANT_SEARCH_CLICKS_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableInstantSearchClicks)
-  },
+    {"enable-instant-search-clicks",
+     IDS_FLAGS_ENABLE_INSTANT_SEARCH_CLICKS_NAME,
+     IDS_FLAGS_ENABLE_INSTANT_SEARCH_CLICKS_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kEnableInstantSearchClicks)},
 #endif
-  {
-    "enable-save-password-bubble",
-    IDS_FLAGS_ENABLE_SAVE_PASSWORD_BUBBLE_NAME,
-    IDS_FLAGS_ENABLE_SAVE_PASSWORD_BUBBLE_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS | kOsMac,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSavePasswordBubble,
-                              switches::kDisableSavePasswordBubble)
-  },
-  {
-    "enable-apps-file-associations",
-    IDS_FLAGS_ENABLE_APPS_FILE_ASSOCIATIONS_NAME,
-    IDS_FLAGS_ENABLE_APPS_FILE_ASSOCIATIONS_DESCRIPTION,
-    kOsMac,
-    SINGLE_VALUE_TYPE(switches::kEnableAppsFileAssociations)
-  },
+    {"enable-save-password-bubble",
+     IDS_FLAGS_ENABLE_SAVE_PASSWORD_BUBBLE_NAME,
+     IDS_FLAGS_ENABLE_SAVE_PASSWORD_BUBBLE_DESCRIPTION,
+     kOsWin | kOsLinux | kOsCrOS | kOsMac,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableSavePasswordBubble,
+                               switches::kDisableSavePasswordBubble)},
+    {"enable-apps-file-associations",
+     IDS_FLAGS_ENABLE_APPS_FILE_ASSOCIATIONS_NAME,
+     IDS_FLAGS_ENABLE_APPS_FILE_ASSOCIATIONS_DESCRIPTION,
+     kOsMac,
+     SINGLE_VALUE_TYPE(switches::kEnableAppsFileAssociations)},
 #if defined(OS_ANDROID)
-  {
-    "enable-embeddedsearch-api",
-    IDS_FLAGS_ENABLE_EMBEDDEDSEARCH_API_NAME,
-    IDS_FLAGS_ENABLE_EMBEDDEDSEARCH_API_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableEmbeddedSearchAPI)
-  },
+    {"enable-embeddedsearch-api",
+     IDS_FLAGS_ENABLE_EMBEDDEDSEARCH_API_NAME,
+     IDS_FLAGS_ENABLE_EMBEDDEDSEARCH_API_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kEnableEmbeddedSearchAPI)},
 #endif
-  {
-    "distance-field-text",
-    IDS_FLAGS_DISTANCE_FIELD_TEXT_NAME,
-    IDS_FLAGS_DISTANCE_FIELD_TEXT_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDistanceFieldText,
-                              switches::kDisableDistanceFieldText)
-  },
-  {
-    "extension-content-verification",
-    IDS_FLAGS_EXTENSION_CONTENT_VERIFICATION_NAME,
-    IDS_FLAGS_EXTENSION_CONTENT_VERIFICATION_DESCRIPTION,
-    kOsDesktop,
-    MULTI_VALUE_TYPE(kExtensionContentVerificationChoices)
-  },
+    {"distance-field-text",
+     IDS_FLAGS_DISTANCE_FIELD_TEXT_NAME,
+     IDS_FLAGS_DISTANCE_FIELD_TEXT_DESCRIPTION,
+     kOsAll,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableDistanceFieldText,
+                               switches::kDisableDistanceFieldText)},
+    {"extension-content-verification",
+     IDS_FLAGS_EXTENSION_CONTENT_VERIFICATION_NAME,
+     IDS_FLAGS_EXTENSION_CONTENT_VERIFICATION_DESCRIPTION,
+     kOsDesktop,
+     MULTI_VALUE_TYPE(kExtensionContentVerificationChoices)},
 #if defined(USE_AURA)
-  {
-    "text-input-focus-manager",
-    IDS_FLAGS_TEXT_INPUT_FOCUS_MANAGER_NAME,
-    IDS_FLAGS_TEXT_INPUT_FOCUS_MANAGER_DESCRIPTION,
-    kOsCrOS | kOsLinux | kOsWin,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTextInputFocusManager,
-                              switches::kDisableTextInputFocusManager)
-  },
+    {"text-input-focus-manager",
+     IDS_FLAGS_TEXT_INPUT_FOCUS_MANAGER_NAME,
+     IDS_FLAGS_TEXT_INPUT_FOCUS_MANAGER_DESCRIPTION,
+     kOsCrOS | kOsLinux | kOsWin,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableTextInputFocusManager,
+                               switches::kDisableTextInputFocusManager)},
 #endif
 #if defined(ENABLE_EXTENSIONS)
-  {
-    "extension-active-script-permission",
-    IDS_FLAGS_USER_CONSENT_FOR_EXTENSION_SCRIPTS_NAME,
-    IDS_FLAGS_USER_CONSENT_FOR_EXTENSION_SCRIPTS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(extensions::switches::kEnableScriptsRequireAction)
-  },
+    {"extension-active-script-permission",
+     IDS_FLAGS_USER_CONSENT_FOR_EXTENSION_SCRIPTS_NAME,
+     IDS_FLAGS_USER_CONSENT_FOR_EXTENSION_SCRIPTS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(extensions::switches::kEnableScriptsRequireAction)},
 #endif
-  {
-    "answers-in-suggest",
-    IDS_FLAGS_ENABLE_ANSWERS_IN_SUGGEST_NAME,
-    IDS_FLAGS_ENABLE_ANSWERS_IN_SUGGEST_DESCRIPTION,
-    kOsAndroid | kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAnswersInSuggest,
-                              switches::kDisableAnswersInSuggest)
-  },
+    {"answers-in-suggest",
+     IDS_FLAGS_ENABLE_ANSWERS_IN_SUGGEST_NAME,
+     IDS_FLAGS_ENABLE_ANSWERS_IN_SUGGEST_DESCRIPTION,
+     kOsAndroid | kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAnswersInSuggest,
+                               switches::kDisableAnswersInSuggest)},
 #if defined(OS_ANDROID)
-  {
-    "enable-data-reduction-proxy-dev",
-    IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_DEV_NAME,
-    IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_DEV_DESCRIPTION,
-    kOsAndroid,
-    ENABLE_DISABLE_VALUE_TYPE(
-        data_reduction_proxy::switches::kEnableDataReductionProxyDev,
-        data_reduction_proxy::switches::kDisableDataReductionProxyDev)
-  },
-  {
-    "enable-data-reduction-proxy-alt",
-    IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_ALTERNATIVE_NAME,
-    IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_ALTERNATIVE_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(
-        data_reduction_proxy::switches::kEnableDataReductionProxyAlt)
-  },
-  {
-    "enable-data-reduction-proxy-carrier-test",
-    IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_CARRIER_TEST_NAME,
-    IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_CARRIER_TEST_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(
-        data_reduction_proxy::switches::kEnableDataReductionProxyCarrierTest)
-  },
+    {"enable-data-reduction-proxy-dev",
+     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_DEV_NAME,
+     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_DEV_DESCRIPTION,
+     kOsAndroid,
+     ENABLE_DISABLE_VALUE_TYPE(
+         data_reduction_proxy::switches::kEnableDataReductionProxyDev,
+         data_reduction_proxy::switches::kDisableDataReductionProxyDev)},
+    {"enable-data-reduction-proxy-alt",
+     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_ALTERNATIVE_NAME,
+     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_ALTERNATIVE_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(
+         data_reduction_proxy::switches::kEnableDataReductionProxyAlt)},
+    {"enable-data-reduction-proxy-carrier-test",
+     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_CARRIER_TEST_NAME,
+     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_CARRIER_TEST_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(
+         data_reduction_proxy::switches::kEnableDataReductionProxyCarrierTest)},
 #endif
-  {
-    "enable-hotword-hardware",
-    IDS_FLAGS_ENABLE_EXPERIMENTAL_HOTWORD_HARDWARE_NAME,
-    IDS_FLAGS_ENABLE_EXPERIMENTAL_HOTWORD_HARDWARE_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kEnableExperimentalHotwordHardware)
-  },
+    {"enable-hotword-hardware",
+     IDS_FLAGS_ENABLE_EXPERIMENTAL_HOTWORD_HARDWARE_NAME,
+     IDS_FLAGS_ENABLE_EXPERIMENTAL_HOTWORD_HARDWARE_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kEnableExperimentalHotwordHardware)},
 #if defined(ENABLE_EXTENSIONS)
-  {
-    "enable-embedded-extension-options",
-    IDS_FLAGS_ENABLE_EMBEDDED_EXTENSION_OPTIONS_NAME,
-    IDS_FLAGS_ENABLE_EMBEDDED_EXTENSION_OPTIONS_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(extensions::switches::kEnableEmbeddedExtensionOptions)
-  },
+    {"enable-embedded-extension-options",
+     IDS_FLAGS_ENABLE_EMBEDDED_EXTENSION_OPTIONS_NAME,
+     IDS_FLAGS_ENABLE_EMBEDDED_EXTENSION_OPTIONS_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(extensions::switches::kEnableEmbeddedExtensionOptions)},
 #endif
 #if defined(USE_ASH)
-  {
-    "enable-web-app-frame",
-    IDS_FLAGS_ENABLE_WEB_APP_FRAME_NAME,
-    IDS_FLAGS_ENABLE_WEB_APP_FRAME_DESCRIPTION,
-    kOsWin | kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kEnableWebAppFrame)
-  },
+    {"enable-web-app-frame",
+     IDS_FLAGS_ENABLE_WEB_APP_FRAME_NAME,
+     IDS_FLAGS_ENABLE_WEB_APP_FRAME_DESCRIPTION,
+     kOsWin | kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kEnableWebAppFrame)},
 #endif
-  {
-    "enable-drop-sync-credential",
-    IDS_FLAGS_ENABLE_DROP_SYNC_CREDENTIAL_NAME,
-    IDS_FLAGS_ENABLE_DROP_SYNC_CREDENTIAL_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE(
-        password_manager::switches::kEnableDropSyncCredential,
-        password_manager::switches::kDisableDropSyncCredential)
-  },
+    {"enable-drop-sync-credential",
+     IDS_FLAGS_ENABLE_DROP_SYNC_CREDENTIAL_NAME,
+     IDS_FLAGS_ENABLE_DROP_SYNC_CREDENTIAL_DESCRIPTION,
+     kOsAll,
+     ENABLE_DISABLE_VALUE_TYPE(
+         password_manager::switches::kEnableDropSyncCredential,
+         password_manager::switches::kDisableDropSyncCredential)},
 #if defined(ENABLE_EXTENSIONS)
-  {
-    "enable-extension-action-redesign",
-    IDS_FLAGS_ENABLE_EXTENSION_ACTION_REDESIGN_NAME,
-    IDS_FLAGS_ENABLE_EXTENSION_ACTION_REDESIGN_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(extensions::switches::kEnableExtensionActionRedesign)
-  },
+    {"enable-extension-action-redesign",
+     IDS_FLAGS_ENABLE_EXTENSION_ACTION_REDESIGN_NAME,
+     IDS_FLAGS_ENABLE_EXTENSION_ACTION_REDESIGN_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(extensions::switches::kEnableExtensionActionRedesign)},
 #endif
-  {
-    "autofill-sync-credential",
-    IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_NAME,
-    IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kAutofillSyncCredentialChoices)
-  },
+    {"autofill-sync-credential",
+     IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_NAME,
+     IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kAutofillSyncCredentialChoices)},
 #if !defined(OS_ANDROID)
-  {
-    "enable-message-center-always-scroll-up-upon-notification-removal",
-    IDS_FLAGS_ENABLE_MESSAGE_CENTER_ALWAYS_SCROLL_UP_UPON_REMOVAL_NAME,
-    IDS_FLAGS_ENABLE_MESSAGE_CENTER_ALWAYS_SCROLL_UP_UPON_REMOVAL_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(
-        switches::kEnableMessageCenterAlwaysScrollUpUponNotificationRemoval)
-  },
-  {
-    "enable-md-settings",
-    IDS_FLAGS_ENABLE_MATERIAL_DESIGN_SETTINGS_NAME,
-    IDS_FLAGS_ENABLE_MATERIAL_DESIGN_SETTINGS_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(
-        switches::kEnableMaterialDesignSettings)
-  },
+    {"enable-message-center-always-scroll-up-upon-notification-removal",
+     IDS_FLAGS_ENABLE_MESSAGE_CENTER_ALWAYS_SCROLL_UP_UPON_REMOVAL_NAME,
+     IDS_FLAGS_ENABLE_MESSAGE_CENTER_ALWAYS_SCROLL_UP_UPON_REMOVAL_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(
+         switches::kEnableMessageCenterAlwaysScrollUpUponNotificationRemoval)},
+    {"enable-md-settings",
+     IDS_FLAGS_ENABLE_MATERIAL_DESIGN_SETTINGS_NAME,
+     IDS_FLAGS_ENABLE_MATERIAL_DESIGN_SETTINGS_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kEnableMaterialDesignSettings)},
 #endif
 #if defined(OS_CHROMEOS)
-  {
-    "disable-memory-pressure-chromeos",
-    IDS_FLAGS_DISABLE_MEMORY_PRESSURE_NAME,
-    IDS_FLAGS_DISABLE_MEMORY_PRESSURE_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kDisableMemoryPressureSystemChromeOS)
-  },
-  {
-    "memory-pressure-thresholds",
-    IDS_FLAGS_MEMORY_PRESSURE_THRESHOLD_NAME,
-    IDS_FLAGS_MEMORY_PRESSURE_THRESHOLD_DESCRIPTION,
-    kOsCrOS,
-    MULTI_VALUE_TYPE(kMemoryPressureThresholdChoices)
-  },
-  {
-    "wake-on-packets",
-    IDS_FLAGS_WAKE_ON_PACKETS_NAME,
-    IDS_FLAGS_WAKE_ON_PACKETS_DESCRIPTION,
-    kOsCrOSOwnerOnly,
-    SINGLE_VALUE_TYPE(chromeos::switches::kWakeOnPackets)
-  },
+    {"disable-memory-pressure-chromeos",
+     IDS_FLAGS_DISABLE_MEMORY_PRESSURE_NAME,
+     IDS_FLAGS_DISABLE_MEMORY_PRESSURE_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(
+         chromeos::switches::kDisableMemoryPressureSystemChromeOS)},
+    {"memory-pressure-thresholds",
+     IDS_FLAGS_MEMORY_PRESSURE_THRESHOLD_NAME,
+     IDS_FLAGS_MEMORY_PRESSURE_THRESHOLD_DESCRIPTION,
+     kOsCrOS,
+     MULTI_VALUE_TYPE(kMemoryPressureThresholdChoices)},
+    {"wake-on-packets",
+     IDS_FLAGS_WAKE_ON_PACKETS_NAME,
+     IDS_FLAGS_WAKE_ON_PACKETS_DESCRIPTION,
+     kOsCrOSOwnerOnly,
+     SINGLE_VALUE_TYPE(chromeos::switches::kWakeOnPackets)},
 #endif  // OS_CHROMEOS
-  {
-    "enable-tab-audio-muting",
-    IDS_FLAGS_ENABLE_TAB_AUDIO_MUTING_NAME,
-    IDS_FLAGS_ENABLE_TAB_AUDIO_MUTING_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kEnableTabAudioMuting)
-  },
-  {
-    "enable-credential-manager-api",
-    IDS_FLAGS_CREDENTIAL_MANAGER_API_NAME,
-    IDS_FLAGS_CREDENTIAL_MANAGER_API_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableCredentialManagerAPI)
-  },
-  {
-    "reduced-referrer-granularity",
-    IDS_FLAGS_REDUCED_REFERRER_GRANULARITY_NAME,
-    IDS_FLAGS_REDUCED_REFERRER_GRANULARITY_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kReducedReferrerGranularity)
-  },
+    {"enable-tab-audio-muting",
+     IDS_FLAGS_ENABLE_TAB_AUDIO_MUTING_NAME,
+     IDS_FLAGS_ENABLE_TAB_AUDIO_MUTING_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kEnableTabAudioMuting)},
+    {"enable-credential-manager-api",
+     IDS_FLAGS_CREDENTIAL_MANAGER_API_NAME,
+     IDS_FLAGS_CREDENTIAL_MANAGER_API_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableCredentialManagerAPI)},
+    {"reduced-referrer-granularity",
+     IDS_FLAGS_REDUCED_REFERRER_GRANULARITY_NAME,
+     IDS_FLAGS_REDUCED_REFERRER_GRANULARITY_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kReducedReferrerGranularity)},
 #if defined(ENABLE_PLUGINS)
-  {
-    "enable-plugin-power-saver",
-    IDS_FLAGS_ENABLE_PLUGIN_POWER_SAVER_NAME,
-    IDS_FLAGS_ENABLE_PLUGIN_POWER_SAVER_DESCRIPTION,
-    kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE(plugins::switches::kEnablePluginPowerSaver,
-                              plugins::switches::kDisablePluginPowerSaver)
-  },
+    {"enable-plugin-power-saver",
+     IDS_FLAGS_ENABLE_PLUGIN_POWER_SAVER_NAME,
+     IDS_FLAGS_ENABLE_PLUGIN_POWER_SAVER_DESCRIPTION,
+     kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(plugins::switches::kEnablePluginPowerSaver,
+                               plugins::switches::kDisablePluginPowerSaver)},
 #endif
 #if defined(OS_CHROMEOS)
-  {
-    "disable-new-zip-unpacker",
-    IDS_FLAGS_DISABLE_NEW_ZIP_UNPACKER_NAME,
-    IDS_FLAGS_DISABLE_NEW_ZIP_UNPACKER_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kDisableNewZIPUnpacker)
-  },
+    {"disable-new-zip-unpacker",
+     IDS_FLAGS_DISABLE_NEW_ZIP_UNPACKER_NAME,
+     IDS_FLAGS_DISABLE_NEW_ZIP_UNPACKER_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kDisableNewZIPUnpacker)},
 #endif  // defined(OS_CHROMEOS)
-  {
-    "enable-credit-card-scan",
-    IDS_FLAGS_ENABLE_CREDIT_CARD_SCAN_NAME,
-    IDS_FLAGS_ENABLE_CREDIT_CARD_SCAN_DESCRIPTION,
-    kOsAndroid,
-    ENABLE_DISABLE_VALUE_TYPE(autofill::switches::kEnableCreditCardScan,
-                              autofill::switches::kDisableCreditCardScan)
-  },
+    {"enable-credit-card-scan",
+     IDS_FLAGS_ENABLE_CREDIT_CARD_SCAN_NAME,
+     IDS_FLAGS_ENABLE_CREDIT_CARD_SCAN_DESCRIPTION,
+     kOsAndroid,
+     ENABLE_DISABLE_VALUE_TYPE(autofill::switches::kEnableCreditCardScan,
+                               autofill::switches::kDisableCreditCardScan)},
 #if defined(OS_CHROMEOS)
-  {
-    "disable-captive-portal-bypass-proxy",
-    IDS_FLAGS_DISABLE_CAPTIVE_PORTAL_BYPASS_PROXY_NAME,
-    IDS_FLAGS_DISABLE_CAPTIVE_PORTAL_BYPASS_PROXY_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kDisableCaptivePortalBypassProxy)
-  },
+    {"disable-captive-portal-bypass-proxy",
+     IDS_FLAGS_DISABLE_CAPTIVE_PORTAL_BYPASS_PROXY_NAME,
+     IDS_FLAGS_DISABLE_CAPTIVE_PORTAL_BYPASS_PROXY_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kDisableCaptivePortalBypassProxy)},
 #endif  // defined(OS_CHROMEOS)
 #if defined(OS_ANDROID)
-  {
-    "enable-seccomp-filter-sandbox",
-    IDS_FLAGS_ENABLE_SECCOMP_FILTER_SANDBOX_ANDROID_NAME,
-    IDS_FLAGS_ENABLE_SECCOMP_FILTER_SANDBOX_ANDROID_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableSeccompFilterSandbox)
-  },
+    {"enable-seccomp-filter-sandbox",
+     IDS_FLAGS_ENABLE_SECCOMP_FILTER_SANDBOX_ANDROID_NAME,
+     IDS_FLAGS_ENABLE_SECCOMP_FILTER_SANDBOX_ANDROID_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(switches::kEnableSeccompFilterSandbox)},
 #endif
-  {
-    "enable-touch-hover",
-    IDS_FLAGS_ENABLE_TOUCH_HOVER_NAME,
-    IDS_FLAGS_ENABLE_TOUCH_HOVER_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE("enable-touch-hover")
-  },
-  {
-    "enable-fill-on-account-select",
-    IDS_FILL_ON_ACCOUNT_SELECT_NAME,
-    IDS_FILL_ON_ACCOUNT_SELECT_DESCRIPTION,
-    kOsAll,
-    MULTI_VALUE_TYPE(kFillOnAccountSelectChoices)
-  },
+    {"enable-touch-hover",
+     IDS_FLAGS_ENABLE_TOUCH_HOVER_NAME,
+     IDS_FLAGS_ENABLE_TOUCH_HOVER_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE("enable-touch-hover")},
+    {"enable-fill-on-account-select",
+     IDS_FILL_ON_ACCOUNT_SELECT_NAME,
+     IDS_FILL_ON_ACCOUNT_SELECT_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kFillOnAccountSelectChoices)},
 #if defined(OS_CHROMEOS)
-  {
-    "enable-wifi-credential-sync",  // FLAGS:RECORD_UMA
-    IDS_FLAGS_ENABLE_WIFI_CREDENTIAL_SYNC_NAME,
-    IDS_FLAGS_ENABLE_WIFI_CREDENTIAL_SYNC_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kEnableWifiCredentialSync)
-  },
-  {
-    "enable-potentially-annoying-security-features",
-    IDS_FLAGS_EXPERIMENTAL_SECURITY_FEATURES_NAME,
-    IDS_FLAGS_EXPERIMENTAL_SECURITY_FEATURES_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnablePotentiallyAnnoyingSecurityFeatures)
-  },
+    {"enable-wifi-credential-sync",  // FLAGS:RECORD_UMA
+     IDS_FLAGS_ENABLE_WIFI_CREDENTIAL_SYNC_NAME,
+     IDS_FLAGS_ENABLE_WIFI_CREDENTIAL_SYNC_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kEnableWifiCredentialSync)},
+    {"enable-potentially-annoying-security-features",
+     IDS_FLAGS_EXPERIMENTAL_SECURITY_FEATURES_NAME,
+     IDS_FLAGS_EXPERIMENTAL_SECURITY_FEATURES_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnablePotentiallyAnnoyingSecurityFeatures)},
 #endif
-  {
-    "disable-delay-agnostic-aec",
-    IDS_FLAGS_DISABLE_DELAY_AGNOSTIC_AEC_NAME,
-    IDS_FLAGS_DISABLE_DELAY_AGNOSTIC_AEC_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kDisableDelayAgnosticAec)
-  },
-  {
-    "enable-delay-agnostic-aec",
-    IDS_FLAGS_ENABLE_DELAY_AGNOSTIC_AEC_NAME,
-    IDS_FLAGS_ENABLE_DELAY_AGNOSTIC_AEC_DESCRIPTION,
-    kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kEnableDelayAgnosticAec)
-  },
-  {
-    "mark-non-secure-as",  // FLAGS:RECORD_UMA
+    {"disable-delay-agnostic-aec",
+     IDS_FLAGS_DISABLE_DELAY_AGNOSTIC_AEC_NAME,
+     IDS_FLAGS_DISABLE_DELAY_AGNOSTIC_AEC_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kDisableDelayAgnosticAec)},
+    {"enable-delay-agnostic-aec",
+     IDS_FLAGS_ENABLE_DELAY_AGNOSTIC_AEC_NAME,
+     IDS_FLAGS_ENABLE_DELAY_AGNOSTIC_AEC_DESCRIPTION,
+     kOsDesktop,
+     SINGLE_VALUE_TYPE(switches::kEnableDelayAgnosticAec)},
+    {"mark-non-secure-as",  // FLAGS:RECORD_UMA
      IDS_MARK_NON_SECURE_AS_NAME,
      IDS_MARK_NON_SECURE_AS_DESCRIPTION,
      kOsAll,
-     MULTI_VALUE_TYPE(kMarkNonSecureAsChoices)
-  },
-  {
-    "enable-site-per-process",
-    IDS_FLAGS_ENABLE_SITE_PER_PROCESS_NAME,
-    IDS_FLAGS_ENABLE_SITE_PER_PROCESS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kSitePerProcess)
-  },
+     MULTI_VALUE_TYPE(kMarkNonSecureAsChoices)},
+    {"enable-site-per-process",
+     IDS_FLAGS_ENABLE_SITE_PER_PROCESS_NAME,
+     IDS_FLAGS_ENABLE_SITE_PER_PROCESS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kSitePerProcess)},
 #if defined(OS_MACOSX)
-  {
-    "enable-harfbuzz-rendertext",
-    IDS_FLAGS_ENABLE_HARFBUZZ_RENDERTEXT_NAME,
-    IDS_FLAGS_ENABLE_HARFBUZZ_RENDERTEXT_DESCRIPTION,
-    kOsMac,
-    SINGLE_VALUE_TYPE(switches::kEnableHarfBuzzRenderText)
-  },
+    {"enable-harfbuzz-rendertext",
+     IDS_FLAGS_ENABLE_HARFBUZZ_RENDERTEXT_NAME,
+     IDS_FLAGS_ENABLE_HARFBUZZ_RENDERTEXT_DESCRIPTION,
+     kOsMac,
+     SINGLE_VALUE_TYPE(switches::kEnableHarfBuzzRenderText)},
 #endif  // defined(OS_MACOSX)
 #if defined(OS_CHROMEOS)
-  {
-    "disable-timezone-tracking",
-    IDS_FLAGS_DISABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_NAME,
-    IDS_FLAGS_DISABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kDisableTimeZoneTrackingOption)
-  },
-  {
-    "disable-webview-signin-flow",
-    IDS_FLAGS_DISABLE_WEBVIEW_SIGNIN_FLOW_NAME,
-    IDS_FLAGS_DISABLE_WEBVIEW_SIGNIN_FLOW_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kDisableWebviewSigninFlow)
-  },
+    {"disable-timezone-tracking",
+     IDS_FLAGS_DISABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_NAME,
+     IDS_FLAGS_DISABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kDisableTimeZoneTrackingOption)},
+    {"disable-webview-signin-flow",
+     IDS_FLAGS_DISABLE_WEBVIEW_SIGNIN_FLOW_NAME,
+     IDS_FLAGS_DISABLE_WEBVIEW_SIGNIN_FLOW_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kDisableWebviewSigninFlow)},
 #endif  // defined(OS_CHROMEOS)
-  {
-    "enable-data-reduction-proxy-lo-fi",
-    IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_LO_FI_NAME,
-    IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_LO_FI_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(data_reduction_proxy::switches::
-                      kEnableDataReductionProxyLoFi)
-  },
-  {
-    "clear-data-reduction-proxy-data-savings",
-    IDS_FLAGS_DATA_REDUCTION_PROXY_RESET_SAVINGS_NAME,
-    IDS_FLAGS_DATA_REDUCTION_PROXY_RESET_SAVINGS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(data_reduction_proxy::switches::
-                      kClearDataReductionProxyDataSavings)
-  },
+    {"data-reduction-proxy-lo-fi",
+     IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_NAME,
+     IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_DESCRIPTION,
+     kOsAll,
+     MULTI_VALUE_TYPE(kDataReductionProxyLoFiChoices)},
+    {"clear-data-reduction-proxy-data-savings",
+     IDS_FLAGS_DATA_REDUCTION_PROXY_RESET_SAVINGS_NAME,
+     IDS_FLAGS_DATA_REDUCTION_PROXY_RESET_SAVINGS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(
+         data_reduction_proxy::switches::kClearDataReductionProxyDataSavings)},
 #if defined(ENABLE_DATA_REDUCTION_PROXY_DEBUGGING)
-  {
-    "enable-data-reduction-proxy-bypass-warnings",
-    IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_BYPASS_WARNING_NAME,
-    IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_BYPASS_WARNING_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(data_reduction_proxy::switches::
-                      kEnableDataReductionProxyBypassWarning)
-  },
+    {"enable-data-reduction-proxy-bypass-warnings",
+     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_BYPASS_WARNING_NAME,
+     IDS_FLAGS_ENABLE_DATA_REDUCTION_PROXY_BYPASS_WARNING_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(data_reduction_proxy::switches::
+                           kEnableDataReductionProxyBypassWarning)},
 #endif
-  {
-    "allow-insecure-localhost",
-    IDS_ALLOW_INSECURE_LOCALHOST,
-    IDS_ALLOW_INSECURE_LOCALHOST_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kAllowInsecureLocalhost)
-  },
-  {
-    "enable-add-to-shelf",
-    IDS_FLAGS_ENABLE_ADD_TO_SHELF_NAME,
-    IDS_FLAGS_ENABLE_ADD_TO_SHELF_DESCRIPTION,
-    kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAddToShelf,
-                              switches::kDisableAddToShelf)
-  },
-  {
-    "bypass-app-banner-engagement-checks",
-    IDS_FLAGS_BYPASS_APP_BANNER_ENGAGEMENT_CHECKS_NAME,
-    IDS_FLAGS_BYPASS_APP_BANNER_ENGAGEMENT_CHECKS_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kBypassAppBannerEngagementChecks)
-  },
-  {
-    "use-sync-sandbox",
-    IDS_FLAGS_SYNC_SANDBOX_NAME,
-    IDS_FLAGS_SYNC_SANDBOX_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE_AND_VALUE(
-        switches::kSyncServiceURL,
-        "https://chrome-sync.sandbox.google.com/chrome-sync/alpha")
-  },
-  {
-    "enable-child-account-detection",
-    IDS_FLAGS_CHILD_ACCOUNT_DETECTION_NAME,
-    IDS_FLAGS_CHILD_ACCOUNT_DETECTION_DESCRIPTION,
-    kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableChildAccountDetection,
-                              switches::kDisableChildAccountDetection)
-  },
+    {"allow-insecure-localhost",
+     IDS_ALLOW_INSECURE_LOCALHOST,
+     IDS_ALLOW_INSECURE_LOCALHOST_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kAllowInsecureLocalhost)},
+    {"enable-add-to-shelf",
+     IDS_FLAGS_ENABLE_ADD_TO_SHELF_NAME,
+     IDS_FLAGS_ENABLE_ADD_TO_SHELF_DESCRIPTION,
+     kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAddToShelf,
+                               switches::kDisableAddToShelf)},
+    {"bypass-app-banner-engagement-checks",
+     IDS_FLAGS_BYPASS_APP_BANNER_ENGAGEMENT_CHECKS_NAME,
+     IDS_FLAGS_BYPASS_APP_BANNER_ENGAGEMENT_CHECKS_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kBypassAppBannerEngagementChecks)},
+    {"use-sync-sandbox",
+     IDS_FLAGS_SYNC_SANDBOX_NAME,
+     IDS_FLAGS_SYNC_SANDBOX_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE_AND_VALUE(
+         switches::kSyncServiceURL,
+         "https://chrome-sync.sandbox.google.com/chrome-sync/alpha")},
+    {"enable-child-account-detection",
+     IDS_FLAGS_CHILD_ACCOUNT_DETECTION_NAME,
+     IDS_FLAGS_CHILD_ACCOUNT_DETECTION_DESCRIPTION,
+     kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableChildAccountDetection,
+                               switches::kDisableChildAccountDetection)},
 #if defined(OS_CHROMEOS) && defined(USE_OZONE)
-  {
-    "ozone-test-single-overlay-support",
-    IDS_FLAGS_OZONE_TEST_SINGLE_HARDWARE_OVERLAY,
-    IDS_FLAGS_OZONE_TEST_SINGLE_HARDWARE_OVERLAY_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(switches::kOzoneTestSingleOverlaySupport)
-  },
+    {"ozone-test-single-overlay-support",
+     IDS_FLAGS_OZONE_TEST_SINGLE_HARDWARE_OVERLAY,
+     IDS_FLAGS_OZONE_TEST_SINGLE_HARDWARE_OVERLAY_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(switches::kOzoneTestSingleOverlaySupport)},
 #endif  // defined(OS_CHROMEOS) && defined(USE_OZONE)
-  {
-    "v8-pac-mojo-out-of-process",
-    IDS_FLAGS_V8_PAC_MOJO_OUT_OF_PROCESS_NAME,
-    IDS_FLAGS_V8_PAC_MOJO_OUT_OF_PROCESS_DESCRIPTION,
-    kOsDesktop,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kV8PacMojoOutOfProcess,
-                              switches::kDisableOutOfProcessPac)
-  },
+    {"v8-pac-mojo-out-of-process",
+     IDS_FLAGS_V8_PAC_MOJO_OUT_OF_PROCESS_NAME,
+     IDS_FLAGS_V8_PAC_MOJO_OUT_OF_PROCESS_DESCRIPTION,
+     kOsDesktop,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kV8PacMojoOutOfProcess,
+                               switches::kDisableOutOfProcessPac)},
 #if defined(ENABLE_MEDIA_ROUTER)
-  {
-    "enable-media-router",
-    IDS_FLAGS_ENABLE_MEDIA_ROUTER_NAME,
-    IDS_FLAGS_ENABLE_MEDIA_ROUTER_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableMediaRouter)
-  },
+    {"enable-media-router",
+     IDS_FLAGS_ENABLE_MEDIA_ROUTER_NAME,
+     IDS_FLAGS_ENABLE_MEDIA_ROUTER_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableMediaRouter)},
 #endif  // defined(ENABLE_MEDIA_ROUTER)
 // Since kEnableLauncherSearchProviderApi is not available when app list is
 // disabled, flag guard enable-launcher-search-provider-api.
 #if defined(ENABLE_APP_LIST)
-  {
-    "enable-launcher-search-provider-api",
-    IDS_FLAGS_ENABLE_LAUNCHER_SEARCH_PROVIDER_API,
-    IDS_FLAGS_ENABLE_LAUNCHER_SEARCH_PROVIDER_API_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(app_list::switches::kEnableLauncherSearchProviderApi)
-  },
+    {"enable-launcher-search-provider-api",
+     IDS_FLAGS_ENABLE_LAUNCHER_SEARCH_PROVIDER_API,
+     IDS_FLAGS_ENABLE_LAUNCHER_SEARCH_PROVIDER_API_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(app_list::switches::kEnableLauncherSearchProviderApi)},
 #endif  // defined(ENABLE_APP_LIST)
 #if defined(OS_CHROMEOS)
-  {
-    "disable-mtp-write-support",
-    IDS_FLAG_DISABLE_MTP_WRITE_SUPPORT_NAME,
-    IDS_FLAG_DISABLE_MTP_WRITE_SUPPORT_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kDisableMtpWriteSupport)
-  },
+    {"disable-mtp-write-support",
+     IDS_FLAG_DISABLE_MTP_WRITE_SUPPORT_NAME,
+     IDS_FLAG_DISABLE_MTP_WRITE_SUPPORT_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kDisableMtpWriteSupport)},
 #endif  // defined(OS_CHROMEOS)
 #if defined(OS_CHROMEOS)
-  {
-    "enable-datasaver-prompt",
-    IDS_FLAGS_DATASAVER_PROMPT_NAME,
-    IDS_FLAGS_DATASAVER_PROMPT_DESCRIPTION,
-    kOsCrOS,
-    MULTI_VALUE_TYPE(kDataSaverPromptChoices)
-  },
+    {"enable-datasaver-prompt",
+     IDS_FLAGS_DATASAVER_PROMPT_NAME,
+     IDS_FLAGS_DATASAVER_PROMPT_DESCRIPTION,
+     kOsCrOS,
+     MULTI_VALUE_TYPE(kDataSaverPromptChoices)},
 #endif  // defined(OS_CHROMEOS)
-  {
-    "supervised-user-safesites",
-    IDS_FLAGS_SUPERVISED_USER_SAFESITES_NAME,
-    IDS_FLAGS_SUPERVISED_USER_SAFESITES_DESCRIPTION,
-    kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
-    MULTI_VALUE_TYPE(kSupervisedUserSafeSitesChoices)
-  },
+    {"supervised-user-safesites",
+     IDS_FLAGS_SUPERVISED_USER_SAFESITES_NAME,
+     IDS_FLAGS_SUPERVISED_USER_SAFESITES_DESCRIPTION,
+     kOsAndroid | kOsMac | kOsWin | kOsLinux | kOsCrOS,
+     MULTI_VALUE_TYPE(kSupervisedUserSafeSitesChoices)},
 #if defined(OS_ANDROID)
-  {
-    "enable-autofill-keyboard-accessory-view",
-    IDS_FLAGS_AUTOFILL_ACCESSORY_VIEW_NAME,
-    IDS_FLAGS_AUTOFILL_ACCESSORY_VIEW_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(autofill::switches::kEnableAccessorySuggestionView)
-  },
+    {"enable-autofill-keyboard-accessory-view",
+     IDS_FLAGS_AUTOFILL_ACCESSORY_VIEW_NAME,
+     IDS_FLAGS_AUTOFILL_ACCESSORY_VIEW_DESCRIPTION,
+     kOsAndroid,
+     SINGLE_VALUE_TYPE(autofill::switches::kEnableAccessorySuggestionView)},
 #endif  // defined(OS_ANDROID)
-  {
-    "disable-new-video-renderer",
-    IDS_FLAGS_DISABLE_NEW_VIDEO_RENDERER_NAME,
-    IDS_FLAGS_DISABLE_NEW_VIDEO_RENDERER_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kDisableNewVideoRenderer)
-  },
+    {"disable-new-video-renderer",
+     IDS_FLAGS_DISABLE_NEW_VIDEO_RENDERER_NAME,
+     IDS_FLAGS_DISABLE_NEW_VIDEO_RENDERER_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kDisableNewVideoRenderer)},
 #if defined(OS_CHROMEOS)
-  {
-    "enable-printer-app-search",
-    IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_NAME,
-    IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_DESCRIPTION,
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kEnablePrinterAppSearch)
-  },
+    {"enable-printer-app-search",
+     IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_NAME,
+     IDS_FLAGS_PRINTER_PROVIDER_SEARCH_APP_DESCRIPTION,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kEnablePrinterAppSearch)},
 #endif  // OS_CHROMEOS
-  // Temporary flag to ease the transition to standard-compliant scrollTop
-  // behavior.  Will be removed shortly after http://crbug.com/157855 ships.
-  {
-    "scroll-top-left-interop",
-    IDS_FLAGS_SCROLL_TOP_LEFT_INTEROP_NAME,
-    IDS_FLAGS_SCROLL_TOP_LEFT_INTEROP_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
-        switches::kEnableBlinkFeatures, "ScrollTopLeftInterop",
-        switches::kDisableBlinkFeatures, "ScrollTopLeftInterop")
-  },
+    // Temporary flag to ease the transition to standard-compliant scrollTop
+    // behavior.  Will be removed shortly after http://crbug.com/157855 ships.
+    {"scroll-top-left-interop",
+     IDS_FLAGS_SCROLL_TOP_LEFT_INTEROP_NAME,
+     IDS_FLAGS_SCROLL_TOP_LEFT_INTEROP_DESCRIPTION,
+     kOsAll,
+     ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(switches::kEnableBlinkFeatures,
+                                         "ScrollTopLeftInterop",
+                                         switches::kDisableBlinkFeatures,
+                                         "ScrollTopLeftInterop")},
 #if defined(OS_WIN)
-  {
-    "try-supported-channel-layouts",
-    IDS_FLAGS_TRY_SUPPORTED_CHANNEL_LAYOUTS_NAME,
-    IDS_FLAGS_TRY_SUPPORTED_CHANNEL_LAYOUTS_DESCRIPTION,
-    kOsWin,
-    SINGLE_VALUE_TYPE(switches::kTrySupportedChannelLayouts)
-  },
+    {"try-supported-channel-layouts",
+     IDS_FLAGS_TRY_SUPPORTED_CHANNEL_LAYOUTS_NAME,
+     IDS_FLAGS_TRY_SUPPORTED_CHANNEL_LAYOUTS_DESCRIPTION,
+     kOsWin,
+     SINGLE_VALUE_TYPE(switches::kTrySupportedChannelLayouts)},
 #endif
-  {
-    "emphasize-titles-in-omnibox-dropdown",
-    IDS_FLAGS_EMPHASIZE_TITLES_IN_OMNIBOX_DROPDOWN_NAME,
-    IDS_FLAGS_EMPHASIZE_TITLES_IN_OMNIBOX_DROPDOWN_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEmphasizeTitlesInOmniboxDropdown)
-  },
+    {"emphasize-titles-in-omnibox-dropdown",
+     IDS_FLAGS_EMPHASIZE_TITLES_IN_OMNIBOX_DROPDOWN_NAME,
+     IDS_FLAGS_EMPHASIZE_TITLES_IN_OMNIBOX_DROPDOWN_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEmphasizeTitlesInOmniboxDropdown)},
 #if defined(ENABLE_WEBRTC)
-  {
-    "enable-webrtc-dtls12",
-    IDS_FLAGS_ENABLE_WEBRTC_DTLS12_NAME,
-    IDS_FLAGS_ENABLE_WEBRTC_DTLS12_DESCRIPTION,
-    kOsAll,
-    SINGLE_VALUE_TYPE(switches::kEnableWebRtcDtls12)
-  },
+    {"enable-webrtc-dtls12",
+     IDS_FLAGS_ENABLE_WEBRTC_DTLS12_NAME,
+     IDS_FLAGS_ENABLE_WEBRTC_DTLS12_DESCRIPTION,
+     kOsAll,
+     SINGLE_VALUE_TYPE(switches::kEnableWebRtcDtls12)},
 #endif
 #if defined(OS_MACOSX)
-  {
-    "app-info-dialog",
-    IDS_FLAGS_APP_INFO_DIALOG_NAME,
-    IDS_FLAGS_APP_INFO_DIALOG_DESCRIPTION,
-    kOsMac,
-    ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAppInfoDialogMac,
-                              switches::kDisableAppInfoDialogMac)
-  },
+    {"app-info-dialog",
+     IDS_FLAGS_APP_INFO_DIALOG_NAME,
+     IDS_FLAGS_APP_INFO_DIALOG_DESCRIPTION,
+     kOsMac,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableAppInfoDialogMac,
+                               switches::kDisableAppInfoDialogMac)},
+    {"mac-views-native-app-windows",
+     IDS_FLAGS_MAC_VIEWS_NATIVE_APP_WINDOWS_NAME,
+     IDS_FLAGS_MAC_VIEWS_NATIVE_APP_WINDOWS_DESCRIPTION,
+     kOsMac,
+     ENABLE_DISABLE_VALUE_TYPE(switches::kEnableMacViewsNativeAppWindows,
+                               switches::kDisableMacViewsNativeAppWindows)},
 #endif
-  // NOTE: Adding new command-line switches requires adding corresponding
-  // entries to enum "LoginCustomFlags" in histograms.xml. See note in
-  // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
+    // NOTE: Adding new command-line switches requires adding corresponding
+    // entries to enum "LoginCustomFlags" in histograms.xml. See note in
+    // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
 };
 
 const Experiment* experiments = kExperiments;
@@ -2545,9 +2123,9 @@
       channel != chrome::VersionInfo::CHANNEL_DEV) {
     return true;
   }
-  // enable-data-reduction-proxy-lo-fi is only available for Chromium builds and
+  // data-reduction-proxy-lo-fi is only available for Chromium builds and
   // the Canary/Dev channel.
-  if (!strcmp("enable-data-reduction-proxy-lo-fi", experiment.internal_name) &&
+  if (!strcmp("data-reduction-proxy-lo-fi", experiment.internal_name) &&
       channel != chrome::VersionInfo::CHANNEL_DEV &&
       channel != chrome::VersionInfo::CHANNEL_CANARY &&
       channel != chrome::VersionInfo::CHANNEL_UNKNOWN) {
@@ -2802,7 +2380,7 @@
                        const std::set<std::string>& command_line_difference) {
   for (const std::string& flag : command_line_difference) {
     int uma_id = about_flags::testing::kBadSwitchFormatHistogramId;
-    if (StartsWithASCII(flag, "--", true /* case_sensitive */)) {
+    if (base::StartsWithASCII(flag, "--", true /* case_sensitive */)) {
       // Skip '--' before switch name.
       std::string switch_name(flag.substr(2));
 
diff --git a/chrome/browser/android/DEPS b/chrome/browser/android/DEPS
index 2b8a00e4..1b7b362 100644
--- a/chrome/browser/android/DEPS
+++ b/chrome/browser/android/DEPS
@@ -4,5 +4,6 @@
   "+components/devtools_http_handler",
   "+components/service_tab_launcher",
   "+components/web_contents_delegate_android",
-  "+cc/layers/layer.h"
+  "+cc/layers/layer.h",
+  "+sandbox/linux/seccomp-bpf/sandbox_bpf.h",
 ]
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index 0765ae0..6ada7d2 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/android/compositor/scene_layer/scene_layer.h"
 #include "chrome/browser/android/compositor/scene_layer/static_tab_scene_layer.h"
 #include "chrome/browser/android/compositor/tab_content_manager.h"
-#include "chrome/browser/android/content_view_util.h"
 #include "chrome/browser/android/cookies/cookies_fetcher.h"
 #include "chrome/browser/android/dev_tools_server.h"
 #include "chrome/browser/android/dom_distiller/external_feedback_reporter_android.h"
@@ -64,6 +63,7 @@
 #include "chrome/browser/android/url_utilities.h"
 #include "chrome/browser/android/voice_search_tab_helper.h"
 #include "chrome/browser/android/warmup_manager.h"
+#include "chrome/browser/android/web_contents_factory.h"
 #include "chrome/browser/autofill/android/personal_data_manager_android.h"
 #include "chrome/browser/dom_distiller/dom_distiller_service_factory_android.h"
 #include "chrome/browser/dom_distiller/tab_utils_android.h"
@@ -187,7 +187,6 @@
      ConnectionInfoPopupAndroid::RegisterConnectionInfoPopupAndroid},
     {"ConnectionSecurityHelper", RegisterConnectionSecurityHelperAndroid},
     {"ConnectivityChecker", RegisterConnectivityChecker},
-    {"ContentViewUtil", RegisterContentViewUtil},
     {"ContextMenuHelper", RegisterContextMenuHelper},
     {"CookiesFetcher", RegisterCookiesFetcher},
     {"Credential", RegisterCredential},
@@ -280,6 +279,7 @@
     {"Variations", variations::android::RegisterVariations},
     {"VariationsSession", chrome::android::RegisterVariationsSession},
     {"WarmupManager", RegisterWarmupManager},
+    {"WebContentsFactory", RegisterWebContentsFactory},
     {"WebsitePreferenceBridge", RegisterWebsitePreferenceBridge},
     {"WebsiteSettingsPopupAndroid",
      WebsiteSettingsPopupAndroid::RegisterWebsiteSettingsPopupAndroid},
diff --git a/chrome/browser/android/chrome_main_delegate_staging_android.cc b/chrome/browser/android/chrome_main_delegate_staging_android.cc
index 3b072b0..19427f01 100644
--- a/chrome/browser/android/chrome_main_delegate_staging_android.cc
+++ b/chrome/browser/android/chrome_main_delegate_staging_android.cc
@@ -10,6 +10,10 @@
 #include "base/path_service.h"
 #include "components/policy/core/common/policy_provider_android.h"
 
+#if defined(SAFE_BROWSING_DB_REMOTE)
+#include "chrome/browser/safe_browsing/safe_browsing_api_handler.h"
+#endif
+
 
 ChromeMainDelegateStagingAndroid::ChromeMainDelegateStagingAndroid() {
 }
@@ -18,6 +22,11 @@
 }
 
 bool ChromeMainDelegateStagingAndroid::BasicStartupComplete(int* exit_code) {
+#if defined(SAFE_BROWSING_DB_REMOTE)
+  safe_browsing_api_handler_.reset(CreateSafeBrowsingApiHandler());
+  SafeBrowsingApiHandler::SetInstance(safe_browsing_api_handler_.get());
+#endif
+
 #if defined(SAFE_BROWSING_SERVICE)
   spdy_proxy_throttle_factory_ .reset(new SpdyProxyResourceThrottleFactory());
   SafeBrowsingResourceThrottleFactory::RegisterFactory(
@@ -63,4 +72,14 @@
 #if defined(SAFE_BROWSING_SERVICE)
   SafeBrowsingResourceThrottleFactory::RegisterFactory(NULL);
 #endif
+#if defined(SAFE_BROWSING_DB_REMOTE)
+  SafeBrowsingApiHandler::SetInstance(NULL);
+#endif
 }
+
+#if defined(SAFE_BROWSING_DB_REMOTE)
+SafeBrowsingApiHandler*
+ChromeMainDelegateStagingAndroid::CreateSafeBrowsingApiHandler() {
+  return NULL;
+}
+#endif
diff --git a/chrome/browser/android/chrome_main_delegate_staging_android.h b/chrome/browser/android/chrome_main_delegate_staging_android.h
index a342b14..ff65cbc2 100644
--- a/chrome/browser/android/chrome_main_delegate_staging_android.h
+++ b/chrome/browser/android/chrome_main_delegate_staging_android.h
@@ -11,6 +11,7 @@
 #include "chrome/browser/android/spdy_proxy_resource_throttle.h"
 #endif
 
+class SafeBrowsingApiHandler;
 class SpdyProxyResourceThrottleFactory;
 
 class ChromeMainDelegateStagingAndroid : public ChromeMainDelegateAndroid {
@@ -22,6 +23,9 @@
   int RunProcess(
       const std::string& process_type,
       const content::MainFunctionParams& main_function_params) override;
+#if defined(SAFE_BROWSING_DB_REMOTE)
+  virtual SafeBrowsingApiHandler* CreateSafeBrowsingApiHandler();
+#endif
 
  private:
   bool BasicStartupComplete(int* exit_code) override;
@@ -30,6 +34,10 @@
   scoped_ptr<SpdyProxyResourceThrottleFactory> spdy_proxy_throttle_factory_;
 #endif
 
+#if defined(SAFE_BROWSING_DB_REMOTE)
+  scoped_ptr<SafeBrowsingApiHandler> safe_browsing_api_handler_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(ChromeMainDelegateStagingAndroid);
 };
 
diff --git a/chrome/browser/android/compositor/layer/tab_layer.cc b/chrome/browser/android/compositor/layer/tab_layer.cc
index a95fdd4..9efaea5 100644
--- a/chrome/browser/android/compositor/layer/tab_layer.cc
+++ b/chrome/browser/android/compositor/layer/tab_layer.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/android/compositor/layer/tab_layer.h"
 
 #include "base/i18n/rtl.h"
-#include "cc/layers/image_layer.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_lists.h"
 #include "cc/layers/nine_patch_layer.h"
diff --git a/chrome/browser/android/compositor/layer/throbber_layer.cc b/chrome/browser/android/compositor/layer/throbber_layer.cc
index cc14ead..04a8c408 100644
--- a/chrome/browser/android/compositor/layer/throbber_layer.cc
+++ b/chrome/browser/android/compositor/layer/throbber_layer.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/android/compositor/layer/throbber_layer.h"
 
-#include "cc/layers/image_layer.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/solid_color_layer.h"
 #include "cc/layers/ui_resource_layer.h"
diff --git a/chrome/browser/android/content_view_util.cc b/chrome/browser/android/content_view_util.cc
deleted file mode 100644
index 75eaff9..0000000
--- a/chrome/browser/android/content_view_util.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/android/content_view_util.h"
-
-#include "base/android/jni_android.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "content/public/browser/android/content_view_core.h"
-#include "content/public/browser/web_contents.h"
-#include "jni/ContentViewUtil_jni.h"
-
-static jobject CreateWebContents(
-    JNIEnv* env, jclass clazz, jboolean incognito, jboolean initially_hidden) {
-  Profile* profile = g_browser_process->profile_manager()->GetLastUsedProfile();
-  if (incognito)
-    profile = profile->GetOffTheRecordProfile();
-
-  content::WebContents::CreateParams params(profile);
-  params.initially_hidden = static_cast<bool>(initially_hidden);
-  return content::WebContents::Create(params)->GetJavaWebContents().Release();
-}
-
-static jobject CreateWebContentsWithSharedSiteInstance(
-    JNIEnv* env,
-    jclass clazz,
-    jobject jcontent_view_core) {
-  content::ContentViewCore* content_view_core =
-      content::ContentViewCore::GetNativeContentViewCore(env,
-                                                         jcontent_view_core);
-  CHECK(content_view_core);
-
-  Profile* profile = Profile::FromBrowserContext(
-      content_view_core->GetWebContents()->GetBrowserContext());
-
-  content::WebContents::CreateParams params(
-      profile, content_view_core->GetWebContents()->GetSiteInstance());
-
-  return content::WebContents::Create(params)->GetJavaWebContents().Release();
-}
-
-static jobject GetWebContentsFromNative(
-    JNIEnv* env, jclass clazz, jlong web_contents_ptr) {
-  content::WebContents* web_contents =
-      reinterpret_cast<content::WebContents*>(web_contents_ptr);
-  if (!web_contents)
-    return NULL;
-  return web_contents->GetJavaWebContents().Release();
-}
-
-static jlong GetNativeWebContentsPtr(
-    JNIEnv* env, jclass clazz, jobject jweb_contents) {
-  return reinterpret_cast<intptr_t>(
-      content::WebContents::FromJavaWebContents(jweb_contents));
-}
-
-bool RegisterContentViewUtil(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
diff --git a/chrome/browser/android/content_view_util.h b/chrome/browser/android/content_view_util.h
deleted file mode 100644
index ea68300..0000000
--- a/chrome/browser/android/content_view_util.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ANDROID_CONTENT_VIEW_UTIL_H_
-#define CHROME_BROWSER_ANDROID_CONTENT_VIEW_UTIL_H_
-
-#include "base/android/jni_android.h"
-
-// Register the ContentViewUtil's native methods through JNI.
-bool RegisterContentViewUtil(JNIEnv* env);
-
-#endif  // CHROME_BROWSER_ANDROID_CONTENT_VIEW_UTIL_H_
-
diff --git a/chrome/browser/android/precache/precache_launcher.cc b/chrome/browser/android/precache/precache_launcher.cc
index f7cc29d..b3f91add 100644
--- a/chrome/browser/android/precache/precache_launcher.cc
+++ b/chrome/browser/android/precache/precache_launcher.cc
@@ -12,12 +12,12 @@
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/history/top_sites_factory.h"
-#include "chrome/browser/precache/most_visited_urls_provider.h"
+#include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/history/core/browser/top_sites.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "components/keyed_service/core/service_access_type.h"
 #include "components/precache/content/precache_manager.h"
 #include "components/precache/content/precache_manager_factory.h"
 #include "jni/PrecacheLauncher_jni.h"
@@ -25,6 +25,10 @@
 using base::android::AttachCurrentThread;
 using precache::PrecacheManager;
 
+namespace history {
+class HistoryService;
+}
+
 namespace {
 
 // Get the profile that should be used for precaching.
@@ -44,12 +48,10 @@
   return precache_manager;
 }
 
-bool IsDataReductionProxyEnabled(Profile* profile) {
-  // TODO(bengr): Use DataReductionProxySettings instead once it is safe to
-  // instantiate from here.
-  PrefService* prefs = profile->GetPrefs();
-  return prefs && prefs->GetBoolean(
-      data_reduction_proxy::prefs::kDataReductionProxyEnabled);
+bool IsSyncTabsEnabled(Profile* profile) {
+  ProfileSyncService* sync = ProfileSyncServiceFactory::GetForProfile(profile);
+  return sync->IsSyncEnabledAndLoggedIn() &&
+         sync->GetPreferredDataTypes().Has(syncer::PROXY_TABS);
 }
 
 }  // namespace
@@ -67,10 +69,11 @@
   // TODO(bengr): Add integration tests for the whole feature.
   Profile* profile = GetProfile();
   PrecacheManager* precache_manager = GetPrecacheManager(profile);
-  scoped_refptr<history::TopSites> ts = TopSitesFactory::GetForProfile(profile);
-  precache::MostVisitedURLsProvider url_list_provider(ts.get());
 
-  if (!IsDataReductionProxyEnabled(profile)) {
+  history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
+      profile, ServiceAccessType::IMPLICIT_ACCESS);
+
+  if (hs == nullptr || !IsSyncTabsEnabled(profile)) {
     Java_PrecacheLauncher_onPrecacheCompletedCallback(
         env, weak_java_precache_launcher_.get(env).obj());
     return;
@@ -79,7 +82,7 @@
   precache_manager->StartPrecaching(
       base::Bind(&PrecacheLauncher::OnPrecacheCompleted,
                  weak_factory_.GetWeakPtr()),
-      &url_list_provider);
+      *hs);
 }
 
 void PrecacheLauncher::Cancel(JNIEnv* env, jobject obj) {
diff --git a/chrome/browser/android/preferences/website_preference_bridge.cc b/chrome/browser/android/preferences/website_preference_bridge.cc
index eded5478..9d575d7 100644
--- a/chrome/browser/android/preferences/website_preference_bridge.cc
+++ b/chrome/browser/android/preferences/website_preference_bridge.cc
@@ -74,11 +74,11 @@
     const char* kHttpPortSuffix = ":80";
     const char* kHttpsPortSuffix = ":443";
     ScopedJavaLocalRef<jstring> jorigin;
-    if (StartsWithASCII(origin, url::kHttpsScheme, false) &&
+    if (base::StartsWithASCII(origin, url::kHttpsScheme, false) &&
         EndsWith(origin, kHttpsPortSuffix, false)) {
       jorigin = ConvertUTF8ToJavaString(
           env, origin.substr(0, origin.size() - strlen(kHttpsPortSuffix)));
-    } else if (StartsWithASCII(origin, url::kHttpScheme, false) &&
+    } else if (base::StartsWithASCII(origin, url::kHttpScheme, false) &&
                EndsWith(origin, kHttpPortSuffix, false)) {
       jorigin = ConvertUTF8ToJavaString(
           env, origin.substr(0, origin.size() - strlen(kHttpPortSuffix)));
diff --git a/chrome/browser/android/seccomp_support_detector.cc b/chrome/browser/android/seccomp_support_detector.cc
index d53911b..30581cc 100644
--- a/chrome/browser/android/seccomp_support_detector.cc
+++ b/chrome/browser/android/seccomp_support_detector.cc
@@ -10,16 +10,21 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
-#include "chrome/common/chrome_utility_messages.h"
-#include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/utility_process_host.h"
-#include "ui/base/l10n/l10n_util.h"
+
+#if defined(USE_SECCOMP_BPF)
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#endif
 
 using content::BrowserThread;
 
 enum AndroidSeccompStatus {
-  DETECTION_FAILED,  // The process crashed during detection.
+  // DETECTION_FAILED was formerly used when probing for seccomp was done
+  // out-of-process. There does not appear to be a gain in doing so, as
+  // explained in the comment in DetectSeccomp(). This enum remains for
+  // historical reasons.
+  DETECTION_FAILED_OBSOLETE,  // The process crashed during detection.
+
   NOT_SUPPORTED,     // Kernel has no seccomp support.
   SUPPORTED,         // Kernel has seccomp support.
   LAST_STATUS
@@ -28,12 +33,13 @@
 // static
 void SeccompSupportDetector::StartDetection() {
   // This is instantiated here, and then ownership is maintained by the
-  // Closure objects when the object is being passed between threads. A
-  // reference is also taken by the UtilityProcessHost, which will release
-  // it when the process exits.
+  // Closure objects when the object is being passed between threads. When
+  // the last Closure runs, it will delete this.
   scoped_refptr<SeccompSupportDetector> detector(new SeccompSupportDetector());
   BrowserThread::PostBlockingPoolTask(FROM_HERE,
       base::Bind(&SeccompSupportDetector::DetectKernelVersion, detector));
+  BrowserThread::PostBlockingPoolTask(FROM_HERE,
+      base::Bind(&SeccompSupportDetector::DetectSeccomp, detector));
 }
 
 SeccompSupportDetector::SeccompSupportDetector() {
@@ -57,51 +63,23 @@
       UMA_HISTOGRAM_SPARSE_SLOWLY("Android.KernelVersion", version);
     }
   }
-
-#if defined(USE_SECCOMP_BPF)
-  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
-      base::Bind(&SeccompSupportDetector::DetectSeccomp, this));
-#else
-  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
-      base::Bind(&SeccompSupportDetector::OnDetectPrctl, this, false));
-#endif
 }
 
 void SeccompSupportDetector::DetectSeccomp() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
 
-  content::UtilityProcessHost* utility_process_host =
-      content::UtilityProcessHost::Create(
-          this, base::MessageLoopProxy::current());
-  utility_process_host->SetName(l10n_util::GetStringUTF16(
-      IDS_UTILITY_PROCESS_SECCOMP_DETECTOR_NAME));
-  utility_process_host->Send(new ChromeUtilityMsg_DetectSeccompSupport());
-}
-
-void SeccompSupportDetector::OnProcessCrashed(int exit_code) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Prctl",
-                            DETECTION_FAILED,
-                            LAST_STATUS);
-}
-
-bool SeccompSupportDetector::OnMessageReceived(const IPC::Message& message) {
-  bool handled = false;
-  IPC_BEGIN_MESSAGE_MAP(SeccompSupportDetector, message)
-    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DetectSeccompSupport_ResultPrctl,
-                        OnDetectPrctl)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void SeccompSupportDetector::OnDetectPrctl(bool prctl_supported) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+#if defined(USE_SECCOMP_BPF)
+  bool prctl_supported = sandbox::SandboxBPF::SupportsSeccompSandbox(
+      sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED);
+#else
+  bool prctl_supported = false;
+#endif
 
   UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Prctl",
                             prctl_supported ? SUPPORTED : NOT_SUPPORTED,
                             LAST_STATUS);
 
-  // The utility process will shutdown after this, and this object will
-  // be deleted when the UtilityProcessHost releases its reference.
+  // Probing for the seccomp syscall can provoke kernel panics in certain LGE
+  // devices. For now, this data will not be collected. In the future, this
+  // should detect SeccompLevel::MULTI_THREADED. http://crbug.com/478478
 }
diff --git a/chrome/browser/android/seccomp_support_detector.h b/chrome/browser/android/seccomp_support_detector.h
index 58d66bd..d74e3fe 100644
--- a/chrome/browser/android/seccomp_support_detector.h
+++ b/chrome/browser/android/seccomp_support_detector.h
@@ -6,35 +6,32 @@
 #define CHROME_BROWSER_ANDROID_SECCOMP_SUPPORT_DETECTOR_H_
 
 #include "base/compiler_specific.h"
-#include "content/public/browser/utility_process_host_client.h"
+#include "base/memory/ref_counted.h"
 
 // This class is used to report via UMA the Android kernel version and
-// level of seccomp-bpf support. The kernel version is read from the blocking
-// thread pool, while seccomp support is tested in a utility process, in case
-// the probing causes a crash.
-class SeccompSupportDetector : public content::UtilityProcessHostClient {
+// level of seccomp-bpf support. The operations are performed on the
+// blocking thread pool.
+class SeccompSupportDetector
+    : public base::RefCountedThreadSafe<SeccompSupportDetector> {
  public:
   // Starts the detection process. This should be called once per browser
   // session. This is safe to call from any thread.
   static void StartDetection();
 
  private:
+  friend class base::RefCountedThreadSafe<SeccompSupportDetector>;
+
   SeccompSupportDetector();
-  ~SeccompSupportDetector() override;
+  ~SeccompSupportDetector();
 
   // Called on the blocking thread pool. This reads the utsname and records
   // the kernel version.
   void DetectKernelVersion();
 
-  // Called on the IO thread. This starts a utility process to detect seccomp.
+  // Called on the blocking thread pool. This tests whether the system
+  // supports PR_SET_SECCOMP.
   void DetectSeccomp();
 
-  // UtilityProcessHostClient:
-  void OnProcessCrashed(int exit_code) override;
-  bool OnMessageReceived(const IPC::Message& message) override;
-
-  void OnDetectPrctl(bool prctl_supported);
-
   DISALLOW_COPY_AND_ASSIGN(SeccompSupportDetector);
 };
 
diff --git a/chrome/browser/android/shortcut_data_fetcher.cc b/chrome/browser/android/shortcut_data_fetcher.cc
index 39bccfa..f4de97a 100644
--- a/chrome/browser/android/shortcut_data_fetcher.cc
+++ b/chrome/browser/android/shortcut_data_fetcher.cc
@@ -22,7 +22,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/frame_navigate_params.h"
 #include "content/public/common/manifest.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/favicon_size.h"
 #include "ui/gfx/screen.h"
diff --git a/chrome/browser/android/shortcut_info.h b/chrome/browser/android/shortcut_info.h
index 9415103..e641c0b6 100644
--- a/chrome/browser/android/shortcut_info.h
+++ b/chrome/browser/android/shortcut_info.h
@@ -7,7 +7,7 @@
 
 #include "base/strings/string16.h"
 #include "content/public/common/manifest.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 #include "url/gurl.h"
 
 // Information needed to create a shortcut via ShortcutHelper.
diff --git a/chrome/browser/android/tab_state.cc b/chrome/browser/android/tab_state.cc
index f22255a..052e28e9 100644
--- a/chrome/browser/android/tab_state.cc
+++ b/chrome/browser/android/tab_state.cc
@@ -444,7 +444,7 @@
   return web_contents.release();
 }
 
-WebContents* WebContentsState::RestoreContentsFromByteBuffer(
+jobject WebContentsState::RestoreContentsFromByteBuffer(
     JNIEnv* env,
     jclass clazz,
     jobject state,
@@ -453,10 +453,13 @@
   void* data = env->GetDirectBufferAddress(state);
   int size = env->GetDirectBufferCapacity(state);
 
-  return WebContentsState::RestoreContentsFromByteBuffer(data,
-                                                         size,
-                                                         saved_state_version,
-                                                         initially_hidden);
+  WebContents* web_contents = WebContentsState::RestoreContentsFromByteBuffer(
+      data,
+      size,
+      saved_state_version,
+      initially_hidden);
+
+  return web_contents ? web_contents->GetJavaWebContents().Release() : nullptr;
 }
 
 ScopedJavaLocalRef<jobject>
@@ -497,17 +500,16 @@
   free(data);
 }
 
-static jlong RestoreContentsFromByteBuffer(JNIEnv* env,
-                                           jclass clazz,
-                                           jobject state,
-                                           jint saved_state_version,
-                                           jboolean initially_hidden) {
-  return reinterpret_cast<intptr_t>(
-      WebContentsState::RestoreContentsFromByteBuffer(env,
-                                                      clazz,
-                                                      state,
-                                                      saved_state_version,
-                                                      initially_hidden));
+static jobject RestoreContentsFromByteBuffer(JNIEnv* env,
+                                             jclass clazz,
+                                             jobject state,
+                                             jint saved_state_version,
+                                             jboolean initially_hidden) {
+  return WebContentsState::RestoreContentsFromByteBuffer(env,
+                                                         clazz,
+                                                         state,
+                                                         saved_state_version,
+                                                         initially_hidden);
 }
 
 static jobject GetContentsStateAsByteBuffer(
@@ -560,11 +562,12 @@
                                 jobject state,
                                 jint saved_state_version) {
   scoped_ptr<WebContents> web_contents(
-      WebContentsState::RestoreContentsFromByteBuffer(env,
-                                                      clazz,
-                                                      state,
-                                                      saved_state_version,
-                                                      true));
+      WebContents::FromJavaWebContents(
+          WebContentsState::RestoreContentsFromByteBuffer(env,
+                                                          clazz,
+                                                          state,
+                                                          saved_state_version,
+                                                          true)));
   if (web_contents.get())
     TabAndroid::CreateHistoricalTabFromContents(web_contents.get());
 }
diff --git a/chrome/browser/android/tab_state.h b/chrome/browser/android/tab_state.h
index 4e33315..3f5f736 100644
--- a/chrome/browser/android/tab_state.h
+++ b/chrome/browser/android/tab_state.h
@@ -51,7 +51,7 @@
       bool initially_hidden);
 
   // Restores a WebContents from the passed in state.
-  static content::WebContents* RestoreContentsFromByteBuffer(
+  static jobject RestoreContentsFromByteBuffer(
       JNIEnv* env,
       jclass clazz,
       jobject state,
diff --git a/chrome/browser/android/web_contents_factory.cc b/chrome/browser/android/web_contents_factory.cc
new file mode 100644
index 0000000..3f3e086
--- /dev/null
+++ b/chrome/browser/android/web_contents_factory.cc
@@ -0,0 +1,28 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/web_contents_factory.h"
+
+#include "base/android/jni_android.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "content/public/browser/android/content_view_core.h"
+#include "content/public/browser/web_contents.h"
+#include "jni/WebContentsFactory_jni.h"
+
+static jobject CreateWebContents(
+    JNIEnv* env, jclass clazz, jboolean incognito, jboolean initially_hidden) {
+  Profile* profile = g_browser_process->profile_manager()->GetLastUsedProfile();
+  if (incognito)
+    profile = profile->GetOffTheRecordProfile();
+
+  content::WebContents::CreateParams params(profile);
+  params.initially_hidden = static_cast<bool>(initially_hidden);
+  return content::WebContents::Create(params)->GetJavaWebContents().Release();
+}
+
+bool RegisterWebContentsFactory(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
diff --git a/chrome/browser/android/web_contents_factory.h b/chrome/browser/android/web_contents_factory.h
new file mode 100644
index 0000000..5915675
--- /dev/null
+++ b/chrome/browser/android/web_contents_factory.h
@@ -0,0 +1,14 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_WEB_CONTENTS_FACTORY_H_
+#define CHROME_BROWSER_ANDROID_WEB_CONTENTS_FACTORY_H_
+
+#include "base/android/jni_android.h"
+
+// Register the WebContentsFactory's native methods through JNI.
+bool RegisterWebContentsFactory(JNIEnv* env);
+
+#endif  // CHROME_BROWSER_ANDROID_WEB_CONTENTS_FACTORY_H_
+
diff --git a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
index 4c1b143..1373dbd 100644
--- a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
@@ -35,6 +35,7 @@
 #include "extensions/browser/app_window/native_app_window.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/test/extension_test_message_listener.h"
+#import "ui/base/test/windowed_nsnotification_observer.h"
 #import "ui/events/test/cocoa_test_event_utils.h"
 
 namespace {
@@ -301,59 +302,6 @@
 
 }  // namespace
 
-// Watches for NSNotifications from the shared workspace.
-@interface WindowedNSNotificationObserver : NSObject {
- @private
-  base::scoped_nsobject<NSString> bundleId_;
-  BOOL notificationReceived_;
-  scoped_ptr<base::RunLoop> runLoop_;
-}
-
-- (id)initForNotification:(NSString*)name
-              andBundleId:(NSString*)bundleId;
-- (void)observe:(NSNotification*)notification;
-- (void)wait;
-@end
-
-@implementation WindowedNSNotificationObserver
-
-- (id)initForNotification:(NSString*)name
-              andBundleId:(NSString*)bundleId {
-  if (self = [super init]) {
-    bundleId_.reset([[bundleId copy] retain]);
-    [[[NSWorkspace sharedWorkspace] notificationCenter]
-        addObserver:self
-           selector:@selector(observe:)
-               name:name
-             object:nil];
-  }
-  return self;
-}
-
-- (void)observe:(NSNotification*)notification {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  NSRunningApplication* application =
-      [[notification userInfo] objectForKey:NSWorkspaceApplicationKey];
-  if (![[application bundleIdentifier] isEqualToString:bundleId_])
-    return;
-
-  [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
-  notificationReceived_ = YES;
-  if (runLoop_.get())
-    runLoop_->Quit();
-}
-
-- (void)wait {
-  if (notificationReceived_)
-    return;
-
-  runLoop_.reset(new base::RunLoop);
-  runLoop_->Run();
-}
-
-@end
-
 namespace apps {
 
 // Shims require static libraries http://crbug.com/386024.
@@ -387,8 +335,8 @@
   {
     base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer;
     ns_observer.reset([[WindowedNSNotificationObserver alloc]
-        initForNotification:NSWorkspaceDidLaunchApplicationNotification
-                andBundleId:bundle_id]);
+        initForWorkspaceNotification:NSWorkspaceDidLaunchApplicationNotification
+                            bundleId:bundle_id]);
     WindowedAppShimLaunchObserver observer(app->id());
     LaunchHostedApp(app);
     [ns_observer wait];
@@ -402,8 +350,9 @@
     ASSERT_EQ(1u, [running_shim count]);
 
     ns_observer.reset([[WindowedNSNotificationObserver alloc]
-        initForNotification:NSWorkspaceDidTerminateApplicationNotification
-                andBundleId:bundle_id]);
+        initForWorkspaceNotification:
+            NSWorkspaceDidTerminateApplicationNotification
+                            bundleId:bundle_id]);
     [base::mac::ObjCCastStrict<NSRunningApplication>(
         [running_shim objectAtIndex:0]) terminate];
     [ns_observer wait];
@@ -458,8 +407,8 @@
   {
     base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer;
     ns_observer.reset([[WindowedNSNotificationObserver alloc]
-        initForNotification:NSWorkspaceDidLaunchApplicationNotification
-                andBundleId:bundle_id]);
+        initForWorkspaceNotification:NSWorkspaceDidLaunchApplicationNotification
+                            bundleId:bundle_id]);
     WindowedAppShimLaunchObserver observer(app->id());
     LaunchPlatformApp(app);
     [ns_observer wait];
@@ -478,8 +427,9 @@
     ASSERT_EQ(1u, [running_shim count]);
 
     ns_observer.reset([[WindowedNSNotificationObserver alloc]
-        initForNotification:NSWorkspaceDidTerminateApplicationNotification
-                andBundleId:bundle_id]);
+        initForWorkspaceNotification:
+            NSWorkspaceDidTerminateApplicationNotification
+                            bundleId:bundle_id]);
     [base::mac::ObjCCastStrict<NSRunningApplication>(
         [running_shim objectAtIndex:0]) terminate];
     [ns_observer wait];
@@ -546,10 +496,10 @@
 
   // Showing the window causes the shim to launch.
   {
-    base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer(
-        [[WindowedNSNotificationObserver alloc]
-            initForNotification:NSWorkspaceDidLaunchApplicationNotification
-                    andBundleId:bundle_id]);
+    base::scoped_nsobject<WindowedNSNotificationObserver>
+    ns_observer([[WindowedNSNotificationObserver alloc]
+        initForWorkspaceNotification:NSWorkspaceDidLaunchApplicationNotification
+                            bundleId:bundle_id]);
     WindowedAppShimLaunchObserver observer(app->id());
     window_1->Show(extensions::AppWindow::SHOW_INACTIVE);
     [ns_observer wait];
@@ -562,8 +512,9 @@
   {
     base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer(
         [[WindowedNSNotificationObserver alloc]
-            initForNotification:NSWorkspaceDidTerminateApplicationNotification
-                    andBundleId:bundle_id]);
+            initForWorkspaceNotification:
+                NSWorkspaceDidTerminateApplicationNotification
+                                bundleId:bundle_id]);
     window_1->Hide();
     [ns_observer wait];
     EXPECT_FALSE(HasAppShimHost(profile(), app->id()));
@@ -587,10 +538,10 @@
 
   // Showing one of the windows should launch the shim.
   {
-    base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer(
-        [[WindowedNSNotificationObserver alloc]
-            initForNotification:NSWorkspaceDidLaunchApplicationNotification
-                    andBundleId:bundle_id]);
+    base::scoped_nsobject<WindowedNSNotificationObserver>
+    ns_observer([[WindowedNSNotificationObserver alloc]
+        initForWorkspaceNotification:NSWorkspaceDidLaunchApplicationNotification
+                            bundleId:bundle_id]);
     WindowedAppShimLaunchObserver observer(app->id());
     window_1->Show(extensions::AppWindow::SHOW_INACTIVE);
     [ns_observer wait];
@@ -625,8 +576,9 @@
     EXPECT_TRUE(HasAppShimHost(profile(), app->id()));
     base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer(
         [[WindowedNSNotificationObserver alloc]
-            initForNotification:NSWorkspaceDidTerminateApplicationNotification
-                    andBundleId:bundle_id]);
+            initForWorkspaceNotification:
+                NSWorkspaceDidTerminateApplicationNotification
+                                bundleId:bundle_id]);
     window_2->Hide();
     [ns_observer wait];
     EXPECT_EQ(1, deactivate_observer.deactivated_count());
diff --git a/chrome/browser/apps/ephemeral_app_browsertest.cc b/chrome/browser/apps/ephemeral_app_browsertest.cc
index 07e01b5..de35c13 100644
--- a/chrome/browser/apps/ephemeral_app_browsertest.cc
+++ b/chrome/browser/apps/ephemeral_app_browsertest.cc
@@ -293,13 +293,6 @@
 void EphemeralAppTestBase::DisableEphemeralApp(
     const Extension* app,
     Extension::DisableReason disable_reason) {
-  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
-
-  // Disabling due to a permissions increase also involves setting the
-  // DidExtensionEscalatePermissions flag.
-  if (disable_reason == Extension::DISABLE_PERMISSIONS_INCREASE)
-    prefs->SetDidExtensionEscalatePermissions(app, true);
-
   ExtensionSystem::Get(profile())->extension_service()->DisableExtension(
       app->id(), disable_reason);
 
diff --git a/chrome/browser/apps/ephemeral_app_launcher_browsertest.cc b/chrome/browser/apps/ephemeral_app_launcher_browsertest.cc
index 5affa8a469..63e6bc96 100644
--- a/chrome/browser/apps/ephemeral_app_launcher_browsertest.cc
+++ b/chrome/browser/apps/ephemeral_app_launcher_browsertest.cc
@@ -287,13 +287,6 @@
         ExtensionSystem::Get(profile())->extension_service();
     service->DisableExtension(app->id(), disable_reason);
 
-    if (disable_reason == Extension::DISABLE_PERMISSIONS_INCREASE) {
-      // When an extension is disabled due to a permissions increase, this
-      // flag needs to be set too, for some reason.
-      ExtensionPrefs::Get(profile())
-          ->SetDidExtensionEscalatePermissions(app, true);
-    }
-
     EXPECT_TRUE(
         ExtensionRegistry::Get(profile())->disabled_extensions().Contains(
             app->id()));
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 7e023e5..bbe1cd8 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -540,13 +540,13 @@
       const std::string& path,
       const GURL& redirect_target,
       const net::test_server::HttpRequest& request) {
-    if (!StartsWithASCII(path, request.relative_url, true))
+    if (!base::StartsWithASCII(path, request.relative_url, true))
       return scoped_ptr<net::test_server::HttpResponse>();
 
     std::map<std::string, std::string>::const_iterator it =
           request.headers.find("User-Agent");
     EXPECT_TRUE(it != request.headers.end());
-    if (!StartsWithASCII("foobar", it->second, true))
+    if (!base::StartsWithASCII("foobar", it->second, true))
       return scoped_ptr<net::test_server::HttpResponse>();
 
     scoped_ptr<net::test_server::BasicHttpResponse> http_response(
@@ -561,7 +561,7 @@
       const std::string& path,
       const GURL& redirect_target,
       const net::test_server::HttpRequest& request) {
-    if (!StartsWithASCII(path, request.relative_url, true))
+    if (!base::StartsWithASCII(path, request.relative_url, true))
       return scoped_ptr<net::test_server::HttpResponse>();
 
     scoped_ptr<net::test_server::BasicHttpResponse> http_response(
@@ -575,7 +575,7 @@
   static scoped_ptr<net::test_server::HttpResponse> EmptyResponseHandler(
       const std::string& path,
       const net::test_server::HttpRequest& request) {
-    if (StartsWithASCII(path, request.relative_url, true))
+    if (base::StartsWithASCII(path, request.relative_url, true))
       return scoped_ptr<net::test_server::HttpResponse>(new EmptyHttpResponse);
 
     return scoped_ptr<net::test_server::HttpResponse>();
@@ -585,7 +585,7 @@
   static scoped_ptr<net::test_server::HttpResponse> CacheControlResponseHandler(
       const std::string& path,
       const net::test_server::HttpRequest& request) {
-    if (!StartsWithASCII(path, request.relative_url, true))
+    if (!base::StartsWithASCII(path, request.relative_url, true))
       return scoped_ptr<net::test_server::HttpResponse>();
 
     scoped_ptr<net::test_server::BasicHttpResponse> http_response(
diff --git a/chrome/browser/auto_launch_trial.cc b/chrome/browser/auto_launch_trial.cc
index ae53d7b..a235de7 100644
--- a/chrome/browser/auto_launch_trial.cc
+++ b/chrome/browser/auto_launch_trial.cc
@@ -24,11 +24,11 @@
 }
 
 bool IsInExperimentGroup(const std::string& brand_code) {
-  return LowerCaseEqualsASCII(brand_code, "rngp");
+  return base::LowerCaseEqualsASCII(brand_code, "rngp");
 }
 
 bool IsInControlGroup(const std::string& brand_code) {
-  return LowerCaseEqualsASCII(brand_code, "rngq");
+  return base::LowerCaseEqualsASCII(brand_code, "rngq");
 }
 
 }  // namespace auto_launch_trial
diff --git a/chrome/browser/autocomplete/autocomplete_classifier_factory.cc b/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
index 28c760166..d6458e9 100644
--- a/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
+++ b/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
@@ -32,15 +32,15 @@
 }
 
 // static
-KeyedService* AutocompleteClassifierFactory::BuildInstanceFor(
+scoped_ptr<KeyedService> AutocompleteClassifierFactory::BuildInstanceFor(
     content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
-  return new AutocompleteClassifier(
+  return make_scoped_ptr(new AutocompleteClassifier(
       make_scoped_ptr(new AutocompleteController(
           profile, TemplateURLServiceFactory::GetForProfile(profile), NULL,
           AutocompleteClassifier::kDefaultOmniboxProviders)),
       scoped_ptr<AutocompleteSchemeClassifier>(
-          new ChromeAutocompleteSchemeClassifier(profile)));
+          new ChromeAutocompleteSchemeClassifier(profile))));
 }
 
 AutocompleteClassifierFactory::AutocompleteClassifierFactory()
@@ -72,5 +72,5 @@
 
 KeyedService* AutocompleteClassifierFactory::BuildServiceInstanceFor(
     content::BrowserContext* profile) const {
-  return BuildInstanceFor(static_cast<Profile*>(profile));
+  return BuildInstanceFor(static_cast<Profile*>(profile)).release();
 }
diff --git a/chrome/browser/autocomplete/autocomplete_classifier_factory.h b/chrome/browser/autocomplete/autocomplete_classifier_factory.h
index 84ef185..bfacf212 100644
--- a/chrome/browser/autocomplete/autocomplete_classifier_factory.h
+++ b/chrome/browser/autocomplete/autocomplete_classifier_factory.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_CLASSIFIER_FACTORY_H_
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
@@ -21,7 +22,8 @@
 
   static AutocompleteClassifierFactory* GetInstance();
 
-  static KeyedService* BuildInstanceFor(content::BrowserContext* context);
+  static scoped_ptr<KeyedService> BuildInstanceFor(
+      content::BrowserContext* context);
 
  private:
   friend struct DefaultSingletonTraits<AutocompleteClassifierFactory>;
diff --git a/chrome/browser/autocomplete/builtin_provider.cc b/chrome/browser/autocomplete/builtin_provider.cc
index d3bd7a7..431ab46 100644
--- a/chrome/browser/autocomplete/builtin_provider.cc
+++ b/chrome/browser/autocomplete/builtin_provider.cc
@@ -81,8 +81,8 @@
   const int kMatch = kUrl | ACMatchClassification::MATCH;
 
   base::string16 text = input.text();
-  bool starting_chrome = StartsWith(kChrome, text, false);
-  if (starting_chrome || StartsWith(kAbout, text, false)) {
+  bool starting_chrome = base::StartsWith(kChrome, text, false);
+  if (starting_chrome || base::StartsWith(kAbout, text, false)) {
     ACMatchClassifications styles;
     // Highlight the input portion matching "chrome://"; or if the user has
     // input "about:" (with optional slashes), highlight the whole "chrome://".
@@ -111,8 +111,10 @@
       // Chrome does not support trailing slashes or paths for about:blank.
       const base::string16 blank_host = base::ASCIIToUTF16("blank");
       const base::string16 host = base::UTF8ToUTF16(url.host());
-      if (StartsWith(text, base::ASCIIToUTF16(url::kAboutScheme), false) &&
-          StartsWith(blank_host, host, false) && (url.path().length() <= 1) &&
+      if (base::StartsWith(text, base::ASCIIToUTF16(url::kAboutScheme),
+                           false) &&
+          base::StartsWith(blank_host, host, false) &&
+          (url.path().length() <= 1) &&
           !EndsWith(text, base::ASCIIToUTF16("/"), false)) {
         ACMatchClassifications styles;
         styles.push_back(ACMatchClassification(0, kMatch));
@@ -130,7 +132,7 @@
       size_t match_length = kChrome.length() + host_and_path.length();
       for (Builtins::const_iterator i(builtins_.begin());
           (i != builtins_.end()) && (matches_.size() < kMaxMatches); ++i) {
-        if (StartsWith(*i, host_and_path, false)) {
+        if (base::StartsWith(*i, host_and_path, false)) {
           ACMatchClassifications styles;
           // Highlight the "chrome://" scheme, even for input "about:foo".
           styles.push_back(ACMatchClassification(0, kMatch));
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
index c64520f..61e5f32 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
@@ -25,9 +25,9 @@
     const std::string& scheme) const {
   if (base::IsStringASCII(scheme) &&
       (ProfileIOData::IsHandledProtocol(scheme) ||
-       LowerCaseEqualsASCII(scheme, content::kViewSourceScheme) ||
-       LowerCaseEqualsASCII(scheme, url::kJavaScriptScheme) ||
-       LowerCaseEqualsASCII(scheme, url::kDataScheme))) {
+       base::LowerCaseEqualsASCII(scheme, content::kViewSourceScheme) ||
+       base::LowerCaseEqualsASCII(scheme, url::kJavaScriptScheme) ||
+       base::LowerCaseEqualsASCII(scheme, url::kDataScheme))) {
     return metrics::OmniboxInputType::URL;
   }
 
diff --git a/chrome/browser/autocomplete/history_provider.cc b/chrome/browser/autocomplete/history_provider.cc
index 3296334..a0bfa79 100644
--- a/chrome/browser/autocomplete/history_provider.cc
+++ b/chrome/browser/autocomplete/history_provider.cc
@@ -8,7 +8,6 @@
 
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/autocomplete/in_memory_url_index_types.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -17,6 +16,7 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/omnibox/autocomplete_input.h"
 #include "components/omnibox/autocomplete_match.h"
+#include "components/omnibox/in_memory_url_index_types.h"
 #include "url/url_util.h"
 
 using bookmarks::BookmarkModel;
diff --git a/chrome/browser/autocomplete/history_provider.h b/chrome/browser/autocomplete/history_provider.h
index 63e29ea..0f06ab8 100644
--- a/chrome/browser/autocomplete/history_provider.h
+++ b/chrome/browser/autocomplete/history_provider.h
@@ -6,8 +6,8 @@
 #define CHROME_BROWSER_AUTOCOMPLETE_HISTORY_PROVIDER_H_
 
 #include "base/compiler_specific.h"
-#include "chrome/browser/autocomplete/in_memory_url_index_types.h"
 #include "components/omnibox/autocomplete_provider.h"
+#include "components/omnibox/in_memory_url_index_types.h"
 
 class AutocompleteInput;
 class Profile;
diff --git a/chrome/browser/autocomplete/history_quick_provider.cc b/chrome/browser/autocomplete/history_quick_provider.cc
index f4b4277ae..96c763b 100644
--- a/chrome/browser/autocomplete/history_quick_provider.cc
+++ b/chrome/browser/autocomplete/history_quick_provider.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
 #include "chrome/browser/autocomplete/history_url_provider.h"
 #include "chrome/browser/autocomplete/in_memory_url_index.h"
-#include "chrome/browser/autocomplete/in_memory_url_index_types.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -33,6 +32,7 @@
 #include "components/metrics/proto/omnibox_input_type.pb.h"
 #include "components/omnibox/autocomplete_match_type.h"
 #include "components/omnibox/autocomplete_result.h"
+#include "components/omnibox/in_memory_url_index_types.h"
 #include "components/omnibox/omnibox_field_trial.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_service.h"
diff --git a/chrome/browser/autocomplete/history_quick_provider_unittest.cc b/chrome/browser/autocomplete/history_quick_provider_unittest.cc
index 0cb203b..eedeb29 100644
--- a/chrome/browser/autocomplete/history_quick_provider_unittest.cc
+++ b/chrome/browser/autocomplete/history_quick_provider_unittest.cc
@@ -169,15 +169,15 @@
     std::set<std::string> matches_;
   };
 
-  static KeyedService* CreateTemplateURLService(
+  static scoped_ptr<KeyedService> CreateTemplateURLService(
       content::BrowserContext* context) {
     Profile* profile = static_cast<Profile*>(context);
-    return new TemplateURLService(
+    return make_scoped_ptr(new TemplateURLService(
         profile->GetPrefs(), make_scoped_ptr(new SearchTermsData), NULL,
         scoped_ptr<TemplateURLServiceClient>(new ChromeTemplateURLServiceClient(
             HistoryServiceFactory::GetForProfile(
                 profile, ServiceAccessType::EXPLICIT_ACCESS))),
-        NULL, NULL, base::Closure());
+        NULL, NULL, base::Closure()));
   }
 
   void SetUp() override;
diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc
index 93581bf..24aa7f0 100644
--- a/chrome/browser/autocomplete/history_url_provider.cc
+++ b/chrome/browser/autocomplete/history_url_provider.cc
@@ -16,7 +16,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
-#include "chrome/browser/autocomplete/in_memory_url_index_types.h"
 #include "chrome/browser/autocomplete/scored_history_match.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -34,6 +33,7 @@
 #include "components/omnibox/autocomplete_match.h"
 #include "components/omnibox/autocomplete_provider_listener.h"
 #include "components/omnibox/autocomplete_result.h"
+#include "components/omnibox/in_memory_url_index_types.h"
 #include "components/omnibox/omnibox_field_trial.h"
 #include "components/omnibox/url_prefix.h"
 #include "components/search_engines/template_url_service.h"
@@ -968,7 +968,7 @@
   // input's text and parts between Parse() and here, it seems better to be
   // paranoid and check.
   if ((input.type() != metrics::OmniboxInputType::UNKNOWN) ||
-      !LowerCaseEqualsASCII(input.scheme(), url::kHttpScheme) ||
+      !base::LowerCaseEqualsASCII(input.scheme(), url::kHttpScheme) ||
       !input.parts().host.is_nonempty())
     return false;
   const std::string host(base::UTF16ToUTF8(
diff --git a/chrome/browser/autocomplete/history_url_provider_unittest.cc b/chrome/browser/autocomplete/history_url_provider_unittest.cc
index d111f25..a5bd316d 100644
--- a/chrome/browser/autocomplete/history_url_provider_unittest.cc
+++ b/chrome/browser/autocomplete/history_url_provider_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
@@ -170,15 +171,15 @@
   void OnProviderUpdate(bool updated_matches) override;
 
  protected:
-  static KeyedService* CreateTemplateURLService(
+  static scoped_ptr<KeyedService> CreateTemplateURLService(
       content::BrowserContext* context) {
     Profile* profile = static_cast<Profile*>(context);
-    return new TemplateURLService(
+    return make_scoped_ptr(new TemplateURLService(
         profile->GetPrefs(), make_scoped_ptr(new SearchTermsData), NULL,
         scoped_ptr<TemplateURLServiceClient>(new ChromeTemplateURLServiceClient(
             HistoryServiceFactory::GetForProfile(
                 profile, ServiceAccessType::EXPLICIT_ACCESS))),
-        NULL, NULL, base::Closure());
+        NULL, NULL, base::Closure()));
   }
 
   // testing::Test
diff --git a/chrome/browser/autocomplete/in_memory_url_index_unittest.cc b/chrome/browser/autocomplete/in_memory_url_index_unittest.cc
index 5c68b40..85359ac9 100644
--- a/chrome/browser/autocomplete/in_memory_url_index_unittest.cc
+++ b/chrome/browser/autocomplete/in_memory_url_index_unittest.cc
@@ -15,7 +15,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autocomplete/in_memory_url_index.h"
-#include "chrome/browser/autocomplete/in_memory_url_index_types.h"
 #include "chrome/browser/autocomplete/url_index_private_data.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
@@ -26,6 +25,7 @@
 #include "components/history/core/browser/history_backend.h"
 #include "components/history/core/browser/history_database.h"
 #include "components/history/core/browser/history_service.h"
+#include "components/omnibox/in_memory_url_index_types.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "sql/transaction.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/autocomplete/scored_history_match.h b/chrome/browser/autocomplete/scored_history_match.h
index 856f8c4b..e2e8379 100644
--- a/chrome/browser/autocomplete/scored_history_match.h
+++ b/chrome/browser/autocomplete/scored_history_match.h
@@ -10,9 +10,9 @@
 
 #include "base/strings/string16.h"
 #include "base/time/time.h"
-#include "chrome/browser/autocomplete/in_memory_url_index_types.h"
 #include "components/history/core/browser/history_match.h"
 #include "components/history/core/browser/history_types.h"
+#include "components/omnibox/in_memory_url_index_types.h"
 #include "testing/gtest/include/gtest/gtest_prod.h"
 
 class ScoredHistoryMatchTest;
diff --git a/chrome/browser/autocomplete/shortcuts_backend.cc b/chrome/browser/autocomplete/shortcuts_backend.cc
index 003be70..4768209 100644
--- a/chrome/browser/autocomplete/shortcuts_backend.cc
+++ b/chrome/browser/autocomplete/shortcuts_backend.cc
@@ -131,9 +131,10 @@
   const base::string16 text_lowercase(base::i18n::ToLower(text));
   const base::Time now(base::Time::Now());
   for (ShortcutMap::const_iterator it(
-       shortcuts_map_.lower_bound(text_lowercase));
+           shortcuts_map_.lower_bound(text_lowercase));
        it != shortcuts_map_.end() &&
-           StartsWith(it->first, text_lowercase, true); ++it) {
+           base::StartsWith(it->first, text_lowercase, true);
+       ++it) {
     if (match.destination_url == it->second.match_core.destination_url) {
       UpdateShortcut(ShortcutsDatabase::Shortcut(
           it->second.id, text, MatchToMatchCore(match, profile_), now,
@@ -315,10 +316,10 @@
   const std::string& url_spec = url.spec();
   ShortcutsDatabase::ShortcutIDs shortcut_ids;
   for (GuidMap::iterator it(guid_map_.begin()); it != guid_map_.end(); ) {
-    if (exact_match ?
-        (it->second->second.match_core.destination_url == url) :
-        StartsWithASCII(it->second->second.match_core.destination_url.spec(),
-                        url_spec, true)) {
+    if (exact_match ? (it->second->second.match_core.destination_url == url)
+                    : base::StartsWithASCII(
+                          it->second->second.match_core.destination_url.spec(),
+                          url_spec, true)) {
       shortcut_ids.push_back(it->first);
       shortcuts_map_.erase(it->second);
       guid_map_.erase(it++);
diff --git a/chrome/browser/autocomplete/shortcuts_provider.cc b/chrome/browser/autocomplete/shortcuts_provider.cc
index 443eb72..dc46d0ca 100644
--- a/chrome/browser/autocomplete/shortcuts_provider.cc
+++ b/chrome/browser/autocomplete/shortcuts_provider.cc
@@ -146,7 +146,8 @@
   for (ShortcutsBackend::ShortcutMap::const_iterator it =
            FindFirstMatch(term_string, backend.get());
        it != backend->shortcuts_map().end() &&
-           StartsWith(it->first, term_string, true); ++it) {
+           base::StartsWith(it->first, term_string, true);
+       ++it) {
     // Don't return shortcuts with zero relevance.
     int relevance = CalculateScore(term_string, it->second, max_relevance);
     if (relevance) {
@@ -216,7 +217,7 @@
   // input of "foo.c" to autocomplete to "foo.com" for a fill_into_edit of
   // "http://foo.com".
   if (AutocompleteMatch::IsSearchType(match.type)) {
-    if (StartsWith(match.fill_into_edit, input.text(), false)) {
+    if (base::StartsWith(match.fill_into_edit, input.text(), false)) {
       match.inline_autocompletion =
           match.fill_into_edit.substr(input.text().length());
       match.allowed_to_be_default_match =
@@ -304,7 +305,7 @@
   base::string16 text_lowercase(base::i18n::ToLower(text));
   ACMatchClassifications match_class;
   size_t last_position = 0;
-  if (StartsWith(text_lowercase, find_text, true)) {
+  if (base::StartsWith(text_lowercase, find_text, true)) {
     match_class.push_back(
         ACMatchClassification(0, ACMatchClassification::MATCH));
     last_position = find_text.length();
@@ -368,8 +369,9 @@
   // Lower bound not necessarily matches the keyword, check for item pointed by
   // the lower bound iterator to at least start with keyword.
   return ((it == backend->shortcuts_map().end()) ||
-    StartsWith(it->first, keyword, true)) ? it :
-    backend->shortcuts_map().end();
+          base::StartsWith(it->first, keyword, true))
+             ? it
+             : backend->shortcuts_map().end();
 }
 
 int ShortcutsProvider::CalculateScore(
diff --git a/chrome/browser/autocomplete/url_index_private_data.cc b/chrome/browser/autocomplete/url_index_private_data.cc
index 2b11380..68943f4 100644
--- a/chrome/browser/autocomplete/url_index_private_data.cc
+++ b/chrome/browser/autocomplete/url_index_private_data.cc
@@ -564,7 +564,7 @@
     SearchTermCacheMap::iterator best_prefix(search_term_cache_.end());
     for (SearchTermCacheMap::iterator cache_iter = search_term_cache_.begin();
          cache_iter != search_term_cache_.end(); ++cache_iter) {
-      if (StartsWith(term, cache_iter->first, false) &&
+      if (base::StartsWith(term, cache_iter->first, false) &&
           (best_prefix == search_term_cache_.end() ||
            cache_iter->first.length() > best_prefix->first.length()))
         best_prefix = cache_iter;
diff --git a/chrome/browser/autocomplete/url_index_private_data.h b/chrome/browser/autocomplete/url_index_private_data.h
index d13246fb..4eaf7e0 100644
--- a/chrome/browser/autocomplete/url_index_private_data.h
+++ b/chrome/browser/autocomplete/url_index_private_data.h
@@ -12,9 +12,9 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/autocomplete/in_memory_url_index_cache.pb.h"
-#include "chrome/browser/autocomplete/in_memory_url_index_types.h"
 #include "chrome/browser/autocomplete/scored_history_match.h"
 #include "components/history/core/browser/history_service.h"
+#include "components/omnibox/in_memory_url_index_types.h"
 
 class HistoryQuickProviderTest;
 
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc
index c280cb8..2da8bad 100644
--- a/chrome/browser/autofill/autofill_browsertest.cc
+++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -246,7 +246,7 @@
     base::SplitString(data, '\n', &lines);
     int parsed_profiles = 0;
     for (size_t i = 0; i < lines.size(); ++i) {
-      if (StartsWithASCII(lines[i], "#", false))
+      if (base::StartsWithASCII(lines[i], "#", false))
         continue;
 
       std::vector<std::string> fields;
diff --git a/chrome/browser/banners/app_banner_data_fetcher.cc b/chrome/browser/banners/app_banner_data_fetcher.cc
index 8507486b..f0530fe 100644
--- a/chrome/browser/banners/app_banner_data_fetcher.cc
+++ b/chrome/browser/banners/app_banner_data_fetcher.cc
@@ -35,7 +35,7 @@
 const int kIconMinimumSize = 144;
 bool DoesManifestContainRequiredIcon(const content::Manifest& manifest) {
   for (const auto& icon : manifest.icons) {
-    if (!EqualsASCII(icon.type.string(), "image/png"))
+    if (!base::EqualsASCII(icon.type.string(), "image/png"))
       continue;
 
     for (const auto& size : icon.sizes) {
@@ -191,11 +191,12 @@
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
   bitmap_fetcher_.reset(new chrome::BitmapFetcher(image_url, this));
-  bitmap_fetcher_->Start(
+  bitmap_fetcher_->Init(
       profile->GetRequestContext(),
       std::string(),
       net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
       net::LOAD_NORMAL);
+  bitmap_fetcher_->Start();
   return true;
 }
 
diff --git a/chrome/browser/banners/app_banner_infobar_delegate_desktop.cc b/chrome/browser/banners/app_banner_infobar_delegate_desktop.cc
index ef551c53..e959a87 100644
--- a/chrome/browser/banners/app_banner_infobar_delegate_desktop.cc
+++ b/chrome/browser/banners/app_banner_infobar_delegate_desktop.cc
@@ -61,11 +61,13 @@
   return l10n_util::GetStringUTF16(IDS_ADD_TO_SHELF_INFOBAR_TITLE);
 }
 
+int AppBannerInfoBarDelegateDesktop::GetButtons() const {
+  return BUTTON_OK;
+}
+
 base::string16 AppBannerInfoBarDelegateDesktop::GetButtonLabel(
     InfoBarButton button) const {
-  return l10n_util::GetStringUTF16((button == BUTTON_OK)
-                                       ? IDS_ADD_TO_SHELF_INFOBAR_ADD_BUTTON
-                                       : IDS_ADD_TO_SHELF_INFOBAR_NEVER_BUTTON);
+  return l10n_util::GetStringUTF16(IDS_ADD_TO_SHELF_INFOBAR_ADD_BUTTON);
 }
 
 bool AppBannerInfoBarDelegateDesktop::Accept() {
@@ -76,7 +78,7 @@
   return true;
 }
 
-bool AppBannerInfoBarDelegateDesktop::Cancel() {
+void AppBannerInfoBarDelegateDesktop::InfoBarDismissed() {
   content::WebContents* web_contents =
       InfoBarService::WebContentsFromInfoBar(infobar());
   if (web_contents) {
@@ -91,11 +93,6 @@
         web_contents, web_manifest_.start_url.spec(),
         AppBannerSettingsHelper::WEB);
   }
-  return true;
-}
-
-void AppBannerInfoBarDelegateDesktop::InfoBarDismissed() {
-  Cancel();
 }
 
 }  // namespace banners
diff --git a/chrome/browser/banners/app_banner_infobar_delegate_desktop.h b/chrome/browser/banners/app_banner_infobar_delegate_desktop.h
index 61d29730..6baa40e 100644
--- a/chrome/browser/banners/app_banner_infobar_delegate_desktop.h
+++ b/chrome/browser/banners/app_banner_infobar_delegate_desktop.h
@@ -41,10 +41,10 @@
 
   // ConfirmInfoBarDelegate overrides.
   base::string16 GetMessageText() const override;
+  int GetButtons() const override;
   base::string16 GetButtonLabel(InfoBarButton button) const override;
 
   bool Accept() override;
-  bool Cancel() override;
 
   // InfoBarDelegate override.
   void InfoBarDismissed() override;
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc
index f99f3c20..f379cff 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc
@@ -19,10 +19,10 @@
 BitmapFetcher::~BitmapFetcher() {
 }
 
-void BitmapFetcher::Start(net::URLRequestContextGetter* request_context,
-                          const std::string& referrer,
-                          net::URLRequest::ReferrerPolicy referrer_policy,
-                          int load_flags) {
+void BitmapFetcher::Init(net::URLRequestContextGetter* request_context,
+                         const std::string& referrer,
+                         net::URLRequest::ReferrerPolicy referrer_policy,
+                         int load_flags) {
   if (url_fetcher_ != NULL)
     return;
 
@@ -31,7 +31,11 @@
   url_fetcher_->SetReferrer(referrer);
   url_fetcher_->SetReferrerPolicy(referrer_policy);
   url_fetcher_->SetLoadFlags(load_flags);
-  url_fetcher_->Start();
+}
+
+void BitmapFetcher::Start() {
+  if (url_fetcher_)
+    url_fetcher_->Start();
 }
 
 // Methods inherited from URLFetcherDelegate.
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher.h b/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
index 11055eaf..6307e5b 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
@@ -29,17 +29,24 @@
   ~BitmapFetcher() override;
 
   const GURL& url() const { return url_; }
+  net::URLFetcher* url_fetcher() { return url_fetcher_.get(); }
+
+  // Initializes internal fetcher.  After this function returns url_fetcher()
+  // can be accessed to configure it further (eg. add user data to request).
+  // All configuration must be done before Start() is called.
+  // Values for |load_flags| are defined in net/base/load_flags.h.  In general,
+  // |net::LOAD_NORMAL| is appropriate.  Init may be called more than once in
+  // some cases.  If so, subsequent starts will be ignored.
+  void Init(net::URLRequestContextGetter* request_context,
+            const std::string& referrer,
+            net::URLRequest::ReferrerPolicy referrer_policy,
+            int load_flags);
 
   // Start fetching the URL with the fetcher. The delegate is notified
   // asynchronously when done.  Start may be called more than once in some
   // cases.  If so, subsequent starts will be ignored since the operation is
-  // already in progress.  Arguments are used to configure the internal fetcher.
-  // Values for |load_flags| are defined in net/base/load_flags.h.  In general,
-  // |net::LOAD_NORMAL| is appropriate.
-  void Start(net::URLRequestContextGetter* request_context,
-             const std::string& referrer,
-             net::URLRequest::ReferrerPolicy referrer_policy,
-             int load_flags);
+  // already in progress.
+  void Start();
 
   // Methods inherited from URLFetcherDelegate
 
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc
index 27bd76e..e149d75 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc
@@ -113,11 +113,12 @@
 
   // We expect that the image decoder will get called and return
   // an image in a callback to OnImageDecoded().
-  fetcher.Start(
+  fetcher.Init(
       browser()->profile()->GetRequestContext(),
       std::string(),
       net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
       net::LOAD_NORMAL);
+  fetcher.Start();
 
   // Blocks until test delegate is notified via a callback.
   delegate.Wait();
@@ -165,11 +166,12 @@
                                         net::HTTP_INTERNAL_SERVER_ERROR,
                                         net::URLRequestStatus::FAILED);
 
-  fetcher.Start(
+  fetcher.Init(
       browser()->profile()->GetRequestContext(),
       std::string(),
       net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
       net::LOAD_NORMAL);
+  fetcher.Start();
 
   // Blocks until test delegate is notified via a callback.
   delegate.Wait();
@@ -186,11 +188,12 @@
                                         net::HTTP_OK,
                                         net::URLRequestStatus::SUCCESS);
 
-  fetcher.Start(
+  fetcher.Init(
       browser()->profile()->GetRequestContext(),
       std::string(),
       net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
       net::LOAD_NORMAL);
+  fetcher.Start();
 
   // Blocks until test delegate is notified via a callback.
   delegate.Wait();
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
index aef3ba6..5613993 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
@@ -121,11 +121,12 @@
 chrome::BitmapFetcher* BitmapFetcherService::CreateFetcher(const GURL& url) {
   chrome::BitmapFetcher* new_fetcher = new chrome::BitmapFetcher(url, this);
 
-  new_fetcher->Start(
+  new_fetcher->Init(
       context_->GetRequestContext(),
       std::string(),
       net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
       net::LOAD_NORMAL);
+  new_fetcher->Start();
   return new_fetcher;
 }
 
diff --git a/chrome/browser/bookmarks/bookmark_model_factory.cc b/chrome/browser/bookmarks/bookmark_model_factory.cc
index e031858..208bb14 100644
--- a/chrome/browser/bookmarks/bookmark_model_factory.cc
+++ b/chrome/browser/bookmarks/bookmark_model_factory.cc
@@ -11,14 +11,14 @@
 #include "base/values.h"
 #include "chrome/browser/bookmarks/chrome_bookmark_client.h"
 #include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
+#include "chrome/browser/bookmarks/startup_task_runner_service_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/startup_task_runner_service.h"
-#include "chrome/browser/profiles/startup_task_runner_service_factory.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/startup_task_runner_service.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
diff --git a/chrome/browser/profiles/startup_task_runner_service_factory.cc b/chrome/browser/bookmarks/startup_task_runner_service_factory.cc
similarity index 76%
rename from chrome/browser/profiles/startup_task_runner_service_factory.cc
rename to chrome/browser/bookmarks/startup_task_runner_service_factory.cc
index 0a84d69..2cf86ed 100644
--- a/chrome/browser/profiles/startup_task_runner_service_factory.cc
+++ b/chrome/browser/bookmarks/startup_task_runner_service_factory.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/profiles/startup_task_runner_service_factory.h"
+#include "chrome/browser/bookmarks/startup_task_runner_service_factory.h"
 
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/startup_task_runner_service.h"
+#include "components/bookmarks/browser/startup_task_runner_service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 
 StartupTaskRunnerServiceFactory::StartupTaskRunnerServiceFactory()
@@ -30,6 +30,7 @@
 }
 
 KeyedService* StartupTaskRunnerServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* profile) const {
-  return new StartupTaskRunnerService(static_cast<Profile*>(profile));
+    content::BrowserContext* context) const {
+  Profile* profile = Profile::FromBrowserContext(context);
+  return new StartupTaskRunnerService(profile->GetIOTaskRunner());
 }
diff --git a/chrome/browser/profiles/startup_task_runner_service_factory.h b/chrome/browser/bookmarks/startup_task_runner_service_factory.h
similarity index 84%
rename from chrome/browser/profiles/startup_task_runner_service_factory.h
rename to chrome/browser/bookmarks/startup_task_runner_service_factory.h
index 49abdf2..a1e66a36 100644
--- a/chrome/browser/profiles/startup_task_runner_service_factory.h
+++ b/chrome/browser/bookmarks/startup_task_runner_service_factory.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_FACTORY_H_
+#ifndef CHROME_BROWSER_BOOKMARKS_STARTUP_TASK_RUNNER_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_BOOKMARKS_STARTUP_TASK_RUNNER_SERVICE_FACTORY_H_
 
 #include "base/basictypes.h"
 #include "base/memory/singleton.h"
@@ -37,4 +37,4 @@
   DISALLOW_COPY_AND_ASSIGN(StartupTaskRunnerServiceFactory);
 };
 
-#endif  // CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_FACTORY_H_
+#endif  // CHROME_BROWSER_BOOKMARKS_STARTUP_TASK_RUNNER_SERVICE_FACTORY_H_
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 42a453a..81b19ca 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -103,13 +103,13 @@
 bool HandleNonNavigationAboutURL(const GURL& url) {
   const std::string spec(url.spec());
 
-  if (LowerCaseEqualsASCII(spec, chrome::kChromeUIRestartURL)) {
+  if (base::LowerCaseEqualsASCII(spec, chrome::kChromeUIRestartURL)) {
     // Call AttemptRestart after chrome::Navigate() completes to avoid access of
     // gtk objects after they are destroyed by BrowserWindowGtk::Close().
     base::MessageLoop::current()->PostTask(FROM_HERE,
         base::Bind(&chrome::AttemptRestart));
     return true;
-  } else if (LowerCaseEqualsASCII(spec, chrome::kChromeUIQuitURL)) {
+  } else if (base::LowerCaseEqualsASCII(spec, chrome::kChromeUIQuitURL)) {
     base::MessageLoop::current()->PostTask(FROM_HERE,
         base::Bind(&chrome::AttemptExit));
     return true;
diff --git a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
index 0531d87..e6d7c9a 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
@@ -744,7 +744,7 @@
 const void* TestingDomainReliabilityServiceFactoryUserData::kKey =
     &TestingDomainReliabilityServiceFactoryUserData::kKey;
 
-KeyedService* TestingDomainReliabilityServiceFactoryFunction(
+scoped_ptr<KeyedService> TestingDomainReliabilityServiceFactoryFunction(
     content::BrowserContext* context) {
   const void* kKey = TestingDomainReliabilityServiceFactoryUserData::kKey;
 
@@ -756,7 +756,7 @@
   EXPECT_FALSE(data->attached);
 
   data->attached = true;
-  return data->service;
+  return make_scoped_ptr(data->service);
 }
 
 class ClearDomainReliabilityTester {
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 2b77ec8..462a27552 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -536,31 +536,6 @@
   }
 }
 
-// Heap allocated class that listens for first page load, kicks off stat
-// recording and then deletes itself.
-class LoadCompleteListener : public content::NotificationObserver {
- public:
-  LoadCompleteListener() {
-    registrar_.Add(this,
-                   content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-                   content::NotificationService::AllSources());
-  }
-  ~LoadCompleteListener() override {}
-
-  // content::NotificationObserver implementation.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override {
-    DCHECK_EQ(content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, type);
-    startup_metric_utils::OnInitialPageLoadComplete();
-    delete this;
-  }
-
- private:
-  content::NotificationRegistrar registrar_;
-  DISALLOW_COPY_AND_ASSIGN(LoadCompleteListener);
-};
-
 }  // namespace
 
 namespace chrome_browser {
@@ -748,9 +723,6 @@
 
   // Record collected startup metrics.
   startup_metric_utils::OnBrowserStartupComplete(is_first_run);
-
-  // Deletes self.
-  new LoadCompleteListener();
 }
 
 // -----------------------------------------------------------------------------
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 78664bf..44f31f2f 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -19,6 +19,7 @@
 #include "base/prefs/scoped_user_pref_update.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/after_startup_task_utils.h"
 #include "chrome/browser/browser_about_handler.h"
@@ -123,6 +124,7 @@
 #include "content/public/common/service_registry.h"
 #include "content/public/common/url_utils.h"
 #include "content/public/common/web_preferences.h"
+#include "device/devices_app/devices_app.h"
 #include "gin/v8_initializer.h"
 #include "net/base/mime_util.h"
 #include "net/cookies/canonical_cookie.h"
@@ -498,15 +500,17 @@
 }
 
 void HandleBlockedPopupOnUIThread(const BlockedWindowParams& params) {
-  // TODO(jochen): This code path should use RenderFrameHosts. See
-  // http://crbug.com/431769 for details.
-  RenderViewHost* render_view_host =
-      RenderViewHost::FromID(params.render_process_id(), params.opener_id());
-  if (!render_view_host)
+  RenderFrameHost* render_frame_host = RenderFrameHost::FromID(
+      params.render_process_id(), params.opener_render_frame_id());
+  if (!render_frame_host)
     return;
-  WebContents* tab = WebContents::FromRenderViewHost(render_view_host);
-  // The tab might already have navigated away.
-  if (!tab || tab->GetRenderViewHost() != render_view_host)
+  WebContents* tab = WebContents::FromRenderFrameHost(render_frame_host);
+  // The tab might already have navigated away.  We only need to do this check
+  // for main frames, since the RenderFrameHost for a subframe opener will have
+  // already been deleted if the main frame navigates away.
+  if (!tab ||
+      (!render_frame_host->GetParent() &&
+       tab->GetMainFrame() != render_frame_host))
     return;
 
   prerender::PrerenderContents* prerender_contents =
@@ -549,9 +553,8 @@
 #if defined(OS_ANDROID)
 
 void HandleSingleTabModeBlockOnUIThread(const BlockedWindowParams& params) {
-  WebContents* web_contents =
-      tab_util::GetWebContentsByID(params.render_process_id(),
-                                   params.opener_id());
+  WebContents* web_contents = tab_util::GetWebContentsByFrameID(
+      params.render_process_id(), params.opener_render_frame_id());
   if (!web_contents)
     return;
 
@@ -1868,7 +1871,8 @@
     bool opener_suppressed,
     content::ResourceContext* context,
     int render_process_id,
-    int opener_id,
+    int opener_render_view_id,
+    int opener_render_frame_id,
     bool* no_javascript_access) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
@@ -1917,7 +1921,7 @@
                                      user_gesture,
                                      opener_suppressed,
                                      render_process_id,
-                                     opener_id);
+                                     opener_render_frame_id);
 
   if (!user_gesture &&
       !base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -1936,7 +1940,8 @@
   }
 
 #if defined(OS_ANDROID)
-  if (SingleTabModeTabHelper::IsRegistered(render_process_id, opener_id)) {
+  if (SingleTabModeTabHelper::IsRegistered(render_process_id,
+                                           opener_render_view_id)) {
     BrowserThread::PostTask(BrowserThread::UI,
                             FROM_HERE,
                             base::Bind(&HandleSingleTabModeBlockOnUIThread,
@@ -2362,6 +2367,15 @@
 #endif
 }
 
+void ChromeContentBrowserClient::RegisterMojoApplications(
+    StaticMojoApplicationMap* apps) {
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  apps->insert(std::make_pair(GURL(device::kDevicesMojoAppUrl),
+                              base::Bind(&device::DevicesApp::CreateDelegate,
+                                         base::ThreadTaskRunnerHandle::Get())));
+#endif
+}
+
 void ChromeContentBrowserClient::OpenURL(
     content::BrowserContext* browser_context,
     const content::OpenURLParams& params,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index b998246..9edd155 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -196,7 +196,8 @@
                        bool opener_suppressed,
                        content::ResourceContext* context,
                        int render_process_id,
-                       int opener_id,
+                       int opener_render_view_id,
+                       int opener_render_frame_id,
                        bool* no_javascript_access) override;
   void ResourceDispatcherHostCreated() override;
   content::SpeechRecognitionManagerDelegate*
@@ -254,6 +255,7 @@
   void OverrideRenderFrameMojoServices(
       content::ServiceRegistry* registry,
       content::RenderFrameHost* render_frame_host) override;
+  void RegisterMojoApplications(StaticMojoApplicationMap* apps) override;
   void OpenURL(content::BrowserContext* browser_context,
                const content::OpenURLParams& params,
                const base::Callback<void(content::WebContents*)>& callback)
diff --git a/chrome/browser/chrome_device_client.cc b/chrome/browser/chrome_device_client.cc
index d0a31a6b..835a4c3 100644
--- a/chrome/browser/chrome_device_client.cc
+++ b/chrome/browser/chrome_device_client.cc
@@ -5,34 +5,12 @@
 #include "chrome/browser/chrome_device_client.h"
 
 #include "base/logging.h"
-#include "base/macros.h"
 #include "content/public/browser/browser_thread.h"
 #include "device/hid/hid_service.h"
-#include "device/usb/public/cpp/device_manager_delegate.h"
-#include "device/usb/public/cpp/device_manager_factory.h"
-#include "device/usb/public/interfaces/device.mojom.h"
 #include "device/usb/usb_service.h"
 
 using content::BrowserThread;
 
-namespace {
-
-// DeviceManagerDelegate implementation which allows access to all devices.
-class BrowserDeviceManagerDelegate : public device::usb::DeviceManagerDelegate {
- public:
-  BrowserDeviceManagerDelegate() {}
-  ~BrowserDeviceManagerDelegate() override {}
-
- private:
-  bool IsDeviceAllowed(const device::usb::DeviceInfo& device) override {
-    return true;
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserDeviceManagerDelegate);
-};
-
-}  // namespace
-
 ChromeDeviceClient::ChromeDeviceClient() {}
 
 ChromeDeviceClient::~ChromeDeviceClient() {}
@@ -43,14 +21,6 @@
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
 }
 
-void ChromeDeviceClient::ConnectToUSBDeviceManager(
-    mojo::InterfaceRequest<device::usb::DeviceManager> request) {
-  device::usb::DeviceManagerFactory::Build(
-      request.Pass(),
-      scoped_ptr<device::usb::DeviceManagerDelegate>(
-          new BrowserDeviceManagerDelegate));
-}
-
 device::HidService* ChromeDeviceClient::GetHidService() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return device::HidService::GetInstance(
diff --git a/chrome/browser/chrome_device_client.h b/chrome/browser/chrome_device_client.h
index 1d1eb38..1cd401f 100644
--- a/chrome/browser/chrome_device_client.h
+++ b/chrome/browser/chrome_device_client.h
@@ -19,8 +19,6 @@
 
   // device::DeviceClient implementation
   device::UsbService* GetUsbService() override;
-  void ConnectToUSBDeviceManager(
-      mojo::InterfaceRequest<device::usb::DeviceManager> request) override;
   device::HidService* GetHidService() override;
 
  private:
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index eebfe76..0a935ea 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -110,6 +110,8 @@
       content::WebContents::FromRenderViewHost(render_view_host);
   if (!web_contents)
     return;
+  if (!extensions::TabHelper::FromWebContents(web_contents))
+    extensions::TabHelper::CreateForWebContents(web_contents);
   extensions::TabHelper::FromWebContents(web_contents)->script_executor()->
       ExecuteScript(HostID(HostID::EXTENSIONS, extension_id),
                     extensions::ScriptExecutor::JAVASCRIPT,
diff --git a/chrome/browser/chromeos/boot_times_recorder.cc b/chrome/browser/chromeos/boot_times_recorder.cc
index ccb5fa3..ef8caf6 100644
--- a/chrome/browser/chromeos/boot_times_recorder.cc
+++ b/chrome/browser/chromeos/boot_times_recorder.cc
@@ -15,12 +15,12 @@
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
diff --git a/chrome/browser/chromeos/chromeos_utils.cc b/chrome/browser/chromeos/chromeos_utils.cc
index c6777e5..e93a5ec9 100644
--- a/chrome/browser/chromeos/chromeos_utils.cc
+++ b/chrome/browser/chromeos/chromeos_utils.cc
@@ -53,15 +53,15 @@
 int GetChromeDeviceTypeResourceId() {
   const std::string board = base::SysInfo::GetLsbReleaseBoard();
   for (size_t i = 0; i < arraysize(kChromeboxBoards); ++i) {
-    if (StartsWithASCII(board, kChromeboxBoards[i], true))
+    if (base::StartsWithASCII(board, kChromeboxBoards[i], true))
       return IDS_CHROMEBOX;
   }
   for (size_t i = 0; i < arraysize(kChromebaseBoards); ++i) {
-    if (StartsWithASCII(board, kChromebaseBoards[i], true))
+    if (base::StartsWithASCII(board, kChromebaseBoards[i], true))
       return IDS_CHROMEBASE;
   }
   for (size_t i = 0; i < arraysize(kChromebitBoards); ++i) {
-    if (StartsWithASCII(board, kChromebitBoards[i], true))
+    if (base::StartsWithASCII(board, kChromebitBoards[i], true))
       return IDS_CHROMEBIT;
   }
   return IDS_CHROMEBOOK;
diff --git a/chrome/browser/chromeos/dbus/printer_service_provider.cc b/chrome/browser/chromeos/dbus/printer_service_provider.cc
index 71edd30..4c4c4cc 100644
--- a/chrome/browser/chromeos/dbus/printer_service_provider.cc
+++ b/chrome/browser/chromeos/dbus/printer_service_provider.cc
@@ -317,11 +317,11 @@
 
   std::string vendor_id;
   reader.PopString(&vendor_id);
-  StringToUpperASCII(&vendor_id);
+  base::StringToUpperASCII(&vendor_id);
 
   std::string product_id;
   reader.PopString(&product_id);
-  StringToUpperASCII(&product_id);
+  base::StringToUpperASCII(&product_id);
 
   // Send an empty response.
   response_sender.Run(dbus::Response::FromMethodCall(method_call));
diff --git a/chrome/browser/chromeos/drive/change_list_loader.cc b/chrome/browser/chromeos/drive/change_list_loader.cc
index 29d4dad0..0f0d924f 100644
--- a/chrome/browser/chromeos/drive/change_list_loader.cc
+++ b/chrome/browser/chromeos/drive/change_list_loader.cc
@@ -19,12 +19,9 @@
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 #include "chrome/browser/drive/event_logger.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/drive_api_parser.h"
 #include "url/gurl.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace internal {
 
@@ -50,7 +47,7 @@
   ~FullFeedFetcher() override {}
 
   void Run(const FeedFetcherCallback& callback) override {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK(!callback.is_null());
 
     // Remember the time stamp for usage stats.
@@ -66,7 +63,7 @@
   void OnFileListFetched(const FeedFetcherCallback& callback,
                          google_apis::DriveApiErrorCode status,
                          scoped_ptr<google_apis::FileList> file_list) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK(!callback.is_null());
 
     FileError error = GDataToFileError(status);
@@ -99,6 +96,7 @@
   JobScheduler* scheduler_;
   ScopedVector<ChangeList> change_lists_;
   base::TimeTicks start_time_;
+  base::ThreadChecker thread_checker_;
   base::WeakPtrFactory<FullFeedFetcher> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(FullFeedFetcher);
 };
@@ -115,7 +113,7 @@
   ~DeltaFeedFetcher() override {}
 
   void Run(const FeedFetcherCallback& callback) override {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK(!callback.is_null());
 
     scheduler_->GetChangeList(
@@ -128,7 +126,7 @@
   void OnChangeListFetched(const FeedFetcherCallback& callback,
                            google_apis::DriveApiErrorCode status,
                            scoped_ptr<google_apis::ChangeList> change_list) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK(!callback.is_null());
 
     FileError error = GDataToFileError(status);
@@ -158,6 +156,7 @@
   JobScheduler* scheduler_;
   int64 start_change_id_;
   ScopedVector<ChangeList> change_lists_;
+  base::ThreadChecker thread_checker_;
   base::WeakPtrFactory<DeltaFeedFetcher> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(DeltaFeedFetcher);
 };
@@ -167,15 +166,14 @@
 LoaderController::LoaderController()
     : lock_count_(0),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 LoaderController::~LoaderController() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 scoped_ptr<base::ScopedClosureRunner> LoaderController::GetLock() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   ++lock_count_;
   return make_scoped_ptr(new base::ScopedClosureRunner(
@@ -184,7 +182,7 @@
 }
 
 void LoaderController::ScheduleRun(const base::Closure& task) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!task.is_null());
 
   if (lock_count_ > 0) {
@@ -195,7 +193,7 @@
 }
 
 void LoaderController::Unlock() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_LT(0, lock_count_);
 
   if (--lock_count_ > 0)
@@ -217,7 +215,7 @@
 
 void AboutResourceLoader::GetAboutResource(
     const google_apis::AboutResourceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   // If the latest UpdateAboutResource task is still running. Wait for it,
@@ -241,7 +239,7 @@
 
 void AboutResourceLoader::UpdateAboutResource(
     const google_apis::AboutResourceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   ++current_update_task_id_;
@@ -257,7 +255,7 @@
     int task_id,
     google_apis::DriveApiErrorCode status,
     scoped_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   FileError error = GDataToFileError(status);
 
   const std::vector<google_apis::AboutResourceCallback> callbacks =
@@ -319,17 +317,17 @@
 }
 
 void ChangeListLoader::AddObserver(ChangeListLoaderObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   observers_.AddObserver(observer);
 }
 
 void ChangeListLoader::RemoveObserver(ChangeListLoaderObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   observers_.RemoveObserver(observer);
 }
 
 void ChangeListLoader::CheckForUpdates(const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   // We only start to check for updates iff the load is done.
@@ -356,7 +354,7 @@
 }
 
 void ChangeListLoader::LoadIfNeeded(const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   // If the metadata is not yet loaded, start loading.
@@ -365,7 +363,7 @@
 }
 
 void ChangeListLoader::Load(const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   // Check if this is the first time this ChangeListLoader do loading.
@@ -397,7 +395,7 @@
     bool is_initial_load,
     const int64* local_changestamp,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (error != FILE_ERROR_OK) {
     OnChangeListLoadComplete(error);
@@ -424,7 +422,7 @@
     int64 local_changestamp,
     google_apis::DriveApiErrorCode status,
     scoped_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   FileError error = GDataToFileError(status);
   if (error != FILE_ERROR_OK) {
@@ -452,7 +450,7 @@
 }
 
 void ChangeListLoader::OnChangeListLoadComplete(FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (!loaded_ && error == FILE_ERROR_OK) {
     loaded_ = true;
@@ -478,7 +476,7 @@
 void ChangeListLoader::OnAboutResourceUpdated(
     google_apis::DriveApiErrorCode error,
     scoped_ptr<google_apis::AboutResource> resource) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (drive::GDataToFileError(error) != drive::FILE_ERROR_OK) {
     logger_->Log(logging::LOG_ERROR,
@@ -492,7 +490,7 @@
 }
 
 void ChangeListLoader::LoadChangeListFromServer(int64 start_changestamp) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!change_feed_fetcher_);
   DCHECK(about_resource_loader_->cached_about_resource());
 
@@ -521,7 +519,7 @@
     bool is_delta_update,
     FileError error,
     ScopedVector<ChangeList> change_lists) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(about_resource);
 
   // Delete the fetcher first.
@@ -563,7 +561,7 @@
     bool should_notify_changed_directories,
     const base::Time& start_time,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   const base::TimeDelta elapsed = base::Time::Now() - start_time;
   logger_->Log(logging::LOG_INFO,
diff --git a/chrome/browser/chromeos/drive/change_list_loader.h b/chrome/browser/chromeos/drive/change_list_loader.h
index 644e6ed..612df97 100644
--- a/chrome/browser/chromeos/drive/change_list_loader.h
+++ b/chrome/browser/chromeos/drive/change_list_loader.h
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 #include "google_apis/drive/drive_common_callbacks.h"
@@ -69,6 +70,8 @@
   int lock_count_;
   std::vector<base::Closure> pending_tasks_;
 
+  base::ThreadChecker thread_checker_;
+
   base::WeakPtrFactory<LoaderController> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(LoaderController);
 };
@@ -118,6 +121,8 @@
   std::map<int, std::vector<google_apis::AboutResourceCallback> >
       pending_callbacks_;
 
+  base::ThreadChecker thread_checker_;
+
   base::WeakPtrFactory<AboutResourceLoader> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(AboutResourceLoader);
 };
@@ -230,6 +235,8 @@
   // stored locally).
   bool loaded_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<ChangeListLoader> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/debug_info_collector.cc b/chrome/browser/chromeos/drive/debug_info_collector.cc
index 6159ea1..cf50912b 100644
--- a/chrome/browser/chromeos/drive/debug_info_collector.cc
+++ b/chrome/browser/chromeos/drive/debug_info_collector.cc
@@ -6,11 +6,8 @@
 
 #include "base/callback.h"
 #include "base/logging.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/task_util.h"
 
-using content::BrowserThread;
-
 namespace drive {
 
 namespace {
@@ -68,7 +65,7 @@
 void DebugInfoCollector::GetResourceEntry(
     const base::FilePath& file_path,
     const GetResourceEntryCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   scoped_ptr<ResourceEntry> entry(new ResourceEntry);
@@ -86,7 +83,7 @@
 void DebugInfoCollector::ReadDirectory(
     const base::FilePath& file_path,
     const ReadDirectoryCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   scoped_ptr<ResourceEntryVector> entries(new ResourceEntryVector);
@@ -104,7 +101,7 @@
 void DebugInfoCollector::IterateFileCache(
     const IterateFileCacheCallback& iteration_callback,
     const base::Closure& completion_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!iteration_callback.is_null());
   DCHECK(!completion_callback.is_null());
 
@@ -118,7 +115,7 @@
 
 void DebugInfoCollector::GetMetadata(
     const GetFilesystemMetadataCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   // Currently, this is just a proxy to the FileSystem.
diff --git a/chrome/browser/chromeos/drive/debug_info_collector.h b/chrome/browser/chromeos/drive/debug_info_collector.h
index 65aded9..213caea 100644
--- a/chrome/browser/chromeos/drive/debug_info_collector.h
+++ b/chrome/browser/chromeos/drive/debug_info_collector.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 
 namespace drive {
@@ -57,6 +58,8 @@
   FileSystemInterface* file_system_;  // Not owned.
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
 
+  base::ThreadChecker thread_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(DebugInfoCollector);
 };
 
diff --git a/chrome/browser/chromeos/drive/directory_loader.cc b/chrome/browser/chromeos/drive/directory_loader.cc
index 7d60858..23df472 100644
--- a/chrome/browser/chromeos/drive/directory_loader.cc
+++ b/chrome/browser/chromeos/drive/directory_loader.cc
@@ -16,12 +16,9 @@
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 #include "chrome/browser/drive/event_logger.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/drive_api_parser.h"
 #include "url/gurl.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace internal {
 
@@ -106,7 +103,7 @@
   }
 
   void Run(const FileOperationCallback& callback) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK(!callback.is_null());
     DCHECK(!directory_fetch_info_.resource_id().empty());
 
@@ -123,7 +120,7 @@
   void OnFileListFetched(const FileOperationCallback& callback,
                          google_apis::DriveApiErrorCode status,
                          scoped_ptr<google_apis::FileList> file_list) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK(!callback.is_null());
 
     FileError error = GDataToFileError(status);
@@ -159,7 +156,7 @@
       const GURL& next_url,
       const std::vector<ResourceEntry>* refreshed_entries,
       FileError error) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK(!callback.is_null());
 
     if (error != FILE_ERROR_OK) {
@@ -191,6 +188,7 @@
   DirectoryFetchInfo directory_fetch_info_;
   std::string root_folder_id_;
   base::TimeTicks start_time_;
+  base::ThreadChecker thread_checker_;
   base::WeakPtrFactory<FeedFetcher> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(FeedFetcher);
 };
@@ -216,12 +214,12 @@
 }
 
 void DirectoryLoader::AddObserver(ChangeListLoaderObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   observers_.AddObserver(observer);
 }
 
 void DirectoryLoader::RemoveObserver(ChangeListLoaderObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   observers_.RemoveObserver(observer);
 }
 
@@ -229,7 +227,7 @@
     const base::FilePath& directory_path,
     const ReadDirectoryEntriesCallback& entries_callback,
     const FileOperationCallback& completion_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!completion_callback.is_null());
 
   ResourceEntry* entry = new ResourceEntry;
@@ -256,7 +254,7 @@
     bool should_try_loading_parent,
     const ResourceEntry* entry,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!completion_callback.is_null());
 
   if (error == FILE_ERROR_NOT_FOUND &&
@@ -308,7 +306,7 @@
     const ReadDirectoryEntriesCallback& entries_callback,
     const FileOperationCallback& completion_callback,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!completion_callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -337,7 +335,7 @@
     const std::string& local_id,
     google_apis::DriveApiErrorCode status,
     scoped_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   FileError error = GDataToFileError(status);
   if (error != FILE_ERROR_OK) {
@@ -374,7 +372,7 @@
     const ResourceEntry* entry,
     const int64* local_changestamp,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(about_resource);
 
   if (error != FILE_ERROR_OK) {
@@ -412,7 +410,7 @@
 
 void DirectoryLoader::OnDirectoryLoadComplete(const std::string& local_id,
                                               FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   LoadCallbackMap::iterator it = pending_load_callback_.find(local_id);
   if (it == pending_load_callback_.end())
@@ -487,7 +485,7 @@
 
 void DirectoryLoader::LoadDirectoryFromServer(
     const DirectoryFetchInfo& directory_fetch_info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!directory_fetch_info.empty());
   DVLOG(1) << "Start loading directory: " << directory_fetch_info.ToString();
 
@@ -516,7 +514,7 @@
     const DirectoryFetchInfo& directory_fetch_info,
     FeedFetcher* fetcher,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!directory_fetch_info.empty());
 
   // Delete the fetcher.
@@ -556,7 +554,7 @@
     const DirectoryFetchInfo& directory_fetch_info,
     const base::FilePath* directory_path,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   DVLOG(1) << "Directory loaded: " << directory_fetch_info.ToString();
   OnDirectoryLoadComplete(directory_fetch_info.local_id(), error);
diff --git a/chrome/browser/chromeos/drive/directory_loader.h b/chrome/browser/chromeos/drive/directory_loader.h
index 12a5b8c..07fd18e8 100644
--- a/chrome/browser/chromeos/drive/directory_loader.h
+++ b/chrome/browser/chromeos/drive/directory_loader.h
@@ -15,6 +15,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 #include "google_apis/drive/drive_api_error_codes.h"
@@ -136,6 +137,8 @@
   // Set of the running feed fetcher for the fast fetch.
   std::set<FeedFetcher*> fast_fetch_feed_fetcher_set_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<DirectoryLoader> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/drive_file_stream_reader.cc b/chrome/browser/chromeos/drive/drive_file_stream_reader.cc
index 8a1650e..97ce158 100644
--- a/chrome/browser/chromeos/drive/drive_file_stream_reader.cc
+++ b/chrome/browser/chromeos/drive/drive_file_stream_reader.cc
@@ -96,7 +96,6 @@
     : file_reader_(file_reader.Pass()),
       remaining_length_(length),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(file_reader_);
 }
 
@@ -105,7 +104,7 @@
 
 int LocalReaderProxy::Read(net::IOBuffer* buffer, int buffer_length,
                            const net::CompletionCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(file_reader_);
 
   if (buffer_length > remaining_length_) {
@@ -135,7 +134,7 @@
 
 void LocalReaderProxy::OnReadCompleted(const net::CompletionCallback& callback,
                                        int read_result) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(file_reader_);
 
   if (read_result >= 0) {
@@ -160,7 +159,6 @@
       error_code_(net::OK),
       buffer_length_(0),
       job_canceller_(job_canceller) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
 }
 
 NetworkReaderProxy::~NetworkReaderProxy() {
@@ -171,7 +169,7 @@
 
 int NetworkReaderProxy::Read(net::IOBuffer* buffer, int buffer_length,
                              const net::CompletionCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   // Check if there is no pending Read operation.
   DCHECK(!buffer_.get());
   DCHECK_EQ(buffer_length_, 0);
@@ -218,7 +216,7 @@
 }
 
 void NetworkReaderProxy::OnGetContent(scoped_ptr<std::string> data) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(data && !data->empty());
 
   if (remaining_offset_ >= static_cast<int64>(data->length())) {
@@ -253,7 +251,7 @@
 }
 
 void NetworkReaderProxy::OnCompleted(FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   // The downloading is completed, so we do not need to cancel the job
   // in the destructor.
   job_canceller_.Reset();
@@ -333,14 +331,13 @@
     : file_system_getter_(file_system_getter),
       file_task_runner_(file_task_runner),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
 }
 
 DriveFileStreamReader::~DriveFileStreamReader() {
 }
 
 bool DriveFileStreamReader::IsInitialized() const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   return reader_proxy_.get() != NULL;
 }
 
@@ -348,7 +345,7 @@
     const base::FilePath& drive_file_path,
     const net::HttpByteRange& byte_range,
     const InitializeCompletionCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   GetFileContent(
@@ -370,7 +367,7 @@
 
 int DriveFileStreamReader::Read(net::IOBuffer* buffer, int buffer_length,
                                 const net::CompletionCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(reader_proxy_);
   DCHECK(buffer);
   DCHECK(!callback.is_null());
@@ -379,7 +376,7 @@
 
 void DriveFileStreamReader::StoreCancelDownloadClosure(
     const base::Closure& cancel_download_closure) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   cancel_download_closure_ = cancel_download_closure;
 }
 
@@ -389,7 +386,7 @@
     FileError error,
     const base::FilePath& local_cache_file_path,
     scoped_ptr<ResourceEntry> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   // StoreCancelDownloadClosure() should be called before this function.
   DCHECK(!cancel_download_closure_.is_null());
 
@@ -445,7 +442,7 @@
     scoped_ptr<ResourceEntry> entry,
     scoped_ptr<util::LocalFileReader> file_reader,
     int open_result) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (open_result != net::OK) {
     callback.Run(net::ERR_FAILED, scoped_ptr<ResourceEntry>());
@@ -460,7 +457,7 @@
 void DriveFileStreamReader::OnGetContent(
     google_apis::DriveApiErrorCode error_code,
     scoped_ptr<std::string> data) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(reader_proxy_);
   reader_proxy_->OnGetContent(data.Pass());
 }
@@ -468,7 +465,7 @@
 void DriveFileStreamReader::OnGetFileContentCompletion(
     const InitializeCompletionCallback& callback,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (reader_proxy_) {
     // If the proxy object available, send the error to it.
diff --git a/chrome/browser/chromeos/drive/drive_file_stream_reader.h b/chrome/browser/chromeos/drive/drive_file_stream_reader.h
index e61f4f0e..9f2073e 100644
--- a/chrome/browser/chromeos/drive/drive_file_stream_reader.h
+++ b/chrome/browser/chromeos/drive/drive_file_stream_reader.h
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 #include "net/base/completion_callback.h"
@@ -78,6 +79,8 @@
   // The number of remaining bytes to be read.
   int64 remaining_length_;
 
+  base::ThreadChecker thread_checker_;
+
   // This should remain the last member so it'll be destroyed first and
   // invalidate its weak pointers before other members are destroyed.
   base::WeakPtrFactory<LocalReaderProxy> weak_ptr_factory_;
@@ -125,6 +128,8 @@
   int buffer_length_;
   net::CompletionCallback callback_;
 
+  base::ThreadChecker thread_checker_;
+
   // Keeps the closure to cancel downloading job if necessary.
   // Will be reset when the job is completed (regardless whether the job is
   // successfully done or not).
@@ -214,6 +219,8 @@
   base::Closure cancel_download_closure_;
   scoped_ptr<internal::ReaderProxy> reader_proxy_;
 
+  base::ThreadChecker thread_checker_;
+
   // This should remain the last member so it'll be destroyed first and
   // invalidate its weak pointers before other members are destroyed.
   base::WeakPtrFactory<DriveFileStreamReader> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/drive_file_stream_reader_unittest.cc b/chrome/browser/chromeos/drive/drive_file_stream_reader_unittest.cc
index 42b7b603..691443dd 100644
--- a/chrome/browser/chromeos/drive/drive_file_stream_reader_unittest.cc
+++ b/chrome/browser/chromeos/drive/drive_file_stream_reader_unittest.cc
@@ -66,7 +66,7 @@
 TEST_F(LocalReaderProxyTest, Read) {
   // Open the file first.
   scoped_ptr<util::LocalFileReader> file_reader(
-      new util::LocalFileReader(worker_thread_->message_loop_proxy().get()));
+      new util::LocalFileReader(worker_thread_->task_runner().get()));
   net::TestCompletionCallback callback;
   file_reader->Open(file_path_, 0, callback.callback());
   ASSERT_EQ(net::OK, callback.WaitForResult());
@@ -87,7 +87,7 @@
 
   // Open the file first.
   scoped_ptr<util::LocalFileReader> file_reader(
-      new util::LocalFileReader(worker_thread_->message_loop_proxy().get()));
+      new util::LocalFileReader(worker_thread_->task_runner().get()));
   net::TestCompletionCallback callback;
   file_reader->Open(file_path_, 0, callback.callback());
   ASSERT_EQ(net::OK, callback.WaitForResult());
@@ -330,7 +330,7 @@
   // Create the reader, and initialize it.
   // In this case, the file is not yet locally cached.
   scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader(
-      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
+      GetFileSystemGetter(), worker_thread_->task_runner().get()));
   EXPECT_FALSE(reader->IsInitialized());
 
   int error = net::ERR_FAILED;
@@ -357,8 +357,8 @@
 
   // Create second instance and initialize it.
   // In this case, the file should be cached one.
-  reader.reset(new DriveFileStreamReader(
-      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
+  reader.reset(new DriveFileStreamReader(GetFileSystemGetter(),
+                                         worker_thread_->task_runner().get()));
   EXPECT_FALSE(reader->IsInitialized());
 
   error = net::ERR_FAILED;
@@ -398,7 +398,7 @@
   // Create the reader, and initialize it.
   // In this case, the file is not yet locally cached.
   scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader(
-      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
+      GetFileSystemGetter(), worker_thread_->task_runner().get()));
   EXPECT_FALSE(reader->IsInitialized());
 
   int error = net::ERR_FAILED;
@@ -430,8 +430,8 @@
 
   // Create second instance and initialize it.
   // In this case, the file should be cached one.
-  reader.reset(new DriveFileStreamReader(
-      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
+  reader.reset(new DriveFileStreamReader(GetFileSystemGetter(),
+                                         worker_thread_->task_runner().get()));
   EXPECT_FALSE(reader->IsInitialized());
 
   error = net::ERR_FAILED;
@@ -467,7 +467,7 @@
   // Create the reader, and initialize it.
   // In this case, the file is not yet locally cached.
   scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader(
-      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
+      GetFileSystemGetter(), worker_thread_->task_runner().get()));
   EXPECT_FALSE(reader->IsInitialized());
 
   int error = net::ERR_FAILED;
@@ -513,7 +513,7 @@
   // Create the reader, and initialize it.
   // In this case, the file is not yet locally cached.
   scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader(
-      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
+      GetFileSystemGetter(), worker_thread_->task_runner().get()));
   EXPECT_FALSE(reader->IsInitialized());
 
   int error = net::ERR_FAILED;
@@ -540,8 +540,8 @@
 
   // Create second instance and initialize it.
   // In this case, the file should be cached one.
-  reader.reset(new DriveFileStreamReader(
-      GetFileSystemGetter(), worker_thread_->message_loop_proxy().get()));
+  reader.reset(new DriveFileStreamReader(GetFileSystemGetter(),
+                                         worker_thread_->task_runner().get()));
   EXPECT_FALSE(reader->IsInitialized());
 
   error = net::ERR_FAILED;
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index eb05e35..b470d0f1 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -259,15 +259,16 @@
   resource_metadata_.reset(new internal::ResourceMetadata(
       metadata_storage_.get(), cache_.get(), blocking_task_runner_));
 
+  file_task_runner_ =
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
   file_system_.reset(
-      test_file_system ? test_file_system : new FileSystem(
-          profile_->GetPrefs(),
-          logger_.get(),
-          cache_.get(),
-          scheduler_.get(),
-          resource_metadata_.get(),
-          blocking_task_runner_.get(),
-          cache_root_directory_.Append(kTemporaryFileDirectory)));
+      test_file_system
+          ? test_file_system
+          : new FileSystem(
+                profile_->GetPrefs(), logger_.get(), cache_.get(),
+                scheduler_.get(), resource_metadata_.get(),
+                blocking_task_runner_.get(), file_task_runner_.get(),
+                cache_root_directory_.Append(kTemporaryFileDirectory)));
   download_handler_.reset(new DownloadHandler(file_system()));
   debug_info_collector_.reset(new DebugInfoCollector(
       resource_metadata_.get(), file_system(), blocking_task_runner_.get()));
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.h b/chrome/browser/chromeos/drive/drive_integration_service.h
index b60b0ad..fcb3e81 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.h
+++ b/chrome/browser/chromeos/drive/drive_integration_service.h
@@ -168,6 +168,7 @@
   base::FilePath cache_root_directory_;
   scoped_ptr<EventLogger> logger_;
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
   scoped_ptr<internal::ResourceMetadataStorage,
              util::DestroyHelper> metadata_storage_;
   scoped_ptr<internal::FileCache, util::DestroyHelper> cache_;
diff --git a/chrome/browser/chromeos/drive/file_cache.cc b/chrome/browser/chromeos/drive/file_cache.cc
index 910c552..085d6c5 100644
--- a/chrome/browser/chromeos/drive/file_cache.cc
+++ b/chrome/browser/chromeos/drive/file_cache.cc
@@ -6,9 +6,12 @@
 
 #include <vector>
 
+#include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/callback_helpers.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
@@ -19,15 +22,12 @@
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 #include "chrome/browser/drive/drive_api_util.h"
 #include "chromeos/chromeos_constants.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/task_util.h"
 #include "net/base/filename_util.h"
 #include "net/base/mime_sniffer.h"
 #include "net/base/mime_util.h"
 #include "third_party/cros_system_api/constants/cryptohome.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace internal {
 namespace {
@@ -49,7 +49,6 @@
       free_disk_space_getter_(free_disk_space_getter),
       weak_ptr_factory_(this) {
   DCHECK(blocking_task_runner_.get());
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 FileCache::~FileCache() {
@@ -417,7 +416,7 @@
 }
 
 void FileCache::Destroy() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   in_shutdown_.Set();
 
diff --git a/chrome/browser/chromeos/drive/file_cache.h b/chrome/browser/chromeos/drive/file_cache.h
index f93c3e1..d2ba35a 100644
--- a/chrome/browser/chromeos/drive/file_cache.h
+++ b/chrome/browser/chromeos/drive/file_cache.h
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/synchronization/cancellation_flag.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 
@@ -180,6 +181,8 @@
   // IDs of files marked mounted.
   std::set<std::string> mounted_files_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   // This object should be accessed only on |blocking_task_runner_|.
diff --git a/chrome/browser/chromeos/drive/file_system.cc b/chrome/browser/chromeos/drive/file_system.cc
index 664908e4..7e04eec 100644
--- a/chrome/browser/chromeos/drive/file_system.cc
+++ b/chrome/browser/chromeos/drive/file_system.cc
@@ -32,11 +32,8 @@
 #include "chrome/browser/chromeos/drive/search_metadata.h"
 #include "chrome/browser/chromeos/drive/sync_client.h"
 #include "chrome/common/pref_names.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/drive_api_parser.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace {
 
@@ -90,7 +87,6 @@
 void RunGetResourceEntryCallback(const GetResourceEntryCallback& callback,
                                  scoped_ptr<ResourceEntry> entry,
                                  FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK)
@@ -160,7 +156,6 @@
     const GetFilesystemMetadataCallback& callback,
     const int64* largest_changestamp,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!callback.is_null());
 
   metadata.largest_changestamp = *largest_changestamp;
@@ -205,7 +200,6 @@
 void GetPathFromResourceIdAfterGetPath(base::FilePath* file_path,
                                        const GetFilePathCallback& callback,
                                        FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   callback.Run(error, *file_path);
 }
 
@@ -218,7 +212,6 @@
 // Used to implement ReadDirectory().
 void FilterHostedDocuments(const ReadDirectoryEntriesCallback& callback,
                            scoped_ptr<ResourceEntryVector> entries) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!callback.is_null());
 
   if (entries) {
@@ -277,14 +270,14 @@
   FileOperationCallback callback;
 };
 
-FileSystem::FileSystem(
-    PrefService* pref_service,
-    EventLogger* logger,
-    internal::FileCache* cache,
-    JobScheduler* scheduler,
-    internal::ResourceMetadata* resource_metadata,
-    base::SequencedTaskRunner* blocking_task_runner,
-    const base::FilePath& temporary_file_directory)
+FileSystem::FileSystem(PrefService* pref_service,
+                       EventLogger* logger,
+                       internal::FileCache* cache,
+                       JobScheduler* scheduler,
+                       internal::ResourceMetadata* resource_metadata,
+                       base::SequencedTaskRunner* blocking_task_runner,
+                       base::SingleThreadTaskRunner* file_task_runner,
+                       const base::FilePath& temporary_file_directory)
     : pref_service_(pref_service),
       logger_(logger),
       cache_(cache),
@@ -292,15 +285,14 @@
       resource_metadata_(resource_metadata),
       last_update_check_error_(FILE_ERROR_OK),
       blocking_task_runner_(blocking_task_runner),
+      file_task_runner_(file_task_runner),
       temporary_file_directory_(temporary_file_directory),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
   ResetComponents();
 }
 
 FileSystem::~FileSystem() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   directory_loader_->RemoveObserver(this);
   change_list_loader_->RemoveObserver(this);
@@ -399,19 +391,16 @@
       blocking_task_runner_.get(), scheduler_, resource_metadata_,
       loader_controller_.get()));
   get_file_for_saving_operation_.reset(
-      new file_system::GetFileForSavingOperation(logger_,
-                                                 blocking_task_runner_.get(),
-                                                 delegate,
-                                                 scheduler_,
-                                                 resource_metadata_,
-                                                 cache_,
-                                                 temporary_file_directory_));
+      new file_system::GetFileForSavingOperation(
+          logger_, blocking_task_runner_.get(), file_task_runner_.get(),
+          delegate, scheduler_, resource_metadata_, cache_,
+          temporary_file_directory_));
   set_property_operation_.reset(new file_system::SetPropertyOperation(
       blocking_task_runner_.get(), delegate, resource_metadata_));
 }
 
 void FileSystem::CheckForUpdates() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DVLOG(1) << "CheckForUpdates";
 
   change_list_loader_->CheckForUpdates(
@@ -419,19 +408,19 @@
 }
 
 void FileSystem::OnUpdateChecked(FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error);
   last_update_check_time_ = base::Time::Now();
   last_update_check_error_ = error;
 }
 
 void FileSystem::AddObserver(FileSystemObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   observers_.AddObserver(observer);
 }
 
 void FileSystem::RemoveObserver(FileSystemObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   observers_.RemoveObserver(observer);
 }
 
@@ -439,7 +428,7 @@
     const base::FilePath& local_src_file_path,
     const base::FilePath& remote_dest_file_path,
     const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
   copy_operation_->TransferFileFromLocalToRemote(local_src_file_path,
                                                  remote_dest_file_path,
@@ -450,7 +439,7 @@
                       const base::FilePath& dest_file_path,
                       bool preserve_last_modified,
                       const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
   copy_operation_->Copy(
       src_file_path, dest_file_path, preserve_last_modified, callback);
@@ -459,7 +448,7 @@
 void FileSystem::Move(const base::FilePath& src_file_path,
                       const base::FilePath& dest_file_path,
                       const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
   move_operation_->Move(src_file_path, dest_file_path, callback);
 }
@@ -467,7 +456,7 @@
 void FileSystem::Remove(const base::FilePath& file_path,
                         bool is_recursive,
                         const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
   remove_operation_->Remove(file_path, is_recursive, callback);
 }
@@ -477,7 +466,7 @@
     bool is_exclusive,
     bool is_recursive,
     const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   CreateDirectoryParams params;
@@ -495,7 +484,7 @@
 
 void FileSystem::CreateDirectoryAfterRead(const CreateDirectoryParams& params,
                                           FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!params.callback.is_null());
 
   DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. "
@@ -510,7 +499,7 @@
                             bool is_exclusive,
                             const std::string& mime_type,
                             const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
   create_file_operation_->CreateFile(
       file_path, is_exclusive, mime_type, callback);
@@ -520,7 +509,7 @@
                            const base::Time& last_access_time,
                            const base::Time& last_modified_time,
                            const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
   touch_operation_->TouchFile(
       file_path, last_access_time, last_modified_time, callback);
@@ -529,14 +518,14 @@
 void FileSystem::TruncateFile(const base::FilePath& file_path,
                               int64 length,
                               const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
   truncate_operation_->Truncate(file_path, length, callback);
 }
 
 void FileSystem::Pin(const base::FilePath& file_path,
                      const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   std::string* local_id = new std::string;
@@ -553,7 +542,7 @@
 void FileSystem::FinishPin(const FileOperationCallback& callback,
                            const std::string* local_id,
                            FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error == FILE_ERROR_OK)
@@ -563,7 +552,7 @@
 
 void FileSystem::Unpin(const base::FilePath& file_path,
                        const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   std::string* local_id = new std::string;
@@ -581,7 +570,7 @@
 void FileSystem::FinishUnpin(const FileOperationCallback& callback,
                              const std::string* local_id,
                              FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error == FILE_ERROR_OK)
@@ -591,7 +580,7 @@
 
 void FileSystem::GetFile(const base::FilePath& file_path,
                          const GetFileCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   download_operation_->EnsureFileDownloadedByPath(
@@ -604,7 +593,7 @@
 
 void FileSystem::GetFileForSaving(const base::FilePath& file_path,
                                   const GetFileCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   get_file_for_saving_operation_->GetFileForSaving(file_path, callback);
@@ -615,7 +604,7 @@
     const GetFileContentInitializedCallback& initialized_callback,
     const google_apis::GetContentCallback& get_content_callback,
     const FileOperationCallback& completion_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!initialized_callback.is_null());
   DCHECK(!get_content_callback.is_null());
   DCHECK(!completion_callback.is_null());
@@ -632,7 +621,7 @@
 void FileSystem::GetResourceEntry(
     const base::FilePath& file_path,
     const GetResourceEntryCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   ReadDirectory(file_path.DirName(),
@@ -647,7 +636,7 @@
     const base::FilePath& file_path,
     const GetResourceEntryCallback& callback,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. "
@@ -670,7 +659,7 @@
     const base::FilePath& directory_path,
     const ReadDirectoryEntriesCallback& entries_callback_in,
     const FileOperationCallback& completion_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!completion_callback.is_null());
 
   const bool hide_hosted_docs =
@@ -689,7 +678,7 @@
 
 void FileSystem::GetAvailableSpace(
     const GetAvailableSpaceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   about_resource_loader_->GetAboutResource(
@@ -702,7 +691,7 @@
     const GetAvailableSpaceCallback& callback,
     google_apis::DriveApiErrorCode status,
     scoped_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   FileError error = GDataToFileError(status);
@@ -719,7 +708,7 @@
 void FileSystem::GetShareUrl(const base::FilePath& file_path,
                              const GURL& embed_origin,
                              const GetShareUrlCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   // Resolve the resource id.
@@ -745,7 +734,7 @@
     const GetShareUrlCallback& callback,
     ResourceEntry* entry,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -771,7 +760,7 @@
     const GetShareUrlCallback& callback,
     google_apis::DriveApiErrorCode status,
     const GURL& share_url) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   FileError error = GDataToFileError(status);
@@ -791,7 +780,7 @@
 void FileSystem::Search(const std::string& search_query,
                         const GURL& next_link,
                         const SearchCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
   search_operation_->Search(search_query, next_link, callback);
 }
@@ -800,7 +789,7 @@
                                 int options,
                                 int at_most_num_matches,
                                 const SearchMetadataCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   // TODO(satorux): Stop handling hide_hosted_docs here. crbug.com/256520.
   if (pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles))
@@ -814,7 +803,7 @@
 
 void FileSystem::SearchByHashes(const std::set<std::string>& hashes,
                                 const SearchByHashesCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   drive::internal::SearchMetadata(
       blocking_task_runner_, resource_metadata_,
       /* any file name */ "", base::Bind(&CheckHashes, hashes),
@@ -823,7 +812,7 @@
 }
 
 void FileSystem::OnFileChangedByOperation(const FileChange& changed_files) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   FOR_EACH_OBSERVER(
       FileSystemObserver, observers_, OnFileChanged(changed_files));
@@ -867,27 +856,27 @@
 }
 
 void FileSystem::OnDirectoryReloaded(const base::FilePath& directory_path) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   FOR_EACH_OBSERVER(
       FileSystemObserver, observers_, OnDirectoryChanged(directory_path));
 }
 
 void FileSystem::OnFileChanged(const FileChange& changed_files) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   FOR_EACH_OBSERVER(
       FileSystemObserver, observers_, OnFileChanged(changed_files));
 }
 
 void FileSystem::OnLoadFromServerComplete() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   sync_client_->StartCheckingExistingPinnedFiles();
 }
 
 void FileSystem::OnInitialLoadComplete() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   blocking_task_runner_->PostTask(FROM_HERE,
                                   base::Bind(&internal::RemoveStaleCacheFiles,
@@ -898,7 +887,7 @@
 
 void FileSystem::GetMetadata(
     const GetFilesystemMetadataCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   FileSystemMetadata metadata;
@@ -924,7 +913,7 @@
 void FileSystem::MarkCacheFileAsMounted(
     const base::FilePath& drive_file_path,
     const MarkMountedCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   base::FilePath* cache_file_path = new base::FilePath;
@@ -943,7 +932,7 @@
 void FileSystem::MarkCacheFileAsUnmounted(
     const base::FilePath& cache_file_path,
     const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) {
@@ -964,7 +953,7 @@
                                const std::string& email,
                                google_apis::drive::PermissionRole role,
                                const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   // Resolve the resource id.
@@ -990,7 +979,7 @@
     const FileOperationCallback& callback,
     ResourceEntry* entry,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (error != FILE_ERROR_OK) {
     callback.Run(error);
@@ -1010,7 +999,7 @@
     const std::string& key,
     const std::string& value,
     const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   set_property_operation_->SetProperty(drive_file_path, visibility, key, value,
@@ -1021,7 +1010,7 @@
                           OpenMode open_mode,
                           const std::string& mime_type,
                           const OpenFileCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   open_file_operation_->OpenFile(file_path, open_mode, mime_type, callback);
@@ -1029,7 +1018,7 @@
 
 void FileSystem::GetPathFromResourceId(const std::string& resource_id,
                                        const GetFilePathCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   base::FilePath* const file_path = new base::FilePath();
@@ -1048,7 +1037,7 @@
 void FileSystem::FreeDiskSpaceIfNeededFor(
     int64 num_bytes,
     const FreeDiskSpaceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(), FROM_HERE,
diff --git a/chrome/browser/chromeos/drive/file_system.h b/chrome/browser/chromeos/drive/file_system.h
index 68362229..7d091ab 100644
--- a/chrome/browser/chromeos/drive/file_system.h
+++ b/chrome/browser/chromeos/drive/file_system.h
@@ -11,6 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/change_list_loader_observer.h"
 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
@@ -70,6 +71,7 @@
              JobScheduler* scheduler,
              internal::ResourceMetadata* resource_metadata,
              base::SequencedTaskRunner* blocking_task_runner,
+             base::SingleThreadTaskRunner* file_task_runner,
              const base::FilePath& temporary_file_directory);
   ~FileSystem() override;
 
@@ -274,6 +276,7 @@
   base::ObserverList<FileSystemObserver> observers_;
 
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
 
   base::FilePath temporary_file_directory_;
 
@@ -292,6 +295,8 @@
       get_file_for_saving_operation_;
   scoped_ptr<file_system::SetPropertyOperation> set_property_operation_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<FileSystem> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/copy_operation.cc b/chrome/browser/chromeos/drive/file_system/copy_operation.cc
index 39b959a..e6b58f1 100644
--- a/chrome/browser/chromeos/drive/file_system/copy_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/copy_operation.cc
@@ -17,11 +17,8 @@
 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 #include "chrome/browser/drive/drive_api_util.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/drive_api_parser.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace file_system {
 
@@ -288,18 +285,17 @@
                                                    delegate,
                                                    metadata)),
     weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 CopyOperation::~CopyOperation() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void CopyOperation::Copy(const base::FilePath& src_file_path,
                          const base::FilePath& dest_file_path,
                          bool preserve_last_modified,
                          const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   CopyParams* params = new CopyParams;
@@ -328,7 +324,7 @@
     const bool* directory_changed,
     const bool* should_copy_on_server,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!params->callback.is_null());
 
   for (const auto& id : *updated_local_ids) {
@@ -366,7 +362,7 @@
 
 void CopyOperation::CopyAfterParentSync(const CopyParams& params,
                                         FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!params.callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -391,7 +387,7 @@
 void CopyOperation::CopyAfterGetParentResourceId(const CopyParams& params,
                                                  const ResourceEntry* parent,
                                                  FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!params.callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -420,7 +416,7 @@
     const base::FilePath& local_src_path,
     const base::FilePath& remote_dest_path,
     const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   std::string* gdoc_resource_id = new std::string;
@@ -446,7 +442,7 @@
     std::string* gdoc_resource_id,
     ResourceEntry* parent_entry,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -483,7 +479,7 @@
 void CopyOperation::TransferJsonGdocFileAfterLocalWork(
     TransferJsonGdocParams* params,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (error != FILE_ERROR_OK) {
     params->callback.Run(error);
@@ -541,7 +537,7 @@
     const std::string& new_title,
     const base::Time& last_modified,
     const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   scheduler_->CopyResource(
@@ -555,7 +551,7 @@
     const FileOperationCallback& callback,
     google_apis::DriveApiErrorCode status,
     scoped_ptr<google_apis::FileResource> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   FileError error = GDataToFileError(status);
@@ -589,7 +585,7 @@
     base::FilePath* file_path,
     const ResourceEntry* entry,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error == FILE_ERROR_OK) {
@@ -604,7 +600,7 @@
     const base::FilePath& local_src_path,
     const base::FilePath& remote_dest_path,
     const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   create_file_operation_->CreateFile(
@@ -621,7 +617,7 @@
     const base::FilePath& remote_dest_path,
     const FileOperationCallback& callback,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -656,7 +652,7 @@
     const ResourceEntry* entry,
     std::string* local_id,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error == FILE_ERROR_OK) {
diff --git a/chrome/browser/chromeos/drive/file_system/copy_operation.h b/chrome/browser/chromeos/drive/file_system/copy_operation.h
index 6a3833d..af3bbdcd 100644
--- a/chrome/browser/chromeos/drive/file_system/copy_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/copy_operation.h
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 
@@ -166,6 +167,8 @@
   // Uploading a new file is internally implemented by creating a dirty file.
   scoped_ptr<CreateFileOperation> create_file_operation_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<CopyOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/create_directory_operation.cc b/chrome/browser/chromeos/drive/file_system/create_directory_operation.cc
index b746b2d..1901c4cd 100644
--- a/chrome/browser/chromeos/drive/file_system/create_directory_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/create_directory_operation.cc
@@ -10,9 +10,6 @@
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace drive {
 namespace file_system {
@@ -75,15 +72,17 @@
   std::vector<base::FilePath::StringType> components;
   directory_path.GetComponents(&components);
 
-  if (components.empty() || components[0] != util::kDriveGrandRootDirName)
+  if (components.empty() ||
+      components[0] != util::GetDriveGrandRootPath().value())
     return FILE_ERROR_NOT_FOUND;
 
   base::FilePath existing_deepest_path(components[0]);
   std::string local_id = util::kDriveGrandRootLocalId;
   for (size_t i = 1; i < components.size(); ++i) {
+    const std::string component = base::FilePath(components[i]).AsUTF8Unsafe();
     std::string child_local_id;
     FileError error =
-        metadata->GetChildId(local_id, components[i], &child_local_id);
+        metadata->GetChildId(local_id, component, &child_local_id);
     if (error == FILE_ERROR_NOT_FOUND)
       break;
     if (error != FILE_ERROR_OK)
@@ -128,11 +127,10 @@
       delegate_(delegate),
       metadata_(metadata),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 CreateDirectoryOperation::~CreateDirectoryOperation() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void CreateDirectoryOperation::CreateDirectory(
@@ -140,7 +138,7 @@
     bool is_exclusive,
     bool is_recursive,
     const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   std::set<std::string>* updated_local_ids = new std::set<std::string>;
@@ -168,7 +166,7 @@
     const std::set<std::string>* updated_local_ids,
     const FileChange* changed_files,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   for (const auto& id : *updated_local_ids) {
diff --git a/chrome/browser/chromeos/drive/file_system/create_directory_operation.h b/chrome/browser/chromeos/drive/file_system/create_directory_operation.h
index f77a599..4b3055b 100644
--- a/chrome/browser/chromeos/drive/file_system/create_directory_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/create_directory_operation.h
@@ -10,6 +10,7 @@
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 
 namespace base {
@@ -64,6 +65,8 @@
   OperationDelegate* delegate_;
   internal::ResourceMetadata* metadata_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<CreateDirectoryOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/create_file_operation.cc b/chrome/browser/chromeos/drive/file_system/create_file_operation.cc
index afbc20cf..12e57aa4 100644
--- a/chrome/browser/chromeos/drive/file_system/create_file_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/create_file_operation.cc
@@ -12,11 +12,8 @@
 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
-#include "content/public/browser/browser_thread.h"
 #include "net/base/mime_util.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace file_system {
 
@@ -78,18 +75,17 @@
       delegate_(delegate),
       metadata_(metadata),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 CreateFileOperation::~CreateFileOperation() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void CreateFileOperation::CreateFile(const base::FilePath& file_path,
                                      bool is_exclusive,
                                      const std::string& mime_type,
                                      const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   ResourceEntry* entry = new ResourceEntry;
@@ -115,7 +111,7 @@
     bool is_exclusive,
     ResourceEntry* entry,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error == FILE_ERROR_EXISTS) {
diff --git a/chrome/browser/chromeos/drive/file_system/create_file_operation.h b/chrome/browser/chromeos/drive/file_system/create_file_operation.h
index d515ac79..6c2b627 100644
--- a/chrome/browser/chromeos/drive/file_system/create_file_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/create_file_operation.h
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 
 namespace base {
@@ -61,6 +62,8 @@
   OperationDelegate* delegate_;
   internal::ResourceMetadata* metadata_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<CreateFileOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/download_operation.cc b/chrome/browser/chromeos/drive/file_system/download_operation.cc
index 1aeb5e7..d3dde19 100644
--- a/chrome/browser/chromeos/drive/file_system/download_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/download_operation.cc
@@ -17,11 +17,8 @@
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace file_system {
 namespace {
@@ -360,7 +357,7 @@
     const GetFileContentInitializedCallback& initialized_callback,
     const google_apis::GetContentCallback& get_content_callback,
     const GetFileCallback& completion_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!completion_callback.is_null());
 
   CheckPreconditionForEnsureFileDownloadedParams params;
@@ -401,7 +398,7 @@
     const GetFileContentInitializedCallback& initialized_callback,
     const google_apis::GetContentCallback& get_content_callback,
     const GetFileCallback& completion_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!completion_callback.is_null());
 
   CheckPreconditionForEnsureFileDownloadedParams params;
@@ -442,7 +439,7 @@
     base::FilePath* cache_file_path,
     base::FilePath* temp_download_file_path,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(params);
   DCHECK(drive_file_path);
   DCHECK(cache_file_path);
@@ -489,7 +486,7 @@
     scoped_ptr<DownloadParams> params,
     google_apis::DriveApiErrorCode gdata_error,
     const base::FilePath& downloaded_file_path) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   DownloadParams* params_ptr = params.get();
   ResourceEntry* entry_after_update = new ResourceEntry;
@@ -519,7 +516,7 @@
     scoped_ptr<ResourceEntry> entry_after_update,
     base::FilePath* cache_file_path,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (error != FILE_ERROR_OK) {
     params->OnError(error);
diff --git a/chrome/browser/chromeos/drive/file_system/download_operation.h b/chrome/browser/chromeos/drive/file_system/download_operation.h
index 9dcd52dc..2ad4018f 100644
--- a/chrome/browser/chromeos/drive/file_system/download_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/download_operation.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 #include "chrome/browser/chromeos/drive/job_list.h"
@@ -118,6 +119,8 @@
   internal::FileCache* cache_;
   const base::FilePath temporary_file_directory_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<DownloadOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc
index 0709a1dc..12f28985 100644
--- a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc
@@ -16,8 +16,6 @@
 #include "chrome/browser/drive/event_logger.h"
 #include "content/public/browser/browser_thread.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace file_system {
 
@@ -40,22 +38,22 @@
 GetFileForSavingOperation::GetFileForSavingOperation(
     EventLogger* logger,
     base::SequencedTaskRunner* blocking_task_runner,
+    base::SingleThreadTaskRunner* file_task_runner,
     OperationDelegate* delegate,
     JobScheduler* scheduler,
     internal::ResourceMetadata* metadata,
     internal::FileCache* cache,
     const base::FilePath& temporary_file_directory)
     : logger_(logger),
-      create_file_operation_(new CreateFileOperation(blocking_task_runner,
-                                                     delegate,
-                                                     metadata)),
+      create_file_operation_(
+          new CreateFileOperation(blocking_task_runner, delegate, metadata)),
       download_operation_(new DownloadOperation(blocking_task_runner,
                                                 delegate,
                                                 scheduler,
                                                 metadata,
                                                 cache,
                                                 temporary_file_directory)),
-      file_write_watcher_(new internal::FileWriteWatcher),
+      file_write_watcher_(new internal::FileWriteWatcher(file_task_runner)),
       blocking_task_runner_(blocking_task_runner),
       delegate_(delegate),
       metadata_(metadata),
@@ -69,7 +67,7 @@
 void GetFileForSavingOperation::GetFileForSaving(
     const base::FilePath& file_path,
     const GetFileCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   create_file_operation_->CreateFile(
@@ -86,7 +84,7 @@
     const base::FilePath& file_path,
     const GetFileCallback& callback,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -109,7 +107,7 @@
     FileError error,
     const base::FilePath& cache_path,
     scoped_ptr<ResourceEntry> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -144,7 +142,7 @@
     scoped_ptr<ResourceEntry> entry,
     scoped_ptr<base::ScopedClosureRunner>* file_closer,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -171,7 +169,7 @@
     const base::FilePath& cache_path,
     scoped_ptr<ResourceEntry> entry,
     bool success) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   logger_->Log(logging::LOG_INFO, "Started watching modification to %s [%s].",
diff --git a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h
index e1f46bc..fc63db1 100644
--- a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 
@@ -44,6 +45,7 @@
  public:
   GetFileForSavingOperation(EventLogger* logger,
                             base::SequencedTaskRunner* blocking_task_runner,
+                            base::SingleThreadTaskRunner* file_task_runner,
                             OperationDelegate* delegate,
                             JobScheduler* scheduler,
                             internal::ResourceMetadata* metadata,
@@ -93,6 +95,8 @@
   internal::ResourceMetadata* metadata_;
   internal::FileCache* cache_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<GetFileForSavingOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc
index 90293db..6c0bc18 100644
--- a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation_unittest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
 #include "chrome/browser/chromeos/drive/file_write_watcher.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_utils.h"
 #include "google_apis/drive/test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -61,14 +62,18 @@
   void SetUp() override {
     OperationTestBase::SetUp();
 
+    file_task_runner_ = content::BrowserThread::GetMessageLoopProxyForThread(
+        content::BrowserThread::FILE);
+
     operation_.reset(new GetFileForSavingOperation(
-        logger(), blocking_task_runner(), &delegate_, scheduler(), metadata(),
-        cache(), temp_dir()));
+        logger(), blocking_task_runner(), file_task_runner_.get(), &delegate_,
+        scheduler(), metadata(), cache(), temp_dir()));
     operation_->file_write_watcher_for_testing()->DisableDelayForTesting();
   }
 
   TestDelegate delegate_;
   scoped_ptr<GetFileForSavingOperation> operation_;
+  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
 };
 
 TEST_F(GetFileForSavingOperationTest, GetFileForSaving_Exist) {
diff --git a/chrome/browser/chromeos/drive/file_system/move_operation.cc b/chrome/browser/chromeos/drive/file_system/move_operation.cc
index 402ee53..9d9391b6 100644
--- a/chrome/browser/chromeos/drive/file_system/move_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/move_operation.cc
@@ -10,9 +10,6 @@
 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace drive {
 namespace file_system {
@@ -74,17 +71,16 @@
       delegate_(delegate),
       metadata_(metadata),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 MoveOperation::~MoveOperation() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void MoveOperation::Move(const base::FilePath& src_file_path,
                          const base::FilePath& dest_file_path,
                          const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   FileChange* changed_files = new FileChange;
@@ -110,7 +106,7 @@
     const FileChange* changed_files,
     const std::string* local_id,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   if (error == FILE_ERROR_OK) {
     // Notify the change of directory.
     delegate_->OnFileChangedByOperation(*changed_files);
diff --git a/chrome/browser/chromeos/drive/file_system/move_operation.h b/chrome/browser/chromeos/drive/file_system/move_operation.h
index 5bea0e6..7b41933 100644
--- a/chrome/browser/chromeos/drive/file_system/move_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/move_operation.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 
@@ -64,6 +65,8 @@
   OperationDelegate* delegate_;
   internal::ResourceMetadata* metadata_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<MoveOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/open_file_operation.cc b/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
index 6f4e9bd..ee779ec 100644
--- a/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
@@ -9,8 +9,8 @@
 #include "base/callback_helpers.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/file_cache.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
@@ -18,9 +18,6 @@
 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace drive {
 namespace file_system {
@@ -50,7 +47,7 @@
                                  OpenMode open_mode,
                                  const std::string& mime_type,
                                  const OpenFileCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   switch (open_mode) {
@@ -83,7 +80,7 @@
     const base::FilePath& file_path,
     const OpenFileCallback& callback,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -106,7 +103,7 @@
     FileError error,
     const base::FilePath& local_file_path,
     scoped_ptr<ResourceEntry> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error == FILE_ERROR_OK) {
@@ -145,7 +142,7 @@
     const OpenFileCallback& callback,
     scoped_ptr<base::ScopedClosureRunner>* file_closer,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -164,7 +161,7 @@
 void OpenFileOperation::CloseFile(
     const std::string& local_id,
     scoped_ptr<base::ScopedClosureRunner> file_closer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_GT(open_files_[local_id], 0);
 
   if (--open_files_[local_id] == 0) {
diff --git a/chrome/browser/chromeos/drive/file_system/open_file_operation.h b/chrome/browser/chromeos/drive/file_system/open_file_operation.h
index 953130b6..02795b6 100644
--- a/chrome/browser/chromeos/drive/file_system/open_file_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/open_file_operation.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 
@@ -94,6 +95,8 @@
   // the file is opened.
   std::map<std::string, int> open_files_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<OpenFileOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/remove_operation.cc b/chrome/browser/chromeos/drive/file_system/remove_operation.cc
index c3f7a1ed..d3d58d9 100644
--- a/chrome/browser/chromeos/drive/file_system/remove_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/remove_operation.cc
@@ -12,9 +12,6 @@
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace drive {
 namespace file_system {
@@ -70,17 +67,16 @@
       metadata_(metadata),
       cache_(cache),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 RemoveOperation::~RemoveOperation() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void RemoveOperation::Remove(const base::FilePath& path,
                              bool is_recursive,
                              const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   std::string* local_id = new std::string;
@@ -111,7 +107,7 @@
     const ResourceEntry* entry,
     const base::FilePath* changed_path,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (!changed_path->empty()) {
diff --git a/chrome/browser/chromeos/drive/file_system/remove_operation.h b/chrome/browser/chromeos/drive/file_system/remove_operation.h
index 215e6a3f..c8cc6f3 100644
--- a/chrome/browser/chromeos/drive/file_system/remove_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/remove_operation.h
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 
@@ -62,6 +63,8 @@
   internal::ResourceMetadata* metadata_;
   internal::FileCache* cache_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<RemoveOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/search_operation.cc b/chrome/browser/chromeos/drive/file_system/search_operation.cc
index 8b32317..182cb6f1 100644
--- a/chrome/browser/chromeos/drive/file_system/search_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/search_operation.cc
@@ -17,12 +17,9 @@
 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 #include "chrome/browser/drive/drive_api_util.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/drive_api_parser.h"
 #include "url/gurl.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace file_system {
 namespace {
@@ -98,7 +95,7 @@
 void SearchOperation::Search(const std::string& search_query,
                              const GURL& next_link,
                              const SearchCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (next_link.is_empty()) {
@@ -120,7 +117,7 @@
     const SearchCallback& callback,
     google_apis::DriveApiErrorCode gdata_error,
     scoped_ptr<google_apis::FileList> file_list) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   FileError error = GDataToFileError(gdata_error);
@@ -167,7 +164,7 @@
     const GURL& next_link,
     scoped_ptr<std::vector<SearchResultInfo> > result,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
   DCHECK(result);
 
diff --git a/chrome/browser/chromeos/drive/file_system/search_operation.h b/chrome/browser/chromeos/drive/file_system/search_operation.h
index aa2e5f7..709371dd 100644
--- a/chrome/browser/chromeos/drive/file_system/search_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/search_operation.h
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 #include "google_apis/drive/drive_api_error_codes.h"
@@ -71,6 +72,8 @@
   internal::ResourceMetadata* metadata_;
   internal::LoaderController* loader_controller_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<SearchOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/set_property_operation.cc b/chrome/browser/chromeos/drive/file_system/set_property_operation.cc
index 111f9b7..509ba2a 100644
--- a/chrome/browser/chromeos/drive/file_system/set_property_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/set_property_operation.cc
@@ -12,9 +12,6 @@
 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace drive {
 namespace file_system {
@@ -90,7 +87,7 @@
     const std::string& key,
     const std::string& value,
     const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   ResourceEntry* entry = new ResourceEntry;
@@ -106,7 +103,7 @@
     const FileOperationCallback& callback,
     const ResourceEntry* entry,
     FileError result) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (result == FILE_ERROR_OK) {
diff --git a/chrome/browser/chromeos/drive/file_system/set_property_operation.h b/chrome/browser/chromeos/drive/file_system/set_property_operation.h
index 5d5634f..6a93a16 100644
--- a/chrome/browser/chromeos/drive/file_system/set_property_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/set_property_operation.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "google_apis/drive/drive_api_requests.h"
 
@@ -55,6 +56,8 @@
   OperationDelegate* delegate_;
   internal::ResourceMetadata* metadata_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<SetPropertyOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/touch_operation.cc b/chrome/browser/chromeos/drive/file_system/touch_operation.cc
index 217bd92..47dd5aa 100644
--- a/chrome/browser/chromeos/drive/file_system/touch_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/touch_operation.cc
@@ -13,9 +13,6 @@
 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace drive {
 namespace file_system {
@@ -60,7 +57,7 @@
                                const base::Time& last_access_time,
                                const base::Time& last_modified_time,
                                const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   ResourceEntry* entry = new ResourceEntry;
@@ -78,7 +75,7 @@
     const FileOperationCallback& callback,
     const ResourceEntry* entry,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   FileChange changed_files;
diff --git a/chrome/browser/chromeos/drive/file_system/touch_operation.h b/chrome/browser/chromeos/drive/file_system/touch_operation.h
index 15d6849c..fe2ebc2 100644
--- a/chrome/browser/chromeos/drive/file_system/touch_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/touch_operation.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 
 namespace base {
@@ -53,6 +54,8 @@
   OperationDelegate* delegate_;
   internal::ResourceMetadata* metadata_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<TouchOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system/truncate_operation.cc b/chrome/browser/chromeos/drive/file_system/truncate_operation.cc
index 0c0edaf6..ff1307e 100644
--- a/chrome/browser/chromeos/drive/file_system/truncate_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/truncate_operation.cc
@@ -18,9 +18,6 @@
 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace drive {
 namespace file_system {
@@ -80,7 +77,7 @@
 void TruncateOperation::Truncate(const base::FilePath& file_path,
                                  int64 length,
                                  const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (length < 0) {
@@ -107,7 +104,7 @@
     FileError error,
     const base::FilePath& local_file_path,
     scoped_ptr<ResourceEntry> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -136,7 +133,7 @@
     const std::string& local_id,
     const FileOperationCallback& callback,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), local_id);
diff --git a/chrome/browser/chromeos/drive/file_system/truncate_operation.h b/chrome/browser/chromeos/drive/file_system/truncate_operation.h
index 0a6d5e7..5067c6b9 100644
--- a/chrome/browser/chromeos/drive/file_system/truncate_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/truncate_operation.h
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 
 namespace base {
@@ -73,6 +74,8 @@
 
   scoped_ptr<DownloadOperation> download_operation_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<TruncateOperation> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/file_system_unittest.cc b/chrome/browser/chromeos/drive/file_system_unittest.cc
index b9af060..27c593a 100644
--- a/chrome/browser/chromeos/drive/file_system_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system_unittest.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/drive/event_logger.h"
 #include "chrome/browser/drive/fake_drive_service.h"
 #include "chrome/browser/drive/test_util.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "google_apis/drive/drive_api_parser.h"
 #include "google_apis/drive/test_util.h"
@@ -141,14 +142,12 @@
 
     const base::FilePath temp_file_dir = temp_dir_.path().AppendASCII("tmp");
     ASSERT_TRUE(base::CreateDirectory(temp_file_dir));
+    file_task_runner_ = content::BrowserThread::GetMessageLoopProxyForThread(
+        content::BrowserThread::FILE);
     file_system_.reset(new FileSystem(
-        pref_service_.get(),
-        logger_.get(),
-        cache_.get(),
-        scheduler_.get(),
-        resource_metadata_.get(),
-        base::ThreadTaskRunnerHandle::Get().get(),
-        temp_file_dir));
+        pref_service_.get(), logger_.get(), cache_.get(), scheduler_.get(),
+        resource_metadata_.get(), base::ThreadTaskRunnerHandle::Get().get(),
+        file_task_runner_.get(), temp_file_dir));
     file_system_->AddObserver(mock_directory_observer_.get());
 
     // Disable delaying so that the sync starts immediately.
@@ -325,6 +324,7 @@
   scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
   scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
       resource_metadata_;
+  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
   scoped_ptr<FileSystem> file_system_;
 };
 
@@ -690,9 +690,12 @@
   for (size_t i = 0; i < entries->size(); ++i)
     found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
   EXPECT_EQ(3U, found.size());
-  EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveMyDriveRootDirName)));
-  EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveOtherDirName)));
-  EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveTrashDirName)));
+  EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe(
+                    util::kDriveMyDriveRootDirName)));
+  EXPECT_EQ(1U, found.count(
+                    base::FilePath::FromUTF8Unsafe(util::kDriveOtherDirName)));
+  EXPECT_EQ(1U, found.count(
+                    base::FilePath::FromUTF8Unsafe(util::kDriveTrashDirName)));
 }
 
 TEST_F(FileSystemTest, ReadDirectory_NonRootDirectory) {
diff --git a/chrome/browser/chromeos/drive/file_system_util.cc b/chrome/browser/chromeos/drive/file_system_util.cc
index f0e905e..1c70e99c 100644
--- a/chrome/browser/chromeos/drive/file_system_util.cc
+++ b/chrome/browser/chromeos/drive/file_system_util.cc
@@ -92,14 +92,16 @@
 }  // namespace
 
 const base::FilePath& GetDriveGrandRootPath() {
-  CR_DEFINE_STATIC_LOCAL(base::FilePath, grand_root_path,
-      (kDriveGrandRootDirName));
+  CR_DEFINE_STATIC_LOCAL(
+      base::FilePath, grand_root_path,
+      (base::FilePath::FromUTF8Unsafe(kDriveGrandRootDirName)));
   return grand_root_path;
 }
 
 const base::FilePath& GetDriveMyDriveRootPath() {
-  CR_DEFINE_STATIC_LOCAL(base::FilePath, drive_root_path,
-                         (FILE_PATH_LITERAL("drive/root")));
+  CR_DEFINE_STATIC_LOCAL(
+      base::FilePath, drive_root_path,
+      (GetDriveGrandRootPath().AppendASCII(kDriveMyDriveRootDirName)));
   return drive_root_path;
 }
 
@@ -182,7 +184,7 @@
     return base::FilePath();
   if (components[1] != FILE_PATH_LITERAL("special"))
     return base::FilePath();
-  if (!StartsWithASCII(components[2], "drive", true))
+  if (!base::StartsWithASCII(components[2], "drive", true))
     return base::FilePath();
 
   base::FilePath drive_path = GetDriveGrandRootPath();
diff --git a/chrome/browser/chromeos/drive/file_system_util.h b/chrome/browser/chromeos/drive/file_system_util.h
index fd72ea1..d06b74d 100644
--- a/chrome/browser/chromeos/drive/file_system_util.h
+++ b/chrome/browser/chromeos/drive/file_system_util.h
@@ -38,17 +38,10 @@
 
 // The directory names used for the Google Drive file system tree. These names
 // are used in URLs for the file manager, hence user-visible.
-const base::FilePath::CharType kDriveGrandRootDirName[] =
-    FILE_PATH_LITERAL("drive");
-
-const base::FilePath::CharType kDriveMyDriveRootDirName[] =
-    FILE_PATH_LITERAL("root");
-
-const base::FilePath::CharType kDriveOtherDirName[] =
-    FILE_PATH_LITERAL("other");
-
-const base::FilePath::CharType kDriveTrashDirName[] =
-    FILE_PATH_LITERAL("trash");
+const char kDriveGrandRootDirName[] = "drive";
+const char kDriveMyDriveRootDirName[] = "root";
+const char kDriveOtherDirName[] = "other";
+const char kDriveTrashDirName[] = "trash";
 
 // Returns the path of the top root of the pseudo tree.
 const base::FilePath& GetDriveGrandRootPath();
diff --git a/chrome/browser/chromeos/drive/file_write_watcher.cc b/chrome/browser/chromeos/drive/file_write_watcher.cc
index 48d7500..a7a75aa 100644
--- a/chrome/browser/chromeos/drive/file_write_watcher.cc
+++ b/chrome/browser/chromeos/drive/file_write_watcher.cc
@@ -12,11 +12,8 @@
 #include "base/files/file_path_watcher.h"
 #include "base/stl_util.h"
 #include "base/timer/timer.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/task_util.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace internal {
 
@@ -29,7 +26,7 @@
 // UI thread and FILE thread, and does all the main tasks in the FILE thread.
 class FileWriteWatcher::FileWriteWatcherImpl {
  public:
-  FileWriteWatcherImpl();
+  explicit FileWriteWatcherImpl(base::SingleThreadTaskRunner* file_task_runner);
 
   // Forwards the call to DestoryOnFileThread(). This method must be used to
   // destruct the instance.
@@ -70,6 +67,9 @@
 
   base::TimeDelta delay_;
   std::map<base::FilePath, PathWatchInfo*> watchers_;
+  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
+
+  base::ThreadChecker thread_checker_;
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
@@ -77,46 +77,45 @@
   DISALLOW_COPY_AND_ASSIGN(FileWriteWatcherImpl);
 };
 
-FileWriteWatcher::FileWriteWatcherImpl::FileWriteWatcherImpl()
+FileWriteWatcher::FileWriteWatcherImpl::FileWriteWatcherImpl(
+    base::SingleThreadTaskRunner* file_task_runner)
     : delay_(base::TimeDelta::FromSeconds(kWriteEventDelayInSeconds)),
+      file_task_runner_(file_task_runner),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 void FileWriteWatcher::FileWriteWatcherImpl::Destroy() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   // Just forwarding the call to FILE thread.
-  BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)->PostTask(
-      FROM_HERE,
-      base::Bind(&FileWriteWatcherImpl::DestroyOnFileThread,
-                 base::Unretained(this)));
+  file_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&FileWriteWatcherImpl::DestroyOnFileThread,
+                            base::Unretained(this)));
 }
 
 void FileWriteWatcher::FileWriteWatcherImpl::StartWatch(
     const base::FilePath& path,
     const StartWatchCallback& on_start_callback,
     const base::Closure& on_write_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   // Forwarding the call to FILE thread and relaying the |callback|.
-  BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)->PostTask(
+  file_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&FileWriteWatcherImpl::StartWatchOnFileThread,
-                 base::Unretained(this),
-                 path,
+                 base::Unretained(this), path,
                  google_apis::CreateRelayCallback(on_start_callback),
                  google_apis::CreateRelayCallback(on_write_callback)));
 }
 
 FileWriteWatcher::FileWriteWatcherImpl::~FileWriteWatcherImpl() {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(file_task_runner_->BelongsToCurrentThread());
 
   STLDeleteContainerPairSecondPointers(watchers_.begin(), watchers_.end());
 }
 
 void FileWriteWatcher::FileWriteWatcherImpl::DestroyOnFileThread() {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(file_task_runner_->BelongsToCurrentThread());
 
   delete this;
 }
@@ -125,7 +124,7 @@
     const base::FilePath& path,
     const StartWatchCallback& on_start_callback,
     const base::Closure& on_write_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(file_task_runner_->BelongsToCurrentThread());
 
   std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path);
   if (it != watchers_.end()) {
@@ -149,7 +148,7 @@
 void FileWriteWatcher::FileWriteWatcherImpl::OnWriteEvent(
     const base::FilePath& path,
     bool error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(file_task_runner_->BelongsToCurrentThread());
 
   if (error)
     return;
@@ -170,7 +169,7 @@
 
 void FileWriteWatcher::FileWriteWatcherImpl::InvokeCallback(
     const base::FilePath& path) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  DCHECK(file_task_runner_->BelongsToCurrentThread());
 
   std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path);
   DCHECK(it != watchers_.end());
@@ -184,19 +183,19 @@
     callbacks[i].Run();
 }
 
-FileWriteWatcher::FileWriteWatcher()
-    : watcher_impl_(new FileWriteWatcherImpl) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+FileWriteWatcher::FileWriteWatcher(
+    base::SingleThreadTaskRunner* file_task_runner)
+    : watcher_impl_(new FileWriteWatcherImpl(file_task_runner)) {
 }
 
 FileWriteWatcher::~FileWriteWatcher() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void FileWriteWatcher::StartWatch(const base::FilePath& file_path,
                                   const StartWatchCallback& on_start_callback,
                                   const base::Closure& on_write_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   watcher_impl_->StartWatch(file_path, on_start_callback, on_write_callback);
 }
 
diff --git a/chrome/browser/chromeos/drive/file_write_watcher.h b/chrome/browser/chromeos/drive/file_write_watcher.h
index 965ea66..68004ca7 100644
--- a/chrome/browser/chromeos/drive/file_write_watcher.h
+++ b/chrome/browser/chromeos/drive/file_write_watcher.h
@@ -7,10 +7,12 @@
 
 #include "base/callback_forward.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 
 namespace base {
 class FilePath;
+class SingleThreadTaskRunner;
 }  // namespace base
 
 namespace drive {
@@ -25,7 +27,7 @@
 // without any special handling about Drive.
 class FileWriteWatcher {
  public:
-  FileWriteWatcher();
+  explicit FileWriteWatcher(base::SingleThreadTaskRunner* file_task_runner);
   ~FileWriteWatcher();
 
   // Starts watching the modification to |path|. When it successfully started
@@ -53,6 +55,8 @@
   class FileWriteWatcherImpl;
   scoped_ptr<FileWriteWatcherImpl, util::DestroyHelper> watcher_impl_;
 
+  base::ThreadChecker thread_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(FileWriteWatcher);
 };
 
diff --git a/chrome/browser/chromeos/drive/file_write_watcher_unittest.cc b/chrome/browser/chromeos/drive/file_write_watcher_unittest.cc
index 978a274..3c9fe1ca 100644
--- a/chrome/browser/chromeos/drive/file_write_watcher_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_write_watcher_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -86,7 +87,10 @@
   TestObserver observer(expected, loop.QuitClosure());
 
   // Set up the watcher.
-  FileWriteWatcher watcher;
+  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner =
+      content::BrowserThread::GetMessageLoopProxyForThread(
+          content::BrowserThread::FILE);
+  FileWriteWatcher watcher(file_task_runner.get());
   watcher.DisableDelayForTesting();
 
   // Start watching and running.
diff --git a/chrome/browser/chromeos/drive/fileapi/webkit_file_stream_reader_impl_unittest.cc b/chrome/browser/chromeos/drive/fileapi/webkit_file_stream_reader_impl_unittest.cc
index bb1d5c0..3aad8a7 100644
--- a/chrome/browser/chromeos/drive/fileapi/webkit_file_stream_reader_impl_unittest.cc
+++ b/chrome/browser/chromeos/drive/fileapi/webkit_file_stream_reader_impl_unittest.cc
@@ -72,9 +72,7 @@
       util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
 
   scoped_ptr<WebkitFileStreamReaderImpl> reader(new WebkitFileStreamReaderImpl(
-      GetFileSystemGetter(),
-      worker_thread_->message_loop_proxy().get(),
-      kDriveFile,
+      GetFileSystemGetter(), worker_thread_->task_runner().get(), kDriveFile,
       0,               // offset
       base::Time()));  // expected modification time
 
@@ -92,9 +90,7 @@
       util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
 
   scoped_ptr<WebkitFileStreamReaderImpl> reader(new WebkitFileStreamReaderImpl(
-      GetFileSystemGetter(),
-      worker_thread_->message_loop_proxy().get(),
-      kDriveFile,
+      GetFileSystemGetter(), worker_thread_->task_runner().get(), kDriveFile,
       0,               // offset
       base::Time()));  // expected modification time
 
@@ -113,9 +109,7 @@
   const int kOffset = 5;
 
   scoped_ptr<WebkitFileStreamReaderImpl> reader(new WebkitFileStreamReaderImpl(
-      GetFileSystemGetter(),
-      worker_thread_->message_loop_proxy().get(),
-      kDriveFile,
+      GetFileSystemGetter(), worker_thread_->task_runner().get(), kDriveFile,
       kOffset,
       base::Time()));  // expected modification time
 
@@ -133,9 +127,7 @@
       util::GetDriveMyDriveRootPath().AppendASCII("non-existing.txt");
 
   scoped_ptr<WebkitFileStreamReaderImpl> reader(new WebkitFileStreamReaderImpl(
-      GetFileSystemGetter(),
-      worker_thread_->message_loop_proxy().get(),
-      kDriveFile,
+      GetFileSystemGetter(), worker_thread_->task_runner().get(), kDriveFile,
       0,               // offset
       base::Time()));  // expected modification time
 
@@ -152,9 +144,7 @@
       util::GetDriveMyDriveRootPath().AppendASCII("non-existing.txt");
 
   scoped_ptr<WebkitFileStreamReaderImpl> reader(new WebkitFileStreamReaderImpl(
-      GetFileSystemGetter(),
-      worker_thread_->message_loop_proxy().get(),
-      kDriveFile,
+      GetFileSystemGetter(), worker_thread_->task_runner().get(), kDriveFile,
       0,               // offset
       base::Time()));  // expected modification time
 
@@ -193,12 +183,10 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
 
-  scoped_ptr<WebkitFileStreamReaderImpl> reader(
-      new WebkitFileStreamReaderImpl(GetFileSystemGetter(),
-                                     worker_thread_->message_loop_proxy().get(),
-                                     kDriveFile,
-                                     0,  // offset
-                                     expected_modification_time));
+  scoped_ptr<WebkitFileStreamReaderImpl> reader(new WebkitFileStreamReaderImpl(
+      GetFileSystemGetter(), worker_thread_->task_runner().get(), kDriveFile,
+      0,  // offset
+      expected_modification_time));
 
   net::TestInt64CompletionCallback callback;
   int64 result = reader->GetLength(callback.callback());
@@ -214,12 +202,10 @@
   const base::FilePath kDriveFile =
       util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
 
-  scoped_ptr<WebkitFileStreamReaderImpl> reader(
-      new WebkitFileStreamReaderImpl(GetFileSystemGetter(),
-                                     worker_thread_->message_loop_proxy().get(),
-                                     kDriveFile,
-                                     0,  // offset
-                                     base::Time::FromInternalValue(1)));
+  scoped_ptr<WebkitFileStreamReaderImpl> reader(new WebkitFileStreamReaderImpl(
+      GetFileSystemGetter(), worker_thread_->task_runner().get(), kDriveFile,
+      0,  // offset
+      base::Time::FromInternalValue(1)));
 
   net::TestInt64CompletionCallback callback;
   int64 result = reader->GetLength(callback.callback());
diff --git a/chrome/browser/chromeos/drive/job_scheduler.cc b/chrome/browser/chromeos/drive/job_scheduler.cc
index bcf1a021..f5c749a 100644
--- a/chrome/browser/chromeos/drive/job_scheduler.cc
+++ b/chrome/browser/chromeos/drive/job_scheduler.cc
@@ -15,11 +15,8 @@
 #include "base/thread_task_runner_handle.h"
 #include "chrome/browser/drive/event_logger.h"
 #include "chrome/common/pref_names.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/drive_api_parser.h"
 
-using content::BrowserThread;
-
 namespace drive {
 
 namespace {
@@ -163,11 +160,10 @@
     : job_info(type),
       context(ClientContext(USER_INITIATED)),
       retry_count(0) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 JobScheduler::JobEntry::~JobEntry() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 struct JobScheduler::ResumeUploadParams {
@@ -189,8 +185,6 @@
       uploader_(new DriveUploader(drive_service, blocking_task_runner)),
       pref_service_(pref_service),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
   for (int i = 0; i < NUM_QUEUES; ++i)
     queue_[i].reset(new JobQueue(kMaxJobCount[i], NUM_CONTEXT_TYPES,
                                  kMaxBatchCount, kMaxBatchSize));
@@ -199,7 +193,7 @@
 }
 
 JobScheduler::~JobScheduler() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   size_t num_queued_jobs = 0;
   for (int i = 0; i < NUM_QUEUES; ++i)
@@ -217,17 +211,17 @@
 }
 
 void JobScheduler::AddObserver(JobListObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   observer_list_.AddObserver(observer);
 }
 
 void JobScheduler::RemoveObserver(JobListObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   observer_list_.RemoveObserver(observer);
 }
 
 void JobScheduler::CancelJob(JobID job_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   JobEntry* job = job_map_.Lookup(job_id);
   if (job) {
@@ -244,7 +238,7 @@
 }
 
 void JobScheduler::CancelAllJobs() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   // CancelJob may remove the entry from |job_map_|. That's OK. IDMap supports
   // removable during iteration.
@@ -254,7 +248,7 @@
 
 void JobScheduler::GetAboutResource(
     const google_apis::AboutResourceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_ABOUT_RESOURCE);
@@ -270,7 +264,7 @@
 }
 
 void JobScheduler::GetAppList(const google_apis::AppListCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_APP_LIST);
@@ -287,7 +281,7 @@
 
 void JobScheduler::GetAllFileList(
     const google_apis::FileListCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_ALL_RESOURCE_LIST);
@@ -305,7 +299,7 @@
 void JobScheduler::GetFileListInDirectory(
     const std::string& directory_resource_id,
     const google_apis::FileListCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(
@@ -324,7 +318,7 @@
 
 void JobScheduler::Search(const std::string& search_query,
                           const google_apis::FileListCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_SEARCH);
@@ -343,7 +337,7 @@
 void JobScheduler::GetChangeList(
     int64 start_changestamp,
     const google_apis::ChangeListCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_CHANGE_LIST);
@@ -362,7 +356,7 @@
 void JobScheduler::GetRemainingChangeList(
     const GURL& next_link,
     const google_apis::ChangeListCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_REMAINING_CHANGE_LIST);
@@ -381,7 +375,7 @@
 void JobScheduler::GetRemainingFileList(
     const GURL& next_link,
     const google_apis::FileListCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_REMAINING_FILE_LIST);
@@ -401,7 +395,7 @@
     const std::string& resource_id,
     const ClientContext& context,
     const google_apis::FileResourceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_RESOURCE_ENTRY);
@@ -423,7 +417,7 @@
     const GURL& embed_origin,
     const ClientContext& context,
     const google_apis::GetShareUrlCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_GET_SHARE_URL);
@@ -445,7 +439,7 @@
     const std::string& resource_id,
     const ClientContext& context,
     const google_apis::EntryActionCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_TRASH_RESOURCE);
@@ -468,7 +462,7 @@
     const std::string& new_title,
     const base::Time& last_modified,
     const google_apis::FileResourceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_COPY_RESOURCE);
@@ -496,7 +490,7 @@
     const google_apis::drive::Properties& properties,
     const ClientContext& context,
     const google_apis::FileResourceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_UPDATE_RESOURCE);
@@ -516,7 +510,7 @@
     const std::string& parent_resource_id,
     const std::string& resource_id,
     const google_apis::EntryActionCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_ADD_RESOURCE_TO_DIRECTORY);
@@ -538,7 +532,7 @@
     const std::string& resource_id,
     const ClientContext& context,
     const google_apis::EntryActionCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   JobEntry* new_job = CreateNewJob(TYPE_REMOVE_RESOURCE_FROM_DIRECTORY);
   new_job->context = context;
@@ -561,7 +555,7 @@
     const AddNewDirectoryOptions& options,
     const ClientContext& context,
     const google_apis::FileResourceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   JobEntry* new_job = CreateNewJob(TYPE_ADD_NEW_DIRECTORY);
   new_job->context = context;
@@ -587,7 +581,7 @@
     const ClientContext& context,
     const google_apis::DownloadActionCallback& download_action_callback,
     const google_apis::GetContentCallback& get_content_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   // Temporary histogram for crbug.com/229650.
   CollectCopyHistogramSample("Drive.DownloadFromDriveFileSize",
@@ -625,7 +619,7 @@
     const UploadNewFileOptions& options,
     const ClientContext& context,
     const google_apis::FileResourceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   JobEntry* new_job = CreateNewJob(TYPE_UPLOAD_NEW_FILE);
   new_job->job_info.file_path = drive_file_path;
@@ -668,7 +662,7 @@
     const UploadExistingFileOptions& options,
     const ClientContext& context,
     const google_apis::FileResourceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   JobEntry* new_job = CreateNewJob(TYPE_UPLOAD_EXISTING_FILE);
   new_job->job_info.file_path = drive_file_path;
@@ -706,7 +700,7 @@
     const std::string& email,
     google_apis::drive::PermissionRole role,
     const google_apis::EntryActionCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   JobEntry* new_job = CreateNewJob(TYPE_ADD_PERMISSION);
@@ -738,7 +732,7 @@
 }
 
 void JobScheduler::QueueJob(JobID job_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   JobEntry* job_entry = job_map_.Lookup(job_id);
   DCHECK(job_entry);
@@ -774,7 +768,7 @@
 }
 
 void JobScheduler::DoJobLoop(QueueType queue_type) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   const int accepted_priority = GetCurrentAcceptedPriority(queue_type);
 
@@ -832,7 +826,7 @@
 }
 
 int JobScheduler::GetCurrentAcceptedPriority(QueueType queue_type) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   const int kNoJobShouldRun = -1;
 
@@ -857,7 +851,7 @@
 }
 
 void JobScheduler::UpdateWait() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (disable_throttling_ || throttle_count_ == 0)
     return;
@@ -873,7 +867,7 @@
 
 bool JobScheduler::OnJobDone(JobID job_id,
                              google_apis::DriveApiErrorCode error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   JobEntry* job_entry = job_map_.Lookup(job_id);
   DCHECK(job_entry);
@@ -935,7 +929,7 @@
     const google_apis::FileListCallback& callback,
     google_apis::DriveApiErrorCode error,
     scoped_ptr<google_apis::FileList> file_list) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (OnJobDone(job_id, error))
@@ -947,7 +941,7 @@
     const google_apis::ChangeListCallback& callback,
     google_apis::DriveApiErrorCode error,
     scoped_ptr<google_apis::ChangeList> change_list) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (OnJobDone(job_id, error))
@@ -959,7 +953,7 @@
     const google_apis::FileResourceCallback& callback,
     google_apis::DriveApiErrorCode error,
     scoped_ptr<google_apis::FileResource> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (OnJobDone(job_id, error))
@@ -971,7 +965,7 @@
     const google_apis::AboutResourceCallback& callback,
     google_apis::DriveApiErrorCode error,
     scoped_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (OnJobDone(job_id, error))
@@ -983,7 +977,7 @@
     const google_apis::GetShareUrlCallback& callback,
     google_apis::DriveApiErrorCode error,
     const GURL& share_url) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (OnJobDone(job_id, error))
@@ -995,7 +989,7 @@
     const google_apis::AppListCallback& callback,
     google_apis::DriveApiErrorCode error,
     scoped_ptr<google_apis::AppList> app_list) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (OnJobDone(job_id, error))
@@ -1006,7 +1000,7 @@
     JobID job_id,
     const google_apis::EntryActionCallback& callback,
     google_apis::DriveApiErrorCode error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (OnJobDone(job_id, error))
@@ -1018,7 +1012,7 @@
     const google_apis::DownloadActionCallback& callback,
     google_apis::DriveApiErrorCode error,
     const base::FilePath& temp_file) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (OnJobDone(job_id, error))
@@ -1032,7 +1026,7 @@
     google_apis::DriveApiErrorCode error,
     const GURL& upload_location,
     scoped_ptr<google_apis::FileResource> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (!upload_location.is_empty()) {
@@ -1069,7 +1063,7 @@
     google_apis::DriveApiErrorCode error,
     const GURL& upload_location,
     scoped_ptr<google_apis::FileResource> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!original_task.is_null());
   DCHECK(!callback.is_null());
 
@@ -1097,7 +1091,7 @@
 
 void JobScheduler::OnConnectionTypeChanged(
     net::NetworkChangeNotifier::ConnectionType type) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   // Resume the job loop.
   // Note that we don't need to check the network connection status as it will
@@ -1138,7 +1132,7 @@
 
 void JobScheduler::AbortNotRunningJob(JobEntry* job,
                                       google_apis::DriveApiErrorCode error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   const base::TimeDelta elapsed = base::Time::Now() - job->job_info.start_time;
   const QueueType queue_type = GetJobQueueType(job->job_info.job_type);
@@ -1159,19 +1153,19 @@
 }
 
 void JobScheduler::NotifyJobAdded(const JobInfo& job_info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   FOR_EACH_OBSERVER(JobListObserver, observer_list_, OnJobAdded(job_info));
 }
 
 void JobScheduler::NotifyJobDone(const JobInfo& job_info,
                                  google_apis::DriveApiErrorCode error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   FOR_EACH_OBSERVER(JobListObserver, observer_list_,
                     OnJobDone(job_info, GDataToFileError(error)));
 }
 
 void JobScheduler::NotifyJobUpdated(const JobInfo& job_info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   FOR_EACH_OBSERVER(JobListObserver, observer_list_, OnJobUpdated(job_info));
 }
 
diff --git a/chrome/browser/chromeos/drive/job_scheduler.h b/chrome/browser/chromeos/drive/job_scheduler.h
index 1d0eae3..39909ca 100644
--- a/chrome/browser/chromeos/drive/job_scheduler.h
+++ b/chrome/browser/chromeos/drive/job_scheduler.h
@@ -11,6 +11,7 @@
 #include "base/id_map.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/job_list.h"
 #include "chrome/browser/chromeos/drive/job_queue.h"
 #include "chrome/browser/drive/drive_service_interface.h"
@@ -239,6 +240,8 @@
     // The callback to notify an error to the client of JobScheduler.
     // This is used to notify cancel of a job that is not running yet.
     base::Callback<void(google_apis::DriveApiErrorCode)> abort_callback;
+
+    base::ThreadChecker thread_checker_;
   };
 
   // Parameters for DriveUploader::ResumeUploadFile.
@@ -395,6 +398,8 @@
 
   PrefService* pref_service_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<JobScheduler> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/local_file_reader_unittest.cc b/chrome/browser/chromeos/drive/local_file_reader_unittest.cc
index b826f68..3636d55 100644
--- a/chrome/browser/chromeos/drive/local_file_reader_unittest.cc
+++ b/chrome/browser/chromeos/drive/local_file_reader_unittest.cc
@@ -49,7 +49,7 @@
     worker_thread_.reset(new base::Thread("LocalFileReaderTest"));
     ASSERT_TRUE(worker_thread_->Start());
     file_reader_.reset(
-        new LocalFileReader(worker_thread_->message_loop_proxy().get()));
+        new LocalFileReader(worker_thread_->task_runner().get()));
   }
 
   base::MessageLoop message_loop_;
diff --git a/chrome/browser/chromeos/drive/resource_metadata.cc b/chrome/browser/chromeos/drive/resource_metadata.cc
index 990b9a5..d63b0c41 100644
--- a/chrome/browser/chromeos/drive/resource_metadata.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 
+#include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/guid.h"
+#include "base/location.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
@@ -13,9 +16,6 @@
 #include "chrome/browser/chromeos/drive/file_cache.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace drive {
 namespace internal {
@@ -32,7 +32,7 @@
 // Returns a file name with a uniquifier appended. (e.g. "File (1).txt")
 std::string GetUniquifiedName(const std::string& name, int uniquifier) {
   base::FilePath name_path = base::FilePath::FromUTF8Unsafe(name);
-  name_path = name_path.InsertBeforeExtension(
+  name_path = name_path.InsertBeforeExtensionASCII(
       base::StringPrintf(" (%d)", uniquifier));
   return name_path.AsUTF8Unsafe();
 }
@@ -72,7 +72,6 @@
     : blocking_task_runner_(blocking_task_runner),
       storage_(storage),
       cache_(cache) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 FileError ResourceMetadata::Initialize() {
@@ -81,7 +80,7 @@
 }
 
 void ResourceMetadata::Destroy() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   blocking_task_runner_->PostTask(
       FROM_HERE,
@@ -474,7 +473,8 @@
   // Start from the root.
   std::vector<base::FilePath::StringType> components;
   file_path.GetComponents(&components);
-  if (components.empty() || components[0] != util::kDriveGrandRootDirName)
+  if (components.empty() ||
+      components[0] != util::GetDriveGrandRootPath().value())
     return FILE_ERROR_NOT_FOUND;
 
   // Iterate over the remaining components.
diff --git a/chrome/browser/chromeos/drive/resource_metadata.h b/chrome/browser/chromeos/drive/resource_metadata.h
index fdafc87..ffdcb1a 100644
--- a/chrome/browser/chromeos/drive/resource_metadata.h
+++ b/chrome/browser/chromeos/drive/resource_metadata.h
@@ -11,6 +11,7 @@
 
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 
@@ -134,6 +135,8 @@
   ResourceMetadataStorage* storage_;
   FileCache* cache_;
 
+  base::ThreadChecker thread_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(ResourceMetadata);
 };
 
diff --git a/chrome/browser/chromeos/drive/search_metadata.cc b/chrome/browser/chromeos/drive/search_metadata.cc
index 7c4c604..efbe464 100644
--- a/chrome/browser/chromeos/drive/search_metadata.cc
+++ b/chrome/browser/chromeos/drive/search_metadata.cc
@@ -14,11 +14,8 @@
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/drive/drive_api_util.h"
-#include "content/public/browser/browser_thread.h"
 #include "net/base/escape.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace internal {
 
@@ -265,7 +262,6 @@
     const SearchMetadataPredicate& predicate,
     size_t at_most_num_matches,
     const SearchMetadataCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!callback.is_null());
 
   const base::TimeTicks start_time = base::TimeTicks::Now();
diff --git a/chrome/browser/chromeos/drive/sync/entry_revert_performer.cc b/chrome/browser/chromeos/drive/sync/entry_revert_performer.cc
index 221fd0b..53a22c5bf 100644
--- a/chrome/browser/chromeos/drive/sync/entry_revert_performer.cc
+++ b/chrome/browser/chromeos/drive/sync/entry_revert_performer.cc
@@ -12,11 +12,8 @@
 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 #include "chrome/browser/drive/drive_api_util.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/drive_api_parser.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace internal {
 namespace {
@@ -93,17 +90,16 @@
       scheduler_(scheduler),
       metadata_(metadata),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 EntryRevertPerformer::~EntryRevertPerformer() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void EntryRevertPerformer::RevertEntry(const std::string& local_id,
                                        const ClientContext& context,
                                        const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   scoped_ptr<ResourceEntry> entry(new ResourceEntry);
@@ -123,7 +119,7 @@
     const FileOperationCallback& callback,
     scoped_ptr<ResourceEntry> entry,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error == FILE_ERROR_OK && entry->resource_id().empty())
@@ -146,7 +142,7 @@
     const std::string& local_id,
     google_apis::DriveApiErrorCode status,
     scoped_ptr<google_apis::FileResource> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   FileChange* changed_files = new FileChange;
@@ -169,7 +165,7 @@
     const FileOperationCallback& callback,
     const FileChange* changed_files,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   delegate_->OnFileChangedByOperation(*changed_files);
diff --git a/chrome/browser/chromeos/drive/sync/entry_revert_performer.h b/chrome/browser/chromeos/drive/sync/entry_revert_performer.h
index e022b26..5a3dac8 100644
--- a/chrome/browser/chromeos/drive/sync/entry_revert_performer.h
+++ b/chrome/browser/chromeos/drive/sync/entry_revert_performer.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 
@@ -78,6 +79,8 @@
   JobScheduler* scheduler_;
   ResourceMetadata* metadata_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<EntryRevertPerformer> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/sync/entry_update_performer.cc b/chrome/browser/chromeos/drive/sync/entry_update_performer.cc
index 4560ec5..f265603b 100644
--- a/chrome/browser/chromeos/drive/sync/entry_update_performer.cc
+++ b/chrome/browser/chromeos/drive/sync/entry_update_performer.cc
@@ -18,11 +18,8 @@
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 #include "chrome/browser/chromeos/drive/sync/entry_revert_performer.h"
 #include "chrome/browser/chromeos/drive/sync/remove_performer.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/drive_api_parser.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace internal {
 
@@ -243,17 +240,16 @@
                                                        scheduler,
                                                        metadata)),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 EntryUpdatePerformer::~EntryUpdatePerformer() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void EntryUpdatePerformer::UpdateEntry(const std::string& local_id,
                                        const ClientContext& context,
                                        const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   scoped_ptr<LocalState> local_state(new LocalState);
@@ -272,7 +268,7 @@
     const FileOperationCallback& callback,
     scoped_ptr<LocalState> local_state,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
@@ -411,7 +407,7 @@
     scoped_ptr<base::ScopedClosureRunner> loader_lock,
     google_apis::DriveApiErrorCode status,
     scoped_ptr<google_apis::FileResource> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (status == google_apis::HTTP_FORBIDDEN) {
@@ -441,7 +437,7 @@
     const FileOperationCallback& callback,
     const FileChange* changed_files,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   delegate_->OnFileChangedByOperation(*changed_files);
diff --git a/chrome/browser/chromeos/drive/sync/entry_update_performer.h b/chrome/browser/chromeos/drive/sync/entry_update_performer.h
index 7f620e6..8c8deb6d 100644
--- a/chrome/browser/chromeos/drive/sync/entry_update_performer.h
+++ b/chrome/browser/chromeos/drive/sync/entry_update_performer.h
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 
@@ -91,6 +92,8 @@
   scoped_ptr<RemovePerformer> remove_performer_;
   scoped_ptr<EntryRevertPerformer> entry_revert_performer_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<EntryUpdatePerformer> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/sync/remove_performer.cc b/chrome/browser/chromeos/drive/sync/remove_performer.cc
index db1a34a5..b320100 100644
--- a/chrome/browser/chromeos/drive/sync/remove_performer.cc
+++ b/chrome/browser/chromeos/drive/sync/remove_performer.cc
@@ -13,11 +13,8 @@
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 #include "chrome/browser/chromeos/drive/sync/entry_revert_performer.h"
 #include "chrome/browser/drive/drive_api_util.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/drive_api_parser.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace internal {
 
@@ -63,11 +60,10 @@
                                                        scheduler,
                                                        metadata)),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 RemovePerformer::~RemovePerformer() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 // Returns |entry| corresponding to |local_id|.
@@ -84,7 +80,7 @@
 void RemovePerformer::Remove(const std::string& local_id,
                              const ClientContext& context,
                              const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   ResourceEntry* entry = new ResourceEntry;
@@ -104,7 +100,7 @@
     const FileOperationCallback& callback,
     const ResourceEntry* entry,
     FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK || entry->resource_id().empty()) {
@@ -132,7 +128,7 @@
                                     const FileOperationCallback& callback,
                                     const std::string& resource_id,
                                     const std::string& local_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   scheduler_->TrashResource(
@@ -147,7 +143,7 @@
     const FileOperationCallback& callback,
     const std::string& local_id,
     google_apis::DriveApiErrorCode status) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   if (status == google_apis::HTTP_FORBIDDEN) {
@@ -174,7 +170,7 @@
                                        const FileOperationCallback& callback,
                                        const std::string& resource_id,
                                        const std::string& local_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   scheduler_->GetFileResource(
@@ -190,7 +186,7 @@
     const std::string& local_id,
     google_apis::DriveApiErrorCode status,
     scoped_ptr<google_apis::FileResource> file_resource) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   FileError error = GDataToFileError(status);
@@ -239,7 +235,7 @@
     const FileOperationCallback& callback,
     const std::string& local_id,
     google_apis::DriveApiErrorCode status) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!callback.is_null());
 
   FileError error = GDataToFileError(status);
diff --git a/chrome/browser/chromeos/drive/sync/remove_performer.h b/chrome/browser/chromeos/drive/sync/remove_performer.h
index 2d0a3bd..d7213dc 100644
--- a/chrome/browser/chromeos/drive/sync/remove_performer.h
+++ b/chrome/browser/chromeos/drive/sync/remove_performer.h
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 
@@ -99,6 +100,8 @@
   ResourceMetadata* metadata_;
   scoped_ptr<EntryRevertPerformer> entry_revert_performer_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
   base::WeakPtrFactory<RemovePerformer> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/drive/sync_client.cc b/chrome/browser/chromeos/drive/sync_client.cc
index 43e4b864..c920606 100644
--- a/chrome/browser/chromeos/drive/sync_client.cc
+++ b/chrome/browser/chromeos/drive/sync_client.cc
@@ -15,11 +15,8 @@
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/sync/entry_update_performer.h"
-#include "content/public/browser/browser_thread.h"
 #include "google_apis/drive/task_util.h"
 
-using content::BrowserThread;
-
 namespace drive {
 namespace internal {
 
@@ -165,15 +162,14 @@
       delay_(base::TimeDelta::FromSeconds(kDelaySeconds)),
       long_delay_(base::TimeDelta::FromSeconds(kLongDelaySeconds)),
       weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 SyncClient::~SyncClient() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 }
 
 void SyncClient::StartProcessingBacklog() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   std::vector<std::string>* to_fetch = new std::vector<std::string>;
   std::vector<std::string>* to_update = new std::vector<std::string>;
@@ -187,7 +183,7 @@
 }
 
 void SyncClient::StartCheckingExistingPinnedFiles() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   std::vector<std::string>* local_ids = new std::vector<std::string>;
   blocking_task_runner_->PostTaskAndReply(
@@ -202,12 +198,12 @@
 }
 
 void SyncClient::AddFetchTask(const std::string& local_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   AddFetchTaskInternal(local_id, delay_);
 }
 
 void SyncClient::RemoveFetchTask(const std::string& local_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   SyncTasks::iterator it = tasks_.find(SyncTasks::key_type(FETCH, local_id));
   if (it == tasks_.end())
@@ -228,14 +224,14 @@
 
 void SyncClient::AddUpdateTask(const ClientContext& context,
                                const std::string& local_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   AddUpdateTaskInternal(context, local_id, delay_);
 }
 
 bool SyncClient:: WaitForUpdateTaskToComplete(
     const std::string& local_id,
     const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   SyncTasks::iterator it = tasks_.find(SyncTasks::key_type(UPDATE, local_id));
   if (it == tasks_.end())
@@ -248,7 +244,7 @@
 
 base::Closure SyncClient::PerformFetchTask(const std::string& local_id,
                                            const ClientContext& context) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   return download_operation_->EnsureFileDownloadedByLocalId(
       local_id,
       context,
@@ -261,7 +257,7 @@
 
 void SyncClient::AddFetchTaskInternal(const std::string& local_id,
                                       const base::TimeDelta& delay) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   SyncTask task;
   task.state = PENDING;
@@ -274,7 +270,7 @@
 
 base::Closure SyncClient::PerformUpdateTask(const std::string& local_id,
                                             const ClientContext& context) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   entry_update_performer_->UpdateEntry(
       local_id,
       context,
@@ -288,7 +284,7 @@
 void SyncClient::AddUpdateTaskInternal(const ClientContext& context,
                                        const std::string& local_id,
                                        const base::TimeDelta& delay) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   SyncTask task;
   task.state = PENDING;
@@ -302,7 +298,7 @@
 void SyncClient::AddTask(const SyncTasks::key_type& key,
                          const SyncTask& task,
                          const base::TimeDelta& delay) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   SyncTasks::iterator it = tasks_.find(key);
   if (it != tasks_.end()) {
@@ -391,7 +387,7 @@
 void SyncClient::OnGetLocalIdsOfBacklog(
     const std::vector<std::string>* to_fetch,
     const std::vector<std::string>* to_update) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   // Give priority to upload tasks over fetch tasks, so that dirty files are
   // uploaded as soon as possible.
@@ -409,7 +405,7 @@
 }
 
 void SyncClient::AddFetchTasks(const std::vector<std::string>* local_ids) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   for (size_t i = 0; i < local_ids->size(); ++i)
     AddFetchTask((*local_ids)[i]);
@@ -418,7 +414,7 @@
 void SyncClient::OnTaskComplete(SyncType type,
                                 const std::string& local_id,
                                 FileError error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   const SyncTasks::key_type key(type, local_id);
   SyncTasks::iterator it = tasks_.find(key);
@@ -478,7 +474,7 @@
                                      FileError error,
                                      const base::FilePath& local_path,
                                      scoped_ptr<ResourceEntry> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(thread_checker_.CalledOnValidThread());
   OnTaskComplete(FETCH, local_id, error);
   if (error == FILE_ERROR_ABORT) {
     // If user cancels download, unpin the file so that we do not sync the file
diff --git a/chrome/browser/chromeos/drive/sync_client.h b/chrome/browser/chromeos/drive/sync_client.h
index bc85efe..d3c0593 100644
--- a/chrome/browser/chromeos/drive/sync_client.h
+++ b/chrome/browser/chromeos/drive/sync_client.h
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
@@ -183,6 +184,8 @@
   // The delay is used for delaying retry of tasks on server errors.
   base::TimeDelta long_delay_;
 
+  base::ThreadChecker thread_checker_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<SyncClient> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/events/event_rewriter.cc b/chrome/browser/chromeos/events/event_rewriter.cc
index 4d75023..2d0ce2d 100644
--- a/chrome/browser/chromeos/events/event_rewriter.cc
+++ b/chrome/browser/chromeos/events/event_rewriter.cc
@@ -145,7 +145,7 @@
     return EventRewriter::kDeviceHotrodRemote;
   }
 
-  if (LowerCaseEqualsASCII(device_name, "virtual core keyboard"))
+  if (base::LowerCaseEqualsASCII(device_name, "virtual core keyboard"))
     return EventRewriter::kDeviceVirtualCoreKeyboard;
 
   std::vector<std::string> tokens;
@@ -157,9 +157,9 @@
   bool found_apple = false;
   bool found_keyboard = false;
   for (size_t i = 0; i < tokens.size(); ++i) {
-    if (!found_apple && LowerCaseEqualsASCII(tokens[i], "apple"))
+    if (!found_apple && base::LowerCaseEqualsASCII(tokens[i], "apple"))
       found_apple = true;
-    if (!found_keyboard && LowerCaseEqualsASCII(tokens[i], "keyboard"))
+    if (!found_keyboard && base::LowerCaseEqualsASCII(tokens[i], "keyboard"))
       found_keyboard = true;
     if (found_apple && found_keyboard)
       return EventRewriter::kDeviceAppleKeyboard;
diff --git a/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc b/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc
index a59c512..814408ba 100644
--- a/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc
@@ -19,7 +19,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/common/extension.h"
-#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window_tree_host.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_switches.h"
@@ -86,8 +86,7 @@
 
 void VirtualKeyboardBrowserTest::ShowVirtualKeyboard() {
   aura::Window* window = ash::Shell::GetPrimaryRootWindow();
-  ui::InputMethod* input_method =
-      window->GetProperty(aura::client::kRootWindowInputMethodKey);
+  ui::InputMethod* input_method = window->GetHost()->GetInputMethod();
   ASSERT_TRUE(input_method);
   input_method->ShowImeIfNeeded();
 }
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index d4cb77eb..b70c7b7 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -228,7 +228,7 @@
   // identified by a prefix "drive-app:" on the extension ID. The legacy task
   // IDs can be stored in preferences.
   if (count == 2) {
-    if (StartsWithASCII(result[0], kDriveTaskExtensionPrefix, true)) {
+    if (base::StartsWithASCII(result[0], kDriveTaskExtensionPrefix, true)) {
       task->task_type = TASK_TYPE_DRIVE_APP;
       task->app_id = result[0].substr(kDriveTaskExtensionPrefixLength);
     } else {
diff --git a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
index 7081d60..e8b55ee 100644
--- a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
+++ b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h"
 
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/io_buffer.h"
 
 namespace chromeos {
@@ -208,11 +208,10 @@
     buffer->data()[current_offset - offset] = entry->contents[current_offset];
     const bool has_more =
         (current_offset + 1 < entry->metadata->size) && (current_length - 1);
-    const int task_id = tracker_.PostTask(
-        base::MessageLoopProxy::current().get(),
-        FROM_HERE,
-        base::Bind(
-            callback, 1 /* chunk_length */, has_more, base::File::FILE_OK));
+    const int task_id =
+        tracker_.PostTask(base::ThreadTaskRunnerHandle::Get().get(), FROM_HERE,
+                          base::Bind(callback, 1 /* chunk_length */, has_more,
+                                     base::File::FILE_OK));
     task_ids.push_back(task_id);
     current_offset++;
     current_length--;
@@ -392,7 +391,7 @@
 AbortCallback FakeProvidedFileSystem::PostAbortableTask(
     const base::Closure& callback) {
   const int task_id = tracker_.PostTask(
-      base::MessageLoopProxy::current().get(), FROM_HERE, callback);
+      base::ThreadTaskRunnerHandle::Get().get(), FROM_HERE, callback);
   return base::Bind(
       &FakeProvidedFileSystem::Abort, weak_ptr_factory_.GetWeakPtr(), task_id);
 }
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader_unittest.cc b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader_unittest.cc
index 2b25c32..2213239 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader_unittest.cc
@@ -71,13 +71,6 @@
       base::FilePath::FromUTF8Unsafe(mount_point_name).Append(file_path));
 }
 
-// Creates a Service instance. Used to be able to destroy the service in
-// TearDown().
-KeyedService* CreateService(content::BrowserContext* context) {
-  return new Service(Profile::FromBrowserContext(context),
-                     extensions::ExtensionRegistry::Get(context));
-}
-
 }  // namespace
 
 class FileSystemProviderFileStreamReader : public testing::Test {
@@ -92,7 +85,6 @@
     ASSERT_TRUE(profile_manager_->SetUp());
     profile_ = profile_manager_->CreateTestingProfile("testing-profile");
 
-    ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService);
     Service* service = Service::Get(profile_);  // Owned by its factory.
     service->SetFileSystemFactoryForTesting(
         base::Bind(&FakeProvidedFileSystem::Create));
@@ -120,12 +112,6 @@
     ASSERT_TRUE(wrong_file_url_.is_valid());
   }
 
-  void TearDown() override {
-    // Setting the testing factory to NULL will destroy the created service
-    // associated with the testing profile.
-    ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL);
-  }
-
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir data_dir_;
   scoped_ptr<TestingProfileManager> profile_manager_;
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer_unittest.cc b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer_unittest.cc
index 187e8c5b..10df3e7 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/file_stream_writer_unittest.cc
@@ -54,13 +54,6 @@
       base::FilePath::FromUTF8Unsafe(mount_point_name).Append(file_path));
 }
 
-// Creates a Service instance. Used to be able to destroy the service in
-// TearDown().
-KeyedService* CreateService(content::BrowserContext* context) {
-  return new Service(Profile::FromBrowserContext(context),
-                     extensions::ExtensionRegistry::Get(context));
-}
-
 }  // namespace
 
 class FileSystemProviderFileStreamWriter : public testing::Test {
@@ -75,7 +68,6 @@
     ASSERT_TRUE(profile_manager_->SetUp());
     profile_ = profile_manager_->CreateTestingProfile("testing-profile");
 
-    ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService);
     Service* service = Service::Get(profile_);  // Owned by its factory.
     service->SetFileSystemFactoryForTesting(
         base::Bind(&FakeProvidedFileSystem::Create));
@@ -99,12 +91,6 @@
     ASSERT_TRUE(wrong_file_url_.is_valid());
   }
 
-  void TearDown() override {
-    // Setting the testing factory to NULL will destroy the created service
-    // associated with the testing profile.
-    ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL);
-  }
-
   content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir data_dir_;
   scoped_ptr<TestingProfileManager> profile_manager_;
diff --git a/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util_unittest.cc b/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util_unittest.cc
index f3789cf..ea4180a0 100644
--- a/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util_unittest.cc
@@ -100,13 +100,6 @@
       base::FilePath::FromUTF8Unsafe(mount_point_name).Append(file_path));
 }
 
-// Creates a Service instance. Used to be able to destroy the service in
-// TearDown().
-KeyedService* CreateService(content::BrowserContext* context) {
-  return new Service(Profile::FromBrowserContext(context),
-                     extensions::ExtensionRegistry::Get(context));
-}
-
 }  // namespace
 
 // Tests in this file are very lightweight and just test integration between
@@ -130,7 +123,6 @@
     file_system_context_ =
         content::CreateFileSystemContextForTesting(NULL, data_dir_.path());
 
-    ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService);
     Service* service = Service::Get(profile_);  // Owned by its factory.
     service->SetFileSystemFactoryForTesting(
         base::Bind(&FakeProvidedFileSystem::Create));
@@ -155,12 +147,6 @@
     ASSERT_TRUE(root_url_.is_valid());
   }
 
-  void TearDown() override {
-    // Setting the testing factory to NULL will destroy the created service
-    // associated with the testing profile.
-    ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL);
-  }
-
   scoped_ptr<storage::FileSystemOperationContext> CreateOperationContext() {
     return make_scoped_ptr(
         new storage::FileSystemOperationContext(file_system_context_.get()));
diff --git a/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc b/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
index 7c5ee2d8..570f0b96 100644
--- a/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
@@ -56,13 +56,6 @@
       base::FilePath(mount_path.BaseName().Append(relative_path)));
 }
 
-// Creates a Service instance. Used to be able to destroy the service in
-// TearDown().
-KeyedService* CreateService(content::BrowserContext* context) {
-  return new Service(Profile::FromBrowserContext(context),
-                     extensions::ExtensionRegistry::Get(context));
-}
-
 }  // namespace
 
 class FileSystemProviderMountPathUtilTest : public testing::Test {
@@ -78,18 +71,11 @@
     user_manager_ = new FakeChromeUserManager();
     user_manager_enabler_.reset(new ScopedUserManagerEnabler(user_manager_));
     user_manager_->AddUser(profile_->GetProfileUserName());
-    ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService);
     file_system_provider_service_ = Service::Get(profile_);
     file_system_provider_service_->SetFileSystemFactoryForTesting(
         base::Bind(&FakeProvidedFileSystem::Create));
   }
 
-  void TearDown() override {
-    // Setting the testing factory to NULL will destroy the created service
-    // associated with the testing profile.
-    ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL);
-  }
-
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfileManager> profile_manager_;
   TestingProfile* profile_;  // Owned by TestingProfileManager.
diff --git a/chrome/browser/chromeos/file_system_provider/service_factory.cc b/chrome/browser/chromeos/file_system_provider/service_factory.cc
index 7322376b..b54a11e 100644
--- a/chrome/browser/chromeos/file_system_provider/service_factory.cc
+++ b/chrome/browser/chromeos/file_system_provider/service_factory.cc
@@ -42,9 +42,8 @@
 
 KeyedService* ServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* profile) const {
-  return new Service(
-      Profile::FromBrowserContext(profile),
-      extensions::ExtensionRegistry::Get(Profile::FromBrowserContext(profile)));
+  return new Service(Profile::FromBrowserContext(profile),
+                     extensions::ExtensionRegistry::Get(profile));
 }
 
 bool ServiceFactory::ServiceIsCreatedWithBrowserContext() const { return true; }
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc b/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc
index 80e446d..8795336 100644
--- a/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc
+++ b/chrome/browser/chromeos/fileapi/external_file_url_request_job_unittest.cc
@@ -163,7 +163,7 @@
         new drive::DriveFileStreamReader(
             base::Bind(&ExternalFileURLRequestJobTest::GetFileSystem,
                        base::Unretained(this)),
-            worker_thread->message_loop_proxy().get()));
+            worker_thread->task_runner().get()));
     int error = net::ERR_FAILED;
     scoped_ptr<drive::ResourceEntry> entry;
     {
diff --git a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
index e20daf5..d423c32 100644
--- a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
@@ -166,7 +166,7 @@
 // static
 bool ComponentExtensionIMEManagerImpl::IsIMEExtensionID(const std::string& id) {
   for (size_t i = 0; i < arraysize(whitelisted_component_extension); ++i) {
-    if (LowerCaseEqualsASCII(id, whitelisted_component_extension[i].id))
+    if (base::LowerCaseEqualsASCII(id, whitelisted_component_extension[i].id))
       return true;
   }
   return false;
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.cc b/chrome/browser/chromeos/input_method/input_method_engine.cc
index 0c53579..c25ff772 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine.cc
@@ -26,6 +26,7 @@
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/ime_keymap.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/input_method.h"
 #include "ui/base/ime/text_input_flags.h"
 #include "ui/chromeos/ime/input_method_menu_item.h"
 #include "ui/chromeos/ime/input_method_menu_manager.h"
@@ -71,13 +72,13 @@
 
 std::string GetKeyFromEvent(const ui::KeyEvent& event) {
   const std::string code = event.GetCodeString();
-  if (StartsWithASCII(code, "Control", true))
+  if (base::StartsWithASCII(code, "Control", true))
     return "Ctrl";
-  if (StartsWithASCII(code, "Shift", true))
+  if (base::StartsWithASCII(code, "Shift", true))
     return "Shift";
-  if (StartsWithASCII(code, "Alt", true))
+  if (base::StartsWithASCII(code, "Alt", true))
     return "Alt";
-  if (StartsWithASCII(code, "Arrow", true))
+  if (base::StartsWithASCII(code, "Arrow", true))
     return code.substr(5);
   if (code == "Escape")
     return "Esc";
@@ -291,8 +292,8 @@
     return false;
   }
 
-  ui::EventProcessor* dispatcher =
-      ash::Shell::GetPrimaryRootWindow()->GetHost()->event_processor();
+  ui::InputMethod* input_method =
+      ash::Shell::GetTargetRootWindow()->GetHost()->GetInputMethod();
 
   for (size_t i = 0; i < events.size(); ++i) {
     const KeyboardEvent& event = events[i];
@@ -323,9 +324,7 @@
         ui::EventTimeForNow());
     base::AutoReset<const ui::KeyEvent*> reset_sent_key(&sent_key_event_,
                                                         &ui_event);
-    ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&ui_event);
-    if (details.dispatcher_destroyed)
-      break;
+    input_method->DispatchKeyEvent(ui_event);
   }
 
   return true;
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index 7baeec4..d658efc 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -70,22 +70,22 @@
       extension_ime_util::GetComponentIDByInputMethodID(input_method_id);
   InputMethodCategory category = INPUT_METHOD_CATEGORY_UNKNOWN;
   char ch = 0;
-  if (StartsWithASCII(component_id, "xkb:", true)) {
+  if (base::StartsWithASCII(component_id, "xkb:", true)) {
     ch = component_id[4];
     category = INPUT_METHOD_CATEGORY_XKB;
-  } else if (StartsWithASCII(component_id, "zh-", true)) {
+  } else if (base::StartsWithASCII(component_id, "zh-", true)) {
     size_t pos = component_id.find("-t-i0-");
     if (pos > 0)
       pos += 6;
     ch = component_id[pos];
     category = INPUT_METHOD_CATEGORY_ZH;
-  } else if (StartsWithASCII(component_id, "nacl_mozc_", true)) {
+  } else if (base::StartsWithASCII(component_id, "nacl_mozc_", true)) {
     ch = component_id[10];
     category = INPUT_METHOD_CATEGORY_JA;
-  } else if (StartsWithASCII(component_id, "hangul_", true)) {
+  } else if (base::StartsWithASCII(component_id, "hangul_", true)) {
     ch = component_id[7];
     category = INPUT_METHOD_CATEGORY_KO;
-  } else if (StartsWithASCII(component_id, "vkd_", true)) {
+  } else if (base::StartsWithASCII(component_id, "vkd_", true)) {
     ch = component_id[4];
     category = INPUT_METHOD_CATEGORY_M17N;
   } else if (component_id.find("-t-i0-") > 0) {
diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/chrome/browser/chromeos/input_method/input_method_util.cc
index 89eec80..ca66fa5 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util.cc
@@ -378,7 +378,7 @@
   if (disp.find("__MSG_") == 0) {
     const InputMethodNameMap* map = kInputMethodNameMap;
     size_t map_size = arraysize(kInputMethodNameMap);
-    std::string name = StringToUpperASCII(disp);
+    std::string name = base::StringToUpperASCII(disp);
     const InputMethodNameMap map_key = {name.c_str(), 0};
     const InputMethodNameMap* p =
         std::lower_bound(map, map + map_size, map_key);
@@ -429,8 +429,8 @@
 
 // static
 bool InputMethodUtil::IsKeyboardLayout(const std::string& input_method_id) {
-  return StartsWithASCII(input_method_id, "xkb:", false) ||
-      extension_ime_util::IsKeyboardLayoutExtension(input_method_id);
+  return base::StartsWithASCII(input_method_id, "xkb:", false) ||
+         extension_ime_util::IsKeyboardLayoutExtension(input_method_id);
 }
 
 std::string InputMethodUtil::GetKeyboardLayoutName(
diff --git a/chrome/browser/chromeos/input_method/textinput_test_helper.cc b/chrome/browser/chromeos/input_method/textinput_test_helper.cc
index b4c601a4..07bedca6 100644
--- a/chrome/browser/chromeos/input_method/textinput_test_helper.cc
+++ b/chrome/browser/chromeos/input_method/textinput_test_helper.cc
@@ -12,16 +12,15 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
 #include "ui/base/ime/input_method_factory.h"
 
 namespace chromeos {
 namespace {
 ui::MockInputMethod* GetInputMethod() {
   ui::MockInputMethod* input_method = static_cast<ui::MockInputMethod*>(
-      ash::Shell::GetPrimaryRootWindow()->GetProperty(
-          aura::client::kRootWindowInputMethodKey));
+      ash::Shell::GetPrimaryRootWindow()->GetHost()->GetInputMethod());
   CHECK(input_method);
   return input_method;
 }
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index f0d78fb5..6bd4c112 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -82,7 +82,6 @@
     ::switches::kDisableGpuWatchdog,
     ::switches::kDisableGpuCompositing,
     ::switches::kDisableGpuRasterization,
-    ::switches::kDisableImplSidePainting,
     ::switches::kDisableLowResTiling,
     ::switches::kDisableMediaSource,
     ::switches::kDisableOneCopy,
@@ -109,7 +108,6 @@
     ::switches::kEnableImageColorProfiles,
     ::switches::kEnableLogging,
     ::switches::kEnableLowResTiling,
-    ::switches::kEnableOneCopy,
     ::switches::kEnablePinch,
     ::switches::kEnablePreferCompositingToLCDText,
     ::switches::kEnablePluginPlaceholderShadowDom,
diff --git a/chrome/browser/chromeos/login/screenshot_testing/screenshot_testing_mixin.cc b/chrome/browser/chromeos/login/screenshot_testing/screenshot_testing_mixin.cc
index de641da..afb3c6e 100644
--- a/chrome/browser/chromeos/login/screenshot_testing/screenshot_testing_mixin.cc
+++ b/chrome/browser/chromeos/login/screenshot_testing/screenshot_testing_mixin.cc
@@ -27,7 +27,8 @@
 void ScreenshotTestingMixin::SetUpCommandLine(base::CommandLine* command_line) {
   if (enable_test_screenshots_) {
     command_line->AppendSwitch(switches::kEnablePixelOutputInTests);
-    command_line->AppendSwitch(switches::kUIEnableImplSidePainting);
+  } else {
+    command_line->AppendSwitch(switches::kUIDisableImplSidePainting);
   }
 }
 
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc
index b03a8a33..65b2c75 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "chrome/common/chrome_version_info.h"
 #include "chrome/common/render_messages.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager_client.h"
@@ -131,9 +132,6 @@
   accel_map_[ui::Accelerator(ui::VKEY_X,
       ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] =
       kAccelNameEnableDebugging;
-  accel_map_[ui::Accelerator(ui::VKEY_W,
-      ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] =
-      kAccelNameToggleWebviewSignin;
   accel_map_[ui::Accelerator(
       ui::VKEY_L, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] =
       kAccelNameToggleNewLoginUI;
@@ -146,6 +144,16 @@
   accel_map_[ui::Accelerator(ui::VKEY_RIGHT, ui::EF_NONE)] =
       kAccelFocusNext;
 
+  // Ctrl-Alt-Shift-W for canary/dev builds only.
+  const chrome::VersionInfo::Channel channel =
+      chrome::VersionInfo::GetChannel();
+  if (channel != chrome::VersionInfo::CHANNEL_STABLE &&
+      channel != chrome::VersionInfo::CHANNEL_BETA) {
+    accel_map_[ui::Accelerator(
+        ui::VKEY_W, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN |
+                        ui::EF_SHIFT_DOWN)] = kAccelNameToggleWebviewSignin;
+  }
+
   // Use KEY_RELEASED because Gaia consumes KEY_PRESSED for up/down key.
   ui::Accelerator key_up(ui::VKEY_UP, ui::EF_NONE);
   key_up.set_type(ui::ET_KEY_RELEASED);
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
index 4e0f819c..1fe0880 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_browsertest.cc
@@ -15,12 +15,12 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "base/prefs/pref_service.h"
 #include "base/prefs/scoped_user_pref_update.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
index 805423e..1df19dc2d 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
@@ -8,7 +8,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_registry_simple.h"
@@ -18,6 +17,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/task_runner_util.h"
 #include "base/thread_task_runner_handle.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_test_util.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_test_util.cc
index a5fb1fc8..2275e46 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_test_util.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_test_util.cc
@@ -8,7 +8,7 @@
 
 #include "base/files/file_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_rep.h"
diff --git a/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc b/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
index 3c180c2..f5701af 100644
--- a/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
+++ b/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
@@ -100,11 +100,11 @@
 // we've ensured the profile has been shut down.
 policy::PolicyCertVerifier* g_policy_cert_verifier_for_factory = NULL;
 
-KeyedService* TestPolicyCertServiceFactory(content::BrowserContext* context) {
+scoped_ptr<KeyedService> TestPolicyCertServiceFactory(
+    content::BrowserContext* context) {
   return policy::PolicyCertService::CreateForTesting(
-             kUsers[0],
-             g_policy_cert_verifier_for_factory,
-             user_manager::UserManager::Get()).release();
+      kUsers[0], g_policy_cert_verifier_for_factory,
+      user_manager::UserManager::Get());
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 136ce50..470c1db 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -383,7 +383,7 @@
       const GURL& url,
       net::URLFetcher::RequestType request_type,
       net::URLFetcherDelegate* d) override {
-    if (StartsWithASCII(
+    if (base::StartsWithASCII(
             url.spec(),
             SimpleGeolocationProvider::DefaultGeolocationProviderURL().spec(),
             true)) {
@@ -391,9 +391,8 @@
           url, d, std::string(kGeolocationResponseBody), net::HTTP_OK,
           net::URLRequestStatus::SUCCESS));
     }
-    if (StartsWithASCII(url.spec(),
-                        chromeos::DefaultTimezoneProviderURL().spec(),
-                        true)) {
+    if (base::StartsWithASCII(
+            url.spec(), chromeos::DefaultTimezoneProviderURL().spec(), true)) {
       return scoped_ptr<net::URLFetcher>(new net::FakeURLFetcher(
           url, d, std::string(kTimezoneResponseBody), net::HTTP_OK,
           net::URLRequestStatus::SUCCESS));
diff --git a/chrome/browser/chromeos/memory/oom_memory_details.cc b/chrome/browser/chromeos/memory/oom_memory_details.cc
new file mode 100644
index 0000000..effd3178
--- /dev/null
+++ b/chrome/browser/chromeos/memory/oom_memory_details.cc
@@ -0,0 +1,52 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/memory/oom_memory_details.h"
+
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chromeos/memory/oom_memory_details.h"
+#include "ui/base/text/bytes_formatting.h"
+
+namespace chromeos {
+
+// static
+void OomMemoryDetails::Log(const std::string& title,
+                           const base::Closure& callback) {
+  // Deletes itself upon completion.
+  OomMemoryDetails* details = new OomMemoryDetails(title, callback);
+  details->StartFetch(MemoryDetails::FROM_CHROME_ONLY);
+}
+
+OomMemoryDetails::OomMemoryDetails(const std::string& title,
+                                   const base::Closure& callback)
+    : title_(title), callback_(callback) {
+  AddRef();  // Released in OnDetailsAvailable().
+  start_time_ = base::TimeTicks::Now();
+}
+
+OomMemoryDetails::~OomMemoryDetails() {
+}
+
+void OomMemoryDetails::OnDetailsAvailable() {
+  base::TimeDelta delta = base::TimeTicks::Now() - start_time_;
+  // These logs are collected by user feedback reports.  We want them to help
+  // diagnose user-reported problems with frequently discarded tabs.
+  std::string log_string = ToLogString();
+  base::SystemMemoryInfoKB memory;
+  if (base::GetSystemMemoryInfo(&memory) && memory.gem_size != -1) {
+    log_string += "Graphics ";
+    log_string += base::UTF16ToASCII(ui::FormatBytes(memory.gem_size));
+  }
+  LOG(WARNING) << title_ << " (" << delta.InMilliseconds() << " ms):\n"
+               << log_string;
+  if (!callback_.is_null())
+    callback_.Run();
+  // Delete ourselves so we don't have to worry about OomPriorityManager
+  // deleting us when we're still working.
+  Release();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/memory/oom_memory_details.h b/chrome/browser/chromeos/memory/oom_memory_details.h
new file mode 100644
index 0000000..fa781a2
--- /dev/null
+++ b/chrome/browser/chromeos/memory/oom_memory_details.h
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_MEMORY_OOM_MEMORY_DETAILS_H_
+#define CHROME_BROWSER_CHROMEOS_MEMORY_OOM_MEMORY_DETAILS_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "chrome/browser/memory_details.h"
+
+namespace chromeos {
+
+////////////////////////////////////////////////////////////////////////////////
+// OomMemoryDetails logs details about all Chrome processes during an out-of-
+// memory event in an attempt to identify the culprit.
+class OomMemoryDetails : public MemoryDetails {
+ public:
+  // Logs the memory details asynchronously and then run |callback|.
+  // The |title| is printed at the beginning of the message.
+  static void Log(const std::string& title, const base::Closure& callback);
+
+ private:
+  OomMemoryDetails(const std::string& title, const base::Closure& callback);
+  ~OomMemoryDetails() override;
+
+  // MemoryDetails overrides:
+  void OnDetailsAvailable() override;
+
+  std::string title_;
+  base::TimeTicks start_time_;
+  base::Closure callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(OomMemoryDetails);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_MEMORY_OOM_MEMORY_DETAILS_H_
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager.cc b/chrome/browser/chromeos/memory/oom_priority_manager.cc
index 76429cf9..093cec3 100644
--- a/chrome/browser/chromeos/memory/oom_priority_manager.cc
+++ b/chrome/browser/chromeos/memory/oom_priority_manager.cc
@@ -24,13 +24,12 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
-#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "chrome/browser/chromeos/memory/low_memory_observer.h"
+#include "chrome/browser/chromeos/memory/oom_memory_details.h"
 #include "chrome/browser/chromeos/memory/system_memory_stats_recorder.h"
-#include "chrome/browser/memory_details.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_iterator.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -48,7 +47,6 @@
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/zygote_host_linux.h"
-#include "ui/base/text/bytes_formatting.h"
 
 using base::TimeDelta;
 using base::TimeTicks;
@@ -87,54 +85,6 @@
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
-// OomMemoryDetails logs details about all Chrome processes during an out-of-
-// memory event in an attempt to identify the culprit, then discards a tab and
-// deletes itself.
-class OomMemoryDetails : public MemoryDetails {
- public:
-  OomMemoryDetails();
-
-  // MemoryDetails overrides:
-  void OnDetailsAvailable() override;
-
- private:
-  ~OomMemoryDetails() override {}
-
-  TimeTicks start_time_;
-
-  DISALLOW_COPY_AND_ASSIGN(OomMemoryDetails);
-};
-
-OomMemoryDetails::OomMemoryDetails() {
-  AddRef();  // Released in OnDetailsAvailable().
-  start_time_ = TimeTicks::Now();
-}
-
-void OomMemoryDetails::OnDetailsAvailable() {
-  TimeDelta delta = TimeTicks::Now() - start_time_;
-  // These logs are collected by user feedback reports.  We want them to help
-  // diagnose user-reported problems with frequently discarded tabs.
-  std::string log_string = ToLogString();
-  base::SystemMemoryInfoKB memory;
-  if (base::GetSystemMemoryInfo(&memory) && memory.gem_size != -1) {
-    log_string += "Graphics ";
-    log_string += base::UTF16ToASCII(ui::FormatBytes(memory.gem_size));
-  }
-  LOG(WARNING) << "OOM details (" << delta.InMilliseconds() << " ms):\n"
-      << log_string;
-  if (g_browser_process &&
-      g_browser_process->platform_part()->oom_priority_manager()) {
-    OomPriorityManager* manager =
-        g_browser_process->platform_part()->oom_priority_manager();
-    manager->PurgeBrowserMemory();
-    manager->DiscardTab();
-  }
-  // Delete ourselves so we don't have to worry about OomPriorityManager
-  // deleting us when we're still working.
-  Release();
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // OomPriorityManager
 
 OomPriorityManager::TabStats::TabStats()
@@ -261,16 +211,31 @@
 }
 
 void OomPriorityManager::LogMemoryAndDiscardTab() {
+  LogMemory("Tab Discards Memory details",
+            base::Bind(&OomPriorityManager::PurgeMemoryAndDiscardTabs));
+}
+
+void OomPriorityManager::LogMemory(const std::string& title,
+                                   const base::Closure& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // Deletes itself upon completion.
-  OomMemoryDetails* details = new OomMemoryDetails();
-  details->StartFetch(MemoryDetails::FROM_CHROME_ONLY);
+  OomMemoryDetails::Log(title, callback);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // OomPriorityManager, private:
 
 // static
+void OomPriorityManager::PurgeMemoryAndDiscardTabs() {
+  if (g_browser_process &&
+      g_browser_process->platform_part()->oom_priority_manager()) {
+    OomPriorityManager* manager =
+        g_browser_process->platform_part()->oom_priority_manager();
+    manager->PurgeBrowserMemory();
+    manager->DiscardTab();
+  }
+}
+
+// static
 bool OomPriorityManager::IsReloadableUI(const GURL& url) {
   // There are many chrome:// UI URLs, but only look for the ones that users
   // are likely to have open. Most of the benefit is the from NTP URL.
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager.h b/chrome/browser/chromeos/memory/oom_priority_manager.h
index b0165f4c..fbb4430 100644
--- a/chrome/browser/chromeos/memory/oom_priority_manager.h
+++ b/chrome/browser/chromeos/memory/oom_priority_manager.h
@@ -64,8 +64,10 @@
   // multiple threads and takes time.
   void LogMemoryAndDiscardTab();
 
+  // Log memory statistics for the running processes, then call the callback.
+  void LogMemory(const std::string& title, const base::Closure& callback);
+
  private:
-  friend class OomMemoryDetails;
   FRIEND_TEST_ALL_PREFIXES(OomPriorityManagerTest, Comparator);
   FRIEND_TEST_ALL_PREFIXES(OomPriorityManagerTest, IsReloadableUI);
   FRIEND_TEST_ALL_PREFIXES(OomPriorityManagerTest, GetProcessHandles);
@@ -87,6 +89,8 @@
   };
   typedef std::vector<TabStats> TabStatsList;
 
+  static void PurgeMemoryAndDiscardTabs();
+
   // Returns true if the |url| represents an internal Chrome web UI page that
   // can be easily reloaded and hence makes a good choice to discard.
   static bool IsReloadableUI(const GURL& url);
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
index dedc6b4..5918728e 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
@@ -41,14 +42,14 @@
 const char kAffiliatedUserID2[] = "test_2@example.com";
 const char kUnaffiliatedUserID[] = "test@other_domain.test";
 
-KeyedService* BuildProfileInvalidationProvider(
+scoped_ptr<KeyedService> BuildProfileInvalidationProvider(
     content::BrowserContext* context) {
   scoped_ptr<invalidation::FakeInvalidationService> invalidation_service(
       new invalidation::FakeInvalidationService);
   invalidation_service->SetInvalidatorState(
       syncer::TRANSIENT_INVALIDATION_ERROR);
-  return new invalidation::ProfileInvalidationProvider(
-      invalidation_service.Pass());
+  return make_scoped_ptr(new invalidation::ProfileInvalidationProvider(
+      invalidation_service.Pass()));
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client.cc b/chrome/browser/chromeos/policy/auto_enrollment_client.cc
index 8bf18c8..49b97096 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
 
+#include <stdint.h>
+
 #include "base/bind.h"
 #include "base/guid.h"
 #include "base/location.h"
@@ -43,7 +45,7 @@
 // Returns the power of the next power-of-2 starting at |value|.
 int NextPowerOf2(int64 value) {
   for (int i = 0; i <= AutoEnrollmentClient::kMaximumPower; ++i) {
-    if ((GG_INT64_C(1) << i) >= value)
+    if ((INT64_C(1) << i) >= value)
       return i;
   }
   // No other value can be represented in an int64.
@@ -239,7 +241,7 @@
     uint64 byte = server_backed_state_key_hash_[31 - i] & 0xff;
     remainder = remainder | (byte << (8 * i));
   }
-  remainder = remainder & ((GG_UINT64_C(1) << current_power_) - 1);
+  remainder = remainder & ((UINT64_C(1) << current_power_) - 1);
 
   ReportProgress(AUTO_ENROLLMENT_STATE_PENDING);
 
@@ -251,7 +253,7 @@
   em::DeviceAutoEnrollmentRequest* request =
       request_job_->GetRequest()->mutable_auto_enrollment_request();
   request->set_remainder(remainder);
-  request->set_modulus(GG_INT64_C(1) << current_power_);
+  request->set_modulus(INT64_C(1) << current_power_);
   request_job_->Start(
       base::Bind(&AutoEnrollmentClient::HandleRequestCompletion,
                  base::Unretained(this),
@@ -321,7 +323,7 @@
 
     int64 modulus = enrollment_response.expected_modulus();
     int power = NextPowerOf2(modulus);
-    if ((GG_INT64_C(1) << power) != modulus) {
+    if ((INT64_C(1) << power) != modulus) {
       LOG(WARNING) << "Auto enrollment: the server didn't ask for a power-of-2 "
                    << "modulus. Using the closest power-of-2 instead "
                    << "(" << modulus << " vs 2^" << power << ")";
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc b/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc
index 39a1b6e2..30372d5f 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
 
+#include <stdint.h>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/message_loop/message_loop.h"
@@ -71,13 +73,10 @@
     client_.reset(new AutoEnrollmentClient(
         base::Bind(&AutoEnrollmentClientTest::ProgressCallback,
                    base::Unretained(this)),
-        service_.get(),
-        local_state_,
+        service_.get(), local_state_,
         new net::TestURLRequestContextGetter(
-            base::MessageLoop::current()->message_loop_proxy()),
-        state_key,
-        power_initial,
-        power_limit));
+            base::MessageLoop::current()->task_runner()),
+        state_key, power_initial, power_limit));
   }
 
   void ProgressCallback(AutoEnrollmentState state) {
@@ -388,7 +387,7 @@
 }
 
 TEST_F(AutoEnrollmentClientTest, ManyBitsUploaded) {
-  int64 bottom62 = GG_INT64_C(0x386e7244d097c3e6);
+  int64 bottom62 = INT64_C(0x386e7244d097c3e6);
   for (int i = 0; i <= 62; ++i) {
     CreateClient(kStateKey, i, i);
     ServerWillReply(-1, false, false);
@@ -396,8 +395,8 @@
     EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_);
     EXPECT_TRUE(auto_enrollment_request().has_remainder());
     EXPECT_TRUE(auto_enrollment_request().has_modulus());
-    EXPECT_EQ(GG_INT64_C(1) << i, auto_enrollment_request().modulus());
-    EXPECT_EQ(bottom62 % (GG_INT64_C(1) << i),
+    EXPECT_EQ(INT64_C(1) << i, auto_enrollment_request().modulus());
+    EXPECT_EQ(bottom62 % (INT64_C(1) << i),
               auto_enrollment_request().remainder());
     VerifyCachedResult(false, i);
     EXPECT_FALSE(HasServerBackedState());
@@ -407,7 +406,7 @@
 TEST_F(AutoEnrollmentClientTest, MoreThan32BitsUploaded) {
   CreateClient(kStateKey, 10, 37);
   InSequence sequence;
-  ServerWillReply(GG_INT64_C(1) << 37, false, false);
+  ServerWillReply(INT64_C(1) << 37, false, false);
   ServerWillReply(-1, true, true);
   ServerWillSendState(
       "example.com",
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc b/chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc
index 7931adec..35114406 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc
+++ b/chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc
@@ -148,8 +148,8 @@
 
 void CloudExternalDataManagerBaseTest::SetUp() {
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-  resource_cache_.reset(new ResourceCache(temp_dir_.path(),
-                                          message_loop_.message_loop_proxy()));
+  resource_cache_.reset(
+      new ResourceCache(temp_dir_.path(), message_loop_.task_runner()));
   SetUpExternalDataManager();
 
   // Set |kStringPolicy| to a string value.
@@ -186,13 +186,11 @@
 
 void CloudExternalDataManagerBaseTest::SetUpExternalDataManager() {
   external_data_manager_.reset(new CloudExternalDataManagerBase(
-      policy_details_.GetCallback(),
-      message_loop_.message_loop_proxy(),
-      message_loop_.message_loop_proxy()));
-  external_data_manager_->SetExternalDataStore(make_scoped_ptr(
-      new CloudExternalDataStore(kCacheKey,
-                                 message_loop_.message_loop_proxy(),
-                                 resource_cache_.get())));
+      policy_details_.GetCallback(), message_loop_.task_runner(),
+      message_loop_.task_runner()));
+  external_data_manager_->SetExternalDataStore(
+      make_scoped_ptr(new CloudExternalDataStore(
+          kCacheKey, message_loop_.task_runner(), resource_cache_.get())));
   external_data_manager_->SetPolicyStore(&cloud_policy_store_);
 }
 
@@ -337,10 +335,10 @@
   external_data_manager_.reset();
   base::RunLoop().RunUntilIdle();
   std::string data;
-  EXPECT_TRUE(CloudExternalDataStore(kCacheKey,
-                                     message_loop_.message_loop_proxy(),
-                                     resource_cache_.get()).Load(
-      k10BytePolicy, crypto::SHA256HashString(k10ByteData), 10, &data));
+  EXPECT_TRUE(CloudExternalDataStore(kCacheKey, message_loop_.task_runner(),
+                                     resource_cache_.get())
+                  .Load(k10BytePolicy, crypto::SHA256HashString(k10ByteData),
+                        10, &data));
   EXPECT_EQ(k10ByteData, data);
 }
 
@@ -395,8 +393,7 @@
   // Verify that the downloaded data is present in the cache.
   external_data_manager_.reset();
   base::RunLoop().RunUntilIdle();
-  CloudExternalDataStore cache(kCacheKey,
-                               message_loop_.message_loop_proxy(),
+  CloudExternalDataStore cache(kCacheKey, message_loop_.task_runner(),
                                resource_cache_.get());
   std::string data;
   EXPECT_TRUE(cache.Load(k10BytePolicy,
@@ -526,10 +523,10 @@
   // Store valid external data for |k10BytePolicy| in the cache.
   external_data_manager_.reset();
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(CloudExternalDataStore(kCacheKey,
-                                     message_loop_.message_loop_proxy(),
-                                     resource_cache_.get()).Store(
-      k10BytePolicy, crypto::SHA256HashString(k10ByteData), k10ByteData));
+  EXPECT_TRUE(CloudExternalDataStore(kCacheKey, message_loop_.task_runner(),
+                                     resource_cache_.get())
+                  .Store(k10BytePolicy, crypto::SHA256HashString(k10ByteData),
+                         k10ByteData));
 
   // Instantiate an external_data_manager_ that uses the primed cache.
   SetUpExternalDataManager();
@@ -551,10 +548,8 @@
 TEST_F(CloudExternalDataManagerBaseTest, PruneCacheOnStartup) {
   external_data_manager_.reset();
   base::RunLoop().RunUntilIdle();
-  scoped_ptr<CloudExternalDataStore>
-      cache(new CloudExternalDataStore(kCacheKey,
-                                       message_loop_.message_loop_proxy(),
-                                       resource_cache_.get()));
+  scoped_ptr<CloudExternalDataStore> cache(new CloudExternalDataStore(
+      kCacheKey, message_loop_.task_runner(), resource_cache_.get()));
   // Store valid external data for |k10BytePolicy| in the cache.
   EXPECT_TRUE(cache->Store(k10BytePolicy,
                            crypto::SHA256HashString(k10ByteData),
@@ -576,8 +571,7 @@
   external_data_manager_.reset();
   base::RunLoop().RunUntilIdle();
 
-  cache.reset(new CloudExternalDataStore(kCacheKey,
-                                         message_loop_.message_loop_proxy(),
+  cache.reset(new CloudExternalDataStore(kCacheKey, message_loop_.task_runner(),
                                          resource_cache_.get()));
   std::string data;
   // Verify that the valid external data for |k10BytePolicy| is still in the
@@ -605,10 +599,8 @@
   // Store valid external data for |k20BytePolicy| in the cache.
   external_data_manager_.reset();
   base::RunLoop().RunUntilIdle();
-  scoped_ptr<CloudExternalDataStore>
-      cache(new CloudExternalDataStore(kCacheKey,
-                                       message_loop_.message_loop_proxy(),
-                                       resource_cache_.get()));
+  scoped_ptr<CloudExternalDataStore> cache(new CloudExternalDataStore(
+      kCacheKey, message_loop_.task_runner(), resource_cache_.get()));
   EXPECT_TRUE(cache->Store(k20BytePolicy,
                            crypto::SHA256HashString(k20ByteData),
                            k20ByteData));
@@ -629,8 +621,7 @@
   // the cache.
   external_data_manager_.reset();
   base::RunLoop().RunUntilIdle();
-  cache.reset(new CloudExternalDataStore(kCacheKey,
-                                         message_loop_.message_loop_proxy(),
+  cache.reset(new CloudExternalDataStore(kCacheKey, message_loop_.task_runner(),
                                          resource_cache_.get()));
   std::string data;
   EXPECT_FALSE(cache->Load(k20BytePolicy,
@@ -643,10 +634,8 @@
 TEST_F(CloudExternalDataManagerBaseTest, CacheCorruption) {
   external_data_manager_.reset();
   base::RunLoop().RunUntilIdle();
-  scoped_ptr<CloudExternalDataStore>
-      cache(new CloudExternalDataStore(kCacheKey,
-                                       message_loop_.message_loop_proxy(),
-                                       resource_cache_.get()));
+  scoped_ptr<CloudExternalDataStore> cache(new CloudExternalDataStore(
+      kCacheKey, message_loop_.task_runner(), resource_cache_.get()));
   // Store external data for |k10BytePolicy| that exceeds the maximal external
   // data size allowed for that policy.
   EXPECT_TRUE(cache->Store(k10BytePolicy,
@@ -697,8 +686,7 @@
 
   external_data_manager_.reset();
   base::RunLoop().RunUntilIdle();
-  cache.reset(new CloudExternalDataStore(kCacheKey,
-                                         message_loop_.message_loop_proxy(),
+  cache.reset(new CloudExternalDataStore(kCacheKey, message_loop_.task_runner(),
                                          resource_cache_.get()));
   std::string data;
   // Verify that the invalid external data for |k10BytePolicy| has been pruned
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
index 3cdb555..f7c2aa5 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
@@ -9,7 +9,6 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/logging.h"
-#include "base/port.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
index f93d637..944061f9 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
@@ -13,12 +13,12 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/thread_task_runner_handle.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
index 28deddf..93f24eb 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
@@ -113,7 +113,7 @@
 }
 
 void DeviceCommandScreenshotJob::OnFailure(UploadJob::ErrorCode error_code) {
-  ResultCode result_code;
+  ResultCode result_code = FAILURE_CLIENT;
   switch (error_code) {
     case UploadJob::AUTHENTICATION_ERROR:
       result_code = FAILURE_AUTHENTICATION;
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
index 6a0b46e..af19f7d 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
@@ -212,9 +212,8 @@
     if (!fetcher)
       return NULL;
     EXPECT_TRUE(fetcher->delegate());
-    EXPECT_TRUE(StartsWithASCII(fetcher->GetOriginalURL().spec(),
-                                expected_url.spec(),
-                                true));
+    EXPECT_TRUE(base::StartsWithASCII(fetcher->GetOriginalURL().spec(),
+                                      expected_url.spec(), true));
     fetcher->set_url(fetcher->GetOriginalURL());
     fetcher->set_response_code(200);
     fetcher->set_status(net::URLRequestStatus());
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.cc
index 7968741..eb7c561 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_factory_chromeos.cc
@@ -9,10 +9,10 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
 #include "base/thread_task_runner_handle.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
index 27a91dcb..bca077a0 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos_unittest.cc
@@ -63,13 +63,10 @@
                                   kSanitizedUsername));
 
     ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
-    store_.reset(new UserCloudPolicyStoreChromeOS(&cryptohome_client_,
-                                                  &session_manager_client_,
-                                                  loop_.message_loop_proxy(),
-                                                  PolicyBuilder::kFakeUsername,
-                                                  user_policy_dir(),
-                                                  token_file(),
-                                                  policy_file()));
+    store_.reset(new UserCloudPolicyStoreChromeOS(
+        &cryptohome_client_, &session_manager_client_, loop_.task_runner(),
+        PolicyBuilder::kFakeUsername, user_policy_dir(), token_file(),
+        policy_file()));
     store_->AddObserver(&observer_);
 
     // Install the initial public key, so that by default the validation of
diff --git a/chrome/browser/chromeos/policy/variations_service_policy_browsertest.cc b/chrome/browser/chromeos/policy/variations_service_policy_browsertest.cc
index 8050393..7cb63abc 100644
--- a/chrome/browser/chromeos/policy/variations_service_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/variations_service_policy_browsertest.cc
@@ -44,7 +44,7 @@
   // Device policy has updated the cros settings.
   const GURL url = chrome_variations::VariationsService::GetVariationsServerURL(
       g_browser_process->local_state(), std::string());
-  EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
+  EXPECT_TRUE(base::StartsWithASCII(url.spec(), default_variations_url, true));
   std::string value;
   EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
   EXPECT_EQ("restricted", value);
diff --git a/chrome/browser/chromeos/power/peripheral_battery_observer.cc b/chrome/browser/chromeos/power/peripheral_battery_observer.cc
index a36a5edc73..fc17ebf 100644
--- a/chrome/browser/chromeos/power/peripheral_battery_observer.cc
+++ b/chrome/browser/chromeos/power/peripheral_battery_observer.cc
@@ -49,8 +49,8 @@
 const char kHIDBatteryPathSuffix[] = "-battery";
 
 bool IsBluetoothHIDBattery(const std::string& path) {
-  return StartsWithASCII(path, kHIDBatteryPathPrefix, false) &&
-      EndsWith(path, kHIDBatteryPathSuffix, false);
+  return base::StartsWithASCII(path, kHIDBatteryPathPrefix, false) &&
+         EndsWith(path, kHIDBatteryPathSuffix, false);
 }
 
 std::string ExtractBluetoothAddress(const std::string& path) {
diff --git a/chrome/browser/chromeos/proxy_cros_settings_parser.cc b/chrome/browser/chromeos/proxy_cros_settings_parser.cc
index 0f9be54..500e7c6 100644
--- a/chrome/browser/chromeos/proxy_cros_settings_parser.cc
+++ b/chrome/browser/chromeos/proxy_cros_settings_parser.cc
@@ -112,7 +112,7 @@
 namespace proxy_cros_settings_parser {
 
 bool IsProxyPref(const std::string& path) {
-  return StartsWithASCII(path, kProxyPrefsPrefix, true);
+  return base::StartsWithASCII(path, kProxyPrefsPrefix, true);
 }
 
 void SetProxyPrefValue(const std::string& path,
@@ -247,11 +247,10 @@
     if (in_value->GetAsString(&val)) {
       config.SetProxyForScheme(
           "socks", CreateProxyServerFromHost(
-              val,
-              config.socks_proxy,
-              StartsWithASCII(val, "socks5://", false) ?
-              net::ProxyServer::SCHEME_SOCKS5 :
-              net::ProxyServer::SCHEME_SOCKS4));
+                       val, config.socks_proxy,
+                       base::StartsWithASCII(val, "socks5://", false)
+                           ? net::ProxyServer::SCHEME_SOCKS5
+                           : net::ProxyServer::SCHEME_SOCKS4));
     }
   } else if (path == kProxySocksPort) {
     int val;
@@ -259,11 +258,10 @@
       std::string host = config.socks_proxy.server.host_port_pair().host();
       config.SetProxyForScheme(
           "socks", CreateProxyServerFromPort(
-              val,
-              config.socks_proxy,
-              StartsWithASCII(host, "socks5://", false) ?
-              net::ProxyServer::SCHEME_SOCKS5 :
-              net::ProxyServer::SCHEME_SOCKS4));
+                       val, config.socks_proxy,
+                       base::StartsWithASCII(host, "socks5://", false)
+                           ? net::ProxyServer::SCHEME_SOCKS5
+                           : net::ProxyServer::SCHEME_SOCKS4));
     }
   } else if (path == kProxyIgnoreList) {
     net::ProxyBypassRules bypass_rules;
diff --git a/chrome/browser/chromeos/settings/cros_settings.cc b/chrome/browser/chromeos/settings/cros_settings.cc
index 016b33a..b981b37 100644
--- a/chrome/browser/chromeos/settings/cros_settings.cc
+++ b/chrome/browser/chromeos/settings/cros_settings.cc
@@ -86,7 +86,7 @@
 }
 
 bool CrosSettings::IsCrosSettings(const std::string& path) {
-  return StartsWithASCII(path, kCrosSettingsPrefix, true);
+  return base::StartsWithASCII(path, kCrosSettingsPrefix, true);
 }
 
 void CrosSettings::Set(const std::string& path, const base::Value& in_value) {
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
index e499498..64c04d8 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
@@ -58,8 +58,9 @@
  public:
   DeviceOAuth2TokenServiceTest()
       : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()),
-        request_context_getter_(new net::TestURLRequestContextGetter(
-            message_loop_.message_loop_proxy())) {}
+        request_context_getter_(
+            new net::TestURLRequestContextGetter(message_loop_.task_runner())) {
+  }
   ~DeviceOAuth2TokenServiceTest() override {}
 
   // Most tests just want a noop crypto impl with a dummy refresh token value in
diff --git a/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc b/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc
index 3b6a89a2..5674feda 100644
--- a/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/stub_cros_settings_provider.cc
@@ -66,6 +66,8 @@
   values_.SetBoolean(kAccountsPrefAllowNewUser, true);
   values_.SetBoolean(kAccountsPrefSupervisedUsersEnabled, true);
   values_.SetBoolean(kAccountsPrefShowUserNamesOnSignIn, true);
+  values_.SetBoolean(kAttestationForContentProtectionEnabled, true);
+  values_.SetBoolean(kStatsReportingPref, true);
   values_.SetValue(kAccountsPrefDeviceLocalAccounts, new base::ListValue);
   // |kDeviceOwner| will be set to the logged-in user by |UserManager|.
 }
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager.cc b/chrome/browser/chromeos/system/automatic_reboot_manager.cc
index c9e7f33..a15e3a7 100644
--- a/chrome/browser/chromeos/system/automatic_reboot_manager.cc
+++ b/chrome/browser/chromeos/system/automatic_reboot_manager.cc
@@ -184,7 +184,7 @@
   }
 
   // In a regular browser, base::ThreadTaskRunnerHandle::Get() and
-  // base::MessageLoopProxy::current() return pointers to the same object.
+  // base::ThreadTaskRunnerHandle::Get() return pointers to the same object.
   // In unit tests, using base::ThreadTaskRunnerHandle::Get() has the advantage
   // that it allows a custom base::SingleThreadTaskRunner to be injected.
   base::SequencedWorkerPool* worker_pool =
diff --git a/chrome/browser/chromeos/system_logs/touch_log_source_ozone.cc b/chrome/browser/chromeos/system_logs/touch_log_source_ozone.cc
index 030536d4..29d8eb5 100644
--- a/chrome/browser/chromeos/system_logs/touch_log_source_ozone.cc
+++ b/chrome/browser/chromeos/system_logs/touch_log_source_ozone.cc
@@ -65,7 +65,7 @@
   std::string log_list;
   for (size_t i = 0; i < log_paths.size(); ++i) {
     const std::string basename = log_paths[i].BaseName().value();
-    if (StartsWithASCII(basename, prefix, true)) {
+    if (base::StartsWithASCII(basename, prefix, true)) {
       log_list.append(" " + log_paths[i].value());
 
       // Limit the max number of collected logs to shorten the log collection
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index cc0fb61..bdb1406 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -117,7 +117,6 @@
   std::string GetLang() const override;
   std::string GetOSLongName() const override;
   std::string ExtraRequestParams() const override;
-  size_t UrlSizeLimit() const override;
   net::URLRequestContextGetter* RequestContext() const override;
   scoped_refptr<OutOfProcessPatcher> CreateOutOfProcessPatcher() const override;
   bool DeltasEnabled() const override;
@@ -237,10 +236,6 @@
   return extra_info_;
 }
 
-size_t ChromeConfigurator::UrlSizeLimit() const {
-  return 1024ul;
-}
-
 net::URLRequestContextGetter* ChromeConfigurator::RequestContext() const {
   return url_request_getter_;
 }
diff --git a/chrome/browser/component_updater/cld_component_installer_unittest.cc b/chrome/browser/component_updater/cld_component_installer_unittest.cc
index fe1efcd9..e3833f14 100644
--- a/chrome/browser/component_updater/cld_component_installer_unittest.cc
+++ b/chrome/browser/component_updater/cld_component_installer_unittest.cc
@@ -126,8 +126,8 @@
   const base::Version version("1.2.3.4");
   traits_.ComponentReady(version, install_dir, manifest.Pass());
   base::FilePath result = CldComponentInstallerTraits::GetLatestCldDataFile();
-  ASSERT_TRUE(
-      StartsWith(result.AsUTF16Unsafe(), install_dir.AsUTF16Unsafe(), true));
+  ASSERT_TRUE(base::StartsWith(result.AsUTF16Unsafe(),
+                               install_dir.AsUTF16Unsafe(), true));
   ASSERT_TRUE(EndsWith(result.value(), kTestCldDataFileName, true));
 }
 
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win.cc b/chrome/browser/component_updater/sw_reporter_installer_win.cc
index f29c5299..95a5ff12 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win.cc
+++ b/chrome/browser/component_updater/sw_reporter_installer_win.cc
@@ -70,6 +70,11 @@
   SW_REPORTER_REGISTRY_EXIT_CODE = 5,
   SW_REPORTER_RESET_RETRIES = 6,  // Deprecated.
   SW_REPORTER_DOWNLOAD_START = 7,
+  SW_REPORTER_NO_BROWSER = 8,
+  SW_REPORTER_NO_LOCAL_STATE = 9,
+  SW_REPORTER_NO_PROMPT_NEEDED = 10,
+  SW_REPORTER_NO_PROMPT_FIELD_TRIAL = 11,
+  SW_REPORTER_ALREADY_PROMPTED = 12,
   SW_REPORTER_MAX,
 };
 enum SRTCompleted {
@@ -201,8 +206,15 @@
                             KEY_SET_VALUE);
   srt_key.DeleteValue(kExitCodeValueName);
 
-  if ((exit_code != kPostRebootCleanupNeeded && exit_code != kCleanupNeeded) ||
-      !IsInSRTPromptFieldTrialGroups()) {
+  if (!IsInSRTPromptFieldTrialGroups()) {
+    // Knowing about disabled field trial is more important than reporter not
+    // finding anything to remove.
+    ReportUmaStep(SW_REPORTER_NO_PROMPT_FIELD_TRIAL);
+    return;
+  }
+
+  if (exit_code != kPostRebootCleanupNeeded && exit_code != kCleanupNeeded) {
+    ReportUmaStep(SW_REPORTER_NO_PROMPT_NEEDED);
     return;
   }
 
@@ -212,8 +224,10 @@
   // have a profile.
   chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop();
   Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type);
-  if (!browser)
+  if (!browser) {
+    ReportUmaStep(SW_REPORTER_NO_BROWSER);
     return;
+  }
 
   Profile* profile = browser->profile();
   DCHECK(profile);
@@ -225,8 +239,10 @@
   // and for the current Finch seed.
   std::string incoming_seed = safe_browsing::GetIncomingSRTSeed();
   std::string old_seed = prefs->GetString(prefs::kSwReporterPromptSeed);
-  if (!incoming_seed.empty() && incoming_seed == old_seed)
+  if (!incoming_seed.empty() && incoming_seed == old_seed) {
+    ReportUmaStep(SW_REPORTER_ALREADY_PROMPTED);
     return;
+  }
 
   if (!incoming_seed.empty())
     prefs->SetString(prefs::kSwReporterPromptSeed, incoming_seed);
@@ -340,8 +356,10 @@
 
     // If we can't access local state, we can't see when we last ran, so
     // just exit without running.
-    if (!g_browser_process || !g_browser_process->local_state())
+    if (!g_browser_process || !g_browser_process->local_state()) {
+      ReportUmaStep(SW_REPORTER_NO_LOCAL_STATE);
       return;
+    }
 
     // Run the reporter if it hasn't been triggered in the
     // kDaysBetweenSwReporterRuns days.
diff --git a/chrome/browser/content_settings/permission_context_base.cc b/chrome/browser/content_settings/permission_context_base.cc
index 8be0b7d2..32b9bad 100644
--- a/chrome/browser/content_settings/permission_context_base.cc
+++ b/chrome/browser/content_settings/permission_context_base.cc
@@ -134,8 +134,6 @@
       permission_type_, requesting_origin);
 
   if (PermissionBubbleManager::Enabled()) {
-    if (pending_bubbles_.get(id.ToString()) != NULL)
-      return;
     PermissionBubbleManager* bubble_manager =
         PermissionBubbleManager::FromWebContents(web_contents);
     // TODO(mlamouri): sometimes |bubble_manager| is null. This check is meant
diff --git a/chrome/browser/content_settings/permission_infobar_delegate.cc b/chrome/browser/content_settings/permission_infobar_delegate.cc
index 61178273..4ff0975 100644
--- a/chrome/browser/content_settings/permission_infobar_delegate.cc
+++ b/chrome/browser/content_settings/permission_infobar_delegate.cc
@@ -34,6 +34,11 @@
   SetPermission(false, false);
 }
 
+PermissionInfobarDelegate*
+PermissionInfobarDelegate::AsPermissionInfobarDelegate() {
+  return this;
+}
+
 base::string16 PermissionInfobarDelegate::GetButtonLabel(
     InfoBarButton button) const {
   return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
diff --git a/chrome/browser/content_settings/permission_infobar_delegate.h b/chrome/browser/content_settings/permission_infobar_delegate.h
index 25bb0b4..519fbcaa 100644
--- a/chrome/browser/content_settings/permission_infobar_delegate.h
+++ b/chrome/browser/content_settings/permission_infobar_delegate.h
@@ -20,6 +20,9 @@
 // provide an icon and a message text to the infobar.
 class PermissionInfobarDelegate : public ConfirmInfoBarDelegate {
 
+ public:
+  ContentSettingsType content_setting() const { return type_; }
+
  protected:
   PermissionInfobarDelegate(PermissionQueueController* controller,
                             const PermissionRequestID& id,
@@ -31,6 +34,7 @@
   // ConfirmInfoBarDelegate:
   Type GetInfoBarType() const override;
   void InfoBarDismissed() override;
+  PermissionInfobarDelegate* AsPermissionInfobarDelegate() override;
   base::string16 GetButtonLabel(InfoBarButton button) const override;
   bool Accept() override;
   bool Cancel() override;
diff --git a/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc b/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc
index 0534993..ab8c80e7 100644
--- a/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc
+++ b/chrome/browser/devtools/devtools_embedder_message_dispatcher.cc
@@ -50,55 +50,148 @@
   using StorageType = T;
 };
 
-template <typename... Ts>
-struct ParamTuple {
-  bool Parse(const base::ListValue& list,
-             const base::ListValue::const_iterator& it) {
-    return it == list.end();
-  }
+// TODO(dgozman): move back to variadic templates once it compiles everywhere.
+// See http://crbug.com/491973.
 
-  template <typename H, typename... As>
-  void Apply(const H& handler, As... args) {
-    handler.Run(args...);
-  }
-};
-
-template <typename T, typename... Ts>
-struct ParamTuple<T, Ts...> {
-  bool Parse(const base::ListValue& list,
-             const base::ListValue::const_iterator& it) {
-    return it != list.end() && GetValue(*it, &head) && tail.Parse(list, it + 1);
-  }
-
-  template <typename H, typename... As>
-  void Apply(const H& handler, As... args) {
-    tail.template Apply<H, As..., T>(handler, args..., head);
-  }
-
-  typename StorageTraits<T>::StorageType head;
-  ParamTuple<Ts...> tail;
-};
-
-template<typename... As>
-bool ParseAndHandle(const base::Callback<void(As...)>& handler,
-                    const DispatchCallback& callback,
-                    const base::ListValue& list) {
-  ParamTuple<As...> tuple;
-  if (!tuple.Parse(list, list.begin()))
+bool ParseAndHandle0(const base::Callback<void()>& handler,
+                     const DispatchCallback& callback,
+                     const base::ListValue& list) {
+  if (list.GetSize() != 0)
     return false;
-  tuple.Apply(handler);
+  handler.Run();
   return true;
 }
 
-template<typename... As>
-bool ParseAndHandleWithCallback(
-    const base::Callback<void(const DispatchCallback&, As...)>& handler,
+template<class A1>
+bool ParseAndHandle1(const base::Callback<void(A1)>& handler,
+                     const DispatchCallback& callback,
+                     const base::ListValue& list) {
+  if (list.GetSize() != 1)
+    return false;
+  const base::Value* value1;
+  list.Get(0, &value1);
+  typename StorageTraits<A1>::StorageType a1;
+  if (!GetValue(value1, &a1))
+    return false;
+  handler.Run(a1);
+  return true;
+}
+
+template<class A1, class A2>
+bool ParseAndHandle2(const base::Callback<void(A1, A2)>& handler,
+                     const DispatchCallback& callback,
+                     const base::ListValue& list) {
+  if (list.GetSize() != 2)
+    return false;
+  const base::Value* value1;
+  list.Get(0, &value1);
+  typename StorageTraits<A1>::StorageType a1;
+  if (!GetValue(value1, &a1))
+    return false;
+  const base::Value* value2;
+  list.Get(1, &value2);
+  typename StorageTraits<A2>::StorageType a2;
+  if (!GetValue(value2, &a2))
+    return false;
+  handler.Run(a1, a2);
+  return true;
+}
+
+template<class A1, class A2, class A3>
+bool ParseAndHandle3(const base::Callback<void(A1, A2, A3)>& handler,
+                     const DispatchCallback& callback,
+                     const base::ListValue& list) {
+  if (list.GetSize() != 3)
+    return false;
+  const base::Value* value1;
+  list.Get(0, &value1);
+  typename StorageTraits<A1>::StorageType a1;
+  if (!GetValue(value1, &a1))
+    return false;
+  const base::Value* value2;
+  list.Get(1, &value2);
+  typename StorageTraits<A2>::StorageType a2;
+  if (!GetValue(value2, &a2))
+    return false;
+  const base::Value* value3;
+  list.Get(2, &value3);
+  typename StorageTraits<A3>::StorageType a3;
+  if (!GetValue(value3, &a3))
+    return false;
+  handler.Run(a1, a2, a3);
+  return true;
+}
+
+bool ParseAndHandleWithCallback0(
+    const base::Callback<void(const DispatchCallback&)>& handler,
     const DispatchCallback& callback,
     const base::ListValue& list) {
-  ParamTuple<As...> tuple;
-  if (!tuple.Parse(list, list.begin()))
+  if (list.GetSize() != 0)
     return false;
-  tuple.Apply(handler, callback);
+  handler.Run(callback);
+  return true;
+}
+
+template<class A1>
+bool ParseAndHandleWithCallback1(
+   const base::Callback<void(const DispatchCallback&, A1)>& handler,
+   const DispatchCallback& callback,
+   const base::ListValue& list) {
+  if (list.GetSize() != 1)
+    return false;
+  const base::Value* value1;
+  list.Get(0, &value1);
+  typename StorageTraits<A1>::StorageType a1;
+  if (!GetValue(value1, &a1))
+    return false;
+  handler.Run(callback, a1);
+  return true;
+}
+
+template<class A1, class A2>
+bool ParseAndHandleWithCallback2(
+    const base::Callback<void(const DispatchCallback&, A1, A2)>& handler,
+    const DispatchCallback& callback,
+    const base::ListValue& list) {
+  if (list.GetSize() != 2)
+    return false;
+  const base::Value* value1;
+  list.Get(0, &value1);
+  typename StorageTraits<A1>::StorageType a1;
+  if (!GetValue(value1, &a1))
+    return false;
+  const base::Value* value2;
+  list.Get(1, &value2);
+  typename StorageTraits<A2>::StorageType a2;
+  if (!GetValue(value2, &a2))
+    return false;
+  handler.Run(callback, a1, a2);
+  return true;
+}
+
+template<class A1, class A2, class A3>
+bool ParseAndHandleWithCallback3(
+    const base::Callback<void(const DispatchCallback&, A1, A2, A3)>& handler,
+    const DispatchCallback& callback,
+    const base::ListValue& list) {
+  if (list.GetSize() != 3)
+    return false;
+  const base::Value* value1;
+  list.Get(0, &value1);
+  typename StorageTraits<A1>::StorageType a1;
+  if (!GetValue(value1, &a1))
+    return false;
+  const base::Value* value2;
+  list.Get(1, &value2);
+  typename StorageTraits<A2>::StorageType a2;
+  if (!GetValue(value2, &a2))
+    return false;
+  const base::Value* value3;
+  list.Get(2, &value3);
+  typename StorageTraits<A3>::StorageType a3;
+  if (!GetValue(value3, &a3))
+    return false;
+  handler.Run(callback, a1, a2, a3);
   return true;
 }
 
@@ -123,25 +216,79 @@
     return it != handlers_.end() && it->second.Run(callback, *params);
   }
 
-  template<typename... As>
   void RegisterHandler(const std::string& method,
-                       void (Delegate::*handler)(As...),
+                       void (Delegate::*handler)(),
                        Delegate* delegate) {
-    handlers_[method] = base::Bind(&ParseAndHandle<As...>,
+    handlers_[method] = base::Bind(&ParseAndHandle0,
                                    base::Bind(handler,
                                               base::Unretained(delegate)));
   }
 
-  template<typename... As>
+  template<class A1>
+  void RegisterHandler(const std::string& method,
+                       void (Delegate::*handler)(A1),
+                       Delegate* delegate) {
+    handlers_[method] = base::Bind(&ParseAndHandle1<A1>,
+                                   base::Bind(handler,
+                                              base::Unretained(delegate)));
+  }
+
+  template<class A1, class A2>
+  void RegisterHandler(const std::string& method,
+                       void (Delegate::*handler)(A1, A2),
+                       Delegate* delegate) {
+    handlers_[method] = base::Bind(&ParseAndHandle2<A1, A2>,
+                                   base::Bind(handler,
+                                              base::Unretained(delegate)));
+  }
+
+  template<class A1, class A2, class A3>
+  void RegisterHandler(const std::string& method,
+                       void (Delegate::*handler)(A1, A2, A3),
+                       Delegate* delegate) {
+    handlers_[method] = base::Bind(&ParseAndHandle3<A1, A2, A3>,
+                                   base::Bind(handler,
+                                              base::Unretained(delegate)));
+  }
+
   void RegisterHandlerWithCallback(
       const std::string& method,
-      void (Delegate::*handler)(const DispatchCallback&, As...),
+      void (Delegate::*handler)(const DispatchCallback&),
       Delegate* delegate) {
-    handlers_[method] = base::Bind(&ParseAndHandleWithCallback<As...>,
+    handlers_[method] = base::Bind(&ParseAndHandleWithCallback0,
                                    base::Bind(handler,
                                               base::Unretained(delegate)));
   }
 
+  template<class A1>
+  void RegisterHandlerWithCallback(
+      const std::string& method,
+      void (Delegate::*handler)(const DispatchCallback&, A1),
+      Delegate* delegate) {
+    handlers_[method] = base::Bind(&ParseAndHandleWithCallback1<A1>,
+                                   base::Bind(handler,
+                                              base::Unretained(delegate)));
+  }
+
+  template<class A1, class A2>
+  void RegisterHandlerWithCallback(
+      const std::string& method,
+      void (Delegate::*handler)(const DispatchCallback&, A1, A2),
+      Delegate* delegate) {
+    handlers_[method] = base::Bind(&ParseAndHandleWithCallback2<A1, A2>,
+                                   base::Bind(handler,
+                                              base::Unretained(delegate)));
+  }
+
+  template<class A1, class A2, class A3>
+  void RegisterHandlerWithCallback(
+      const std::string& method,
+      void (Delegate::*handler)(const DispatchCallback&, A1, A2, A3),
+      Delegate* delegate) {
+    handlers_[method] = base::Bind(&ParseAndHandleWithCallback3<A1, A2, A3>,
+                                   base::Bind(handler,
+                                              base::Unretained(delegate)));
+  }
 
  private:
   using Handler = base::Callback<bool(const DispatchCallback&,
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 80a336b..2bea4f7 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -813,6 +813,13 @@
   RunTest("testDeviceMetricsOverrides", "about:blank");
 }
 
+// Tests that settings are stored in profile correctly.
+IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestSettings) {
+  OpenDevToolsWindow("about:blank", true);
+  RunTestFunction(window_, "testSettings");
+  CloseDevToolsWindow();
+}
+
 // Tests that external navigation from inspector page is always handled by
 // DevToolsWindow and results in inspected page navigation.
 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestDevToolsExternalNavigation) {
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index bde9f9e..7774ddc 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/devtools/devtools_ui_bindings.h"
 
-#include "base/command_line.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/metrics/histogram.h"
@@ -20,9 +19,6 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/themes/theme_properties.h"
-#include "chrome/browser/themes/theme_service.h"
-#include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_iterator.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -84,15 +80,6 @@
 base::LazyInstance<DevToolsUIBindingsList>::Leaky g_instances =
     LAZY_INSTANCE_INITIALIZER;
 
-std::string SkColorToRGBAString(SkColor color) {
-  // We avoid StringPrintf because it will use locale specific formatters for
-  // the double (e.g. ',' instead of '.' in German).
-  return "rgba(" + base::IntToString(SkColorGetR(color)) + "," +
-      base::IntToString(SkColorGetG(color)) + "," +
-      base::IntToString(SkColorGetB(color)) + "," +
-      base::DoubleToString(SkColorGetA(color) / 255.0) + ")";
-}
-
 base::DictionaryValue* CreateFileSystemValue(
     DevToolsFileHelper::FileSystem file_system) {
   base::DictionaryValue* file_system_value = new base::DictionaryValue();
@@ -387,29 +374,6 @@
  return NULL;
 }
 
-// static
-GURL DevToolsUIBindings::ApplyThemeToURL(Profile* profile,
-                                         const GURL& base_url) {
-  std::string frontend_url = base_url.spec();
-  ThemeService* tp = ThemeServiceFactory::GetForProfile(profile);
-  DCHECK(tp);
-  std::string url_string(
-      frontend_url +
-      ((frontend_url.find("?") == std::string::npos) ? "?" : "&") +
-      "dockSide=undocked" + // TODO(dgozman): remove this support in M38.
-      "&toolbarColor=" +
-      SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
-      "&textColor=" +
-      SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)));
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableDevToolsExperiments))
-    url_string += "&experiments=true";
-#if defined(DEBUG_DEVTOOLS)
-  url_string += "&debugFrontend=true";
-#endif  // defined(DEBUG_DEVTOOLS)
-  return GURL(url_string);
-}
-
 DevToolsUIBindings::DevToolsUIBindings(content::WebContents* web_contents)
     : profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
       android_bridge_(DevToolsAndroidBridge::Factory::GetForProfile(profile_)),
@@ -434,11 +398,6 @@
   entry->GetFavicon().valid = true;
 
   // Register on-load actions.
-  registrar_.Add(
-      this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
-      content::Source<ThemeService>(
-          ThemeServiceFactory::GetForProfile(profile_)));
-
   embedder_message_dispatcher_.reset(
       DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this));
 
@@ -468,14 +427,6 @@
   instances->erase(it);
 }
 
-// content::NotificationObserver overrides ------------------------------------
-void DevToolsUIBindings::Observe(int type,
-                                 const content::NotificationSource& source,
-                                 const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
-  UpdateTheme();
-}
-
 // content::DevToolsFrontendHost::Delegate implementation ---------------------
 void DevToolsUIBindings::HandleMessageFromDevToolsFrontend(
     const std::string& message) {
@@ -945,18 +896,6 @@
       callback, message);
 }
 
-void DevToolsUIBindings::UpdateTheme() {
-  ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_);
-  DCHECK(tp);
-
-  std::string command("DevToolsAPI.setToolbarColors(\"" +
-      SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
-      "\", \"" +
-      SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) +
-      "\")");
-  web_contents_->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(command));
-}
-
 void DevToolsUIBindings::AddDevToolsExtensionsToClient() {
   const extensions::ExtensionRegistry* registry =
       extensions::ExtensionRegistry::Get(profile_->GetOriginalProfile());
@@ -1057,6 +996,5 @@
   // Call delegate first - it seeds importants bit of information.
   delegate_->OnLoadCompleted();
 
-  UpdateTheme();
   AddDevToolsExtensionsToClient();
 }
diff --git a/chrome/browser/devtools/devtools_ui_bindings.h b/chrome/browser/devtools/devtools_ui_bindings.h
index 060ac32..a705d7e 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.h
+++ b/chrome/browser/devtools/devtools_ui_bindings.h
@@ -19,8 +19,6 @@
 #include "chrome/browser/devtools/devtools_targets_ui.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/devtools_frontend_host.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -34,8 +32,7 @@
 }
 
 // Base implementation of DevTools bindings around front-end.
-class DevToolsUIBindings : public content::NotificationObserver,
-                           public content::DevToolsFrontendHost::Delegate,
+class DevToolsUIBindings :public content::DevToolsFrontendHost::Delegate,
                            public DevToolsEmbedderMessageDispatcher::Delegate,
                            public DevToolsAndroidBridge::DeviceCountListener,
                            public content::DevToolsAgentHostClient,
@@ -43,7 +40,6 @@
  public:
   static DevToolsUIBindings* ForWebContents(
       content::WebContents* web_contents);
-  static GURL ApplyThemeToURL(Profile* profile, const GURL& base_url);
 
   class Delegate {
    public:
@@ -81,10 +77,6 @@
   bool IsAttachedTo(content::DevToolsAgentHost* agent_host);
 
  private:
-  // content::NotificationObserver overrides.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
 
   // content::DevToolsFrontendHost::Delegate implementation.
   void HandleMessageFromDevToolsFrontend(const std::string& message) override;
@@ -188,8 +180,7 @@
   void ShowDevToolsConfirmInfoBar(const base::string16& message,
                                   const InfoBarCallback& callback);
 
-  // Theme and extensions support.
-  void UpdateTheme();
+  // Extensions support.
   void AddDevToolsExtensionsToClient();
 
   class FrontendWebContentsObserver;
@@ -201,7 +192,6 @@
   content::WebContents* web_contents_;
   scoped_ptr<Delegate> delegate_;
   scoped_refptr<content::DevToolsAgentHost> agent_host_;
-  content::NotificationRegistrar registrar_;
   scoped_ptr<content::DevToolsFrontendHost> frontend_host_;
   scoped_ptr<DevToolsFileHelper> file_helper_;
   scoped_refptr<DevToolsFileSystemIndexer> file_system_indexer_;
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index 04d9c806..76d1f609 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/command_line.h"
 #include "base/json/json_reader.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/scoped_user_pref_update.h"
@@ -171,6 +172,23 @@
     return browser->window();
   return NULL;
 }
+
+// static
+GURL DecorateFrontendURL(const GURL& base_url) {
+  std::string frontend_url = base_url.spec();
+  std::string url_string(
+      frontend_url +
+      ((frontend_url.find("?") == std::string::npos) ? "?" : "&") +
+      "dockSide=undocked"); // TODO(dgozman): remove this support in M38.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableDevToolsExperiments))
+    url_string += "&experiments=true";
+#if defined(DEBUG_DEVTOOLS)
+  url_string += "&debugFrontend=true";
+#endif  // defined(DEBUG_DEVTOOLS)
+  return GURL(url_string);
+}
+
 }  // namespace
 
 // DevToolsEventForwarder -----------------------------------------------------
@@ -732,7 +750,7 @@
   scoped_ptr<WebContents> main_web_contents(
       WebContents::Create(WebContents::CreateParams(profile)));
   main_web_contents->GetController().LoadURL(
-      DevToolsUIBindings::ApplyThemeToURL(profile, url), content::Referrer(),
+      DecorateFrontendURL(url), content::Referrer(),
       ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
   DevToolsUIBindings* bindings =
       DevToolsUIBindings::ForWebContents(main_web_contents.get());
diff --git a/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc b/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
index 7bdf935..942eddb0 100644
--- a/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
+++ b/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/guid.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/dom_distiller/dom_distiller_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -93,22 +94,19 @@
     command_line->AppendSwitch(switches::kEnableDomDistiller);
   }
 
-  static KeyedService* Build(content::BrowserContext* context) {
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* context) {
     FakeDB<ArticleEntry>* fake_db = new FakeDB<ArticleEntry>(database_model_);
     distiller_factory_ = new MockDistillerFactory();
     MockDistillerPageFactory* distiller_page_factory_ =
         new MockDistillerPageFactory();
-    DomDistillerContextKeyedService* service =
+    scoped_ptr<DomDistillerContextKeyedService> service(
         new DomDistillerContextKeyedService(
-            scoped_ptr<DomDistillerStoreInterface>(
-                CreateStoreWithFakeDB(fake_db,
-                                      FakeDB<ArticleEntry>::EntryMap())),
+            scoped_ptr<DomDistillerStoreInterface>(CreateStoreWithFakeDB(
+                fake_db, FakeDB<ArticleEntry>::EntryMap())),
             scoped_ptr<DistillerFactory>(distiller_factory_),
             scoped_ptr<DistillerPageFactory>(distiller_page_factory_),
-            scoped_ptr<DistilledPagePrefs>(
-                new DistilledPagePrefs(
-                      Profile::FromBrowserContext(
-                          context)->GetPrefs())));
+            scoped_ptr<DistilledPagePrefs>(new DistilledPagePrefs(
+                Profile::FromBrowserContext(context)->GetPrefs()))));
     fake_db->InitCallback(true);
     fake_db->LoadCallback(true);
     if (expect_distillation_) {
@@ -123,7 +121,7 @@
       EXPECT_CALL(*distiller_page_factory_, CreateDistillerPageImpl())
           .WillOnce(testing::Return(distiller_page));
     }
-    return service;
+    return service.Pass();
   }
 
   void ViewSingleDistilledPage(const GURL& url,
diff --git a/chrome/browser/download/download_extensions.cc b/chrome/browser/download/download_extensions.cc
index 623bdf4..df961a5 100644
--- a/chrome/browser/download/download_extensions.cc
+++ b/chrome/browser/download/download_extensions.cc
@@ -221,7 +221,7 @@
     ascii_extension.erase(0, 1);
 
   for (size_t i = 0; i < arraysize(g_executables); ++i) {
-    if (LowerCaseEqualsASCII(ascii_extension, g_executables[i].extension))
+    if (base::LowerCaseEqualsASCII(ascii_extension, g_executables[i].extension))
       return g_executables[i].level;
   }
   return NOT_DANGEROUS;
diff --git a/chrome/browser/download/download_service.cc b/chrome/browser/download/download_service.cc
index 4efd3c9..1ca08a8 100644
--- a/chrome/browser/download/download_service.cc
+++ b/chrome/browser/download/download_service.cc
@@ -1,118 +1,19 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "chrome/browser/download/download_service.h"
 
-#include "base/callback.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/download/chrome_download_manager_delegate.h"
-#include "chrome/browser/download/download_history.h"
 #include "chrome/browser/download/download_service_factory.h"
-#include "chrome/browser/download/download_status_updater.h"
-#include "chrome/browser/download/download_ui_controller.h"
-#include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/net/chrome_net_log.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "components/history/core/browser/history_service.h"
-#include "content/public/browser/download_manager.h"
 
-#if defined(ENABLE_EXTENSIONS)
-#include "chrome/browser/extensions/api/downloads/downloads_api.h"
-#endif
-
-using content::BrowserContext;
-using content::DownloadManager;
-using content::DownloadManagerDelegate;
-
-DownloadService::DownloadService(Profile* profile)
-    : download_manager_created_(false),
-      profile_(profile) {
+DownloadService::DownloadService() {
 }
 
 DownloadService::~DownloadService() {}
 
-ChromeDownloadManagerDelegate* DownloadService::GetDownloadManagerDelegate() {
-  DownloadManager* manager = BrowserContext::GetDownloadManager(profile_);
-  // If we've already created the delegate, just return it.
-  if (download_manager_created_) {
-    DCHECK(static_cast<DownloadManagerDelegate*>(manager_delegate_.get()) ==
-           manager->GetDelegate());
-    return manager_delegate_.get();
-  }
-  download_manager_created_ = true;
-
-  // In case the delegate has already been set by
-  // SetDownloadManagerDelegateForTesting.
-  if (!manager_delegate_.get())
-    manager_delegate_.reset(new ChromeDownloadManagerDelegate(profile_));
-
-  manager_delegate_->SetDownloadManager(manager);
-
-#if defined(ENABLE_EXTENSIONS)
-  extension_event_router_.reset(
-      new extensions::ExtensionDownloadsEventRouter(profile_, manager));
-#endif
-
-  if (!profile_->IsOffTheRecord()) {
-    history::HistoryService* history = HistoryServiceFactory::GetForProfile(
-        profile_, ServiceAccessType::EXPLICIT_ACCESS);
-    history->GetNextDownloadId(
-        manager_delegate_->GetDownloadIdReceiverCallback());
-    download_history_.reset(new DownloadHistory(
-        manager,
-        scoped_ptr<DownloadHistory::HistoryAdapter>(
-            new DownloadHistory::HistoryAdapter(history))));
-  }
-
-  // Pass an empty delegate when constructing the DownloadUIController. The
-  // default delegate does all the notifications we need.
-  download_ui_.reset(new DownloadUIController(
-      manager, scoped_ptr<DownloadUIController::Delegate>()));
-
-  // Include this download manager in the set monitored by the
-  // global status updater.
-  g_browser_process->download_status_updater()->AddManager(manager);
-
-  return manager_delegate_.get();
-}
-
-DownloadHistory* DownloadService::GetDownloadHistory() {
-  if (!download_manager_created_) {
-    GetDownloadManagerDelegate();
-  }
-  DCHECK(download_manager_created_);
-  return download_history_.get();
-}
-
-bool DownloadService::HasCreatedDownloadManager() {
-  return download_manager_created_;
-}
-
-int DownloadService::NonMaliciousDownloadCount() const {
-  if (!download_manager_created_)
-    return 0;
-  return BrowserContext::GetDownloadManager(profile_)->
-      NonMaliciousInProgressCount();
-}
-
-void DownloadService::CancelDownloads() {
-  if (!download_manager_created_)
-    return;
-
-  DownloadManager* download_manager =
-      BrowserContext::GetDownloadManager(profile_);
-  DownloadManager::DownloadVector downloads;
-  download_manager->GetAllDownloads(&downloads);
-  for (DownloadManager::DownloadVector::iterator it = downloads.begin();
-       it != downloads.end();
-       ++it) {
-    if ((*it)->GetState() == content::DownloadItem::IN_PROGRESS)
-      (*it)->Cancel(false);
-  }
-}
-
 // static
 int DownloadService::NonMaliciousDownloadCountAllProfiles() {
   std::vector<Profile*> profiles(
@@ -144,37 +45,3 @@
   }
 }
 
-void DownloadService::SetDownloadManagerDelegateForTesting(
-    scoped_ptr<ChromeDownloadManagerDelegate> new_delegate) {
-  manager_delegate_.swap(new_delegate);
-  DownloadManager* dm = BrowserContext::GetDownloadManager(profile_);
-  dm->SetDelegate(manager_delegate_.get());
-  manager_delegate_->SetDownloadManager(dm);
-  if (new_delegate)
-    new_delegate->Shutdown();
-}
-
-bool DownloadService::IsShelfEnabled() {
-#if defined(OS_ANDROID)
-  return true;
-#else
-  return !extension_event_router_ ||
-         extension_event_router_->IsShelfEnabled();
-#endif
-}
-
-void DownloadService::Shutdown() {
-  if (download_manager_created_) {
-    // Normally the DownloadManager would be shutdown later, after the Profile
-    // goes away and BrowserContext's destructor runs. But that would be too
-    // late for us since we need to use the profile (indirectly through history
-    // code) when the DownloadManager is shutting down. So we shut it down
-    // manually earlier. See http://crbug.com/131692
-    BrowserContext::GetDownloadManager(profile_)->Shutdown();
-  }
-#if defined(ENABLE_EXTENSIONS)
-  extension_event_router_.reset();
-#endif
-  manager_delegate_.reset();
-  download_history_.reset();
-}
diff --git a/chrome/browser/download/download_service.h b/chrome/browser/download/download_service.h
index ad6c745..b492ee9ae 100644
--- a/chrome/browser/download/download_service.h
+++ b/chrome/browser/download/download_service.h
@@ -5,14 +5,11 @@
 #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SERVICE_H_
 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SERVICE_H_
 
-#include "base/basictypes.h"
-#include "base/callback_forward.h"
 #include "base/memory/scoped_ptr.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 class ChromeDownloadManagerDelegate;
 class DownloadHistory;
-class DownloadUIController;
 class ExtensionDownloadsEventRouter;
 class Profile;
 
@@ -24,35 +21,35 @@
 class ExtensionDownloadsEventRouter;
 }
 
-// Owning class for ChromeDownloadManagerDelegate.
+// Abstract base class for the download service; see DownloadServiceImpl for
+// implementation.
 class DownloadService : public KeyedService {
  public:
-  explicit DownloadService(Profile* profile);
+  DownloadService();
   ~DownloadService() override;
 
   // Get the download manager delegate, creating it if it doesn't already exist.
-  ChromeDownloadManagerDelegate* GetDownloadManagerDelegate();
+  virtual ChromeDownloadManagerDelegate* GetDownloadManagerDelegate() = 0;
 
   // Get the interface to the history system. Returns NULL if profile is
   // incognito or if the DownloadManager hasn't been created yet or if there is
   // no HistoryService for profile. Virtual for testing.
-  virtual DownloadHistory* GetDownloadHistory();
+  virtual DownloadHistory* GetDownloadHistory() = 0;
 
 #if defined(ENABLE_EXTENSIONS)
-  extensions::ExtensionDownloadsEventRouter* GetExtensionEventRouter() {
-    return extension_event_router_.get();
-  }
+  virtual extensions::ExtensionDownloadsEventRouter*
+  GetExtensionEventRouter() = 0;
 #endif
 
   // Has a download manager been created?
-  bool HasCreatedDownloadManager();
+  virtual bool HasCreatedDownloadManager() = 0;
 
   // Number of non-malicious downloads associated with this instance of the
   // service.
-  int NonMaliciousDownloadCount() const;
+  virtual int NonMaliciousDownloadCount() const = 0;
 
   // Cancels all in-progress downloads for this profile.
-  void CancelDownloads();
+  virtual void CancelDownloads() = 0;
 
   // Number of non-malicious downloads associated with all profiles.
   static int NonMaliciousDownloadCountAllProfiles();
@@ -63,49 +60,14 @@
   // Sets the DownloadManagerDelegate associated with this object and
   // its DownloadManager.  Takes ownership of |delegate|, and destroys
   // the previous delegate.  For testing.
-  void SetDownloadManagerDelegateForTesting(
-      scoped_ptr<ChromeDownloadManagerDelegate> delegate);
-
-  // Will be called to release references on other services as part
-  // of Profile shutdown.
-  void Shutdown() override;
+  virtual void SetDownloadManagerDelegateForTesting(
+      scoped_ptr<ChromeDownloadManagerDelegate> delegate) = 0;
 
   // Returns false if at least one extension has disabled the shelf, true
   // otherwise.
-  bool IsShelfEnabled();
+  virtual bool IsShelfEnabled() = 0;
 
  private:
-  bool download_manager_created_;
-  Profile* profile_;
-
-  // ChromeDownloadManagerDelegate may be the target of callbacks from
-  // the history service/DB thread and must be kept alive for those
-  // callbacks.
-  scoped_ptr<ChromeDownloadManagerDelegate> manager_delegate_;
-
-  scoped_ptr<DownloadHistory> download_history_;
-
-  // The UI controller is responsible for observing the download manager and
-  // notifying the UI of any new downloads. Its lifetime matches that of the
-  // associated download manager.
-  // Note on destruction order: download_ui_ depends on download_history_ and
-  // should be destroyed before the latter.
-  scoped_ptr<DownloadUIController> download_ui_;
-
-  // On Android, GET downloads are not handled by the DownloadManager.
-  // Once we have extensions on android, we probably need the EventRouter
-  // in ContentViewDownloadDelegate which knows about both GET and POST
-  // downloads.
-#if defined(ENABLE_EXTENSIONS)
-  // The ExtensionDownloadsEventRouter dispatches download creation, change, and
-  // erase events to extensions. Like ChromeDownloadManagerDelegate, it's a
-  // chrome-level concept and its lifetime should match DownloadManager. There
-  // should be a separate EDER for on-record and off-record managers.
-  // There does not appear to be a separate ExtensionSystem for on-record and
-  // off-record profiles, so ExtensionSystem cannot own the EDER.
-  scoped_ptr<extensions::ExtensionDownloadsEventRouter> extension_event_router_;
-#endif
-
   DISALLOW_COPY_AND_ASSIGN(DownloadService);
 };
 
diff --git a/chrome/browser/download/download_service_factory.cc b/chrome/browser/download/download_service_factory.cc
index 6828dc7..fb0b919 100644
--- a/chrome/browser/download/download_service_factory.cc
+++ b/chrome/browser/download/download_service_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/download/download_service_factory.h"
 
-#include "chrome/browser/download/download_service.h"
+#include "chrome/browser/download/download_service_impl.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
@@ -35,7 +35,7 @@
 KeyedService* DownloadServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* profile) const {
   DownloadService* service =
-      new DownloadService(static_cast<Profile*>(profile));
+      new DownloadServiceImpl(static_cast<Profile*>(profile));
 
   // No need for initialization; initialization can be done on first
   // use of service.
diff --git a/chrome/browser/download/download_service_impl.cc b/chrome/browser/download/download_service_impl.cc
new file mode 100644
index 0000000..7d0aab0
--- /dev/null
+++ b/chrome/browser/download/download_service_impl.cc
@@ -0,0 +1,152 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/download/download_service_impl.h"
+
+#include "base/callback.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/chrome_download_manager_delegate.h"
+#include "chrome/browser/download/download_history.h"
+#include "chrome/browser/download/download_status_updater.h"
+#include "chrome/browser/download/download_ui_controller.h"
+#include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/net/chrome_net_log.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/history/core/browser/history_service.h"
+#include "content/public/browser/download_manager.h"
+
+#if defined(ENABLE_EXTENSIONS)
+#include "chrome/browser/extensions/api/downloads/downloads_api.h"
+#endif
+
+using content::BrowserContext;
+using content::DownloadManager;
+using content::DownloadManagerDelegate;
+
+DownloadServiceImpl::DownloadServiceImpl(Profile* profile)
+    : download_manager_created_(false), profile_(profile) {
+}
+
+DownloadServiceImpl::~DownloadServiceImpl() {
+}
+
+ChromeDownloadManagerDelegate*
+DownloadServiceImpl::GetDownloadManagerDelegate() {
+  DownloadManager* manager = BrowserContext::GetDownloadManager(profile_);
+  // If we've already created the delegate, just return it.
+  if (download_manager_created_) {
+    DCHECK(static_cast<DownloadManagerDelegate*>(manager_delegate_.get()) ==
+           manager->GetDelegate());
+    return manager_delegate_.get();
+  }
+  download_manager_created_ = true;
+
+  // In case the delegate has already been set by
+  // SetDownloadManagerDelegateForTesting.
+  if (!manager_delegate_.get())
+    manager_delegate_.reset(new ChromeDownloadManagerDelegate(profile_));
+
+  manager_delegate_->SetDownloadManager(manager);
+
+#if defined(ENABLE_EXTENSIONS)
+  extension_event_router_.reset(
+      new extensions::ExtensionDownloadsEventRouter(profile_, manager));
+#endif
+
+  if (!profile_->IsOffTheRecord()) {
+    history::HistoryService* history = HistoryServiceFactory::GetForProfile(
+        profile_, ServiceAccessType::EXPLICIT_ACCESS);
+    history->GetNextDownloadId(
+        manager_delegate_->GetDownloadIdReceiverCallback());
+    download_history_.reset(new DownloadHistory(
+        manager, scoped_ptr<DownloadHistory::HistoryAdapter>(
+                     new DownloadHistory::HistoryAdapter(history))));
+  }
+
+  // Pass an empty delegate when constructing the DownloadUIController. The
+  // default delegate does all the notifications we need.
+  download_ui_.reset(new DownloadUIController(
+      manager, scoped_ptr<DownloadUIController::Delegate>()));
+
+  // Include this download manager in the set monitored by the
+  // global status updater.
+  g_browser_process->download_status_updater()->AddManager(manager);
+
+  return manager_delegate_.get();
+}
+
+DownloadHistory* DownloadServiceImpl::GetDownloadHistory() {
+  if (!download_manager_created_) {
+    GetDownloadManagerDelegate();
+  }
+  DCHECK(download_manager_created_);
+  return download_history_.get();
+}
+
+#if defined(ENABLE_EXTENSIONS)
+extensions::ExtensionDownloadsEventRouter*
+DownloadServiceImpl::GetExtensionEventRouter() {
+  return extension_event_router_.get();
+}
+#endif
+
+bool DownloadServiceImpl::HasCreatedDownloadManager() {
+  return download_manager_created_;
+}
+
+int DownloadServiceImpl::NonMaliciousDownloadCount() const {
+  if (!download_manager_created_)
+    return 0;
+  return BrowserContext::GetDownloadManager(profile_)
+      ->NonMaliciousInProgressCount();
+}
+
+void DownloadServiceImpl::CancelDownloads() {
+  if (!download_manager_created_)
+    return;
+
+  DownloadManager* download_manager =
+      BrowserContext::GetDownloadManager(profile_);
+  DownloadManager::DownloadVector downloads;
+  download_manager->GetAllDownloads(&downloads);
+  for (DownloadManager::DownloadVector::iterator it = downloads.begin();
+       it != downloads.end(); ++it) {
+    if ((*it)->GetState() == content::DownloadItem::IN_PROGRESS)
+      (*it)->Cancel(false);
+  }
+}
+
+void DownloadServiceImpl::SetDownloadManagerDelegateForTesting(
+    scoped_ptr<ChromeDownloadManagerDelegate> new_delegate) {
+  manager_delegate_.swap(new_delegate);
+  DownloadManager* dm = BrowserContext::GetDownloadManager(profile_);
+  dm->SetDelegate(manager_delegate_.get());
+  manager_delegate_->SetDownloadManager(dm);
+  if (new_delegate)
+    new_delegate->Shutdown();
+}
+
+bool DownloadServiceImpl::IsShelfEnabled() {
+#if defined(OS_ANDROID)
+  return true;
+#else
+  return !extension_event_router_ || extension_event_router_->IsShelfEnabled();
+#endif
+}
+
+void DownloadServiceImpl::Shutdown() {
+  if (download_manager_created_) {
+    // Normally the DownloadManager would be shutdown later, after the Profile
+    // goes away and BrowserContext's destructor runs. But that would be too
+    // late for us since we need to use the profile (indirectly through history
+    // code) when the DownloadManager is shutting down. So we shut it down
+    // manually earlier. See http://crbug.com/131692
+    BrowserContext::GetDownloadManager(profile_)->Shutdown();
+  }
+#if defined(ENABLE_EXTENSIONS)
+  extension_event_router_.reset();
+#endif
+  manager_delegate_.reset();
+  download_history_.reset();
+}
diff --git a/chrome/browser/download/download_service_impl.h b/chrome/browser/download/download_service_impl.h
new file mode 100644
index 0000000..21eb635
--- /dev/null
+++ b/chrome/browser/download/download_service_impl.h
@@ -0,0 +1,85 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SERVICE_IMPL_H_
+#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SERVICE_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/download/download_service.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+class ChromeDownloadManagerDelegate;
+class DownloadHistory;
+class DownloadUIController;
+class ExtensionDownloadsEventRouter;
+class Profile;
+
+namespace content {
+class DownloadManager;
+}
+
+namespace extensions {
+class ExtensionDownloadsEventRouter;
+}
+
+// Owning class for ChromeDownloadManagerDelegate.
+class DownloadServiceImpl : public DownloadService {
+ public:
+  explicit DownloadServiceImpl(Profile* profile);
+  ~DownloadServiceImpl() override;
+
+  // DownloadService
+  ChromeDownloadManagerDelegate* GetDownloadManagerDelegate() override;
+  DownloadHistory* GetDownloadHistory() override;
+#if defined(ENABLE_EXTENSIONS)
+  extensions::ExtensionDownloadsEventRouter* GetExtensionEventRouter() override;
+#endif
+  bool HasCreatedDownloadManager() override;
+  int NonMaliciousDownloadCount() const override;
+  void CancelDownloads() override;
+  void SetDownloadManagerDelegateForTesting(
+      scoped_ptr<ChromeDownloadManagerDelegate> delegate) override;
+  bool IsShelfEnabled() override;
+
+  // KeyedService
+  void Shutdown() override;
+
+ private:
+  bool download_manager_created_;
+  Profile* profile_;
+
+  // ChromeDownloadManagerDelegate may be the target of callbacks from
+  // the history service/DB thread and must be kept alive for those
+  // callbacks.
+  scoped_ptr<ChromeDownloadManagerDelegate> manager_delegate_;
+
+  scoped_ptr<DownloadHistory> download_history_;
+
+  // The UI controller is responsible for observing the download manager and
+  // notifying the UI of any new downloads. Its lifetime matches that of the
+  // associated download manager.
+  // Note on destruction order: download_ui_ depends on download_history_ and
+  // should be destroyed before the latter.
+  scoped_ptr<DownloadUIController> download_ui_;
+
+// On Android, GET downloads are not handled by the DownloadManager.
+// Once we have extensions on android, we probably need the EventRouter
+// in ContentViewDownloadDelegate which knows about both GET and POST
+// downloads.
+#if defined(ENABLE_EXTENSIONS)
+  // The ExtensionDownloadsEventRouter dispatches download creation, change, and
+  // erase events to extensions. Like ChromeDownloadManagerDelegate, it's a
+  // chrome-level concept and its lifetime should match DownloadManager. There
+  // should be a separate EDER for on-record and off-record managers.
+  // There does not appear to be a separate ExtensionSystem for on-record and
+  // off-record profiles, so ExtensionSystem cannot own the EDER.
+  scoped_ptr<extensions::ExtensionDownloadsEventRouter> extension_event_router_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadServiceImpl);
+};
+
+#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SERVICE_IMPL_H_
diff --git a/chrome/browser/download/download_shelf_unittest.cc b/chrome/browser/download/download_shelf_unittest.cc
index 6311536..f54faffd 100644
--- a/chrome/browser/download/download_shelf_unittest.cc
+++ b/chrome/browser/download/download_shelf_unittest.cc
@@ -8,8 +8,8 @@
 #include "base/run_loop.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/download/download_item_model.h"
-#include "chrome/browser/download/download_service.h"
 #include "chrome/browser/download/download_service_factory.h"
+#include "chrome/browser/download/download_service_impl.h"
 #include "chrome/browser/download/test_download_shelf.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/notification_service.h"
@@ -28,10 +28,6 @@
 
 namespace {
 
-KeyedService* CreateDownloadService(content::BrowserContext* context) {
-  return new DownloadService(Profile::FromBrowserContext(context));
-}
-
 class DownloadShelfTest : public testing::Test {
  public:
   DownloadShelfTest();
@@ -49,13 +45,9 @@
   Profile* profile() { return profile_.get(); }
 
   void SetUp() override {
-    DownloadServiceFactory::GetInstance()->SetTestingFactory(
-        profile(), &CreateDownloadService);
   }
 
   void TearDown() override {
-    DownloadServiceFactory::GetInstance()->SetTestingFactory(
-        profile(), NULL);
   }
 
  private:
diff --git a/chrome/browser/download/download_ui_controller_unittest.cc b/chrome/browser/download/download_ui_controller_unittest.cc
index d29878d44..04fc1f9b 100644
--- a/chrome/browser/download/download_ui_controller_unittest.cc
+++ b/chrome/browser/download/download_ui_controller_unittest.cc
@@ -10,8 +10,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/download/download_history.h"
-#include "chrome/browser/download/download_service.h"
 #include "chrome/browser/download/download_service_factory.h"
+#include "chrome/browser/download/download_service_impl.h"
 #include "chrome/browser/download/download_ui_controller.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -56,7 +56,7 @@
 }
 
 // A DownloadService that returns a custom DownloadHistory.
-class TestDownloadService : public DownloadService {
+class TestDownloadService : public DownloadServiceImpl {
  public:
   explicit TestDownloadService(Profile* profile);
   ~TestDownloadService() override;
@@ -71,7 +71,7 @@
 };
 
 TestDownloadService::TestDownloadService(Profile* profile)
-    : DownloadService(profile) {
+    : DownloadServiceImpl(profile) {
 }
 
 TestDownloadService::~TestDownloadService() {
@@ -135,7 +135,7 @@
   };
 
   // Constructs and returns a TestDownloadService.
-  static KeyedService* TestingDownloadServiceFactory(
+  static scoped_ptr<KeyedService> TestingDownloadServiceFactory(
       content::BrowserContext* browser_context);
 
   scoped_ptr<MockDownloadManager> manager_;
@@ -148,9 +148,11 @@
 };
 
 // static
-KeyedService* DownloadUIControllerTest::TestingDownloadServiceFactory(
+scoped_ptr<KeyedService>
+DownloadUIControllerTest::TestingDownloadServiceFactory(
     content::BrowserContext* browser_context) {
-  return new TestDownloadService(Profile::FromBrowserContext(browser_context));
+  return make_scoped_ptr(
+      new TestDownloadService(Profile::FromBrowserContext(browser_context)));
 }
 
 DownloadUIControllerTest::DownloadUIControllerTest()
diff --git a/chrome/browser/drive/drive_uploader.cc b/chrome/browser/drive/drive_uploader.cc
index f15d9c2..e267d24 100644
--- a/chrome/browser/drive/drive_uploader.cc
+++ b/chrome/browser/drive/drive_uploader.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_util.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task_runner_util.h"
 #include "chrome/browser/drive/drive_service_interface.h"
@@ -42,6 +43,20 @@
 // Maximum file size to be uploaded by multipart requests. The file that is
 // larger than the size is processed by resumable upload.
 const int64 kMaxMultipartUploadSize = (1LL << 20);  // 1MB
+
+// Drive upload protocol. This is used to back a histogram. Sync this with UMA
+// enum "DriveUploadProtocol" and treat this as append-only.
+enum DriveUploadProtocol {
+  UPLOAD_METHOD_RESUMABLE,
+  UPLOAD_METHOD_MULTIPART,
+  UPLOAD_METHOD_BATCH,
+  UPLOAD_METHOD_MAX_VALUE
+};
+
+void RecordDriveUploadProtocol(DriveUploadProtocol protocol) {
+  UMA_HISTOGRAM_ENUMERATION(
+      "Drive.UploadProtocol", protocol, UPLOAD_METHOD_MAX_VALUE);
+}
 }  // namespace
 
 // Refcounted helper class to manage batch request. DriveUploader uses the class
@@ -283,10 +298,15 @@
 
   UploadFileInfo* const info_ptr = upload_file_info.get();
   if (info_ptr->content_length <= kMaxMultipartUploadSize) {
-    DriveServiceBatchOperationsInterface* service = drive_service_;
+    DriveServiceBatchOperationsInterface* service;
     // If this is a batched request, calls the API on the request instead.
-    if (batch_request.get())
+    if (batch_request.get()) {
       service = batch_request->configurator();
+      RecordDriveUploadProtocol(UPLOAD_METHOD_BATCH);
+    } else {
+      service = drive_service_;
+      RecordDriveUploadProtocol(UPLOAD_METHOD_MULTIPART);
+    }
     info_ptr->cancel_callback = service->MultipartUploadNewFile(
         info_ptr->content_type, info_ptr->content_length, parent_resource_id,
         title, info_ptr->file_path, options,
@@ -295,6 +315,7 @@
                    base::Passed(&upload_file_info)),
         info_ptr->progress_callback);
   } else {
+    RecordDriveUploadProtocol(UPLOAD_METHOD_RESUMABLE);
     info_ptr->cancel_callback = drive_service_->InitiateUploadNewFile(
         info_ptr->content_type, info_ptr->content_length, parent_resource_id,
         title, options, base::Bind(&DriveUploader::OnUploadLocationReceived,
@@ -312,10 +333,15 @@
 
   UploadFileInfo* const info_ptr = upload_file_info.get();
   if (info_ptr->content_length <= kMaxMultipartUploadSize) {
-    DriveServiceBatchOperationsInterface* service = drive_service_;
+    DriveServiceBatchOperationsInterface* service;
     // If this is a batched request, calls the API on the request instead.
-    if (batch_request.get())
+    if (batch_request.get()) {
       service = batch_request->configurator();
+      RecordDriveUploadProtocol(UPLOAD_METHOD_BATCH);
+    } else {
+      service = drive_service_;
+      RecordDriveUploadProtocol(UPLOAD_METHOD_MULTIPART);
+    }
     info_ptr->cancel_callback = service->MultipartUploadExistingFile(
         info_ptr->content_type, info_ptr->content_length, resource_id,
         info_ptr->file_path, options,
@@ -324,6 +350,7 @@
                    base::Passed(&upload_file_info)),
         info_ptr->progress_callback);
   } else {
+    RecordDriveUploadProtocol(UPLOAD_METHOD_RESUMABLE);
     info_ptr->cancel_callback = drive_service_->InitiateUploadExistingFile(
         info_ptr->content_type, info_ptr->content_length, resource_id, options,
         base::Bind(&DriveUploader::OnUploadLocationReceived,
diff --git a/chrome/browser/enhanced_bookmarks/android/bookmark_image_service_android.cc b/chrome/browser/enhanced_bookmarks/android/bookmark_image_service_android.cc
index 5f8bd9c..4a72c9f 100644
--- a/chrome/browser/enhanced_bookmarks/android/bookmark_image_service_android.cc
+++ b/chrome/browser/enhanced_bookmarks/android/bookmark_image_service_android.cc
@@ -274,8 +274,9 @@
   update_bookmark_ = update_bookmark;
   page_url_ = page_url;
 
-  bitmap_fetcher_.Start(browser_context->GetRequestContext(), referrer,
-                        referrer_policy, load_flags);
+  bitmap_fetcher_.Init(browser_context->GetRequestContext(), referrer,
+                       referrer_policy, load_flags);
+  bitmap_fetcher_.Start();
 }
 
 void BookmarkImageServiceAndroid::BitmapFetcherHandler::OnFetchComplete(
diff --git a/chrome/browser/enumerate_modules_model_win.cc b/chrome/browser/enumerate_modules_model_win.cc
index 15c53dc..4a23e1ddf 100644
--- a/chrome/browser/enumerate_modules_model_win.cc
+++ b/chrome/browser/enumerate_modules_model_win.cc
@@ -690,7 +690,7 @@
   for (PathMapping::const_iterator mapping = path_mapping_.begin();
        mapping != path_mapping_.end(); ++mapping) {
     base::string16 prefix = mapping->first;
-    if (StartsWith(location, prefix, false)) {
+    if (base::StartsWith(location, prefix, false)) {
       base::string16 new_location = mapping->second +
                               location.substr(prefix.length() - 1);
       size_t length = new_location.length() - mapping->second.length();
@@ -734,8 +734,8 @@
     // for blacklisting individually. Mark them as suspicious if we haven't
     // classified them as bad yet.
     if (module->status == NOT_MATCHED || module->status == GOOD) {
-      if (StartsWith(module->location, L"%temp%", false) ||
-          StartsWith(module->location, L"%tmp%", false)) {
+      if (base::StartsWith(module->location, L"%temp%", false) ||
+          base::StartsWith(module->location, L"%tmp%", false)) {
         module->status = SUSPECTED_BAD;
       }
     }
diff --git a/chrome/browser/extensions/active_script_controller_unittest.cc b/chrome/browser/extensions/active_script_controller_unittest.cc
index 3f191ade..497077d 100644
--- a/chrome/browser/extensions/active_script_controller_unittest.cc
+++ b/chrome/browser/extensions/active_script_controller_unittest.cc
@@ -32,11 +32,6 @@
 
 const char kAllHostsPermission[] = "*://*/*";
 
-// We skip syncing for testing purposes.
-KeyedService* BuildSyncService(content::BrowserContext* context) {
-  return nullptr;
-}
-
 }  // namespace
 
 // Unittests for the ActiveScriptController mostly test the internal logic
@@ -169,8 +164,9 @@
 void ActiveScriptControllerUnitTest::SetUp() {
   ChromeRenderViewHostTestHarness::SetUp();
 
-  ExtensionSyncServiceFactory::GetInstance()->SetTestingFactory(
-      profile(), &BuildSyncService);
+  // Skip syncing for testing purposes.
+  ExtensionSyncServiceFactory::GetInstance()->SetTestingFactory(profile(),
+                                                                nullptr);
 
   TabHelper::CreateForWebContents(web_contents());
   TabHelper* tab_helper = TabHelper::FromWebContents(web_contents());
diff --git a/chrome/browser/extensions/activity_log/activity_actions.cc b/chrome/browser/extensions/activity_log/activity_actions.cc
index b22d4347..6d6db0d 100644
--- a/chrome/browser/extensions/activity_log/activity_actions.cc
+++ b/chrome/browser/extensions/activity_log/activity_actions.cc
@@ -191,7 +191,8 @@
 }
 
 void Action::ParsePageUrl(const std::string& url) {
-  set_page_incognito(StartsWithASCII(url, constants::kIncognitoUrl, true));
+  set_page_incognito(
+      base::StartsWithASCII(url, constants::kIncognitoUrl, true));
   if (page_incognito())
     set_page_url(GURL(url.substr(strlen(constants::kIncognitoUrl))));
   else
@@ -203,7 +204,7 @@
 }
 
 void Action::ParseArgUrl(const std::string& url) {
-  set_arg_incognito(StartsWithASCII(url, constants::kIncognitoUrl, true));
+  set_arg_incognito(base::StartsWithASCII(url, constants::kIncognitoUrl, true));
   if (arg_incognito())
     set_arg_url(GURL(url.substr(strlen(constants::kIncognitoUrl))));
   else
diff --git a/chrome/browser/extensions/activity_log/activity_log.cc b/chrome/browser/extensions/activity_log/activity_log.cc
index 9963a2572..6a8263c7 100644
--- a/chrome/browser/extensions/activity_log/activity_log.cc
+++ b/chrome/browser/extensions/activity_log/activity_log.cc
@@ -521,7 +521,7 @@
 
   // Mark DOM XHR requests as such, for easier processing later.
   if (action->action_type() == Action::ACTION_DOM_ACCESS &&
-      StartsWithASCII(action->api_name(), kDomXhrPrefix, true) &&
+      base::StartsWithASCII(action->api_name(), kDomXhrPrefix, true) &&
       action->other()) {
     base::DictionaryValue* other = action->mutable_other();
     int dom_verb = -1;
diff --git a/chrome/browser/extensions/activity_log/activity_log_browsertest.cc b/chrome/browser/extensions/activity_log/activity_log_browsertest.cc
index b4410f11..41fb708 100644
--- a/chrome/browser/extensions/activity_log/activity_log_browsertest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_browsertest.cc
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
@@ -38,7 +41,7 @@
       uint16 port,
       scoped_ptr<std::vector<scoped_refptr<Action> > > i) {
     // This is to exit RunLoop (base::MessageLoop::current()->Run()) below
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::MessageLoop::QuitClosure());
 
     ASSERT_TRUE(i->size());
diff --git a/chrome/browser/extensions/activity_log/counting_policy_unittest.cc b/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
index e52a03c..45ac541 100644
--- a/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
+++ b/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
@@ -4,13 +4,16 @@
 
 #include "base/cancelable_callback.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/simple_test_clock.h"
 #include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/activity_log/counting_policy.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -113,7 +116,7 @@
     // when the timeout triggers then assume that the test is broken.
     base::CancelableClosure timeout(
         base::Bind(&CountingPolicyTest::TimeoutCallback));
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, timeout.callback(), TestTimeouts::action_timeout());
 
     // Wait for results; either the checker or the timeout callbacks should
diff --git a/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc b/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
index 47e9e7e..a96d0d3 100644
--- a/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
+++ b/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
@@ -4,12 +4,15 @@
 
 #include "base/cancelable_callback.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/simple_test_clock.h"
 #include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -103,7 +106,7 @@
     // when the timeout triggers then assume that the test is broken.
     base::CancelableClosure timeout(
         base::Bind(&FullStreamUIPolicyTest::TimeoutCallback));
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, timeout.callback(), TestTimeouts::action_timeout());
 
     // Wait for results; either the checker or the timeout callbacks should
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc b/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc
index 126ce54..351e9ae 100644
--- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc
+++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc
@@ -13,6 +13,10 @@
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 
+#if defined(OS_MACOSX)
+#include "base/mac/mac_util.h"
+#endif
+
 using net::test_server::BasicHttpResponse;
 using net::test_server::HttpResponse;
 using net::test_server::HttpRequest;
@@ -56,6 +60,12 @@
 // The test extension sends a message to its 'friend'. The test completes
 // if it successfully sees the 'friend' receive the message.
 IN_PROC_BROWSER_TEST_F(ActivityLogApiTest, MAYBE_TriggerEvent) {
+#if defined(OS_MACOSX)
+  if (base::mac::IsOSSnowLeopard()) {
+    // This test flakes on 10.6 only. http://crbug.com/499176
+    return;
+  }
+#endif
   ActivityLog::GetInstance(profile())->SetWatchdogAppActiveForTesting(true);
 
   host_resolver()->AddRule("*", "127.0.0.1");
diff --git a/chrome/browser/extensions/api/audio_modem/audio_modem_api_unittest.cc b/chrome/browser/extensions/api/audio_modem/audio_modem_api_unittest.cc
index 3728e67..f2cd614 100644
--- a/chrome/browser/extensions/api/audio_modem/audio_modem_api_unittest.cc
+++ b/chrome/browser/extensions/api/audio_modem/audio_modem_api_unittest.cc
@@ -47,13 +47,13 @@
 std::map<BrowserContext*, StubModem*> g_modems;
 
 // Create a test AudioModemAPI and store the modem it uses.
-KeyedService* ApiFactoryFunction(BrowserContext* context) {
+scoped_ptr<KeyedService> ApiFactoryFunction(BrowserContext* context) {
   StubModem* modem = new StubModem;
   g_modems[context] = modem;
-  return new AudioModemAPI(
+  return make_scoped_ptr(new AudioModemAPI(
       context,
       make_scoped_ptr<audio_modem::WhispernetClient>(new StubWhispernetClient),
-      make_scoped_ptr<audio_modem::Modem>(modem));
+      make_scoped_ptr<audio_modem::Modem>(modem)));
 }
 
 DictionaryValue* CreateParams(const std::string& audio_band) {
@@ -131,8 +131,9 @@
 };
 
 // StubEventRouter factory function
-KeyedService* StubEventRouterFactoryFunction(content::BrowserContext* context) {
-  return new StubEventRouter(context);
+scoped_ptr<KeyedService> StubEventRouterFactoryFunction(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(new StubEventRouter(context));
 }
 
 }  // namespace
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc
index 42199e3..e3c1aff 100644
--- a/chrome/browser/extensions/api/automation/automation_apitest.cc
+++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -3,8 +3,11 @@
 // found in the LICENSE file.
 
 #include "base/files/file_path.h"
+#include "base/location.h"
 #include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/api/automation_internal/automation_util.h"
 #include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -368,27 +371,25 @@
     using api::automation_internal::EnableTab::Params;
     scoped_ptr<Params> params(Params::Create(*args_));
     EXTENSION_FUNCTION_VALIDATE(params.get());
-    if (!params->tab_id.get())
+    if (!params->args.tab_id.get())
       return RespondNow(Error("tab_id not specified"));
-    int tab_id = *params->tab_id;
+    int tab_id = *params->args.tab_id;
     if (tab_id == 0) {
       // tab 0 <--> tree0
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&TreeSerializationState::InitializeTree0,
-                     base::Unretained(&state),
-                     base::Unretained(browser_context())));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&TreeSerializationState::InitializeTree0,
+                                base::Unretained(&state),
+                                base::Unretained(browser_context())));
       // TODO(aboxhall): Need to rewrite this test in terms of tree ids.
       return RespondNow(ArgumentList(
           api::automation_internal::EnableTab::Results::Create(0)));
     }
     if (tab_id == 1) {
       // tab 1 <--> tree1
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&TreeSerializationState::InitializeTree1,
-                     base::Unretained(&state),
-                     base::Unretained(browser_context())));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&TreeSerializationState::InitializeTree1,
+                                base::Unretained(&state),
+                                base::Unretained(browser_context())));
       return RespondNow(ArgumentList(
           api::automation_internal::EnableTab::Results::Create(0)));
     }
diff --git a/chrome/browser/extensions/api/automation_internal/automation_event_router.cc b/chrome/browser/extensions/api/automation_internal/automation_event_router.cc
new file mode 100644
index 0000000..5dee32f
--- /dev/null
+++ b/chrome/browser/extensions/api/automation_internal/automation_event_router.cc
@@ -0,0 +1,139 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "chrome/browser/accessibility/ax_tree_id_registry.h"
+#include "chrome/common/extensions/api/automation_internal.h"
+#include "chrome/common/extensions/chrome_extension_messages.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
+#include "extensions/browser/event_router.h"
+#include "ui/accessibility/ax_enums.h"
+#include "ui/accessibility/ax_node_data.h"
+
+namespace extensions {
+
+// static
+AutomationEventRouter* AutomationEventRouter::GetInstance() {
+  return Singleton<AutomationEventRouter,
+                   LeakySingletonTraits<AutomationEventRouter>>::get();
+}
+
+AutomationEventRouter::AutomationEventRouter() {
+  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+}
+
+AutomationEventRouter::~AutomationEventRouter() {
+}
+
+void AutomationEventRouter::RegisterListenerForOneTree(
+    int listener_process_id,
+    int listener_routing_id,
+    int source_ax_tree_id) {
+  Register(listener_process_id, listener_routing_id, source_ax_tree_id, false);
+}
+
+void AutomationEventRouter::RegisterListenerWithDesktopPermission(
+    int listener_process_id,
+    int listener_routing_id) {
+  Register(listener_process_id, listener_routing_id, 0, true);
+}
+
+void AutomationEventRouter::DispatchAccessibilityEvent(
+    const ExtensionMsg_AccessibilityEventParams& params) {
+  for (const auto& listener : listeners_) {
+    if (!listener.desktop &&
+        listener.tree_ids.find(params.tree_id) == listener.tree_ids.end()) {
+      continue;
+    }
+
+    content::RenderProcessHost* rph =
+        content::RenderProcessHost::FromID(listener.process_id);
+    rph->Send(new ExtensionMsg_AccessibilityEvent(listener.routing_id, params));
+  }
+}
+
+void AutomationEventRouter::DispatchTreeDestroyedEvent(
+    int tree_id,
+    content::BrowserContext* browser_context) {
+  std::string event_name(
+      api::automation_internal::OnAccessibilityTreeDestroyed::kEventName);
+  scoped_ptr<base::ListValue> args(
+      api::automation_internal::OnAccessibilityTreeDestroyed::Create(tree_id));
+  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
+  event->restrict_to_browser_context = browser_context;
+  EventRouter::Get(browser_context)->BroadcastEvent(event.Pass());
+}
+
+AutomationEventRouter::AutomationListener::AutomationListener() {
+}
+
+AutomationEventRouter::AutomationListener::~AutomationListener() {
+}
+
+void AutomationEventRouter::Register(
+    int listener_process_id,
+    int listener_routing_id,
+    int ax_tree_id,
+    bool desktop) {
+  auto iter = std::find_if(
+      listeners_.begin(),
+      listeners_.end(),
+      [listener_process_id, listener_routing_id](AutomationListener& item) {
+        return (item.process_id == listener_process_id &&
+                item.routing_id == listener_routing_id);
+      });
+
+  // Add a new entry if we don't have one with that process and routing id.
+  if (iter == listeners_.end()) {
+    AutomationListener listener;
+    listener.routing_id = listener_routing_id;
+    listener.process_id = listener_process_id;
+    listener.desktop = desktop;
+    listener.tree_ids.insert(ax_tree_id);
+    listeners_.push_back(listener);
+    return;
+  }
+
+  // We have an entry with that process and routing id, so update the set of
+  // tree ids it wants to listen to, and update its desktop permission.
+  iter->tree_ids.insert(ax_tree_id);
+  if (desktop)
+    iter->desktop = true;
+}
+
+void AutomationEventRouter::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  if (type != content::NOTIFICATION_RENDERER_PROCESS_TERMINATED &&
+      type != content::NOTIFICATION_RENDERER_PROCESS_CLOSED) {
+    NOTREACHED();
+    return;
+  }
+
+  content::RenderProcessHost* rph =
+      content::Source<content::RenderProcessHost>(source).ptr();
+  int process_id = rph->GetID();
+  std::remove_if(
+      listeners_.begin(),
+      listeners_.end(),
+      [process_id](AutomationListener& item) {
+        return item.process_id = process_id;
+      });
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/automation_internal/automation_event_router.h b/chrome/browser/extensions/api/automation_internal/automation_event_router.h
new file mode 100644
index 0000000..1389b432
--- /dev/null
+++ b/chrome/browser/extensions/api/automation_internal/automation_event_router.h
@@ -0,0 +1,89 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
+
+#include <vector>
+
+#include "base/memory/singleton.h"
+#include "chrome/common/extensions/api/automation_internal.h"
+#include "content/public/browser/ax_event_notification_details.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "extensions/common/extension.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+struct ExtensionMsg_AccessibilityEventParams;
+
+namespace extensions {
+
+struct AutomationListener;
+
+class AutomationEventRouter : public content::NotificationObserver {
+ public:
+  static AutomationEventRouter* GetInstance();
+
+  // Indicates that the listener at |listener_process_id|, |listener_routing_id|
+  // wants to receive automation events from the accessibility tree indicated
+  // by |source_ax_tree_id|. Automation events are forwarded from now on
+  // until the listener process dies.
+  void RegisterListenerForOneTree(int listener_process_id,
+                                  int listener_routing_id,
+                                  int source_ax_tree_id);
+
+  // Indicates that the listener at |listener_process_id|, |listener_routing_id|
+  // wants to receive automation events from all accessibility trees because
+  // it has Desktop permission.
+  void RegisterListenerWithDesktopPermission(int listener_process_id,
+                                             int listener_routing_id);
+
+  void DispatchAccessibilityEvent(
+      const ExtensionMsg_AccessibilityEventParams& params);
+
+  // Notify all automation extensions that an accessibility tree was
+  // destroyed. If |browser_context| is null,
+  void DispatchTreeDestroyedEvent(
+      int tree_id,
+      content::BrowserContext* browser_context);
+
+ private:
+  struct AutomationListener {
+    AutomationListener();
+    ~AutomationListener();
+
+    int routing_id;
+    int process_id;
+    bool desktop;
+    std::set<int> tree_ids;
+  };
+
+  AutomationEventRouter();
+  ~AutomationEventRouter() override;
+
+  void Register(
+      int listener_process_id,
+      int listener_routing_id,
+      int source_ax_tree_id,
+      bool desktop);
+
+  // content::NotificationObserver interface.
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
+  content::NotificationRegistrar registrar_;
+  std::vector<AutomationListener> listeners_;
+
+  friend struct DefaultSingletonTraits<AutomationEventRouter>;
+
+  DISALLOW_COPY_AND_ASSIGN(AutomationEventRouter);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
index 784b11c..5f2e8c8 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
+++ b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
@@ -11,6 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/accessibility/ax_tree_id_registry.h"
 #include "chrome/browser/extensions/api/automation_internal/automation_action_adapter.h"
+#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
 #include "chrome/browser/extensions/api/automation_internal/automation_util.h"
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
@@ -18,6 +19,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/extensions/api/automation_internal.h"
+#include "chrome/common/extensions/chrome_extension_messages.h"
 #include "chrome/common/extensions/manifest_handlers/automation.h"
 #include "content/public/browser/ax_event_notification_details.h"
 #include "content/public/browser/browser_accessibility_state.h"
@@ -226,8 +228,8 @@
   scoped_ptr<Params> params(Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
   content::WebContents* contents = NULL;
-  if (params->tab_id.get()) {
-    int tab_id = *params->tab_id;
+  if (params->args.tab_id.get()) {
+    int tab_id = *params->args.tab_id;
     if (!ExtensionTabUtil::GetTabById(tab_id,
                                       GetProfile(),
                                       include_incognito(),
@@ -251,10 +253,18 @@
     return RespondNow(
         Error(kCannotRequestAutomationOnPage, contents->GetURL().spec()));
   }
+
   AutomationWebContentsObserver::CreateForWebContents(contents);
   contents->EnableTreeOnlyAccessibilityMode();
   int ax_tree_id = AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID(
       rfh->GetProcess()->GetID(), rfh->GetRoutingID());
+
+  // This gets removed when the extension process dies.
+  AutomationEventRouter::GetInstance()->RegisterListenerForOneTree(
+      source_process_id(),
+      params->args.routing_id,
+      ax_tree_id);
+
   return RespondNow(ArgumentList(
       api::automation_internal::EnableTab::Results::Create(ax_tree_id)));
 }
@@ -359,6 +369,15 @@
   if (!automation_info || !automation_info->desktop)
     return RespondNow(Error("desktop permission must be requested"));
 
+  using api::automation_internal::EnableDesktop::Params;
+  scoped_ptr<Params> params(Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  // This gets removed when the extension process dies.
+  AutomationEventRouter::GetInstance()->RegisterListenerWithDesktopPermission(
+      source_process_id(),
+      params->routing_id);
+
   AutomationManagerAura::GetInstance()->Enable(browser_context());
   return RespondNow(NoArguments());
 #else
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
index 52cd9113..31a04f4 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
@@ -416,12 +416,15 @@
 }
 
 bool BookmarkManagerPrivateCanPasteFunction::RunOnReady() {
-  if (!EditBookmarksEnabled())
-    return false;
-
   scoped_ptr<CanPaste::Params> params(CanPaste::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
+  PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile());
+  if (!prefs->GetBoolean(bookmarks::prefs::kEditBookmarksEnabled)) {
+    SetResult(new base::FundamentalValue(false));
+    return true;
+  }
+
   BookmarkModel* model = BookmarkModelFactory::GetForProfile(GetProfile());
   const BookmarkNode* parent_node = GetNodeFromString(model, params->parent_id);
   if (!parent_node) {
@@ -545,8 +548,7 @@
   WebContents* web_contents =
       WebContents::FromRenderViewHost(render_view_host_);
   if (GetViewType(web_contents) == VIEW_TYPE_TAB_CONTENTS) {
-    WebContents* web_contents =
-        dispatcher()->delegate()->GetAssociatedWebContents();
+    WebContents* web_contents = GetAssociatedWebContents();
     CHECK(web_contents);
 
     ui::DragDropTypes::DragEventSource source =
@@ -586,8 +588,7 @@
   WebContents* web_contents =
       WebContents::FromRenderViewHost(render_view_host_);
   if (GetViewType(web_contents) == VIEW_TYPE_TAB_CONTENTS) {
-    WebContents* web_contents =
-        dispatcher()->delegate()->GetAssociatedWebContents();
+    WebContents* web_contents = GetAssociatedWebContents();
     CHECK(web_contents);
     ExtensionWebUI* web_ui =
         static_cast<ExtensionWebUI*>(web_contents->GetWebUI()->GetController());
@@ -651,6 +652,9 @@
 }
 
 bool BookmarkManagerPrivateCreateWithMetaInfoFunction::RunOnReady() {
+  if (!EditBookmarksEnabled())
+    return false;
+
   scoped_ptr<CreateWithMetaInfo::Params> params(
       CreateWithMetaInfo::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
@@ -721,6 +725,9 @@
 }
 
 bool BookmarkManagerPrivateSetMetaInfoFunction::RunOnReady() {
+  if (!EditBookmarksEnabled())
+    return false;
+
   scoped_ptr<SetMetaInfo::Params> params(SetMetaInfo::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
@@ -742,6 +749,9 @@
 }
 
 bool BookmarkManagerPrivateUpdateMetaInfoFunction::RunOnReady() {
+  if (!EditBookmarksEnabled())
+    return false;
+
   scoped_ptr<UpdateMetaInfo::Params> params(
       UpdateMetaInfo::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
@@ -777,6 +787,9 @@
 }
 
 bool BookmarkManagerPrivateRemoveTreesFunction::RunOnReady() {
+  if (!EditBookmarksEnabled())
+    return false;
+
   scoped_ptr<RemoveTrees::Params> params(RemoveTrees::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
@@ -795,12 +808,18 @@
 }
 
 bool BookmarkManagerPrivateUndoFunction::RunOnReady() {
+  if (!EditBookmarksEnabled())
+    return false;
+
   BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
       Undo();
   return true;
 }
 
 bool BookmarkManagerPrivateRedoFunction::RunOnReady() {
+  if (!EditBookmarksEnabled())
+    return false;
+
   BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
       Redo();
   return true;
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
index 4160332..2e08bda36 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -774,8 +774,7 @@
   // either FileSelectionCanceled, MultiFilesSelected, or FileSelected
   AddRef();
 
-  WebContents* web_contents = dispatcher()->delegate()->
-      GetAssociatedWebContents();
+  WebContents* web_contents = GetAssociatedWebContents();
 
   select_file_dialog_ = ui::SelectFileDialog::Create(
       this, new ChromeSelectFilePolicy(web_contents));
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
index d9a299d..8d5eca6 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -10,12 +10,15 @@
 #include "chrome/browser/extensions/api/management/chrome_management_api_delegate.h"
 #include "chrome/browser/extensions/api/storage/sync_value_store_cache.h"
 #include "chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.h"
+#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
+#include "chrome/browser/favicon/favicon_helper.h"
 #include "chrome/browser/guest_view/app_view/chrome_app_view_guest_delegate.h"
 #include "chrome/browser/guest_view/extension_options/chrome_extension_options_guest_delegate.h"
-#include "chrome/browser/guest_view/extension_view/chrome_extension_view_guest_delegate.h"
 #include "chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.h"
 #include "chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h"
 #include "chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h"
+#include "chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.h"
+#include "components/pdf/browser/pdf_web_contents_helper.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h"
@@ -30,6 +33,15 @@
 #include "chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h"
 #endif
 
+#if defined(ENABLE_PRINTING)
+#if defined(ENABLE_PRINT_PREVIEW)
+#include "chrome/browser/printing/print_preview_message_handler.h"
+#include "chrome/browser/printing/print_view_manager.h"
+#else
+#include "chrome/browser/printing/print_view_manager_basic.h"
+#endif  // defined(ENABLE_PRINT_PREVIEW)
+#endif  // defined(ENABLE_PRINTING)
+
 namespace extensions {
 
 ChromeExtensionsAPIClient::ChromeExtensionsAPIClient() {}
@@ -53,6 +65,26 @@
 #endif
 }
 
+void ChromeExtensionsAPIClient::AttachWebContentsHelpers(
+    content::WebContents* web_contents) const {
+  favicon::CreateContentFaviconDriverForWebContents(web_contents);
+#if defined(ENABLE_PRINTING)
+#if defined(ENABLE_PRINT_PREVIEW)
+  printing::PrintViewManager::CreateForWebContents(web_contents);
+  printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents);
+#else
+  printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
+#endif  // defined(ENABLE_PRINT_PREVIEW)
+#endif  // defined(ENABLE_PRINTING)
+  pdf::PDFWebContentsHelper::CreateForWebContentsWithClient(
+      web_contents,
+      scoped_ptr<pdf::PDFWebContentsHelperClient>(
+          new ChromePDFWebContentsHelperClient()));
+
+  extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
+      web_contents);
+}
+
 AppViewGuestDelegate* ChromeExtensionsAPIClient::CreateAppViewGuestDelegate()
     const {
   return new ChromeAppViewGuestDelegate();
@@ -64,16 +96,10 @@
   return new ChromeExtensionOptionsGuestDelegate(guest);
 }
 
-ExtensionViewGuestDelegate*
-ChromeExtensionsAPIClient::CreateExtensionViewGuestDelegate(
-    ExtensionViewGuest* guest) const {
-  return new ChromeExtensionViewGuestDelegate(guest);
-}
-
 scoped_ptr<MimeHandlerViewGuestDelegate>
 ChromeExtensionsAPIClient::CreateMimeHandlerViewGuestDelegate(
     MimeHandlerViewGuest* guest) const {
-  return make_scoped_ptr(new ChromeMimeHandlerViewGuestDelegate(guest));
+  return make_scoped_ptr(new ChromeMimeHandlerViewGuestDelegate());
 }
 
 WebViewGuestDelegate* ChromeExtensionsAPIClient::CreateWebViewGuestDelegate(
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.h b/chrome/browser/extensions/api/chrome_extensions_api_client.h
index 24bdfe2..7f590b3 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.h
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.h
@@ -24,11 +24,11 @@
           observers,
       std::map<settings_namespace::Namespace, ValueStoreCache*>* caches)
       override;
+  void AttachWebContentsHelpers(content::WebContents* web_contents) const
+      override;
   AppViewGuestDelegate* CreateAppViewGuestDelegate() const override;
   ExtensionOptionsGuestDelegate* CreateExtensionOptionsGuestDelegate(
       ExtensionOptionsGuest* guest) const override;
-  ExtensionViewGuestDelegate* CreateExtensionViewGuestDelegate(
-      ExtensionViewGuest* guest) const override;
   scoped_ptr<MimeHandlerViewGuestDelegate> CreateMimeHandlerViewGuestDelegate(
       MimeHandlerViewGuest* guest) const override;
   WebViewGuestDelegate* CreateWebViewGuestDelegate(
diff --git a/chrome/browser/extensions/api/commands/command_service.cc b/chrome/browser/extensions/api/commands/command_service.cc
index 7503726..45be93b6 100644
--- a/chrome/browser/extensions/api/commands/command_service.cc
+++ b/chrome/browser/extensions/api/commands/command_service.cc
@@ -69,7 +69,7 @@
 }
 
 bool IsForCurrentPlatform(const std::string& key) {
-  return StartsWithASCII(key, Command::CommandPlatform() + ":", true);
+  return base::StartsWithASCII(key, Command::CommandPlatform() + ":", true);
 }
 
 std::string StripCurrentPlatform(const std::string& key) {
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
index 4933696..06efb10 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
@@ -2,8 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/location.h"
 #include "base/prefs/pref_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/cookie_settings.h"
@@ -55,7 +58,7 @@
   void TearDownOnMainThread() override {
     // ReleaseBrowserProcessModule() needs to be called in a message loop, so we
     // post a task to do it, then run the message loop.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&ReleaseBrowserProcessModule));
     content::RunAllPendingInMessageLoop();
 
diff --git a/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.cc b/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.cc
index da88ec2..e0912b51 100644
--- a/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.cc
+++ b/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/extensions/api/declarative_content/content_action.h"
 #include "chrome/browser/extensions/api/declarative_content/content_condition.h"
 #include "chrome/browser/extensions/api/declarative_content/content_constants.h"
-#include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -17,12 +16,10 @@
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
-#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/api/declarative/rules_registry_service.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/common/extension_messages.h"
 
 using url_matcher::URLMatcherConditionSet;
 
@@ -35,13 +32,11 @@
                            declarative_content_constants::kOnPageChanged,
                            content::BrowserThread::UI,
                            cache_delegate,
-                           RulesRegistryService::kDefaultRulesRegistryID) {
+                           RulesRegistryService::kDefaultRulesRegistryID),
+      css_condition_tracker_(browser_context, this) {
   extension_info_map_ = ExtensionSystem::Get(browser_context)->info_map();
 
   registrar_.Add(this,
-                 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this,
                  content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
                  content::NotificationService::AllBrowserContextsAndSources());
 }
@@ -51,62 +46,41 @@
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
   switch (type) {
-    case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
-      content::RenderProcessHost* process =
-          content::Source<content::RenderProcessHost>(source).ptr();
-      InstructRenderProcessIfSameBrowserContext(process);
-      break;
-    }
     case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
       content::WebContents* tab =
           content::Source<content::WebContents>(source).ptr();
       // Note that neither non-tab WebContents nor tabs from other browser
       // contexts will be in the map.
       active_rules_.erase(tab);
-      matching_css_selectors_.erase(tab);
       break;
     }
   }
 }
 
-void ChromeContentRulesRegistry::Apply(
-    content::WebContents* contents,
-    const std::vector<std::string>& matching_css_selectors) {
-  matching_css_selectors_[contents] = matching_css_selectors;
-
+void ChromeContentRulesRegistry::RequestEvaluation(
+    content::WebContents* contents) {
   EvaluateConditionsForTab(contents);
 }
 
+bool ChromeContentRulesRegistry::ShouldManageConditionsForBrowserContext(
+    content::BrowserContext* context) {
+  return ManagingRulesForBrowserContext(context);
+}
+
+void ChromeContentRulesRegistry::MonitorWebContentsForRuleEvaluation(
+    content::WebContents* contents) {
+  // We rely on active_rules_ to have a key-value pair for |contents| to know
+  // which WebContents we are working with.
+  active_rules_[contents] = std::set<const ContentRule*>();
+  css_condition_tracker_.TrackForWebContents(contents);
+}
+
 void ChromeContentRulesRegistry::DidNavigateMainFrame(
     content::WebContents* contents,
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
-  OnTabNavigation(contents, details.is_in_page);
-}
-
-void ChromeContentRulesRegistry::DidNavigateMainFrameOfOriginalContext(
-    content::WebContents* contents,
-    const content::LoadCommittedDetails& details,
-    const content::FrameNavigateParams& params) {
-  DCHECK(browser_context()->IsOffTheRecord());
-  OnTabNavigation(contents, details.is_in_page);
-}
-
-void ChromeContentRulesRegistry::OnTabNavigation(content::WebContents* tab,
-                                                 bool is_in_page_navigation) {
-  if (is_in_page_navigation) {
-    // Within-page navigations don't change the set of elements that
-    // exist, and we only support filtering on the top-level URL, so
-    // this can't change which rules match.
-    return;
-  }
-
-  // Top-level navigation produces a new document. Initially, the
-  // document's empty, so no CSS rules match.  The renderer will send
-  // an ExtensionHostMsg_OnWatchedPageChange later if any CSS rules
-  // match.
-  matching_css_selectors_[tab].clear();
-  EvaluateConditionsForTab(tab);
+  if (ContainsKey(active_rules_, contents))
+    css_condition_tracker_.OnWebContentsNavigation(contents, details, params);
 }
 
 bool ChromeContentRulesRegistry::ManagingRulesForBrowserContext(
@@ -219,7 +193,7 @@
   }
   url_matcher_.AddConditionSets(all_new_condition_sets);
 
-  UpdateConditionCache();
+  UpdateCssSelectorsFromRules();
   EvaluateConditionsForAllTabs();
 
   return std::string();
@@ -266,7 +240,7 @@
   // Clear URLMatcher based on condition_set_ids that are not needed any more.
   url_matcher_.RemoveConditionSets(remove_from_url_matcher);
 
-  UpdateConditionCache();
+  UpdateCssSelectorsFromRules();
 
   return std::string();
 }
@@ -286,7 +260,7 @@
   return RemoveRulesImpl(extension_id, rule_identifiers);
 }
 
-void ChromeContentRulesRegistry::UpdateConditionCache() {
+void ChromeContentRulesRegistry::UpdateCssSelectorsFromRules() {
   std::set<std::string> css_selectors;  // We rely on this being sorted.
   for (const std::pair<ContentRule::GlobalRuleId,
                        linked_ptr<const ContentRule>>& rule_id_rule_pair :
@@ -301,34 +275,15 @@
     }
   }
 
-  if (css_selectors.size() != watched_css_selectors_.size() ||
-      !std::equal(css_selectors.begin(),
-                  css_selectors.end(),
-                  watched_css_selectors_.begin())) {
-    watched_css_selectors_.assign(css_selectors.begin(), css_selectors.end());
-
-    for (content::RenderProcessHost::iterator it(
-             content::RenderProcessHost::AllHostsIterator());
-         !it.IsAtEnd();
-         it.Advance()) {
-      content::RenderProcessHost* process = it.GetCurrentValue();
-      InstructRenderProcessIfSameBrowserContext(process);
-    }
-  }
-}
-
-void ChromeContentRulesRegistry::InstructRenderProcessIfSameBrowserContext(
-    content::RenderProcessHost* process) {
-  if (ManagingRulesForBrowserContext(process->GetBrowserContext()))
-    process->Send(new ExtensionMsg_WatchPages(watched_css_selectors_));
+  css_condition_tracker_.SetWatchedCssSelectors(css_selectors);
 }
 
 void ChromeContentRulesRegistry::EvaluateConditionsForTab(
     content::WebContents* tab) {
   extensions::RendererContentMatchData renderer_data;
   renderer_data.page_url_matches = url_matcher_.MatchURL(tab->GetURL());
-  renderer_data.css_selectors.insert(matching_css_selectors_[tab].begin(),
-                                     matching_css_selectors_[tab].end());
+  css_condition_tracker_.GetMatchingCssSelectors(tab,
+                                                 &renderer_data.css_selectors);
   std::set<const ContentRule*> matching_rules =
       GetMatches(renderer_data, tab->GetBrowserContext()->IsOffTheRecord());
   if (matching_rules.empty() && !ContainsKey(active_rules_, tab))
@@ -352,22 +307,14 @@
   }
 
   if (matching_rules.empty())
-    active_rules_.erase(tab);
+    active_rules_[tab].clear();
   else
     swap(matching_rules, prev_matching_rules);
 }
 
 void ChromeContentRulesRegistry::EvaluateConditionsForAllTabs() {
-  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-    Browser* browser = *it;
-    if (!ManagingRulesForBrowserContext(browser->profile()))
-      continue;
-
-    for (int i = 0, tab_count = browser->tab_strip_model()->count();
-         i < tab_count;
-         ++i)
-      EvaluateConditionsForTab(browser->tab_strip_model()->GetWebContentsAt(i));
-  }
+  for (const auto& web_contents_active_rules_pair : active_rules_)
+    EvaluateConditionsForTab(web_contents_active_rules_pair.first);
 }
 
 bool ChromeContentRulesRegistry::IsEmpty() const {
@@ -375,6 +322,21 @@
          url_matcher_.IsEmpty();
 }
 
+void ChromeContentRulesRegistry::UpdateMatchingCssSelectorsForTesting(
+    content::WebContents* contents,
+    const std::vector<std::string>& matching_css_selectors) {
+  css_condition_tracker_.UpdateMatchingCssSelectorsForTesting(
+      contents,
+      matching_css_selectors);
+}
+
+size_t ChromeContentRulesRegistry::GetActiveRulesCountForTesting() {
+  size_t count = 0;
+  for (auto web_contents_rules_pair : active_rules_)
+    count += web_contents_rules_pair.second.size();
+  return count;
+}
+
 ChromeContentRulesRegistry::~ChromeContentRulesRegistry() {
 }
 
diff --git a/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h b/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h
index 316fc9e..a34d0e9d 100644
--- a/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h
+++ b/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h
@@ -16,6 +16,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/extensions/api/declarative_content/content_action.h"
 #include "chrome/browser/extensions/api/declarative_content/content_condition.h"
+#include "chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h"
 #include "components/url_matcher/url_matcher.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -66,35 +67,25 @@
 // side of split-mode extensions to incognito tabs. The non-incognito instance
 // handles incognito tabs for spanning-mode extensions, plus all non-incognito
 // tabs.
-class ChromeContentRulesRegistry : public ContentRulesRegistry,
-                                   public content::NotificationObserver {
+class ChromeContentRulesRegistry
+    : public ContentRulesRegistry,
+      public content::NotificationObserver,
+      public DeclarativeContentCssConditionTrackerDelegate {
  public:
   // For testing, |ui_part| can be NULL. In that case it constructs the
   // registry with storage functionality suspended.
   ChromeContentRulesRegistry(content::BrowserContext* browser_context,
                              RulesCacheDelegate* cache_delegate);
 
-  // ChromeContentRulesRegistry implementation:
-  // Applies all content rules given an update (CSS match change or
-  // page navigation, for now) from the renderer.
-  void Apply(content::WebContents* contents,
-             const std::vector<std::string>& matching_css_selectors) override;
-
-  // Applies all content rules given that a tab was just navigated.
+  // ContentRulesRegistry:
+  void MonitorWebContentsForRuleEvaluation(
+      content::WebContents* contents) override;
   void DidNavigateMainFrame(
       content::WebContents* tab,
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) override;
 
-  // Applies all content rules given that a tab was just navigated on the
-  // original context. Only invoked on the OffTheRecord registry instance. |tab|
-  // is owned by the original context, not this one.
-  void DidNavigateMainFrameOfOriginalContext(
-      content::WebContents* tab,
-      const content::LoadCommittedDetails& details,
-      const content::FrameNavigateParams& params) override;
-
-  // Implementation of RulesRegistry:
+  // RulesRegistry:
   std::string AddRulesImpl(
       const std::string& extension_id,
       const std::vector<linked_ptr<RulesRegistry::Rule>>& rules) override;
@@ -103,14 +94,31 @@
       const std::vector<std::string>& rule_identifiers) override;
   std::string RemoveAllRulesImpl(const std::string& extension_id) override;
 
-  // content::NotificationObserver implementation.
+  // content::NotificationObserver:
   void Observe(int type,
                const content::NotificationSource& source,
                const content::NotificationDetails& details) override;
 
+  // DeclarativeContentCssConditionTrackerDelegate:
+  void RequestEvaluation(content::WebContents* contents) override;
+  bool ShouldManageConditionsForBrowserContext(
+      content::BrowserContext* context) override;
+
   // Returns true if this object retains no allocated data. Only for debugging.
   bool IsEmpty() const;
 
+  // TODO(wittman): Remove once DeclarativeChromeContentRulesRegistry no longer
+  // depends on concrete condition implementations. At that point
+  // DeclarativeChromeContentRulesRegistryTest.ActiveRulesDoesntGrow will be
+  // able to use a test condition object and not need to depend on force setting
+  // matching CSS seleectors.
+  void UpdateMatchingCssSelectorsForTesting(
+      content::WebContents* contents,
+      const std::vector<std::string>& matching_css_selectors);
+
+  // Returns the number of active rules.
+  size_t GetActiveRulesCountForTesting();
+
  protected:
   ~ChromeContentRulesRegistry() override;
 
@@ -119,27 +127,15 @@
       const std::string& extension_id) const;
 
  private:
-  friend class DeclarativeChromeContentRulesRegistryTest;
-
   // True if this object is managing the rules for |context|.
   bool ManagingRulesForBrowserContext(content::BrowserContext* context);
 
-  // Applies all content rules given that a tab was just navigated.
-  void OnTabNavigation(content::WebContents* tab, bool is_in_page_navigation);
-
   std::set<const ContentRule*> GetMatches(
       const RendererContentMatchData& renderer_data,
       bool is_incognito_renderer) const;
 
-  // Scans the rules for the set of conditions they're watching.  If the set has
-  // changed, calls InstructRenderProcess() for each RenderProcessHost in the
-  // current browser_context.
-  void UpdateConditionCache();
-
-  // If the renderer process is associated with our browser context, tells it
-  // what page attributes to watch for using an ExtensionMsg_WatchPages.
-  void InstructRenderProcessIfSameBrowserContext(
-      content::RenderProcessHost* process);
+  // Updates the condition evaluator with the current watched CSS selectors.
+  void UpdateCssSelectorsFromRules();
 
   // Evaluates the conditions for |tab| based on the tab state and matching CSS
   // selectors.
@@ -152,8 +148,6 @@
       URLMatcherIdToRule;
   typedef std::map<ContentRule::GlobalRuleId, linked_ptr<const ContentRule>>
       RulesMap;
-  typedef std::map<content::WebContents*, std::vector<std::string>>
-      CssSelectors;
 
   // Map that tells us which ContentRules may match under the condition that
   // the URLMatcherConditionSet::ID was returned by the |url_matcher_|.
@@ -162,23 +156,22 @@
   RulesMap content_rules_;
 
   // Maps a WebContents to the set of rules that match on that WebContents.
-  // This lets us call Revert as appropriate.
+  // This lets us call Revert as appropriate. Note that this is expected to have
+  // a key-value pair for every WebContents the registry is tracking, even if
+  // the value is the empty set.
   std::map<content::WebContents*, std::set<const ContentRule*>> active_rules_;
 
   // Matches URLs for the page_url condition.
   url_matcher::URLMatcher url_matcher_;
 
-  // All CSS selectors any rule's conditions watch for.
-  std::vector<std::string> watched_css_selectors_;
+  // Responsible for evaluating the declarative content conditions.
+  DeclarativeContentCssConditionTracker css_condition_tracker_;
 
   // Manages our notification registrations.
   content::NotificationRegistrar registrar_;
 
   scoped_refptr<InfoMap> extension_info_map_;
 
-  // Maps tab_id to the matching CSS selectors for the tab.
-  CssSelectors matching_css_selectors_;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeContentRulesRegistry);
 };
 
diff --git a/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry_unittest.cc
index 4c6c04c..0b3e2323 100644
--- a/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry_unittest.cc
@@ -7,7 +7,6 @@
 #include <string>
 
 #include "base/test/values_test_util.h"
-#include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/test_extension_environment.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/navigation_details.h"
@@ -18,42 +17,24 @@
 
 namespace extensions {
 
-using base::test::ParseJson;
-using testing::HasSubstr;
-using content::WebContents;
-
-// Must be outside the anonymous namespace to be a friend of
-// ContentRulesRegistry.
-class DeclarativeChromeContentRulesRegistryTest : public testing::Test {
- protected:
-  using RulesMap =
-      std::map<content::WebContents*, std::set<const ContentRule*>>;
-  static const RulesMap& active_rules(
-      const ChromeContentRulesRegistry& registry) {
-    return registry.active_rules_;
-  }
-};
-
-namespace {
-
-TEST_F(DeclarativeChromeContentRulesRegistryTest, ActiveRulesDoesntGrow) {
+TEST(DeclarativeChromeContentRulesRegistryTest, ActiveRulesDoesntGrow) {
   TestExtensionEnvironment env;
 
   scoped_refptr<ChromeContentRulesRegistry> registry(
       new ChromeContentRulesRegistry(env.profile(), NULL));
 
-  EXPECT_EQ(0u, active_rules(*registry.get()).size());
+  EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
 
-  content::LoadCommittedDetails load_details;
-  content::FrameNavigateParams navigate_params;
-  scoped_ptr<WebContents> tab = env.MakeTab();
-  registry->DidNavigateMainFrame(tab.get(), load_details, navigate_params);
-  EXPECT_EQ(0u, active_rules(*registry.get()).size());
+  scoped_ptr<content::WebContents> tab = env.MakeTab();
+  registry->MonitorWebContentsForRuleEvaluation(tab.get());
+  registry->DidNavigateMainFrame(tab.get(), content::LoadCommittedDetails(),
+                                 content::FrameNavigateParams());
+  EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
 
   // Add a rule.
   linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule);
   RulesRegistry::Rule::Populate(
-      *ParseJson(
+      *base::test::ParseJson(
           "{\n"
           "  \"id\": \"rule1\",\n"
           "  \"priority\": 100,\n"
@@ -70,30 +51,32 @@
   std::vector<linked_ptr<RulesRegistry::Rule> > rules;
   rules.push_back(rule);
 
-  const Extension* extension = env.MakeExtension(*ParseJson(
+  const Extension* extension = env.MakeExtension(*base::test::ParseJson(
       "{\"page_action\": {}}"));
   registry->AddRulesImpl(extension->id(), rules);
 
-  registry->DidNavigateMainFrame(tab.get(), load_details, navigate_params);
-  EXPECT_EQ(0u, active_rules(*registry.get()).size());
+  registry->DidNavigateMainFrame(tab.get(), content::LoadCommittedDetails(),
+                                 content::FrameNavigateParams());
+  EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
 
   std::vector<std::string> css_selectors;
   css_selectors.push_back("input");
-  registry->Apply(tab.get(), css_selectors);
-  EXPECT_EQ(1u, active_rules(*registry.get()).size());
+  registry->UpdateMatchingCssSelectorsForTesting(tab.get(), css_selectors);
+  EXPECT_EQ(1u, registry->GetActiveRulesCountForTesting());
 
   // Closing the tab should erase its entry from active_rules_.
   tab.reset();
-  EXPECT_EQ(0u, active_rules(*registry.get()).size());
+  EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
 
   tab = env.MakeTab();
-  registry->Apply(tab.get(), css_selectors);
-  EXPECT_EQ(1u, active_rules(*registry.get()).size());
+  registry->MonitorWebContentsForRuleEvaluation(tab.get());
+  registry->UpdateMatchingCssSelectorsForTesting(tab.get(), css_selectors);
+  EXPECT_EQ(1u, registry->GetActiveRulesCountForTesting());
   // Navigating the tab should erase its entry from active_rules_ if
   // it no longer matches.
-  registry->DidNavigateMainFrame(tab.get(), load_details, navigate_params);
-  EXPECT_EQ(0u, active_rules(*registry.get()).size());
+  registry->DidNavigateMainFrame(tab.get(), content::LoadCommittedDetails(),
+                                 content::FrameNavigateParams());
+  EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
 }
 
-}  // namespace
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/declarative_content/content_action.h b/chrome/browser/extensions/api/declarative_content/content_action.h
index acc13e07..1420e86 100644
--- a/chrome/browser/extensions/api/declarative_content/content_action.h
+++ b/chrome/browser/extensions/api/declarative_content/content_action.h
@@ -16,6 +16,7 @@
 namespace base {
 class Time;
 class Value;
+class DictionaryValue;
 }
 
 namespace content {
diff --git a/chrome/browser/extensions/api/declarative_content/content_condition.h b/chrome/browser/extensions/api/declarative_content/content_condition.h
index 134fa8c9..b8c92f2 100644
--- a/chrome/browser/extensions/api/declarative_content/content_condition.h
+++ b/chrome/browser/extensions/api/declarative_content/content_condition.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_CONTENT_CONTENT_CONDITION_H_
 #define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_CONTENT_CONTENT_CONDITION_H_
 
-#include <map>
 #include <set>
 #include <string>
 #include <vector>
@@ -13,12 +12,17 @@
 #include "base/containers/hash_tables.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/values.h"
 #include "components/url_matcher/url_matcher.h"
 #include "extensions/browser/api/declarative/declarative_rule.h"
 
+namespace base {
+class Value;
+}
+
 namespace extensions {
 
+class Extension;
+
 struct RendererContentMatchData {
   RendererContentMatchData();
   ~RendererContentMatchData();
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
index 9c68d60..0834e76 100644
--- a/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc
@@ -621,5 +621,21 @@
               testing::ContainsRegex("compound selector.*: div input$"));
 }
 
+// https://crbug.com/497586
+IN_PROC_BROWSER_TEST_F(DeclarativeContentApiTest,
+                       WebContentsWithoutTabAddedNotificationAtOnLoaded) {
+  // Add a web contents to the tab strip in a way that doesn't trigger
+  // NOTIFICATION_TAB_ADDED.
+  content::WebContents* contents = content::WebContents::Create(
+      content::WebContents::CreateParams(profile()));
+  browser()->tab_strip_model()->AppendWebContents(contents, false);
+
+  // The actual extension contents don't matter here -- we're just looking to
+  // trigger OnExtensionLoaded.
+  ext_dir_.WriteManifest(kDeclarativeContentManifest);
+  ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundHelpers);
+  ASSERT_TRUE(LoadExtension(ext_dir_.unpacked_path()));
+}
+
 }  // namespace
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.cc
new file mode 100644
index 0000000..e2e474a
--- /dev/null
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.cc
@@ -0,0 +1,208 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h"
+
+#include <algorithm>
+
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/render_process_host.h"
+#include "extensions/common/extension_messages.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+
+namespace extensions {
+
+//
+// PerWebContentsTracker
+//
+
+DeclarativeContentCssConditionTracker::PerWebContentsTracker::
+PerWebContentsTracker(
+    content::WebContents* contents,
+    const RequestEvaluationCallback& request_evaluation,
+    const WebContentsDestroyedCallback& web_contents_destroyed)
+    : WebContentsObserver(contents),
+      request_evaluation_(request_evaluation),
+      web_contents_destroyed_(web_contents_destroyed) {
+}
+
+DeclarativeContentCssConditionTracker::PerWebContentsTracker::
+~PerWebContentsTracker() {
+}
+
+void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
+OnWebContentsNavigation(const content::LoadCommittedDetails& details,
+                        const content::FrameNavigateParams& params) {
+  if (details.is_in_page) {
+    // Within-page navigations don't change the set of elements that
+    // exist, and we only support filtering on the top-level URL, so
+    // this can't change which rules match.
+    return;
+  }
+
+  // Top-level navigation produces a new document. Initially, the
+  // document's empty, so no CSS rules match.  The renderer will send
+  // an ExtensionHostMsg_OnWatchedPageChange later if any CSS rules
+  // match.
+  matching_css_selectors_.clear();
+  request_evaluation_.Run(web_contents());
+}
+
+void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
+UpdateMatchingCssSelectorsForTesting(
+    const std::vector<std::string>& matching_css_selectors) {
+  matching_css_selectors_ = matching_css_selectors;
+  request_evaluation_.Run(web_contents());
+}
+
+bool
+DeclarativeContentCssConditionTracker::PerWebContentsTracker::
+OnMessageReceived(
+    const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(PerWebContentsTracker, message)
+    IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange,
+                        OnWatchedPageChange)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
+WebContentsDestroyed() {
+  web_contents_destroyed_.Run(web_contents());
+}
+
+void
+DeclarativeContentCssConditionTracker::PerWebContentsTracker::
+OnWatchedPageChange(
+    const std::vector<std::string>& css_selectors) {
+  matching_css_selectors_ = css_selectors;
+  request_evaluation_.Run(web_contents());
+}
+
+//
+// DeclarativeContentCssConditionTrackerDelegate
+//
+
+DeclarativeContentCssConditionTrackerDelegate::
+DeclarativeContentCssConditionTrackerDelegate() {}
+
+DeclarativeContentCssConditionTrackerDelegate::
+~DeclarativeContentCssConditionTrackerDelegate() {}
+
+//
+// DeclarativeContentCssConditionTracker
+//
+
+DeclarativeContentCssConditionTracker::DeclarativeContentCssConditionTracker(
+    content::BrowserContext* context,
+    DeclarativeContentCssConditionTrackerDelegate* delegate)
+    : context_(context),
+      delegate_(delegate) {
+  registrar_.Add(this,
+                 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+}
+
+DeclarativeContentCssConditionTracker::
+~DeclarativeContentCssConditionTracker() {}
+
+// We use the sorted propery of the set for equality checks with
+// watched_css_selectors_, which is guaranteed to be sorted because it's set
+// from the set contents.
+void DeclarativeContentCssConditionTracker::SetWatchedCssSelectors(
+    const std::set<std::string>& new_watched_css_selectors) {
+  if (new_watched_css_selectors.size() != watched_css_selectors_.size() ||
+      !std::equal(new_watched_css_selectors.begin(),
+                  new_watched_css_selectors.end(),
+                  watched_css_selectors_.begin())) {
+    watched_css_selectors_.assign(new_watched_css_selectors.begin(),
+                                  new_watched_css_selectors.end());
+
+    for (content::RenderProcessHost::iterator it(
+             content::RenderProcessHost::AllHostsIterator());
+         !it.IsAtEnd();
+         it.Advance()) {
+      InstructRenderProcessIfManagingBrowserContext(it.GetCurrentValue());
+    }
+  }
+}
+
+void DeclarativeContentCssConditionTracker::TrackForWebContents(
+    content::WebContents* contents) {
+  CreatePerWebContentsTracker(contents);
+}
+
+void DeclarativeContentCssConditionTracker::OnWebContentsNavigation(
+    content::WebContents* contents,
+    const content::LoadCommittedDetails& details,
+    const content::FrameNavigateParams& params) {
+  per_web_contents_tracker_[contents]->OnWebContentsNavigation(details, params);
+}
+
+void DeclarativeContentCssConditionTracker::GetMatchingCssSelectors(
+    content::WebContents* contents,
+    base::hash_set<std::string>* css_selectors) {
+  const std::vector<std::string>& matching_css_selectors =
+      per_web_contents_tracker_[contents]->matching_css_selectors();
+  css_selectors->insert(matching_css_selectors.begin(),
+                        matching_css_selectors.end());
+}
+
+void DeclarativeContentCssConditionTracker::
+UpdateMatchingCssSelectorsForTesting(
+    content::WebContents* contents,
+    const std::vector<std::string>& matching_css_selectors) {
+  per_web_contents_tracker_[contents]->
+      UpdateMatchingCssSelectorsForTesting(matching_css_selectors);
+}
+
+void DeclarativeContentCssConditionTracker::CreatePerWebContentsTracker(
+    content::WebContents* contents) {
+  per_web_contents_tracker_[contents] =
+      make_linked_ptr(new PerWebContentsTracker(
+          contents,
+          base::Bind(&DeclarativeContentCssConditionTrackerDelegate::
+                     RequestEvaluation,
+                     base::Unretained(delegate_)),
+          base::Bind(&DeclarativeContentCssConditionTracker::
+                     DeletePerWebContentsTracker,
+                     base::Unretained(this))));
+}
+
+void DeclarativeContentCssConditionTracker::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  switch (type) {
+    case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
+      content::RenderProcessHost* process =
+          content::Source<content::RenderProcessHost>(source).ptr();
+      InstructRenderProcessIfManagingBrowserContext(process);
+      break;
+    }
+  }
+}
+
+void DeclarativeContentCssConditionTracker::
+InstructRenderProcessIfManagingBrowserContext(
+    content::RenderProcessHost* process) {
+  if (delegate_->ShouldManageConditionsForBrowserContext(
+          process->GetBrowserContext())) {
+    process->Send(new ExtensionMsg_WatchPages(watched_css_selectors_));
+  }
+}
+
+void DeclarativeContentCssConditionTracker::DeletePerWebContentsTracker(
+    content::WebContents* contents) {
+  per_web_contents_tracker_.erase(contents);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h
new file mode 100644
index 0000000..6c7131f
--- /dev/null
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h
@@ -0,0 +1,172 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_CONTENT_DECLARATIVE_CONTENT_CSS_CONDITION_TRACKER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_CONTENT_DECLARATIVE_CONTENT_CSS_CONDITION_TRACKER_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/linked_ptr.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/web_contents_observer.h"
+
+
+namespace content {
+class BrowserContext;
+struct FrameNavigateParams;
+struct LoadCommittedDetails;
+class RenderProcessHost;
+class WebContents;
+}
+
+namespace extensions {
+
+// Interface that allows the DeclarativeContentCssConditionTracker to request
+// condition evaluation, and shields it from having to know about Browsers.
+class DeclarativeContentCssConditionTrackerDelegate {
+ public:
+  // Requests re-evaluation of conditions for |contents|.
+  virtual void RequestEvaluation(content::WebContents* contents) = 0;
+
+  // Returns true if the evaluator should manage condition state for |context|.
+  virtual bool ShouldManageConditionsForBrowserContext(
+      content::BrowserContext* context) = 0;
+
+ protected:
+  DeclarativeContentCssConditionTrackerDelegate();
+  virtual ~DeclarativeContentCssConditionTrackerDelegate();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DeclarativeContentCssConditionTrackerDelegate);
+};
+
+// Supports watching of CSS selectors to across tab contents in a browser
+// context, and querying for the matching CSS selectors for a context.
+class DeclarativeContentCssConditionTracker
+    : public content::NotificationObserver {
+ public:
+  DeclarativeContentCssConditionTracker(
+      content::BrowserContext* context,
+      DeclarativeContentCssConditionTrackerDelegate* delegate);
+  ~DeclarativeContentCssConditionTracker() override;
+
+  // Sets the set of CSS selectors to watch for CSS condition evaluation.
+  void SetWatchedCssSelectors(
+      const std::set<std::string>& watched_css_selectors);
+
+  // Requests that CSS conditions be tracked for |contents|.
+  void TrackForWebContents(content::WebContents* contents);
+
+  // Handles navigation of |contents|. We depend on the caller to notify us of
+  // this event rather than listening for it ourselves, so that the caller can
+  // coordinate evaluation with all the trackers that respond to it. If we
+  // listened ourselves and requested rule evaluation before another tracker
+  // received the notification, our conditions would be evaluated based on the
+  // new URL while the other tracker's conditions would still be evaluated based
+  // on the previous URL.
+  void OnWebContentsNavigation(content::WebContents* contents,
+                               const content::LoadCommittedDetails& details,
+                               const content::FrameNavigateParams& params);
+
+  // Inserts the currently-matching CSS selectors into |css_selectors|. We use
+  // hash_set for maximally efficient lookup.
+  void GetMatchingCssSelectors(content::WebContents* contents,
+                               base::hash_set<std::string>* css_selectors);
+
+  // TODO(wittman): Remove once DeclarativeChromeContentRulesRegistry no longer
+  // depends on concrete condition implementations. At that point
+  // DeclarativeChromeContentRulesRegistryTest.ActiveRulesDoesntGrow will be
+  // able to use a test condition object and not need to depend on force setting
+  // matching CSS seleectors.
+  void UpdateMatchingCssSelectorsForTesting(
+      content::WebContents* contents,
+      const std::vector<std::string>& matching_css_selectors);
+
+ private:
+  // Monitors CSS selector matching state on one WebContents.
+  class PerWebContentsTracker : public content::WebContentsObserver {
+   public:
+    using RequestEvaluationCallback =
+        base::Callback<void(content::WebContents*)>;
+    using WebContentsDestroyedCallback =
+        base::Callback<void(content::WebContents*)>;
+
+    PerWebContentsTracker(
+        content::WebContents* contents,
+        const RequestEvaluationCallback& request_evaluation,
+        const WebContentsDestroyedCallback& web_contents_destroyed);
+    ~PerWebContentsTracker() override;
+
+    void OnWebContentsNavigation(const content::LoadCommittedDetails& details,
+                                 const content::FrameNavigateParams& params);
+
+    // See comment on similar function above.
+    void UpdateMatchingCssSelectorsForTesting(
+        const std::vector<std::string>& matching_css_selectors);
+
+    const std::vector<std::string>& matching_css_selectors() const {
+      return matching_css_selectors_;
+    }
+
+   private:
+    // content::WebContentsObserver overrides.
+    bool OnMessageReceived(const IPC::Message& message) override;
+    void WebContentsDestroyed() override;
+
+    void OnWatchedPageChange(const std::vector<std::string>& css_selectors);
+
+    const RequestEvaluationCallback request_evaluation_;
+    const WebContentsDestroyedCallback web_contents_destroyed_;
+
+    std::vector<std::string> matching_css_selectors_;
+
+    DISALLOW_COPY_AND_ASSIGN(PerWebContentsTracker);
+  };
+
+  // Instantiate a PerWebContentsTracker watching |contents|.
+  void CreatePerWebContentsTracker(content::WebContents* contents);
+
+  // content::NotificationObserver implementation.
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
+  // If the renderer process is associated with our browser context, tells it
+  // what page attributes to watch for using an ExtensionMsg_WatchPages.
+  void InstructRenderProcessIfManagingBrowserContext(
+      content::RenderProcessHost* process);
+
+  // Called by PerWebContentsTracker on web contents destruction.
+  void DeletePerWebContentsTracker(content::WebContents* tracker);
+
+  // The context whose state we're monitoring for evaluation.
+  content::BrowserContext* context_;
+
+  // All CSS selectors that are watched for by any rule's conditions. This
+  // vector is sorted by construction.
+  std::vector<std::string> watched_css_selectors_;
+
+  // Maps WebContents to the tracker for that WebContents
+  // state.
+  std::map<content::WebContents*, linked_ptr<PerWebContentsTracker>>
+      per_web_contents_tracker_;
+
+  // Weak.
+  DeclarativeContentCssConditionTrackerDelegate* delegate_;
+
+  // Manages our notification registrations.
+  content::NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeclarativeContentCssConditionTracker);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_CONTENT_DECLARATIVE_CONTENT_CSS_CONDITION_TRACKER_H_
diff --git a/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
new file mode 100644
index 0000000..5ef2f04
--- /dev/null
+++ b/chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc
@@ -0,0 +1,189 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
+#include "extensions/common/extension_messages.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+using testing::UnorderedElementsAreArray;
+
+class DeclarativeContentCssConditionTrackerTest : public testing::Test {
+ public:
+  DeclarativeContentCssConditionTrackerTest() : profile_(new TestingProfile) {}
+
+  ~DeclarativeContentCssConditionTrackerTest() override {
+    // MockRenderProcessHosts are deleted from the message loop, and their
+    // deletion must complete before RenderViewHostTestEnabler's destructor is
+    // run.
+    base::RunLoop().RunUntilIdle();
+  }
+
+ protected:
+  class Delegate : public DeclarativeContentCssConditionTrackerDelegate {
+   public:
+    Delegate() : evaluation_requests_(0) {}
+
+    int evaluation_requests() { return evaluation_requests_; }
+
+    // DeclarativeContentCssConditionTrackerDelegate:
+    void RequestEvaluation(content::WebContents* contents) override {
+      ++evaluation_requests_;
+    }
+
+    bool ShouldManageConditionsForBrowserContext(
+        content::BrowserContext* context) override {
+      return true;
+    }
+
+   private:
+    int evaluation_requests_;
+
+    DISALLOW_COPY_AND_ASSIGN(Delegate);
+  };
+
+  // Creates a new WebContents and retains ownership.
+  scoped_ptr<content::WebContents> MakeTab() {
+    return make_scoped_ptr(content::WebContentsTester::CreateTestWebContents(
+        profile_.get(),
+        nullptr));
+  }
+
+  // Expect an ExtensionMsg_WatchPages message in |sink| with |selectors| as the
+  // param, after invoking |func|.
+  template <class Func>
+  void ExpectWatchPagesMessage(IPC::TestSink& sink,
+                               const std::set<std::string>& selectors,
+                               const Func& func) {
+    sink.ClearMessages();
+    func();
+    EXPECT_EQ(1u, sink.message_count());
+    const IPC::Message* message =
+        sink.GetUniqueMessageMatching(ExtensionMsg_WatchPages::ID);
+    ASSERT_TRUE(message);
+    ExtensionMsg_WatchPages::Param params;
+    ExtensionMsg_WatchPages::Read(message, &params);
+    EXPECT_THAT(base::get<0>(params), UnorderedElementsAreArray(selectors));
+  }
+
+  // Sends an OnWatchedPageChange message to the tab.
+  void SendOnWatchedPageChangeMessage(
+      content::WebContents* tab,
+      const std::vector<std::string>& selectors) {
+    ExtensionHostMsg_OnWatchedPageChange page_change(tab->GetRoutingID(),
+                                                     selectors);
+    content::MockRenderProcessHost* process =
+        static_cast<content::MockRenderProcessHost*>(
+            tab->GetRenderViewHost()->GetProcess());
+
+    EXPECT_TRUE(process->OnMessageReceived(page_change));
+  }
+
+  Profile* profile() { return profile_.get(); }
+  Delegate* delegate() { return &delegate_; }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+
+  // Enables MockRenderProcessHosts.
+  content::RenderViewHostTestEnabler render_view_host_test_enabler_;
+
+  const scoped_ptr<TestingProfile> profile_;
+  Delegate delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeclarativeContentCssConditionTrackerTest);
+};
+
+// Tests the basic flow of operations on the
+// DeclarativeContentCssConditionTracker.
+TEST_F(DeclarativeContentCssConditionTrackerTest, Basic) {
+  DeclarativeContentCssConditionTracker tracker(profile(), delegate());
+  int expected_evaluation_requests = 0;
+
+  const scoped_ptr<content::WebContents> tab = MakeTab();
+  tracker.TrackForWebContents(tab.get());
+  EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
+
+  content::MockRenderProcessHost* process =
+          static_cast<content::MockRenderProcessHost*>(
+              tab->GetRenderViewHost()->GetProcess());
+
+  // Check that calling SetWatchedCssSelectors sends a WatchPages message with
+  // the selectors to the tab's RenderProcessHost.
+  std::set<std::string> watched_selectors;
+  watched_selectors.insert("a");
+  watched_selectors.insert("div");
+  ExpectWatchPagesMessage(process->sink(), watched_selectors,
+                          [&tracker, &watched_selectors]() {
+    tracker.SetWatchedCssSelectors(watched_selectors);
+  });
+  EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
+
+  // Check that receiving an OnWatchedPageChange message from the tab results in
+  // a request for condition evaluation.
+  const std::vector<std::string> matched_selectors(1, "div");
+  SendOnWatchedPageChangeMessage(tab.get(), matched_selectors);
+  EXPECT_EQ(++expected_evaluation_requests, delegate()->evaluation_requests());
+
+  // Check that GetMatchingCssSelectors produces the same matched selectors as
+  // were sent by the OnWatchedPageChange message.
+  base::hash_set<std::string> matching_selectors;
+  tracker.GetMatchingCssSelectors(tab.get(), &matching_selectors);
+  EXPECT_THAT(matching_selectors,
+              UnorderedElementsAreArray(matched_selectors));
+  EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
+
+  // Check that an in-page navigation has no effect on the matching selectors.
+  {
+    content::LoadCommittedDetails details;
+    details.is_in_page = true;
+    content::FrameNavigateParams params;
+    tracker.OnWebContentsNavigation(tab.get(), details, params);
+    matching_selectors.clear();
+    tracker.GetMatchingCssSelectors(tab.get(), &matching_selectors);
+    EXPECT_THAT(matching_selectors,
+                UnorderedElementsAreArray(matched_selectors));
+    EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
+  }
+
+  // Check that a non in-page navigation clears the matching selectors and
+  // requests condition evaluation.
+  {
+    content::LoadCommittedDetails details;
+    details.is_in_page = false;
+    content::FrameNavigateParams params;
+    tracker.OnWebContentsNavigation(tab.get(), details, params);
+    matching_selectors.clear();
+    tracker.GetMatchingCssSelectors(tab.get(), &matching_selectors);
+    EXPECT_TRUE(matching_selectors.empty());
+    EXPECT_EQ(++expected_evaluation_requests,
+              delegate()->evaluation_requests());
+  }
+}
+
+// https://crbug.com/497586
+TEST_F(DeclarativeContentCssConditionTrackerTest, WebContentsOutlivesTracker) {
+  const scoped_ptr<content::WebContents> tab = MakeTab();
+
+  {
+    DeclarativeContentCssConditionTracker tracker(profile(), delegate());
+    tracker.TrackForWebContents(tab.get());
+  }
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index 97ac5c2..2b135879 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/api/developer_private/developer_private_api.h"
 #include "chrome/browser/extensions/error_console/error_console.h"
@@ -38,12 +39,13 @@
 
 namespace {
 
-KeyedService* BuildAPI(content::BrowserContext* context) {
-  return new DeveloperPrivateAPI(context);
+scoped_ptr<KeyedService> BuildAPI(content::BrowserContext* context) {
+  return make_scoped_ptr(new DeveloperPrivateAPI(context));
 }
 
-KeyedService* BuildEventRouter(content::BrowserContext* profile) {
-  return new EventRouter(profile, ExtensionPrefs::Get(profile));
+scoped_ptr<KeyedService> BuildEventRouter(content::BrowserContext* profile) {
+  return make_scoped_ptr(
+      new EventRouter(profile, ExtensionPrefs::Get(profile)));
 }
 
 }  // namespace
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
index 850be35..11abd8b 100644
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
@@ -5,7 +5,10 @@
 #include "chrome/browser/extensions/api/developer_private/extension_info_generator.h"
 
 #include "base/base64.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/api/commands/command_service.h"
 #include "chrome/browser/extensions/api/developer_private/inspectable_views_finder.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
@@ -244,8 +247,8 @@
 
   if (pending_image_loads_ == 0) {
     // Don't call the callback re-entrantly.
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::Bind(callback, list_));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback, list_));
     list_.clear();
   } else {
     callback_ = callback;
@@ -280,8 +283,8 @@
 
   if (pending_image_loads_ == 0) {
     // Don't call the callback re-entrantly.
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::Bind(callback, list_));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback, list_));
     list_.clear();
   } else {
     callback_ = callback;
diff --git a/chrome/browser/extensions/api/dial/dial_service.cc b/chrome/browser/extensions/api/dial/dial_service.cc
index fb34806..fd86783a 100644
--- a/chrome/browser/extensions/api/dial/dial_service.cc
+++ b/chrome/browser/extensions/api/dial/dial_service.cc
@@ -10,10 +10,13 @@
 
 #include "base/basictypes.h"
 #include "base/callback.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/extensions/api/dial/dial_device_data.h"
 #include "chrome/common/chrome_version_info.h"
@@ -110,7 +113,7 @@
 
 #if !defined(OS_CHROMEOS)
 void GetNetworkListOnFileThread(
-    const scoped_refptr<base::MessageLoopProxy>& loop,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const base::Callback<void(const NetworkInterfaceList& networks)>& cb) {
   NetworkInterfaceList list;
   bool success = net::GetNetworkList(
@@ -118,7 +121,7 @@
   if (!success)
     VLOG(1) << "Could not retrieve network list!";
 
-  loop->PostTask(FROM_HERE, base::Bind(cb, list));
+  task_runner->PostTask(FROM_HERE, base::Bind(cb, list));
 }
 
 #else
@@ -448,10 +451,11 @@
   DiscoverOnAddresses(chrome_os_address_list);
 
 #else
-  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
-      &GetNetworkListOnFileThread,
-      base::MessageLoopProxy::current(), base::Bind(
-          &DialServiceImpl::SendNetworkList, AsWeakPtr())));
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&GetNetworkListOnFileThread,
+                 base::ThreadTaskRunnerHandle::Get(),
+                 base::Bind(&DialServiceImpl::SendNetworkList, AsWeakPtr())));
 #endif
 }
 
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index 0d614aa..a89ed49 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -15,15 +15,18 @@
 #include "base/files/file_util.h"
 #include "base/json/json_writer.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_danger_prompt.h"
@@ -636,7 +639,7 @@
     // Ensure that the callback is called within a time limit.
     weak_ptr_factory_.reset(
         new base::WeakPtrFactory<ExtensionDownloadsEventRouterData>(this));
-    base::MessageLoopForUI::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&ExtensionDownloadsEventRouterData::DetermineFilenameTimeout,
                    weak_ptr_factory_->GetWeakPtr()),
@@ -802,7 +805,7 @@
     // doesn't keep hogging memory.
     weak_ptr_factory_.reset(
         new base::WeakPtrFactory<ExtensionDownloadsEventRouterData>(this));
-    base::MessageLoopForUI::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&ExtensionDownloadsEventRouterData::ClearPendingDeterminers,
                    weak_ptr_factory_->GetWeakPtr()),
@@ -1244,8 +1247,7 @@
 void DownloadsAcceptDangerFunction::PromptOrWait(int download_id, int retries) {
   DownloadItem* download_item =
       GetDownload(GetProfile(), include_incognito(), download_id);
-  content::WebContents* web_contents =
-      dispatcher()->delegate()->GetVisibleWebContents();
+  content::WebContents* web_contents = dispatcher()->GetVisibleWebContents();
   if (InvalidId(download_item, &error_) ||
       Fault(download_item->GetState() != DownloadItem::IN_PROGRESS,
             errors::kNotInProgress, &error_) ||
@@ -1257,10 +1259,9 @@
   bool visible = platform_util::IsVisible(web_contents->GetNativeView());
   if (!visible) {
     if (retries > 0) {
-      base::MessageLoopForUI::current()->PostDelayedTask(
-          FROM_HERE,
-          base::Bind(&DownloadsAcceptDangerFunction::PromptOrWait,
-                     this, download_id, retries - 1),
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+          FROM_HERE, base::Bind(&DownloadsAcceptDangerFunction::PromptOrWait,
+                                this, download_id, retries - 1),
           base::TimeDelta::FromMilliseconds(100));
       return;
     }
@@ -1373,7 +1374,7 @@
   DownloadItem* download_item =
       GetDownload(GetProfile(), include_incognito(), params->download_id);
   content::WebContents* web_contents =
-      dispatcher()->delegate()->GetVisibleWebContents();
+      dispatcher()->GetVisibleWebContents();
   if (InvalidId(download_item, &error_) ||
       Fault(!web_contents, errors::kInvisibleContext, &error_))
     return false;
@@ -1482,7 +1483,7 @@
   DCHECK(icon_size == 16 || icon_size == 32);
   float scale = 1.0;
   content::WebContents* web_contents =
-      dispatcher()->delegate()->GetVisibleWebContents();
+      dispatcher()->GetVisibleWebContents();
   if (web_contents) {
     scale = ui::GetScaleFactorForNativeView(
         web_contents->GetRenderWidgetHostView()->GetNativeView());
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc
index 6a3de13..ab24ca2 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc
@@ -5,6 +5,7 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/stringprintf.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/values.h"
@@ -14,6 +15,7 @@
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/extensions/test_extension_prefs.h"
 #include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/easy_unlock_app_manager.h"
 #include "chrome/browser/signin/easy_unlock_service_factory.h"
 #include "chrome/browser/signin/easy_unlock_service_regular.h"
@@ -419,13 +421,14 @@
 };
 
 // Test factory to register EasyUnlockService.
-KeyedService* BuildTestEasyUnlockService(content::BrowserContext* context) {
-  EasyUnlockService* service =
-      new EasyUnlockServiceRegular(static_cast<Profile*>(context));
+scoped_ptr<KeyedService> BuildTestEasyUnlockService(
+    content::BrowserContext* context) {
+  scoped_ptr<EasyUnlockServiceRegular> service(
+      new EasyUnlockServiceRegular(Profile::FromBrowserContext(context)));
   service->Initialize(
       EasyUnlockAppManager::Create(extensions::ExtensionSystem::Get(context),
-                                   -1 /* manifest id*/, base::FilePath()));
-  return service;
+                                   -1 /* manifest id */, base::FilePath()));
+  return service.Pass();
 }
 
 // A fake EventRouter that logs event it dispatches for testing.
@@ -456,11 +459,12 @@
 };
 
 // FakeEventRouter factory function
-KeyedService* FakeEventRouterFactoryFunction(content::BrowserContext* profile) {
+scoped_ptr<KeyedService> FakeEventRouterFactoryFunction(
+    content::BrowserContext* profile) {
   scoped_ptr<extensions::TestExtensionPrefs> extension_prefs(
       new extensions::TestExtensionPrefs(base::ThreadTaskRunnerHandle::Get()));
-  return new FakeEventRouter(static_cast<Profile*>(profile),
-                             extension_prefs.Pass());
+  return make_scoped_ptr(new FakeEventRouter(static_cast<Profile*>(profile),
+                                             extension_prefs.Pass()));
 }
 
 TEST_F(EasyUnlockPrivateApiTest, AutoPairing) {
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index c00dbc4..c011538d 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -5,7 +5,10 @@
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 
 #include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/active_script_controller.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
@@ -373,7 +376,7 @@
 
 bool ExtensionActionFunction::RunSync() {
   ExtensionActionManager* manager = ExtensionActionManager::Get(GetProfile());
-  if (StartsWithASCII(name(), "systemIndicator.", false)) {
+  if (base::StartsWithASCII(name(), "systemIndicator.", false)) {
     extension_action_ = manager->GetSystemIndicator(*extension());
   } else {
     extension_action_ = manager->GetBrowserAction(*extension());
@@ -644,7 +647,7 @@
   // Waiting is required so that the popup view can be retrieved by the custom
   // bindings for the response callback. It's also needed to keep this function
   // instance around until a notification is observed.
-  base::MessageLoopForUI::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&BrowserActionOpenPopupFunction::OpenPopupTimedOut, this),
       base::TimeDelta::FromSeconds(10));
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
index 821a886e..414a05a 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
@@ -31,7 +31,7 @@
 // This is undesirable, strip it if it exists.
 std::string StripFakepath(const std::string& path) {
   const char kFakePathStr[] = "C:\\fakepath\\";
-  if (StartsWithASCII(path, kFakePathStr, false))
+  if (base::StartsWithASCII(path, kFakePathStr, false))
     return path.substr(arraysize(kFakePathStr) - 1);
   return path;
 }
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
index 37cf8c6..c18938da 100644
--- a/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
@@ -329,8 +329,16 @@
       << message_;
 }
 
+#if defined(ADDRESS_SANITIZER)
+// Flaky when run under ASan: crbug.com/499233.
+#define MAYBE_FileSystemApiOpenDirectoryWithWriteTest \
+  DISABLED_FileSystemApiOpenDirectoryWithWriteTest
+#else
+#define MAYBE_FileSystemApiOpenDirectoryWithWriteTest \
+  FileSystemApiOpenDirectoryWithWriteTest
+#endif
 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive,
-                       FileSystemApiOpenDirectoryWithWriteTest) {
+                       MAYBE_FileSystemApiOpenDirectoryWithWriteTest) {
   base::FilePath test_directory =
       drive::util::GetDriveMountPointPath(browser()->profile()).AppendASCII(
           "root/subdir");
diff --git a/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc b/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
index c63202f..013ebc0b 100644
--- a/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
+++ b/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
@@ -5,10 +5,13 @@
 #include "chrome/browser/extensions/api/gcd_private/gcd_private_api.h"
 
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/local_discovery/cloud_device_list.h"
 #include "chrome/browser/local_discovery/cloud_print_printer_list.h"
 #include "chrome/browser/local_discovery/gcd_api_flow.h"
@@ -447,9 +450,9 @@
 }
 
 void GcdPrivateAPIImpl::RemoveSessionDelayed(int session_id) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-    base::Bind(&GcdPrivateAPIImpl::RemoveSession,
-               weak_ptr_factory_.GetWeakPtr(), session_id));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&GcdPrivateAPIImpl::RemoveSession,
+                            weak_ptr_factory_.GetWeakPtr(), session_id));
 }
 
 scoped_ptr<base::ListValue> GcdPrivateAPIImpl::GetPrefetchedSSIDList() {
diff --git a/chrome/browser/extensions/api/history/history_api.cc b/chrome/browser/extensions/api/history/history_api.cc
index 3354f0f..f95204fc 100644
--- a/chrome/browser/extensions/api/history/history_api.cc
+++ b/chrome/browser/extensions/api/history/history_api.cc
@@ -10,12 +10,14 @@
 #include "base/command_line.h"
 #include "base/json/json_writer.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
@@ -261,7 +263,7 @@
 }
 
 void HistoryFunctionWithCallback::SendAsyncResponse() {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&HistoryFunctionWithCallback::SendResponseToCallback, this));
 }
diff --git a/chrome/browser/extensions/api/hotword_private/hotword_private_apitest.cc b/chrome/browser/extensions/api/hotword_private/hotword_private_apitest.cc
index 1dbf3567..a6c63bf 100644
--- a/chrome/browser/extensions/api/hotword_private/hotword_private_apitest.cc
+++ b/chrome/browser/extensions/api/hotword_private/hotword_private_apitest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/extensions/api/hotword_private/hotword_private_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -98,8 +99,9 @@
     service_available_ = available;
   }
 
-  static KeyedService* Build(content::BrowserContext* profile) {
-    return new MockHotwordService(static_cast<Profile*>(profile));
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* profile) {
+    return make_scoped_ptr(
+        new MockHotwordService(static_cast<Profile*>(profile)));
   }
 
   LaunchMode GetHotwordAudioVerificationLaunchMode() override {
diff --git a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
index 9e1d497..3301db8 100644
--- a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
+++ b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
@@ -179,7 +179,7 @@
   // interpreted as a path, including the fragment.
 
   if (url.scheme() == redirect_scheme_ && !url.has_host() && !url.has_port() &&
-      StartsWithASCII(url.GetContent(), redirect_path_prefix_, true)) {
+      base::StartsWithASCII(url.GetContent(), redirect_path_prefix_, true)) {
     web_flow_.release()->DetachDelegateAndDelete();
 
     std::string fragment = url.GetContent().substr(
@@ -223,7 +223,7 @@
   const char kRedirectPrefix[] = "Loading ";
   std::string prefix(kRedirectPrefix);
 
-  if (StartsWithASCII(title, prefix, true)) {
+  if (base::StartsWithASCII(title, prefix, true)) {
     GURL url(title.substr(prefix.length(), std::string::npos));
     if (url.is_valid())
       OnAuthFlowURLChange(url);
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index f406ec26..0850b45 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -801,7 +801,7 @@
   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
   std::string error =
       utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
-  EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
+  EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false));
   EXPECT_FALSE(func->login_ui_shown());
   EXPECT_FALSE(func->scope_ui_shown());
 }
@@ -814,7 +814,7 @@
   func->set_login_access_token_result(false);
   std::string error = utils::RunFunctionAndReturnError(
       func.get(), "[{}]", browser());
-  EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
+  EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false));
 }
 
 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -843,7 +843,7 @@
       TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
   std::string error =
       utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
-  EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
+  EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false));
   EXPECT_FALSE(func->login_ui_shown());
   EXPECT_FALSE(func->scope_ui_shown());
 }
@@ -857,7 +857,7 @@
       TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR);
   std::string error =
       utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
-  EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
+  EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false));
   EXPECT_FALSE(func->login_ui_shown());
   EXPECT_FALSE(func->scope_ui_shown());
 }
@@ -959,7 +959,7 @@
   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
   std::string error = utils::RunFunctionAndReturnError(
       func.get(), "[{\"interactive\": true}]", browser());
-  EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
+  EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false));
   EXPECT_TRUE(func->login_ui_shown());
   EXPECT_FALSE(func->scope_ui_shown());
 }
@@ -972,7 +972,7 @@
   func->set_login_access_token_result(false);
   std::string error = utils::RunFunctionAndReturnError(
       func.get(), "[{\"interactive\": true}]", browser());
-  EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
+  EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false));
   EXPECT_TRUE(func->login_ui_shown());
   EXPECT_FALSE(func->scope_ui_shown());
 }
@@ -1076,7 +1076,7 @@
   func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR);
   std::string error = utils::RunFunctionAndReturnError(
       func.get(), "[{\"interactive\": true}]", browser());
-  EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
+  EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false));
   EXPECT_FALSE(func->login_ui_shown());
   EXPECT_TRUE(func->scope_ui_shown());
 }
@@ -1498,7 +1498,7 @@
   func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
   std::string error = utils::RunFunctionAndReturnError(
       func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
-  EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
+  EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false));
   EXPECT_FALSE(func->login_ui_shown());
   EXPECT_FALSE(func->scope_ui_shown());
 }
@@ -1515,7 +1515,7 @@
   func->set_login_access_token_result(false);
   std::string error = utils::RunFunctionAndReturnError(
       func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
-  EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
+  EXPECT_TRUE(base::StartsWithASCII(error, errors::kAuthFailure, false));
 }
 
 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
index a2efe15..a8c49da69 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
@@ -97,6 +97,7 @@
 #endif
 
  protected:
+  base::MessageLoopForUI message_loop_;
   image_writer::ImageWriterTestUtils test_utils_;
 };
 
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.cc
index 9c77870..c27385d8 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.cc
@@ -3,7 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h"
 #include "chrome/common/extensions/chrome_utility_extensions_messages.h"
@@ -14,7 +15,8 @@
 using content::BrowserThread;
 
 ImageWriterUtilityClient::ImageWriterUtilityClient()
-    : message_loop_proxy_(base::MessageLoopProxy::current()) {}
+    : task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+}
 ImageWriterUtilityClient::~ImageWriterUtilityClient() {}
 
 void ImageWriterUtilityClient::Write(const ProgressCallback& progress_callback,
@@ -32,7 +34,7 @@
 
   if (!Send(new ChromeUtilityMsg_ImageWriter_Write(source, target))) {
     DLOG(ERROR) << "Unable to send Write message to Utility Process.";
-    message_loop_proxy_->PostTask(
+    task_runner_->PostTask(
         FROM_HERE, base::Bind(error_callback_, "IPC communication failed"));
   }
 }
@@ -52,7 +54,7 @@
 
   if (!Send(new ChromeUtilityMsg_ImageWriter_Verify(source, target))) {
     DLOG(ERROR) << "Unable to send Verify message to Utility Process.";
-    message_loop_proxy_->PostTask(
+    task_runner_->PostTask(
         FROM_HERE, base::Bind(error_callback_, "IPC communication failed"));
   }
 }
@@ -62,7 +64,7 @@
 
   if (!utility_process_host_) {
     // If we haven't connected, there is nothing to cancel.
-    message_loop_proxy_->PostTask(FROM_HERE, cancel_callback);
+    task_runner_->PostTask(FROM_HERE, cancel_callback);
     return;
   }
 
@@ -89,7 +91,7 @@
 void ImageWriterUtilityClient::StartHost() {
   if (!utility_process_host_) {
     scoped_refptr<base::SequencedTaskRunner> task_runner =
-        base::MessageLoop::current()->message_loop_proxy();
+        base::MessageLoop::current()->task_runner();
     utility_process_host_ = content::UtilityProcessHost::Create(
                                 this, task_runner.get())->AsWeakPtr();
     utility_process_host_->SetName(l10n_util::GetStringUTF16(
@@ -105,12 +107,12 @@
 }
 
 void ImageWriterUtilityClient::OnProcessCrashed(int exit_code) {
-  message_loop_proxy_->PostTask(
+  task_runner_->PostTask(
       FROM_HERE, base::Bind(error_callback_, "Utility process crashed."));
 }
 
 void ImageWriterUtilityClient::OnProcessLaunchFailed() {
-  message_loop_proxy_->PostTask(
+  task_runner_->PostTask(
       FROM_HERE, base::Bind(error_callback_, "Process launch failed."));
 }
 
@@ -136,26 +138,24 @@
 
 void ImageWriterUtilityClient::OnWriteImageSucceeded() {
   if (!success_callback_.is_null()) {
-    message_loop_proxy_->PostTask(FROM_HERE, success_callback_);
+    task_runner_->PostTask(FROM_HERE, success_callback_);
   }
 }
 
 void ImageWriterUtilityClient::OnWriteImageCancelled() {
   if (!cancel_callback_.is_null()) {
-    message_loop_proxy_->PostTask(FROM_HERE, cancel_callback_);
+    task_runner_->PostTask(FROM_HERE, cancel_callback_);
   }
 }
 
 void ImageWriterUtilityClient::OnWriteImageFailed(const std::string& message) {
   if (!error_callback_.is_null()) {
-    message_loop_proxy_->PostTask(FROM_HERE,
-                                  base::Bind(error_callback_, message));
+    task_runner_->PostTask(FROM_HERE, base::Bind(error_callback_, message));
   }
 }
 
 void ImageWriterUtilityClient::OnWriteImageProgress(int64 progress) {
   if (!progress_callback_.is_null()) {
-    message_loop_proxy_->PostTask(FROM_HERE,
-                                  base::Bind(progress_callback_, progress));
+    task_runner_->PostTask(FROM_HERE, base::Bind(progress_callback_, progress));
   }
 }
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h
index 5e2d9b5..7af98d0 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h
@@ -7,6 +7,7 @@
 
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/public/browser/utility_process_host.h"
 #include "content/public/browser/utility_process_host_client.h"
@@ -79,7 +80,7 @@
 
   base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
 
-  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(ImageWriterUtilityClient);
 };
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc b/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc
index bec81903..da5fa7423 100644
--- a/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h"
 #include "chrome/browser/extensions/api/image_writer_private/test_utils.h"
@@ -35,8 +36,9 @@
 };
 
 // FakeEventRouter factory function
-KeyedService* FakeEventRouterFactoryFunction(content::BrowserContext* context) {
-  return new FakeEventRouter(static_cast<Profile*>(context));
+scoped_ptr<KeyedService> FakeEventRouterFactoryFunction(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(new FakeEventRouter(static_cast<Profile*>(context)));
 }
 
 namespace {
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
index 4a1b08a4..bc32d81 100644
--- a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
+++ b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "chrome/browser/extensions/api/instance_id/instance_id_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -22,11 +23,12 @@
 
 namespace {
 
-KeyedService* BuildFakeGCMProfileService(content::BrowserContext* context) {
-  gcm::FakeGCMProfileService* service =
-      new gcm::FakeGCMProfileService(Profile::FromBrowserContext(context));
+scoped_ptr<KeyedService> BuildFakeGCMProfileService(
+    content::BrowserContext* context) {
+  scoped_ptr<gcm::FakeGCMProfileService> service(
+      new gcm::FakeGCMProfileService(Profile::FromBrowserContext(context)));
   service->SetDriverForTesting(new instance_id::FakeGCMDriverForInstanceID());
-  return service;
+  return service.Pass();
 }
 
 }  // namespace
diff --git a/chrome/browser/extensions/api/management/management_api_browsertest.cc b/chrome/browser/extensions/api/management/management_api_browsertest.cc
index 26d7a19..22e2f27 100644
--- a/chrome/browser/extensions/api/management/management_api_browsertest.cc
+++ b/chrome/browser/extensions/api/management/management_api_browsertest.cc
@@ -8,7 +8,6 @@
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
-#include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -19,6 +18,7 @@
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/api/management/management_api.h"
 #include "extensions/browser/api/management/management_api_constants.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_system.h"
@@ -110,51 +110,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
-                       UninstallWithConfirmDialog) {
-  ExtensionService* service = ExtensionSystem::Get(browser()->profile())->
-      extension_service();
-
-  // Install an extension.
-  const Extension* extension = InstallExtension(
-      test_data_dir_.AppendASCII("api_test/management/enabled_extension"), 1);
-  ASSERT_TRUE(extension);
-
-  const std::string id = extension->id();
-
-  scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
-  // Uninstall, then cancel via the confirm dialog.
-  scoped_refptr<ManagementUninstallFunction> uninstall_function(
-      new ManagementUninstallFunction());
-  uninstall_function->set_extension(empty_extension.get());
-  uninstall_function->set_user_gesture(true);
-  ManagementUninstallFunction::SetAutoConfirmForTest(false);
-
-  EXPECT_TRUE(MatchPattern(
-      util::RunFunctionAndReturnError(
-          uninstall_function.get(),
-          base::StringPrintf("[\"%s\", {\"showConfirmDialog\": true}]",
-                             id.c_str()),
-          browser()),
-      keys::kUninstallCanceledError));
-
-  // Make sure the extension wasn't uninstalled.
-  EXPECT_TRUE(service->GetExtensionById(id, false) != NULL);
-
-  // Uninstall, then accept via the confirm dialog.
-  uninstall_function = new ManagementUninstallFunction();
-  uninstall_function->set_extension(empty_extension.get());
-  ManagementUninstallFunction::SetAutoConfirmForTest(true);
-  uninstall_function->set_user_gesture(true);
-  util::RunFunctionAndReturnSingleResult(
-      uninstall_function.get(),
-      base::StringPrintf("[\"%s\", {\"showConfirmDialog\": true}]", id.c_str()),
-      browser());
-
-  // Make sure the extension was uninstalled.
-  EXPECT_TRUE(service->GetExtensionById(id, false) == NULL);
-}
-
-IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
                        CreateAppShortcutConfirmDialog) {
   const Extension* app = InstallExtension(
       test_data_dir_.AppendASCII("api_test/management/packaged_app"), 1);
@@ -299,31 +254,40 @@
   // Expect an error about no gesture.
   SetEnabled(true, false, keys::kGestureNeededForEscalationError);
 
-  // Expect an error that user cancelled the dialog.
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::CANCEL;
-  SetEnabled(true, true, keys::kUserDidNotReEnableError);
+  {
+    // Expect an error that user cancelled the dialog.
+    ScopedTestDialogAutoConfirm auto_confirm(
+        ScopedTestDialogAutoConfirm::CANCEL);
+    SetEnabled(true, true, keys::kUserDidNotReEnableError);
+  }
 
-  // This should succeed when user accepts dialog.  We must wait for the process
-  // to connect *and* for the channel to finish initializing before trying to
-  // crash it.  (NOTIFICATION_RENDERER_PROCESS_CREATED does not wait for the
-  // latter and can cause KillProcess to fail on Windows.)
-  content::WindowedNotificationObserver observer(
-      extensions::NOTIFICATION_EXTENSION_HOST_CREATED,
-      content::NotificationService::AllSources());
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
-  SetEnabled(true, true, std::string());
-  observer.Wait();
+  {
+    // This should succeed when user accepts dialog. We must wait for the
+    // process to connect *and* for the channel to finish initializing before
+    // trying to crash it. (NOTIFICATION_RENDERER_PROCESS_CREATED does not wait
+    // for the latter and can cause KillProcess to fail on Windows.)
+    content::WindowedNotificationObserver observer(
+        extensions::NOTIFICATION_EXTENSION_HOST_CREATED,
+        content::NotificationService::AllSources());
+    ScopedTestDialogAutoConfirm auto_confirm(
+        ScopedTestDialogAutoConfirm::ACCEPT);
+    SetEnabled(true, true, std::string());
+    observer.Wait();
+  }
 
-  // Crash the extension. Mock a reload by disabling and then enabling. The
-  // extension should be reloaded and enabled.
-  ASSERT_TRUE(CrashEnabledExtension(kId));
-  SetEnabled(false, true, std::string());
-  SetEnabled(true, true, std::string());
-  const Extension* extension = ExtensionSystem::Get(browser()->profile())
-      ->extension_service()->GetExtensionById(kId, false);
-  EXPECT_TRUE(extension);
+  {
+    // Crash the extension. Mock a reload by disabling and then enabling. The
+    // extension should be reloaded and enabled.
+    ScopedTestDialogAutoConfirm auto_confirm(
+        ScopedTestDialogAutoConfirm::ACCEPT);
+    ASSERT_TRUE(CrashEnabledExtension(kId));
+    SetEnabled(false, true, std::string());
+    SetEnabled(true, true, std::string());
+    const Extension* extension = ExtensionSystem::Get(browser()->profile())
+                                     ->extension_service()
+                                     ->GetExtensionById(kId, false);
+    EXPECT_TRUE(extension);
+  }
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/management/management_api_unittest.cc b/chrome/browser/extensions/api/management/management_api_unittest.cc
index a4845ba1..4d0a4d9f 100644
--- a/chrome/browser/extensions/api/management/management_api_unittest.cc
+++ b/chrome/browser/extensions/api/management/management_api_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_service_test_base.h"
@@ -12,6 +13,7 @@
 #include "extensions/browser/api/management/management_api.h"
 #include "extensions/browser/api/management/management_api_constants.h"
 #include "extensions/browser/event_router_factory.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
@@ -26,12 +28,13 @@
 
 namespace {
 
-KeyedService* BuildManagementApi(content::BrowserContext* context) {
-  return new ManagementAPI(context);
+scoped_ptr<KeyedService> BuildManagementApi(content::BrowserContext* context) {
+  return make_scoped_ptr(new ManagementAPI(context));
 }
 
-KeyedService* BuildEventRouter(content::BrowserContext* profile) {
-  return new extensions::EventRouter(profile, ExtensionPrefs::Get(profile));
+scoped_ptr<KeyedService> BuildEventRouter(content::BrowserContext* profile) {
+  return make_scoped_ptr(
+      new extensions::EventRouter(profile, ExtensionPrefs::Get(profile)));
 }
 
 }  // namespace
@@ -154,60 +157,70 @@
   uninstall_args.AppendString(extension->id());
 
   // Auto-accept any uninstalls.
-  ManagementUninstallFunctionBase::SetAutoConfirmForTest(true);
+  {
+    ScopedTestDialogAutoConfirm auto_confirm(
+        ScopedTestDialogAutoConfirm::ACCEPT);
 
-  // Uninstall requires a user gesture, so this should fail.
-  scoped_refptr<UIThreadExtensionFunction> function(
-      new ManagementUninstallFunction());
-  EXPECT_FALSE(RunFunction(function, uninstall_args));
-  EXPECT_EQ(std::string(constants::kGestureNeededForUninstallError),
-            function->GetError());
+    // Uninstall requires a user gesture, so this should fail.
+    scoped_refptr<UIThreadExtensionFunction> function(
+        new ManagementUninstallFunction());
+    EXPECT_FALSE(RunFunction(function, uninstall_args));
+    EXPECT_EQ(std::string(constants::kGestureNeededForUninstallError),
+              function->GetError());
 
-  ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture;
+    ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture;
 
-  function = new ManagementUninstallFunction();
-  EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
-  EXPECT_TRUE(RunFunction(function, uninstall_args)) << function->GetError();
-  // The extension should be uninstalled.
-  EXPECT_FALSE(registry()->GetExtensionById(
-      extension_id, ExtensionRegistry::EVERYTHING));
+    function = new ManagementUninstallFunction();
+    EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
+    EXPECT_TRUE(RunFunction(function, uninstall_args)) << function->GetError();
+    // The extension should be uninstalled.
+    EXPECT_FALSE(registry()->GetExtensionById(extension_id,
+                                              ExtensionRegistry::EVERYTHING));
+  }
 
   // Install the extension again, and try uninstalling, auto-canceling the
   // dialog.
-  service()->AddExtension(extension.get());
-  function = new ManagementUninstallFunction();
-  ManagementUninstallFunctionBase::SetAutoConfirmForTest(false);
-  EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
-  EXPECT_FALSE(RunFunction(function, uninstall_args));
-  // The uninstall should have failed.
-  EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
-  EXPECT_EQ(ErrorUtils::FormatErrorMessage(constants::kUninstallCanceledError,
-                                           extension_id),
-            function->GetError());
+  {
+    ScopedTestDialogAutoConfirm auto_confirm(
+        ScopedTestDialogAutoConfirm::CANCEL);
+    ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture;
 
-  // Try again, using showConfirmDialog: false.
-  scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue());
-  options->SetBoolean("showConfirmDialog", false);
-  uninstall_args.Append(options.release());
-  function = new ManagementUninstallFunction();
-  EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
-  EXPECT_FALSE(RunFunction(function, uninstall_args));
-  // This should still fail, since extensions can only suppress the dialog for
-  // uninstalling themselves.
-  EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
-  EXPECT_EQ(ErrorUtils::FormatErrorMessage(constants::kUninstallCanceledError,
-                                           extension_id),
-            function->GetError());
+    service()->AddExtension(extension.get());
+    scoped_refptr<UIThreadExtensionFunction> function =
+        new ManagementUninstallFunction();
+    EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
+    EXPECT_FALSE(RunFunction(function, uninstall_args));
+    // The uninstall should have failed.
+    EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
+    EXPECT_EQ(ErrorUtils::FormatErrorMessage(constants::kUninstallCanceledError,
+                                             extension_id),
+              function->GetError());
 
-  // If we try uninstall the extension itself, the uninstall should succeed
-  // (even though we auto-cancel any dialog), because the dialog is never shown.
-  uninstall_args.Remove(0u, nullptr);
-  function = new ManagementUninstallSelfFunction();
-  function->set_extension(extension);
-  EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
-  EXPECT_TRUE(RunFunction(function, uninstall_args)) << function->GetError();
-  EXPECT_FALSE(registry()->GetExtensionById(
-      extension_id, ExtensionRegistry::EVERYTHING));
+    // Try again, using showConfirmDialog: false.
+    scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue());
+    options->SetBoolean("showConfirmDialog", false);
+    uninstall_args.Append(options.release());
+    function = new ManagementUninstallFunction();
+    EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
+    EXPECT_FALSE(RunFunction(function, uninstall_args));
+    // This should still fail, since extensions can only suppress the dialog for
+    // uninstalling themselves.
+    EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
+    EXPECT_EQ(ErrorUtils::FormatErrorMessage(constants::kUninstallCanceledError,
+                                             extension_id),
+              function->GetError());
+
+    // If we try uninstall the extension itself, the uninstall should succeed
+    // (even though we auto-cancel any dialog), because the dialog is never
+    // shown.
+    uninstall_args.Remove(0u, nullptr);
+    function = new ManagementUninstallSelfFunction();
+    function->set_extension(extension);
+    EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
+    EXPECT_TRUE(RunFunction(function, uninstall_args)) << function->GetError();
+    EXPECT_FALSE(registry()->GetExtensionById(extension_id,
+                                              ExtensionRegistry::EVERYTHING));
+  }
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/management/management_apitest.cc b/chrome/browser/extensions/api/management/management_apitest.cc
index d64a32e..91d0b66b 100644
--- a/chrome/browser/extensions/api/management/management_apitest.cc
+++ b/chrome/browser/extensions/api/management/management_apitest.cc
@@ -19,6 +19,7 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/api/management/management_api.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/test_management_policy.h"
 #include "extensions/common/manifest.h"
@@ -128,7 +129,8 @@
 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, MAYBE_Uninstall) {
   LoadExtensions();
   // Confirmation dialog will be shown for uninstallations except for self.
-  extensions::ManagementUninstallFunction::SetAutoConfirmForTest(true);
+  extensions::ScopedTestDialogAutoConfirm auto_confirm(
+      extensions::ScopedTestDialogAutoConfirm::ACCEPT);
   ASSERT_TRUE(RunExtensionSubtest("management/test", "uninstall.html"));
 }
 
@@ -158,7 +160,8 @@
 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,
                        MAYBE_ManagementPolicyAllowed) {
   LoadExtensions();
-  extensions::ManagementUninstallFunction::SetAutoConfirmForTest(true);
+  extensions::ScopedTestDialogAutoConfirm auto_confirm(
+      extensions::ScopedTestDialogAutoConfirm::ACCEPT);
   ExtensionService* service = extensions::ExtensionSystem::Get(
       browser()->profile())->extension_service();
   EXPECT_TRUE(service->GetExtensionById(extension_ids_["enabled_extension"],
diff --git a/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc b/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
index 84e1f08..7c8a190 100644
--- a/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
+++ b/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/api/mdns/mdns_api.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_service_test_base.h"
@@ -10,7 +11,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "extensions/browser/event_router_factory.h"
-#include "extensions/browser/extension_prefs_factory.h"
+#include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/manifest_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -20,14 +21,14 @@
 
 namespace {
 
-KeyedService* MDnsAPITestingFactoryFunction(content::BrowserContext* context) {
-  return new MDnsAPI(context);
+scoped_ptr<KeyedService> MDnsAPITestingFactoryFunction(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(new MDnsAPI(context));
 }
 
-KeyedService* BuildEventRouter(content::BrowserContext* profile) {
-  return new extensions::EventRouter(
-      profile,
-      ExtensionPrefsFactory::GetInstance()->GetForBrowserContext((profile)));
+scoped_ptr<KeyedService> BuildEventRouter(content::BrowserContext* context) {
+  return make_scoped_ptr(
+      new extensions::EventRouter(context, ExtensionPrefs::Get(context)));
 }
 
 // For ExtensionService interface when it requires a path that is not used.
@@ -93,11 +94,6 @@
         .Times(1);
     render_process_host_.reset();
     extensions::ExtensionServiceTestBase::TearDown();
-    MDnsAPI::GetFactoryInstance()->SetTestingFactory(
-        browser_context(),
-        nullptr);
-
-    registry_ = nullptr;
   }
 
   virtual MockDnsSdRegistry* dns_sd_registry() {
@@ -226,10 +222,10 @@
   MOCK_METHOD1(BroadcastEventPtr, void(Event* event));
 };
 
-KeyedService* MockEventRouterFactoryFunction(content::BrowserContext* profile) {
-  return new MockEventRouter(
-      profile,
-      ExtensionPrefsFactory::GetInstance()->GetForBrowserContext((profile)));
+scoped_ptr<KeyedService> MockEventRouterFactoryFunction(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(
+      new MockEventRouter(context, ExtensionPrefs::Get(context)));
 }
 
 class MDnsAPIMaxServicesTest : public MDnsAPITest {
diff --git a/chrome/browser/extensions/api/messaging/message_property_provider.cc b/chrome/browser/extensions/api/messaging/message_property_provider.cc
index 1d6603b..b52b027 100644
--- a/chrome/browser/extensions/api/messaging/message_property_provider.cc
+++ b/chrome/browser/extensions/api/messaging/message_property_provider.cc
@@ -48,7 +48,7 @@
 // MessagePropertyProvider::GetChannelID.
 struct MessagePropertyProvider::GetChannelIDOutput {
   scoped_ptr<crypto::ECPrivateKey> channel_id_key;
-  net::ChannelIDService::RequestHandle request_handle;
+  net::ChannelIDService::Request request;
 };
 
 // static
@@ -67,9 +67,8 @@
                  original_task_runner,
                  base::Owned(output),
                  reply);
-  int status = channel_id_service->GetChannelID(host, &output->channel_id_key,
-                                                net_completion_callback,
-                                                &output->request_handle);
+  int status = channel_id_service->GetChannelID(
+      host, &output->channel_id_key, net_completion_callback, &output->request);
   if (status == net::ERR_IO_PENDING)
     return;
   GotChannelID(original_task_runner, output, reply, status);
diff --git a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
index f6734ef..1e09561 100644
--- a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
@@ -13,7 +13,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
index 6a3a503d..7bc876ae 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
@@ -7,6 +7,7 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/onc/onc_constants.h"
@@ -276,10 +277,10 @@
     }
   }
 
-  static KeyedService* GetNetworkingPrivateDelegate(
+  static scoped_ptr<KeyedService> GetNetworkingPrivateDelegate(
       content::BrowserContext* profile) {
     CHECK(s_test_delegate_);
-    return s_test_delegate_;
+    return make_scoped_ptr(s_test_delegate_);
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
index 89a201f..17f9050 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
@@ -6,6 +6,7 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
@@ -229,10 +230,11 @@
                               state, true /* add_to_visible */);
   }
 
-  static KeyedService* CreateNetworkingPrivateServiceClient(
-      content::BrowserContext* profile) {
+  static scoped_ptr<KeyedService> CreateNetworkingPrivateServiceClient(
+      content::BrowserContext* context) {
     scoped_ptr<CryptoVerifyStub> crypto_verify(new CryptoVerifyStub);
-    return new NetworkingPrivateChromeOS(profile, crypto_verify.Pass());
+    return make_scoped_ptr(
+        new NetworkingPrivateChromeOS(context, crypto_verify.Pass()));
   }
 
   void SetUpOnMainThread() override {
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_service_client_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_service_client_apitest.cc
index 6de03c9..eafc1e5 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_service_client_apitest.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_service_client_apitest.cc
@@ -6,6 +6,7 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/networking_private/networking_private_credentials_getter.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -83,12 +84,12 @@
         "epcifkihnkjgphfkloaaleeakhpmgdmn");
   }
 
-  static KeyedService* CreateNetworkingPrivateServiceClient(
-      content::BrowserContext* profile) {
+  static scoped_ptr<KeyedService> CreateNetworkingPrivateServiceClient(
+      content::BrowserContext* context) {
     scoped_ptr<wifi::FakeWiFiService> wifi_service(new wifi::FakeWiFiService());
     scoped_ptr<CryptoVerifyStub> crypto_verify(new CryptoVerifyStub);
-    return new NetworkingPrivateServiceClient(wifi_service.Pass(),
-                                              crypto_verify.Pass());
+    return scoped_ptr<KeyedService>(new NetworkingPrivateServiceClient(
+        wifi_service.Pass(), crypto_verify.Pass()));
   }
 
   void SetUpOnMainThread() override {
diff --git a/chrome/browser/extensions/api/preference/preference_apitest.cc b/chrome/browser/extensions/api/preference/preference_apitest.cc
index 0728517..441f597b 100644
--- a/chrome/browser/extensions/api/preference/preference_apitest.cc
+++ b/chrome/browser/extensions/api/preference/preference_apitest.cc
@@ -2,8 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/location.h"
 #include "base/prefs/pref_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -88,7 +91,7 @@
   void TearDownOnMainThread() override {
     // ReleaseBrowserProcessModule() needs to be called in a message loop, so we
     // post a task to do it, then run the message loop.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&ReleaseBrowserProcessModule));
     content::RunAllPendingInMessageLoop();
 
diff --git a/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc b/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc
index 89bc5e81..3798371a 100644
--- a/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc
+++ b/chrome/browser/extensions/api/preferences_private/preferences_private_apitest.cc
@@ -7,9 +7,12 @@
 #include "base/bind_helpers.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/preferences_private/preferences_private_api.h"
@@ -54,9 +57,10 @@
 
   ~FakeProfileSyncService() override {}
 
-  static KeyedService* BuildFakeProfileSyncService(
+  static scoped_ptr<KeyedService> BuildFakeProfileSyncService(
       content::BrowserContext* context) {
-    return new FakeProfileSyncService(static_cast<Profile*>(context));
+    return make_scoped_ptr(
+        new FakeProfileSyncService(static_cast<Profile*>(context)));
   }
 
   void set_sync_initialized(bool sync_initialized) {
@@ -74,7 +78,7 @@
     // Set sync initialized state to true so the function will run after
     // OnStateChanged is called.
     sync_initialized_ = true;
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&sync_driver::SyncServiceObserver::OnStateChanged,
                               base::Unretained(observer)));
   }
diff --git a/chrome/browser/extensions/api/processes/processes_api.cc b/chrome/browser/extensions/api/processes/processes_api.cc
index e2cc202b..23dffa1 100644
--- a/chrome/browser/extensions/api/processes/processes_api.cc
+++ b/chrome/browser/extensions/api/processes/processes_api.cc
@@ -7,10 +7,12 @@
 #include "base/callback.h"
 #include "base/json/json_writer.h"
 #include "base/lazy_instance.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/processes/processes_api_constants.h"
@@ -548,8 +550,9 @@
   if (ProcessesAPI::Get(GetProfile())
           ->processes_event_router()
           ->is_task_manager_listening()) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
-        &GetProcessIdForTabFunction::GetProcessIdForTab, this));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&GetProcessIdForTabFunction::GetProcessIdForTab, this));
   } else {
     TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
         base::Bind(&GetProcessIdForTabFunction::GetProcessIdForTab, this));
@@ -609,8 +612,8 @@
   if (ProcessesAPI::Get(GetProfile())
           ->processes_event_router()
           ->is_task_manager_listening()) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
-        &TerminateFunction::TerminateProcess, this));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&TerminateFunction::TerminateProcess, this));
   } else {
     TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
         base::Bind(&TerminateFunction::TerminateProcess, this));
@@ -697,8 +700,9 @@
   if (ProcessesAPI::Get(GetProfile())
           ->processes_event_router()
           ->is_task_manager_listening()) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
-        &GetProcessInfoFunction::GatherProcessInfo, this));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&GetProcessInfoFunction::GatherProcessInfo, this));
   } else {
     TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
         base::Bind(&GetProcessInfoFunction::GatherProcessInfo, this));
diff --git a/chrome/browser/extensions/api/reading_list_private/reading_list_private_apitest.cc b/chrome/browser/extensions/api/reading_list_private/reading_list_private_apitest.cc
index 375ff99..1a5bea5 100644
--- a/chrome/browser/extensions/api/reading_list_private/reading_list_private_apitest.cc
+++ b/chrome/browser/extensions/api/reading_list_private/reading_list_private_apitest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/dom_distiller/dom_distiller_service_factory.h"
 #include "chrome/browser/extensions/api/reading_list_private/reading_list_private_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -31,7 +32,7 @@
 
 class ReadingListPrivateApiTest : public ExtensionApiTest {
  public:
-  static KeyedService* Build(content::BrowserContext* context) {
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* context) {
     FakeDB<ArticleEntry>* fake_db =
         new FakeDB<ArticleEntry>(new FakeDB<ArticleEntry>::EntryMap);
     FakeDistiller* distiller = new FakeDistiller(true);
@@ -46,22 +47,21 @@
     dom_distiller::DistilledPagePrefs::RegisterProfilePrefs(
         pref_service->registry());
 
-    DomDistillerContextKeyedService* service =
+    scoped_ptr<DomDistillerContextKeyedService> service(
         new DomDistillerContextKeyedService(
-            scoped_ptr<DomDistillerStoreInterface>(
-                CreateStoreWithFakeDB(fake_db,
-                                      FakeDB<ArticleEntry>::EntryMap())),
+            scoped_ptr<DomDistillerStoreInterface>(CreateStoreWithFakeDB(
+                fake_db, FakeDB<ArticleEntry>::EntryMap())),
             scoped_ptr<DistillerFactory>(distiller_factory),
             scoped_ptr<DistillerPageFactory>(distiller_page_factory),
             scoped_ptr<dom_distiller::DistilledPagePrefs>(
-                new dom_distiller::DistilledPagePrefs(pref_service)));
+                new dom_distiller::DistilledPagePrefs(pref_service))));
     fake_db->InitCallback(true);
     fake_db->LoadCallback(true);
     EXPECT_CALL(*distiller_factory, CreateDistillerImpl())
         .WillOnce(testing::Return(distiller));
     EXPECT_CALL(*distiller_page_factory, CreateDistillerPageImpl())
         .WillOnce(testing::Return(distiller_page));
-    return service;
+    return service.Pass();
   }
 };
 
diff --git a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc
index 7c48a56..1652078f 100644
--- a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc
+++ b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc
@@ -7,8 +7,10 @@
 #include <string>
 #include <utility>
 
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
@@ -119,29 +121,23 @@
     // extension function unloading the extension has to be done
     // asynchronously. Fortunately PostTask guarentees FIFO order so just
     // post both tasks.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&ExtensionService::TerminateExtension,
-                   service->AsWeakPtr(),
-                   extension_id));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&ExtensionService::TerminateExtension,
+                              service->AsWeakPtr(), extension_id));
     extensions::WarningSet warnings;
     warnings.insert(
         extensions::Warning::CreateReloadTooFrequentWarning(
             extension_id));
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&extensions::WarningService::NotifyWarningsOnUI,
-                   browser_context_,
-                   warnings));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&extensions::WarningService::NotifyWarningsOnUI,
+                              browser_context_, warnings));
   } else {
     // We can't call ReloadExtension directly, since when this method finishes
     // it tries to decrease the reference count for the extension, which fails
     // if the extension has already been reloaded; so instead we post a task.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&ExtensionService::ReloadExtension,
-                   service->AsWeakPtr(),
-                   extension_id));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&ExtensionService::ReloadExtension,
+                              service->AsWeakPtr(), extension_id));
   }
 }
 
@@ -159,7 +155,7 @@
           base::Bind(&ChromeRuntimeAPIDelegate::UpdateCheckComplete,
                      base::Unretained(this),
                      extension_id))) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(callback, UpdateCheckResult(true, kUpdateThrottled, "")));
   } else {
diff --git a/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
index 36c02d59..f85f4797 100644
--- a/chrome/browser/extensions/api/sessions/sessions_apitest.cc
+++ b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -90,7 +90,7 @@
   void SetUpOnMainThread() override;
 
  protected:
-  static KeyedService* BuildProfileSyncService(
+  static scoped_ptr<KeyedService> BuildProfileSyncService(
       content::BrowserContext* profile);
 
   void CreateTestProfileSyncService();
@@ -121,11 +121,10 @@
   CreateTestExtension();
 }
 
-KeyedService* ExtensionSessionsTest::BuildProfileSyncService(
-    content::BrowserContext* profile) {
-
-  ProfileSyncComponentsFactoryMock* factory =
-      new ProfileSyncComponentsFactoryMock();
+scoped_ptr<KeyedService> ExtensionSessionsTest::BuildProfileSyncService(
+    content::BrowserContext* context) {
+  scoped_ptr<ProfileSyncComponentsFactoryMock> factory(
+      new ProfileSyncComponentsFactoryMock());
 
   factory->SetLocalDeviceInfoProvider(
       scoped_ptr<sync_driver::LocalDeviceInfoProvider>(
@@ -137,9 +136,8 @@
               sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
               "device_id")));
 
-  return new ProfileSyncServiceMock(
-      scoped_ptr<ProfileSyncComponentsFactory>(factory),
-      static_cast<Profile*>(profile));
+  return make_scoped_ptr(new ProfileSyncServiceMock(
+      factory.Pass(), static_cast<Profile*>(context)));
 }
 
 void ExtensionSessionsTest::CreateTestProfileSyncService() {
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 11440853..ac8d93f 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -36,15 +36,29 @@
   if (s_whitelist)
     return *s_whitelist;
   s_whitelist = new PrefsUtil::TypedPrefMap();
-  (*s_whitelist)["browser.show_home_button"] =
+  (*s_whitelist)["alternate_error_pages.enabled"] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)["bookmark_bar.show_on_all_tabs"] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["browser.show_home_button"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)["download.default_directory"] =
       settings_private::PrefType::PREF_TYPE_STRING;
   (*s_whitelist)["download.prompt_for_download"] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["enable_do_not_track"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)["homepage"] = settings_private::PrefType::PREF_TYPE_URL;
+  (*s_whitelist)["net.network_prediction_options"] =
+      settings_private::PrefType::PREF_TYPE_NUMBER;
+  (*s_whitelist)["safebrowsing.enabled"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["safebrowsing.extended_reporting_enabled"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["search.suggest_enabled"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["spellcheck.use_spelling_service"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
 
 #if defined(OS_CHROMEOS)
   (*s_whitelist)["cros.accounts.allowBWSI"] =
@@ -77,6 +91,12 @@
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)["settings.touchpad.enable_tap_dragging"] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["cros.metrics.reportingEnabled"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["cros.device.attestation_for_content_protection_enabled"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["settings.internet.wake_on_wifi_ssid"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
 #endif
 
   return *s_whitelist;
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc b/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
index d2e48cf..4941a237 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
+++ b/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/settings_private/settings_private_delegate.h"
diff --git a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
index 1cb5733..34ad282 100644
--- a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
+++ b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api_unittest.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "base/guid.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/values.h"
@@ -144,9 +145,10 @@
   MOCK_CONST_METHOD0(GetDeviceInfoTracker, DeviceInfoTracker*());
 };
 
-KeyedService* CreateProfileSyncServiceMock(content::BrowserContext* profile) {
-  return new ProfileSyncServiceMockForExtensionTests(
-      Profile::FromBrowserContext(profile));
+scoped_ptr<KeyedService> CreateProfileSyncServiceMock(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(new ProfileSyncServiceMockForExtensionTests(
+      Profile::FromBrowserContext(context)));
 }
 
 class ExtensionSignedInDevicesTest : public ExtensionApiUnittest {
diff --git a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_manager_unittest.cc b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_manager_unittest.cc
index 322ef96..b044515d 100644
--- a/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_manager_unittest.cc
+++ b/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_manager_unittest.cc
@@ -19,20 +19,14 @@
 
 namespace extensions {
 
-namespace {
-KeyedService* CreateProfileSyncServiceMock(content::BrowserContext* profile) {
-  return NULL;
-}
-}  // namespace
-
 // Adds a listener and removes it.
 TEST(SignedInDevicesManager, UpdateListener) {
   content::TestBrowserThreadBundle thread_bundle;
   scoped_ptr<TestingProfile> profile(new TestingProfile());
   SigninManagerFactory::GetForProfile(profile.get())->
       SetAuthenticatedAccountInfo("gaia_id", "foo");
-  ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
-      profile.get(), CreateProfileSyncServiceMock);
+  ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(profile.get(),
+                                                              nullptr);
   SignedInDevicesManager manager(profile.get());
 
   EventListenerInfo info(api::signed_in_devices::OnDeviceInfoChange::kEventName,
diff --git a/chrome/browser/extensions/api/socket/socket_api_unittest.cc b/chrome/browser/extensions/api/socket/socket_api_unittest.cc
index 7634f1e9..00447a8 100644
--- a/chrome/browser/extensions/api/socket/socket_api_unittest.cc
+++ b/chrome/browser/extensions/api/socket/socket_api_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process_impl.h"
 #include "chrome/browser/extensions/extension_api_unittest.h"
@@ -16,7 +17,8 @@
 
 namespace extensions {
 
-KeyedService* ApiResourceManagerTestFactory(content::BrowserContext* context) {
+scoped_ptr<KeyedService> ApiResourceManagerTestFactory(
+    content::BrowserContext* context) {
   content::BrowserThread::ID id;
   CHECK(content::BrowserThread::GetCurrentThreadIdentifier(&id));
   return ApiResourceManager<Socket>::CreateApiResourceManagerForTest(context,
diff --git a/chrome/browser/extensions/api/socket/udp_socket_unittest.cc b/chrome/browser/extensions/api/socket/udp_socket_unittest.cc
index e8dce59..deced9d 100644
--- a/chrome/browser/extensions/api/socket/udp_socket_unittest.cc
+++ b/chrome/browser/extensions/api/socket/udp_socket_unittest.cc
@@ -6,9 +6,11 @@
 
 #include <string>
 
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "net/base/io_buffer.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -90,9 +92,9 @@
   if (result == 0) {
     scoped_refptr<net::IOBuffer> data = new net::WrappedIOBuffer(test_message);
     src->Write(data, test_message_length, base::Bind(&OnSendCompleted));
-    base::MessageLoopForIO::current()->PostDelayedTask(FROM_HERE,
-          base::Bind(&SendMulticastPacket, src, result),
-          base::TimeDelta::FromSeconds(1));
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&SendMulticastPacket, src, result),
+        base::TimeDelta::FromSeconds(1));
   } else {
     QuitMessageLoop();
     FAIL() << "Failed to connect to multicast address. Error code: " << result;
@@ -126,9 +128,8 @@
   src.Connect(kGroup, kPort, base::Bind(&SendMulticastPacket, &src));
 
   // If not received within the test action timeout, quit the message loop.
-  io_loop.PostDelayedTask(FROM_HERE,
-                          base::Bind(&QuitMessageLoop),
-                          TestTimeouts::action_timeout());
+  io_loop.task_runner()->PostDelayedTask(
+      FROM_HERE, base::Bind(&QuitMessageLoop), TestTimeouts::action_timeout());
 
   io_loop.Run();
 
diff --git a/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api_unittest.cc b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api_unittest.cc
index 1a31f09..a18abba3 100644
--- a/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api_unittest.cc
+++ b/chrome/browser/extensions/api/sockets_tcp_server/sockets_tcp_server_api_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process_impl.h"
 #include "chrome/browser/extensions/extension_api_unittest.h"
@@ -18,7 +19,7 @@
 namespace extensions {
 namespace core_api {
 
-static KeyedService* ApiResourceManagerTestFactory(
+static scoped_ptr<KeyedService> ApiResourceManagerTestFactory(
     content::BrowserContext* context) {
   content::BrowserThread::ID id;
   CHECK(content::BrowserThread::GetCurrentThreadIdentifier(&id));
@@ -26,7 +27,7 @@
       ResumableTCPSocket>::CreateApiResourceManagerForTest(context, id);
 }
 
-static KeyedService* ApiResourceManagerTestServerFactory(
+static scoped_ptr<KeyedService> ApiResourceManagerTestServerFactory(
     content::BrowserContext* context) {
   content::BrowserThread::ID id;
   CHECK(content::BrowserThread::GetCurrentThreadIdentifier(&id));
diff --git a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
index 100303e..c0f7656 100644
--- a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
+++ b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
@@ -195,13 +195,13 @@
   std::map<std::string, TestingValueStore*> created_;
 };
 
-KeyedService* MockExtensionSystemFactoryFunction(
+scoped_ptr<KeyedService> MockExtensionSystemFactoryFunction(
     content::BrowserContext* context) {
-  return new MockExtensionSystem(context);
+  return make_scoped_ptr(new MockExtensionSystem(context));
 }
 
-KeyedService* BuildEventRouter(content::BrowserContext* profile) {
-  return new extensions::EventRouter(profile, nullptr);
+scoped_ptr<KeyedService> BuildEventRouter(content::BrowserContext* profile) {
+  return make_scoped_ptr(new extensions::EventRouter(profile, nullptr));
 }
 
 }  // namespace
@@ -220,8 +220,8 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     profile_.reset(new TestingProfile(temp_dir_.path()));
     storage_factory_->Reset(new LeveldbSettingsStorageFactory());
-    frontend_.reset(
-        StorageFrontend::CreateForTesting(storage_factory_, profile_.get()));
+    frontend_ = StorageFrontend::CreateForTesting(storage_factory_,
+                                                  profile_.get()).Pass();
 
     ExtensionsBrowserClient::Get()
         ->GetExtensionSystemFactory()
diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc b/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
index c58fa82..a903caf 100644
--- a/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
+++ b/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
@@ -44,7 +44,8 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_F(SystemIndicatorApiTest, FLAKY_SystemIndicator) {
+// Failing on 10.6, flaky elsewhere http://crbug.com/497643
+IN_PROC_BROWSER_TEST_F(SystemIndicatorApiTest, DISABLED_SystemIndicator) {
   // Only run this test on supported platforms.  SystemIndicatorManagerFactory
   // returns NULL on unsupported platforms.
   extensions::SystemIndicatorManager* manager =
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
index 7908329..06ae5b2 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -4,8 +4,10 @@
 
 #include "base/basictypes.h"
 #include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/tab_helper.h"
@@ -333,7 +335,7 @@
       const bool has_changed = media_state != last_media_state_;
       last_media_state_ = media_state;
       if (has_changed) {
-        base::MessageLoop::current()->PostTask(
+        base::ThreadTaskRunnerHandle::Get()->PostTask(
             FROM_HERE, base::MessageLoop::QuitClosure());
       }
     }
diff --git a/chrome/browser/extensions/api/tabs/ash_panel_contents.cc b/chrome/browser/extensions/api/tabs/ash_panel_contents.cc
index 8502c00..86286c3 100644
--- a/chrome/browser/extensions/api/tabs/ash_panel_contents.cc
+++ b/chrome/browser/extensions/api/tabs/ash_panel_contents.cc
@@ -18,7 +18,6 @@
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/app_window/native_app_window.h"
 #include "extensions/common/extension.h"
-#include "extensions/common/extension_messages.h"
 #include "ui/gfx/image/image.h"
 
 using extensions::AppWindow;
@@ -168,9 +167,6 @@
                                   const GURL& url) {
   url_ = url;
 
-  extension_function_dispatcher_.reset(
-      new extensions::ExtensionFunctionDispatcher(context, this));
-
   web_contents_.reset(
       content::WebContents::Create(content::WebContents::CreateParams(
           context, content::SiteInstance::CreateForURL(context, url_))));
@@ -187,8 +183,6 @@
   // AppWindow::Init())
   launcher_favicon_loader_.reset(
       new LauncherFaviconLoader(this, web_contents_.get()));
-
-  content::WebContentsObserver::Observe(web_contents_.get());
 }
 
 void AshPanelContents::LoadContents(int32 creator_process_id) {
@@ -216,32 +210,12 @@
   return web_contents_.get();
 }
 
+extensions::WindowController* AshPanelContents::GetWindowController() const {
+  return window_controller_.get();
+}
+
 void AshPanelContents::FaviconUpdated() {
   gfx::Image new_image = gfx::Image::CreateFrom1xBitmap(
       launcher_favicon_loader_->GetFavicon());
   host_->UpdateAppIcon(new_image);
 }
-
-bool AshPanelContents::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(AshPanelContents, message)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-extensions::WindowController*
-AshPanelContents::GetExtensionWindowController() const {
-  return window_controller_.get();
-}
-
-content::WebContents* AshPanelContents::GetAssociatedWebContents() const {
-  return web_contents_.get();
-}
-
-void AshPanelContents::OnRequest(
-    const ExtensionHostMsg_Request_Params& params) {
-  extension_function_dispatcher_->Dispatch(
-      params, web_contents_->GetRenderViewHost());
-}
diff --git a/chrome/browser/extensions/api/tabs/ash_panel_contents.h b/chrome/browser/extensions/api/tabs/ash_panel_contents.h
index 9c11365..bedb4ae 100644
--- a/chrome/browser/extensions/api/tabs/ash_panel_contents.h
+++ b/chrome/browser/extensions/api/tabs/ash_panel_contents.h
@@ -10,9 +10,7 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/ash/launcher/launcher_favicon_loader.h"
-#include "content/public/browser/web_contents_observer.h"
 #include "extensions/browser/app_window/app_window.h"
-#include "extensions/browser/extension_function_dispatcher.h"
 
 class AshPanelWindowController;
 class GURL;
@@ -32,9 +30,7 @@
 // extensions API.
 class AshPanelContents
     : public extensions::AppWindowContents,
-      public content::WebContentsObserver,
-      public LauncherFaviconLoader::Delegate,
-      public extensions::ExtensionFunctionDispatcher::Delegate {
+      public LauncherFaviconLoader::Delegate {
  public:
   explicit AshPanelContents(extensions::AppWindow* host);
   ~AshPanelContents() override;
@@ -47,29 +43,19 @@
   void NativeWindowClosed() override;
   void DispatchWindowShownForTests() const override;
   content::WebContents* GetWebContents() const override;
+  extensions::WindowController* GetWindowController() const override;
 
   // LauncherFaviconLoader::Delegate overrides:
   void FaviconUpdated() override;
 
-  // extensions::ExtensionFunctionDispatcher::Delegate
-  extensions::WindowController* GetExtensionWindowController() const override;
-  content::WebContents* GetAssociatedWebContents() const override;
-
   LauncherFaviconLoader* launcher_favicon_loader_for_test() {
     return launcher_favicon_loader_.get();
   }
 
  private:
-  // content::WebContentsObserver
-  bool OnMessageReceived(const IPC::Message& message) override;
-
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
-
   extensions::AppWindow* host_;
   GURL url_;
   scoped_ptr<content::WebContents> web_contents_;
-  scoped_ptr<extensions::ExtensionFunctionDispatcher>
-      extension_function_dispatcher_;
   scoped_ptr<AshPanelWindowController> window_controller_;
   scoped_ptr<LauncherFaviconLoader> launcher_favicon_loader_;
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index 72795ac..828f6fd7 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -10,15 +10,17 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/apps/scoped_keep_alive.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
@@ -573,7 +575,7 @@
           extension());
       AshPanelContents* ash_panel_contents = new AshPanelContents(app_window);
       app_window->Init(urls[0], ash_panel_contents, create_params);
-      SetResult(ash_panel_contents->GetExtensionWindowController()
+      SetResult(ash_panel_contents->GetWindowController()
                     ->CreateWindowValueWithTabs(extension()));
       return true;
     }
@@ -1677,11 +1679,10 @@
            .empty()) {
     // Delay the callback invocation until after the current JS call has
     // returned.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(
-            &TabsDetectLanguageFunction::GotLanguage,
-            this,
+            &TabsDetectLanguageFunction::GotLanguage, this,
             chrome_translate_client->GetLanguageState().original_language()));
     return true;
   }
diff --git a/chrome/browser/extensions/api/tabs/windows_util.cc b/chrome/browser/extensions/api/tabs/windows_util.cc
index 0cb10e3..48c6824f 100644
--- a/chrome/browser/extensions/api/tabs/windows_util.cc
+++ b/chrome/browser/extensions/api/tabs/windows_util.cc
@@ -22,7 +22,7 @@
   ChromeExtensionFunctionDetails function_details(function);
   if (window_id == extension_misc::kCurrentWindowId) {
     extensions::WindowController* extension_window_controller =
-        function->dispatcher()->delegate()->GetExtensionWindowController();
+        function->dispatcher()->GetExtensionWindowController();
     // If there is a window controller associated with this extension, use that.
     if (extension_window_controller) {
       *controller = extension_window_controller;
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index 797bde9..25d132336 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -11,10 +11,11 @@
 #include "base/files/file_path.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_string_value_serializer.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_member.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
@@ -160,7 +161,8 @@
     EXPECT_EQ(ExtensionMsg_MessageInvoke::ID, message->type());
 
     EXPECT_FALSE(task_queue_.empty());
-    base::MessageLoop::current()->PostTask(FROM_HERE, task_queue_.front());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  task_queue_.front());
     task_queue_.pop();
 
     sent_messages_.push_back(linked_ptr<IPC::Message>(message));
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
index d03bf541..1089877 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -614,10 +614,11 @@
 
     // The bitmap fetcher will call us back via OnFetchComplete.
     icon_fetcher_.reset(new chrome::BitmapFetcher(icon_url, this));
-    icon_fetcher_->Start(
+    icon_fetcher_->Init(
         browser_context()->GetRequestContext(), std::string(),
         net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
         net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES);
+    icon_fetcher_->Start();
   } else {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
index 245d053..a304a04 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
@@ -26,6 +26,7 @@
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/browser/api/management/management_api.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/install/extension_install_ui.h"
 #include "gpu/config/gpu_feature_type.h"
@@ -117,8 +118,8 @@
   void SetUpOnMainThread() override {
     ExtensionApiTest::SetUpOnMainThread();
 
-    ExtensionInstallPrompt::g_auto_confirm_for_tests =
-        ExtensionInstallPrompt::ACCEPT;
+    auto_confirm_install_.reset(
+        new ScopedTestDialogAutoConfirm(ScopedTestDialogAutoConfirm::ACCEPT));
 
     ASSERT_TRUE(webstore_install_dir_.CreateUniqueTempDir());
     webstore_install_dir_copy_ = webstore_install_dir_.path();
@@ -148,8 +149,6 @@
   // Navigates to |page| and runs the Extension API test there. Any downloads
   // of extensions will return the contents of |crx_file|.
   bool RunInstallTest(const std::string& page, const std::string& crx_file) {
-    // Auto-confirm the uninstallation dialog.
-    ManagementUninstallFunction::SetAutoConfirmForTest(true);
 #if defined(OS_WIN) && !defined(NDEBUG)
     // See http://crbug.com/177163 for details.
     return true;
@@ -176,6 +175,10 @@
   // WebstoreInstaller needs a reference to a FilePath when setting the download
   // directory for testing.
   base::FilePath webstore_install_dir_copy_;
+
+  scoped_ptr<ScopedTestDialogAutoConfirm> auto_confirm_install_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExtensionWebstorePrivateApiTest);
 };
 
 // Test cases for webstore origin frame blocking.
@@ -238,8 +241,7 @@
 
 // Now test the case where the user cancels the confirmation dialog.
 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallCancelled) {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::CANCEL;
+  ScopedTestDialogAutoConfirm auto_cancel(ScopedTestDialogAutoConfirm::CANCEL);
   ASSERT_TRUE(RunInstallTest("cancelled.html", "extension.crx"));
 }
 
diff --git a/chrome/browser/extensions/app_background_page_apitest.cc b/chrome/browser/extensions/app_background_page_apitest.cc
index a494945..50f6469 100644
--- a/chrome/browser/extensions/app_background_page_apitest.cc
+++ b/chrome/browser/extensions/app_background_page_apitest.cc
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/location.h"
 #include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/background/background_contents_service.h"
 #include "chrome/browser/background/background_contents_service_factory.h"
 #include "chrome/browser/background/background_mode_manager.h"
@@ -109,7 +112,7 @@
   }
 
   void UnloadExtensionViaTask(const std::string& id) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&AppBackgroundPageApiTest::UnloadExtension, this, id));
   }
diff --git a/chrome/browser/extensions/app_data_migrator_unittest.cc b/chrome/browser/extensions/app_data_migrator_unittest.cc
index c369710..8bb4f43 100644
--- a/chrome/browser/extensions/app_data_migrator_unittest.cc
+++ b/chrome/browser/extensions/app_data_migrator_unittest.cc
@@ -5,7 +5,6 @@
 #include <string>
 
 #include "base/callback_forward.h"
-#include "base/message_loop/message_loop.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/extensions/app_data_migrator.h"
 #include "chrome/browser/extensions/extension_special_storage_policy.h"
@@ -49,7 +48,7 @@
 
     idb_context_ = default_partition_->GetIndexedDBContext();
     idb_context_->SetTaskRunnerForTesting(
-        base::MessageLoop::current()->message_loop_proxy().get());
+        base::MessageLoop::current()->task_runner().get());
 
     default_fs_context_ = default_partition_->GetFileSystemContext();
 
diff --git a/chrome/browser/extensions/app_sync_data_unittest.cc b/chrome/browser/extensions/app_sync_data_unittest.cc
index ca4e7ef..0c0b28e 100644
--- a/chrome/browser/extensions/app_sync_data_unittest.cc
+++ b/chrome/browser/extensions/app_sync_data_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/extensions/app_sync_data.h"
 
+#include "extensions/common/extension.h"
 #include "sync/api/string_ordinal.h"
 #include "sync/protocol/app_specifics.pb.h"
 #include "sync/protocol/sync.pb.h"
@@ -15,6 +16,7 @@
 const char kName[] = "MyExtension";
 const char kValidVersion[] = "0.0.0.0";
 const char kValidUpdateUrl[] = "http://clients2.google.com/service/update2/crx";
+const int kValidDisableReasons = Extension::DISABLE_USER_ACTION;
 
 class AppSyncDataTest : public testing::Test {
  public:
@@ -27,7 +29,7 @@
     extension_specifics->set_update_url(kValidUpdateUrl);
     extension_specifics->set_version(kValidVersion);
     extension_specifics->set_enabled(false);
-    extension_specifics->set_disable_reasons(0);
+    extension_specifics->set_disable_reasons(kValidDisableReasons);
     extension_specifics->set_incognito_enabled(true);
     extension_specifics->set_remote_install(false);
     extension_specifics->set_all_urls_enabled(true);
diff --git a/chrome/browser/extensions/blob_reader.cc b/chrome/browser/extensions/blob_reader.cc
index c8d4218..33ec6327 100644
--- a/chrome/browser/extensions/blob_reader.cc
+++ b/chrome/browser/extensions/blob_reader.cc
@@ -21,7 +21,7 @@
     : callback_(callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   GURL blob_url;
-  if (StartsWithASCII(blob_uuid, "blob:blobinternal", true)) {
+  if (base::StartsWithASCII(blob_uuid, "blob:blobinternal", true)) {
     // TODO(michaeln): remove support for deprecated blob urls
     blob_url = GURL(blob_uuid);
   } else {
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc
index c15e0de0..57ec926a 100644
--- a/chrome/browser/extensions/bookmark_app_helper.cc
+++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -253,10 +253,11 @@
     bitmap_fetcher_.reset(
         new chrome::BitmapFetcher(urls_to_download_.back(), this));
     urls_to_download_.pop_back();
-    bitmap_fetcher_->Start(
+    bitmap_fetcher_->Init(
         service_->profile()->GetRequestContext(), std::string(),
         net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
         net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES);
+    bitmap_fetcher_->Start();
   }
 
   void FinishInstallation() {
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
index 35e9a17..88bbd94 100644
--- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -54,15 +54,6 @@
 #include "chrome/browser/extensions/token_cache/token_cache_service_factory.h"
 #include "chrome/browser/extensions/warning_badge_service_factory.h"
 #include "chrome/browser/speech/extension_api/tts_extension_api.h"
-#include "extensions/browser/api/api_resource_manager.h"
-#include "extensions/browser/api/bluetooth/bluetooth_api.h"
-#include "extensions/browser/api/bluetooth/bluetooth_private_api.h"
-#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
-#include "extensions/browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h"
-#include "extensions/browser/api/power/power_api.h"
-#include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_private_api.h"
-#include "extensions/browser/api/web_request/web_request_api.h"
-#include "extensions/browser/declarative_user_script_manager_factory.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/extensions/file_manager/event_router_factory.h"
@@ -84,15 +75,11 @@
   extensions::AutofillPrivateEventRouterFactory::GetInstance();
   extensions::BookmarksAPI::GetFactoryInstance();
   extensions::BookmarkManagerPrivateAPI::GetFactoryInstance();
-  extensions::BluetoothAPI::GetFactoryInstance();
-  extensions::BluetoothLowEnergyAPI::GetFactoryInstance();
-  extensions::BluetoothPrivateAPI::GetFactoryInstance();
   extensions::BrailleDisplayPrivateAPI::GetFactoryInstance();
   extensions::chromedirectsetting::ChromeDirectSettingAPI::GetFactoryInstance();
   extensions::CommandService::GetFactoryInstance();
   extensions::ContentSettingsService::GetFactoryInstance();
   extensions::CookiesAPI::GetFactoryInstance();
-  extensions::DeclarativeUserScriptManagerFactory::GetInstance();
   extensions::DeveloperPrivateAPI::GetFactoryInstance();
   extensions::DialAPIFactory::GetInstance();
   extensions::EasyUnlockPrivateAPI::GetFactoryInstance();
@@ -127,7 +114,6 @@
 #if defined(ENABLE_PLUGINS)
   extensions::PluginManager::GetFactoryInstance();
 #endif  // defined(ENABLE_PLUGINS)
-  extensions::PowerAPI::GetFactoryInstance();
   extensions::PreferenceAPI::GetFactoryInstance();
   extensions::ProcessesAPI::GetFactoryInstance();
   extensions::ScreenlockPrivateEventRouter::GetFactoryInstance();
@@ -143,12 +129,8 @@
   extensions::TabCaptureRegistry::GetFactoryInstance();
   extensions::TabsWindowsAPI::GetFactoryInstance();
   extensions::TtsAPI::GetFactoryInstance();
-#if defined(OS_CHROMEOS)
-  extensions::VirtualKeyboardAPI::GetFactoryInstance();
-#endif
   extensions::WarningBadgeServiceFactory::GetInstance();
   extensions::WebNavigationAPI::GetFactoryInstance();
-  extensions::WebRequestAPI::GetFactoryInstance();
   extensions::WebrtcAudioPrivateEventService::GetFactoryInstance();
   extensions::WebstoreAPI::GetFactoryInstance();
 #if defined(OS_CHROMEOS)
@@ -156,7 +138,6 @@
 #endif
   TokenCacheServiceFactory::GetInstance();
   extensions::ExtensionGCMAppHandler::GetFactoryInstance();
-  extensions::core_api::BluetoothSocketEventDispatcher::GetFactoryInstance();
 }
 
 }  // namespace chrome_extensions
diff --git a/chrome/browser/extensions/chrome_content_verifier_delegate.cc b/chrome/browser/extensions/chrome_content_verifier_delegate.cc
new file mode 100644
index 0000000..5e412e7
--- /dev/null
+++ b/chrome/browser/extensions/chrome_content_verifier_delegate.cc
@@ -0,0 +1,188 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/chrome_content_verifier_delegate.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/string_util.h"
+#include "base/version.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/management_policy.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_urls.h"
+#include "extensions/common/extensions_client.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_url_handlers.h"
+#include "net/base/escape.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
+#endif
+
+namespace {
+
+const char kContentVerificationExperimentName[] =
+    "ExtensionContentVerification";
+
+}  // namespace
+
+namespace extensions {
+
+// static
+ContentVerifierDelegate::Mode ChromeContentVerifierDelegate::GetDefaultMode() {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+
+  Mode experiment_value = NONE;
+  const std::string group =
+      base::FieldTrialList::FindFullName(kContentVerificationExperimentName);
+  if (group == "EnforceStrict")
+    experiment_value = ContentVerifierDelegate::ENFORCE_STRICT;
+  else if (group == "Enforce")
+    experiment_value = ContentVerifierDelegate::ENFORCE;
+  else if (group == "Bootstrap")
+    experiment_value = ContentVerifierDelegate::BOOTSTRAP;
+
+  // The field trial value that normally comes from the server can be
+  // overridden on the command line, which we don't want to allow since
+  // malware can set chrome command line flags. There isn't currently a way
+  // to find out what the server-provided value is in this case, so we
+  // conservatively default to the strictest mode if we detect our experiment
+  // name being overridden.
+  if (command_line->HasSwitch(switches::kForceFieldTrials)) {
+    std::string forced_trials =
+        command_line->GetSwitchValueASCII(switches::kForceFieldTrials);
+    if (forced_trials.find(kContentVerificationExperimentName) !=
+        std::string::npos)
+      experiment_value = ContentVerifierDelegate::ENFORCE_STRICT;
+  }
+
+  Mode cmdline_value = NONE;
+  if (command_line->HasSwitch(switches::kExtensionContentVerification)) {
+    std::string switch_value = command_line->GetSwitchValueASCII(
+        switches::kExtensionContentVerification);
+    if (switch_value == switches::kExtensionContentVerificationBootstrap)
+      cmdline_value = ContentVerifierDelegate::BOOTSTRAP;
+    else if (switch_value == switches::kExtensionContentVerificationEnforce)
+      cmdline_value = ContentVerifierDelegate::ENFORCE;
+    else if (switch_value ==
+             switches::kExtensionContentVerificationEnforceStrict)
+      cmdline_value = ContentVerifierDelegate::ENFORCE_STRICT;
+    else
+      // If no value was provided (or the wrong one), just default to enforce.
+      cmdline_value = ContentVerifierDelegate::ENFORCE;
+  }
+
+  // We don't want to allow the command-line flags to eg disable enforcement
+  // if the experiment group says it should be on, or malware may just modify
+  // the command line flags. So return the more restrictive of the 2 values.
+  return std::max(experiment_value, cmdline_value);
+}
+
+ChromeContentVerifierDelegate::ChromeContentVerifierDelegate(
+    content::BrowserContext* context)
+    : context_(context), default_mode_(GetDefaultMode()) {
+}
+
+ChromeContentVerifierDelegate::~ChromeContentVerifierDelegate() {
+}
+
+ContentVerifierDelegate::Mode ChromeContentVerifierDelegate::ShouldBeVerified(
+    const Extension& extension) {
+#if defined(OS_CHROMEOS)
+  if (ExtensionAssetsManagerChromeOS::IsSharedInstall(&extension))
+    return ContentVerifierDelegate::ENFORCE_STRICT;
+#endif
+
+  if (!extension.is_extension() && !extension.is_legacy_packaged_app())
+    return ContentVerifierDelegate::NONE;
+  if (!Manifest::IsAutoUpdateableLocation(extension.location()))
+    return ContentVerifierDelegate::NONE;
+
+  if (!ManifestURL::UpdatesFromGallery(&extension)) {
+    // It's possible that the webstore update url was overridden for testing
+    // so also consider extensions with the default (production) update url
+    // to be from the store as well.
+    GURL default_webstore_url = extension_urls::GetDefaultWebstoreUpdateUrl();
+    if (ManifestURL::GetUpdateURL(&extension) != default_webstore_url)
+      return ContentVerifierDelegate::NONE;
+  }
+
+  return default_mode_;
+}
+
+ContentVerifierKey ChromeContentVerifierDelegate::GetPublicKey() {
+  return ContentVerifierKey(extension_misc::kWebstoreSignaturesPublicKey,
+                            extension_misc::kWebstoreSignaturesPublicKeySize);
+}
+
+GURL ChromeContentVerifierDelegate::GetSignatureFetchUrl(
+    const std::string& extension_id,
+    const base::Version& version) {
+  // TODO(asargent) Factor out common code from the extension updater's
+  // ManifestFetchData class that can be shared for use here.
+  std::vector<std::string> parts;
+  parts.push_back("uc");
+  parts.push_back("installsource=signature");
+  parts.push_back("id=" + extension_id);
+  parts.push_back("v=" + version.GetString());
+  std::string x_value =
+      net::EscapeQueryParamValue(JoinString(parts, "&"), true);
+  std::string query = "response=redirect&x=" + x_value;
+
+  GURL base_url = extension_urls::GetWebstoreUpdateUrl();
+  GURL::Replacements replacements;
+  replacements.SetQuery(query.c_str(), url::Component(0, query.length()));
+  return base_url.ReplaceComponents(replacements);
+}
+
+std::set<base::FilePath> ChromeContentVerifierDelegate::GetBrowserImagePaths(
+    const extensions::Extension* extension) {
+  return ExtensionsClient::Get()->GetBrowserImagePaths(extension);
+}
+
+void ChromeContentVerifierDelegate::VerifyFailed(
+    const std::string& extension_id,
+    ContentVerifyJob::FailureReason reason) {
+  ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
+  const Extension* extension =
+      registry->enabled_extensions().GetByID(extension_id);
+  if (!extension)
+    return;
+  ExtensionSystem* system = ExtensionSystem::Get(context_);
+  Mode mode = ShouldBeVerified(*extension);
+  if (mode >= ContentVerifierDelegate::ENFORCE) {
+    if (!system->management_policy()->UserMayModifySettings(extension, NULL)) {
+      LogFailureForPolicyForceInstall(extension_id);
+      return;
+    }
+    system->extension_service()->DisableExtension(extension_id,
+                                                  Extension::DISABLE_CORRUPTED);
+    ExtensionPrefs::Get(context_)->IncrementCorruptedDisableCount();
+    UMA_HISTOGRAM_BOOLEAN("Extensions.CorruptExtensionBecameDisabled", true);
+    UMA_HISTOGRAM_ENUMERATION("Extensions.CorruptExtensionDisabledReason",
+                              reason, ContentVerifyJob::FAILURE_REASON_MAX);
+  } else if (!ContainsKey(would_be_disabled_ids_, extension_id)) {
+    UMA_HISTOGRAM_BOOLEAN("Extensions.CorruptExtensionWouldBeDisabled", true);
+    would_be_disabled_ids_.insert(extension_id);
+  }
+}
+
+void ChromeContentVerifierDelegate::LogFailureForPolicyForceInstall(
+    const std::string& extension_id) {
+  if (!ContainsKey(corrupt_policy_extensions_, extension_id)) {
+    corrupt_policy_extensions_.insert(extension_id);
+    UMA_HISTOGRAM_BOOLEAN("Extensions.CorruptPolicyExtensionWouldBeDisabled",
+                          true);
+  }
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_content_verifier_delegate.h b/chrome/browser/extensions/chrome_content_verifier_delegate.h
new file mode 100644
index 0000000..4104f56
--- /dev/null
+++ b/chrome/browser/extensions/chrome_content_verifier_delegate.h
@@ -0,0 +1,55 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_CHROME_CONTENT_VERIFIER_DELEGATE_H_
+#define CHROME_BROWSER_EXTENSIONS_CHROME_CONTENT_VERIFIER_DELEGATE_H_
+
+#include "extensions/browser/content_verifier_delegate.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+
+class ChromeContentVerifierDelegate : public ContentVerifierDelegate {
+ public:
+  static Mode GetDefaultMode();
+
+  explicit ChromeContentVerifierDelegate(content::BrowserContext* context);
+
+  ~ChromeContentVerifierDelegate() override;
+
+  // ContentVerifierDelegate:
+  Mode ShouldBeVerified(const Extension& extension) override;
+  ContentVerifierKey GetPublicKey() override;
+  GURL GetSignatureFetchUrl(const std::string& extension_id,
+                            const base::Version& version) override;
+  std::set<base::FilePath> GetBrowserImagePaths(
+      const extensions::Extension* extension) override;
+  void VerifyFailed(const std::string& extension_id,
+                    ContentVerifyJob::FailureReason reason) override;
+
+ private:
+  void LogFailureForPolicyForceInstall(const std::string& extension_id);
+
+  content::BrowserContext* context_;
+  ContentVerifierDelegate::Mode default_mode_;
+
+  // For reporting metrics in BOOTSTRAP mode, when an extension would be
+  // disabled if content verification was in ENFORCE mode.
+  std::set<std::string> would_be_disabled_ids_;
+
+  // Currently enterprise policy extensions that must remain enabled will not
+  // be disabled due to content verification failure, but we are considering
+  // changing this (crbug.com/447040), so for now we are tracking how often
+  // this happens to help inform the decision.
+  std::set<std::string> corrupt_policy_extensions_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeContentVerifierDelegate);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_CHROME_CONTENT_VERIFIER_DELEGATE_H_
diff --git a/chrome/browser/extensions/chrome_extension_function.cc b/chrome/browser/extensions/chrome_extension_function.cc
index 15cbe1f..5b749974 100644
--- a/chrome/browser/extensions/chrome_extension_function.cc
+++ b/chrome/browser/extensions/chrome_extension_function.cc
@@ -48,7 +48,7 @@
   // If the delegate has an associated browser, return it.
   if (dispatcher()) {
     extensions::WindowController* window_controller =
-        dispatcher()->delegate()->GetExtensionWindowController();
+        dispatcher()->GetExtensionWindowController();
     if (window_controller) {
       Browser* browser = window_controller->GetBrowser();
       if (browser)
@@ -87,7 +87,7 @@
   // If the delegate has an associated window controller, return it.
   if (dispatcher()) {
     extensions::WindowController* window_controller =
-        dispatcher()->delegate()->GetExtensionWindowController();
+        dispatcher()->GetExtensionWindowController();
     if (window_controller)
       return window_controller;
   }
diff --git a/chrome/browser/extensions/chrome_extension_function_details.cc b/chrome/browser/extensions/chrome_extension_function_details.cc
index d80c0812..614511fc 100644
--- a/chrome/browser/extensions/chrome_extension_function_details.cc
+++ b/chrome/browser/extensions/chrome_extension_function_details.cc
@@ -54,7 +54,7 @@
   // If the delegate has an associated browser, return it.
   if (function_->dispatcher()) {
     extensions::WindowController* window_controller =
-        function_->dispatcher()->delegate()->GetExtensionWindowController();
+        function_->dispatcher()->GetExtensionWindowController();
     if (window_controller) {
       Browser* browser = window_controller->GetBrowser();
       if (browser)
@@ -93,7 +93,7 @@
   // If the delegate has an associated window controller, return it.
   if (function_->dispatcher()) {
     extensions::WindowController* window_controller =
-        function_->dispatcher()->delegate()->GetExtensionWindowController();
+        function_->dispatcher()->GetExtensionWindowController();
     if (window_controller)
       return window_controller;
   }
diff --git a/chrome/browser/extensions/chrome_extension_web_contents_observer.h b/chrome/browser/extensions/chrome_extension_web_contents_observer.h
index e501199..a43842bb 100644
--- a/chrome/browser/extensions/chrome_extension_web_contents_observer.h
+++ b/chrome/browser/extensions/chrome_extension_web_contents_observer.h
@@ -32,6 +32,9 @@
 
   // content::WebContentsObserver overrides.
   void RenderViewCreated(content::RenderViewHost* render_view_host) override;
+
+  // Silence a warning about hiding a virtual function.
+  using ExtensionWebContentsObserver::OnMessageReceived;
   bool OnMessageReceived(const IPC::Message& message,
                          content::RenderFrameHost* render_frame_host) override;
 
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 1e838eaa..a1f2547 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/extensions/chrome_app_sorting.h"
 #include "chrome/browser/extensions/chrome_component_extension_resource_manager.h"
 #include "chrome/browser/extensions/chrome_extension_host_delegate.h"
+#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/extensions/chrome_mojo_service_registration.h"
 #include "chrome/browser/extensions/chrome_process_manager_delegate.h"
 #include "chrome/browser/extensions/chrome_url_request_util.h"
@@ -317,4 +318,10 @@
   return true;
 }
 
+ExtensionWebContentsObserver*
+ChromeExtensionsBrowserClient::GetExtensionWebContentsObserver(
+    content::WebContents* web_contents) {
+  return ChromeExtensionWebContentsObserver::FromWebContents(web_contents);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h
index 021ec62..10e0d714 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.h
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -101,6 +101,8 @@
   ExtensionCache* GetExtensionCache() override;
   bool IsBackgroundUpdateAllowed() override;
   bool IsMinBrowserVersionSupported(const std::string& min_version) override;
+  ExtensionWebContentsObserver* GetExtensionWebContentsObserver(
+      content::WebContents* web_contents) override;
 
  private:
   friend struct base::DefaultLazyInstanceTraits<ChromeExtensionsBrowserClient>;
diff --git a/chrome/browser/extensions/chrome_url_request_util.cc b/chrome/browser/extensions/chrome_url_request_util.cc
index 45511510..fcfa3a57 100644
--- a/chrome/browser/extensions/chrome_url_request_util.cc
+++ b/chrome/browser/extensions/chrome_url_request_util.cc
@@ -98,7 +98,7 @@
                       const net::CompletionCallback& callback,
                       bool read_result) {
     *out_mime_type = *read_mime_type;
-    if (StartsWithASCII(*read_mime_type, "text/", false)) {
+    if (base::StartsWithASCII(*read_mime_type, "text/", false)) {
       // All of our HTML files should be UTF-8 and for other resource types
       // (like images), charset doesn't matter.
       DCHECK(base::IsStringUTF8(base::StringPiece(
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 1d14a83..ce26c96 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -319,19 +319,6 @@
 
 void ComponentLoader::AddFileManagerExtension() {
 #if defined(OS_CHROMEOS)
-#ifndef NDEBUG
-  const base::CommandLine* command_line =
-      base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) {
-    base::FilePath filemgr_extension_path(
-        command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath));
-    AddWithNameAndDescription(IDR_FILEMANAGER_MANIFEST,
-                              filemgr_extension_path,
-                              IDS_FILEMANAGER_APP_NAME,
-                              IDS_FILEMANAGER_APP_DESCRIPTION);
-    return;
-  }
-#endif  // NDEBUG
   AddWithNameAndDescription(IDR_FILEMANAGER_MANIFEST,
                             base::FilePath(FILE_PATH_LITERAL("file_manager")),
                             IDS_FILEMANAGER_APP_NAME,
diff --git a/chrome/browser/extensions/display_info_provider_chromeos.cc b/chrome/browser/extensions/display_info_provider_chromeos.cc
index 673a15a..687c4182 100644
--- a/chrome/browser/extensions/display_info_provider_chromeos.cc
+++ b/chrome/browser/extensions/display_info_provider_chromeos.cc
@@ -7,7 +7,6 @@
 #include "ash/display/display_controller.h"
 #include "ash/display/display_manager.h"
 #include "ash/shell.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/string_number_conversions.h"
 #include "extensions/common/api/system_display.h"
 #include "ui/gfx/display.h"
diff --git a/chrome/browser/extensions/extension_action_test_util.cc b/chrome/browser/extensions/extension_action_test_util.cc
index da6756e..6a6eddc 100644
--- a/chrome/browser/extensions/extension_action_test_util.cc
+++ b/chrome/browser/extensions/extension_action_test_util.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/extensions/extension_action_test_util.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
@@ -69,10 +70,10 @@
 }
 
 // Creates a new ExtensionToolbarModel for the given |context|.
-KeyedService* BuildToolbarModel(content::BrowserContext* context) {
-  return new extensions::ExtensionToolbarModel(
+scoped_ptr<KeyedService> BuildToolbarModel(content::BrowserContext* context) {
+  return make_scoped_ptr(new extensions::ExtensionToolbarModel(
       Profile::FromBrowserContext(context),
-      extensions::ExtensionPrefs::Get(context));
+      extensions::ExtensionPrefs::Get(context)));
 }
 
 // Creates a new ExtensionToolbarModel for the given profile, optionally
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index c370197..febd0962 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -41,7 +41,7 @@
 
 scoped_ptr<net::test_server::HttpResponse> HandleServerRedirectRequest(
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(request.relative_url, "/server-redirect?", true))
+  if (!base::StartsWithASCII(request.relative_url, "/server-redirect?", true))
     return nullptr;
 
   size_t query_string_pos = request.relative_url.find('?');
@@ -57,7 +57,7 @@
 
 scoped_ptr<net::test_server::HttpResponse> HandleEchoHeaderRequest(
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(request.relative_url, "/echoheader?", true))
+  if (!base::StartsWithASCII(request.relative_url, "/echoheader?", true))
     return nullptr;
 
   size_t query_string_pos = request.relative_url.find('?');
@@ -79,7 +79,7 @@
 
 scoped_ptr<net::test_server::HttpResponse> HandleSetCookieRequest(
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(request.relative_url, "/set-cookie?", true))
+  if (!base::StartsWithASCII(request.relative_url, "/set-cookie?", true))
     return nullptr;
 
   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
@@ -101,7 +101,7 @@
 
 scoped_ptr<net::test_server::HttpResponse> HandleSetHeaderRequest(
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(request.relative_url, "/set-header?", true))
+  if (!base::StartsWithASCII(request.relative_url, "/set-header?", true))
     return nullptr;
 
   size_t query_string_pos = request.relative_url.find('?');
diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc
index b66804f..c5499b5 100644
--- a/chrome/browser/extensions/extension_disabled_ui.cc
+++ b/chrome/browser/extensions/extension_disabled_ui.cc
@@ -9,12 +9,14 @@
 
 #include "base/bind.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -351,7 +353,8 @@
   if (extensions::util::IsExtensionSupervised(extension_, service_->profile()))
     return;
   // Delay extension reenabling so this bubble closes properly.
-  base::MessageLoop::current()->PostTask(FROM_HERE,
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
       base::Bind(&ExtensionService::GrantPermissionsAndEnableExtension,
                  service_->AsWeakPtr(), extension_));
 }
@@ -367,7 +370,7 @@
       service_->profile(), browser->window()->GetNativeWindow(), this));
   // Delay showing the uninstall dialog, so that this function returns
   // immediately, to close the bubble properly. See crbug.com/121544.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&extensions::ExtensionUninstallDialog::ConfirmUninstall,
                  uninstall_dialog_->AsWeakPtr(), extension_,
@@ -400,6 +403,9 @@
   GlobalErrorServiceFactory::GetForProfile(service_->profile())->
       RemoveGlobalError(this);
 
+  // Make sure we don't call RemoveGlobalError again.
+  registrar_.RemoveAll();
+
   if (type == extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED)
     user_response_ = REENABLE;
   else if (type == extensions::NOTIFICATION_EXTENSION_REMOVED)
diff --git a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
index 34eaa7ce..c35d8b4 100644
--- a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
@@ -19,6 +19,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
@@ -147,8 +148,8 @@
 
 // Tests uninstalling a disabled extension with an uninstall dialog.
 IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, UninstallFromDialog) {
-  extensions::ExtensionUninstallDialog::ScopedAutoConfirm auto_confirm(
-      extensions::ExtensionUninstallDialog::ACCEPT);
+  extensions::ScopedTestDialogAutoConfirm auto_confirm(
+      extensions::ScopedTestDialogAutoConfirm::ACCEPT);
   const Extension* extension = InstallAndUpdateIncreasingPermissionsExtension();
   ASSERT_TRUE(extension);
   std::string extension_id = extension->id();
diff --git a/chrome/browser/extensions/extension_function_test_utils.cc b/chrome/browser/extensions/extension_function_test_utils.cc
index 9403b17..9ac1523 100644
--- a/chrome/browser/extensions/extension_function_test_utils.cc
+++ b/chrome/browser/extensions/extension_function_test_utils.cc
@@ -176,8 +176,8 @@
                  RunFunctionFlags flags) {
   TestFunctionDispatcherDelegate dispatcher_delegate(browser);
   scoped_ptr<extensions::ExtensionFunctionDispatcher> dispatcher(
-      new extensions::ExtensionFunctionDispatcher(browser->profile(),
-                                                  &dispatcher_delegate));
+      new extensions::ExtensionFunctionDispatcher(browser->profile()));
+  dispatcher->set_delegate(&dispatcher_delegate);
   // TODO(yoz): The cast is a hack; these flags should be defined in
   // only one place.  See crbug.com/394840.
   return extensions::api_test_utils::RunFunction(
diff --git a/chrome/browser/extensions/extension_garbage_collector.cc b/chrome/browser/extensions/extension_garbage_collector.cc
index 12877296..febd496 100644
--- a/chrome/browser/extensions/extension_garbage_collector.cc
+++ b/chrome/browser/extensions/extension_garbage_collector.cc
@@ -7,12 +7,14 @@
 #include "base/bind.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/extensions/extension_garbage_collector_factory.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -171,7 +173,7 @@
     // Don't garbage collect while there are installations in progress,
     // which may be using the temporary installation directory. Try to garbage
     // collect again later.
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&ExtensionGarbageCollector::GarbageCollectExtensions,
                    weak_factory_.GetWeakPtr()),
diff --git a/chrome/browser/extensions/extension_garbage_collector_factory.cc b/chrome/browser/extensions/extension_garbage_collector_factory.cc
index ea93370..debcaf0f 100644
--- a/chrome/browser/extensions/extension_garbage_collector_factory.cc
+++ b/chrome/browser/extensions/extension_garbage_collector_factory.cc
@@ -42,18 +42,18 @@
 ExtensionGarbageCollectorFactory::~ExtensionGarbageCollectorFactory() {}
 
 // static
-KeyedService* ExtensionGarbageCollectorFactory::BuildInstanceFor(
+scoped_ptr<KeyedService> ExtensionGarbageCollectorFactory::BuildInstanceFor(
     content::BrowserContext* context) {
 #if defined(OS_CHROMEOS)
-  return new ExtensionGarbageCollectorChromeOS(context);
+  return make_scoped_ptr(new ExtensionGarbageCollectorChromeOS(context));
 #else
-  return new ExtensionGarbageCollector(context);
+  return make_scoped_ptr(new ExtensionGarbageCollector(context));
 #endif
 }
 
 KeyedService* ExtensionGarbageCollectorFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  return BuildInstanceFor(context);
+  return BuildInstanceFor(context).release();
 }
 
 bool ExtensionGarbageCollectorFactory::ServiceIsCreatedWithBrowserContext()
diff --git a/chrome/browser/extensions/extension_garbage_collector_factory.h b/chrome/browser/extensions/extension_garbage_collector_factory.h
index 2f4f5d14..5e5852c 100644
--- a/chrome/browser/extensions/extension_garbage_collector_factory.h
+++ b/chrome/browser/extensions/extension_garbage_collector_factory.h
@@ -24,7 +24,8 @@
 
   static ExtensionGarbageCollectorFactory* GetInstance();
 
-  static KeyedService* BuildInstanceFor(content::BrowserContext* profile);
+  static scoped_ptr<KeyedService> BuildInstanceFor(
+      content::BrowserContext* context);
 
  private:
   friend struct DefaultSingletonTraits<ExtensionGarbageCollectorFactory>;
diff --git a/chrome/browser/extensions/extension_gcm_app_handler.cc b/chrome/browser/extensions/extension_gcm_app_handler.cc
index 2a43d18..835c3d4 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler.cc
@@ -7,6 +7,8 @@
 #include "base/bind.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/gcm/gcm_api.h"
 #include "chrome/browser/profiles/profile.h"
@@ -121,10 +123,9 @@
     // the single function ExtensionService::AddExtension.
     AddDummyAppHandler();
 
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&ExtensionGCMAppHandler::RemoveDummyAppHandler,
-                   weak_factory_.GetWeakPtr()));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&ExtensionGCMAppHandler::RemoveDummyAppHandler,
+                              weak_factory_.GetWeakPtr()));
   }
 
   // When the extention is being uninstalled, it will be unloaded first. We
@@ -182,11 +183,9 @@
   // InstanceIDDriver::RemoveInstanceID will delete the InstanceID itself.
   // Postpone to do it outside this calling context to avoid any risk to
   // the caller.
-  base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&ExtensionGCMAppHandler::RemoveInstanceID,
-                   weak_factory_.GetWeakPtr(),
-                   app_id));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&ExtensionGCMAppHandler::RemoveInstanceID,
+                            weak_factory_.GetWeakPtr(), app_id));
 }
 
 void ExtensionGCMAppHandler::RemoveInstanceID(const std::string& app_id) {
diff --git a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
index 1daefc7..cf3feb4 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
@@ -187,15 +188,15 @@
 
 class ExtensionGCMAppHandlerTest : public testing::Test {
  public:
-  static KeyedService* BuildGCMProfileService(
+  static scoped_ptr<KeyedService> BuildGCMProfileService(
       content::BrowserContext* context) {
-    return new gcm::GCMProfileService(
+    return make_scoped_ptr(new gcm::GCMProfileService(
         Profile::FromBrowserContext(context),
         scoped_ptr<gcm::GCMClientFactory>(new gcm::FakeGCMClientFactory(
             content::BrowserThread::GetMessageLoopProxyForThread(
                 content::BrowserThread::UI),
             content::BrowserThread::GetMessageLoopProxyForThread(
-                content::BrowserThread::IO))));
+                content::BrowserThread::IO)))));
   }
 
   ExtensionGCMAppHandlerTest()
diff --git a/chrome/browser/extensions/extension_install_checker_unittest.cc b/chrome/browser/extensions/extension_install_checker_unittest.cc
index 7f3ff309..0758a3f 100644
--- a/chrome/browser/extensions/extension_install_checker_unittest.cc
+++ b/chrome/browser/extensions/extension_install_checker_unittest.cc
@@ -3,8 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/extension_install_checker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -101,21 +103,19 @@
   void CheckRequirements() override {
     requirements_check_called_ = true;
 
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ExtensionInstallCheckerForTest::MockCheckRequirements,
-                   base::Unretained(this),
-                   current_sequence_number()));
+                   base::Unretained(this), current_sequence_number()));
   }
 
   void CheckBlacklistState() override {
     blacklist_check_called_ = true;
 
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ExtensionInstallCheckerForTest::MockCheckBlacklistState,
-                   base::Unretained(this),
-                   current_sequence_number()));
+                   base::Unretained(this), current_sequence_number()));
   }
 };
 
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index 6ad43587..cbc7a6e 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -7,13 +7,15 @@
 #include <map>
 
 #include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/prefs/pref_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/bundle_installer.h"
 #include "chrome/browser/extensions/extension_install_prompt_show_params.h"
 #include "chrome/browser/extensions/extension_util.h"
@@ -24,6 +26,7 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_util.h"
 #include "extensions/browser/image_loader.h"
@@ -154,20 +157,23 @@
 // If auto confirm is enabled then posts a task to proceed with or cancel the
 // install and returns true. Otherwise returns false.
 bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate* delegate) {
-  switch (ExtensionInstallPrompt::g_auto_confirm_for_tests) {
-    case ExtensionInstallPrompt::NONE:
+  switch (extensions::ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
+    case extensions::ScopedTestDialogAutoConfirm::NONE:
+      LOG(WARNING) << "None!";
       return false;
     // We use PostTask instead of calling the delegate directly here, because in
     // the real implementations it's highly likely the message loop will be
     // pumping a few times before the user clicks accept or cancel.
-    case ExtensionInstallPrompt::ACCEPT:
+    case extensions::ScopedTestDialogAutoConfirm::ACCEPT:
+      LOG(WARNING) << "Proceeding!";
       base::MessageLoop::current()->PostTask(
           FROM_HERE,
           base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed,
                      base::Unretained(delegate)));
       return true;
-    case ExtensionInstallPrompt::CANCEL:
-      base::MessageLoop::current()->PostTask(
+    case extensions::ScopedTestDialogAutoConfirm::CANCEL:
+      LOG(WARNING) << "Canceling!";
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort,
                      base::Unretained(delegate),
@@ -194,10 +200,6 @@
     ~InstallPromptPermissions() {
 }
 
-// static
-ExtensionInstallPrompt::AutoConfirmForTests
-ExtensionInstallPrompt::g_auto_confirm_for_tests = ExtensionInstallPrompt::NONE;
-
 ExtensionInstallPrompt::PromptType
 ExtensionInstallPrompt::g_last_prompt_type_for_tests =
     ExtensionInstallPrompt::UNSET_PROMPT_TYPE;
diff --git a/chrome/browser/extensions/extension_install_prompt.h b/chrome/browser/extensions/extension_install_prompt.h
index da1dd30..1613d2b35 100644
--- a/chrome/browser/extensions/extension_install_prompt.h
+++ b/chrome/browser/extensions/extension_install_prompt.h
@@ -52,15 +52,6 @@
 class ExtensionInstallPrompt
     : public base::SupportsWeakPtr<ExtensionInstallPrompt> {
  public:
-  // A setting to cause extension/app installs from the webstore skip the normal
-  // confirmation dialog. This should only be used in tests.
-  enum AutoConfirmForTests {
-    NONE,    // The prompt will show normally.
-    ACCEPT,  // The prompt will always accept.
-    CANCEL,  // The prompt will always cancel.
-  };
-  static AutoConfirmForTests g_auto_confirm_for_tests;
-
   // This enum is associated with Extensions.InstallPrompt_Type UMA histogram.
   // Do not modify existing values and add new values only to the end.
   enum PromptType {
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc
index f99e521..dcebd09c 100644
--- a/chrome/browser/extensions/extension_install_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -161,8 +161,8 @@
     WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
     ASSERT_TRUE(web_contents);
-    EXPECT_TRUE(StartsWithASCII(web_contents->GetURL().spec(),
-                                "chrome://newtab/", false));
+    EXPECT_TRUE(base::StartsWithASCII(web_contents->GetURL().spec(),
+                                      "chrome://newtab/", false));
   } else {
     // TODO(xiyuan): Figure out how to test extension installed bubble?
   }
@@ -187,8 +187,8 @@
     WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
     ASSERT_TRUE(web_contents);
-    EXPECT_TRUE(StartsWithASCII(web_contents->GetURL().spec(),
-                                "chrome://newtab/", false));
+    EXPECT_TRUE(base::StartsWithASCII(web_contents->GetURL().spec(),
+                                      "chrome://newtab/", false));
   } else {
     // TODO(xiyuan): Figure out how to test extension installed bubble?
   }
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc
index bd995e5..d46eacd 100644
--- a/chrome/browser/extensions/extension_management.cc
+++ b/chrome/browser/extensions/extension_management.cc
@@ -374,8 +374,8 @@
         continue;
       if (!iter.value().GetAsDictionary(&subdict))
         continue;
-      if (StartsWithASCII(iter.key(), schema_constants::kUpdateUrlPrefix,
-                          true)) {
+      if (base::StartsWithASCII(iter.key(), schema_constants::kUpdateUrlPrefix,
+                                true)) {
         const std::string& update_url =
             iter.key().substr(strlen(schema_constants::kUpdateUrlPrefix));
         if (!GURL(update_url).is_valid()) {
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 39c87265..6203f29 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -974,13 +974,13 @@
     scoped_refptr<net::URLRequestContextGetter> request_context_getter(
         profile()->GetRequestContext());
     scoped_ptr<crypto::ECPrivateKey> channel_id_key;
-    net::ChannelIDService::RequestHandle request_handle;
+    net::ChannelIDService::Request request;
     content::BrowserThread::PostTask(
         content::BrowserThread::IO, FROM_HERE,
         base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
                        CreateDomainBoundCertOnIOThread,
                    base::Unretained(this), base::Unretained(&channel_id_key),
-                   base::Unretained(&request_handle), request_context_getter));
+                   base::Unretained(&request), request_context_getter));
     tls_channel_id_created_.Wait();
     // Create the expected value.
     std::vector<uint8> spki_vector;
@@ -998,7 +998,7 @@
  private:
   void CreateDomainBoundCertOnIOThread(
       scoped_ptr<crypto::ECPrivateKey>* channel_id_key,
-      net::ChannelIDService::RequestHandle* request_handle,
+      net::ChannelIDService::Request* request,
       scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
     net::ChannelIDService* channel_id_service =
@@ -1009,7 +1009,7 @@
         base::Bind(&ExternallyConnectableMessagingWithTlsChannelIdTest::
                        GotDomainBoundCert,
                    base::Unretained(this)),
-        request_handle);
+        request);
     if (status == net::ERR_IO_PENDING)
       return;
     GotDomainBoundCert(status);
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index 9b2b74e..65ed8c5 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -44,7 +44,8 @@
 
 ExtensionPrefsTest::ExtensionPrefsTest()
     : ui_thread_(BrowserThread::UI, &message_loop_),
-      prefs_(message_loop_.message_loop_proxy().get()) {}
+      prefs_(message_loop_.task_runner().get()) {
+}
 
 ExtensionPrefsTest::~ExtensionPrefsTest() {
 }
@@ -142,7 +143,8 @@
  public:
   void Initialize() override {
     extension = prefs_.AddExtension("test");
-    prefs()->SetDidExtensionEscalatePermissions(extension.get(), true);
+    prefs()->AddDisableReason(extension->id(),
+                              Extension::DISABLE_PERMISSIONS_INCREASE);
   }
 
   void Verify() override {
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index e70cddc..1924109 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -298,7 +298,7 @@
     // Check that cache-related headers are set.
     std::string etag;
     request->GetResponseHeaderByName("ETag", &etag);
-    EXPECT_TRUE(StartsWithASCII(etag, "\"", false));
+    EXPECT_TRUE(base::StartsWithASCII(etag, "\"", false));
     EXPECT_TRUE(EndsWith(etag, "\"", false));
 
     std::string revalidation_header;
diff --git a/chrome/browser/extensions/extension_reenabler_unittest.cc b/chrome/browser/extensions/extension_reenabler_unittest.cc
index 9e5d883..3c6f7c1 100644
--- a/chrome/browser/extensions/extension_reenabler_unittest.cc
+++ b/chrome/browser/extensions/extension_reenabler_unittest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/crx_file/id_util.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/management_policy.h"
 #include "extensions/browser/test_extensions_browser_client.h"
@@ -160,8 +161,8 @@
     EXPECT_TRUE(registry()->disabled_extensions().Contains(extension->id()));
 
     // Automatically confirm install prompts.
-    ExtensionInstallPrompt::g_auto_confirm_for_tests =
-        ExtensionInstallPrompt::ACCEPT;
+    ScopedTestDialogAutoConfirm auto_confirm(
+        ScopedTestDialogAutoConfirm::ACCEPT);
 
     // Run the ExtensionReenabler.
     scoped_ptr<ExtensionReenabler> extension_reenabler =
@@ -181,6 +182,9 @@
   // Check that we don't re-enable extensions that must remain disabled, and
   // that the re-enabler reports failure correctly.
   {
+    ScopedTestDialogAutoConfirm auto_confirm(
+        ScopedTestDialogAutoConfirm::ACCEPT);
+
     ManagementPolicy* management_policy =
         ExtensionSystem::Get(browser_context())->management_policy();
     ASSERT_TRUE(management_policy);
@@ -210,8 +214,8 @@
     // Disable it again, and try canceling the prompt.
     service()->DisableExtension(extension->id(),
                                 Extension::DISABLE_PERMISSIONS_INCREASE);
-    ExtensionInstallPrompt::g_auto_confirm_for_tests =
-        ExtensionInstallPrompt::CANCEL;
+    ScopedTestDialogAutoConfirm auto_confirm(
+        ScopedTestDialogAutoConfirm::CANCEL);
     scoped_ptr<ExtensionReenabler> extension_reenabler =
         ExtensionReenabler::PromptForReenable(extension,
                                               profile(),
@@ -229,9 +233,6 @@
   // Test that if the extension is re-enabled while the prompt is active, the
   // prompt exits and reports success.
   {
-    // Don't auto-confirm, so that the prompt "stays around".
-    ExtensionInstallPrompt::g_auto_confirm_for_tests =
-        ExtensionInstallPrompt::NONE;
     base::RunLoop run_loop;
     scoped_ptr<ExtensionReenabler> extension_reenabler =
         ExtensionReenabler::PromptForReenableWithPromptForTest(
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 687b340e..16c3a6b5 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -9,11 +9,14 @@
 #include <set>
 
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/profiler/scoped_profile.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
@@ -1002,7 +1005,6 @@
     const Extension* extension) {
   GrantPermissions(extension);
   RecordPermissionMessagesHistogram(extension, "ReEnable");
-  extension_prefs_->SetDidExtensionEscalatePermissions(extension, false);
   EnableExtension(extension->id());
 }
 
@@ -1016,23 +1018,6 @@
     const Extension* extension, const char* histogram) {
   // Since this is called from multiple sources, and since the histogram macros
   // use statics, we need to manually lookup the histogram ourselves.
-  base::HistogramBase* legacy_counter = base::LinearHistogram::FactoryGet(
-      base::StringPrintf("Extensions.Permissions_%s2", histogram),
-      1,
-      PermissionMessage::kEnumBoundary,
-      PermissionMessage::kEnumBoundary + 1,
-      base::HistogramBase::kUmaTargetedHistogramFlag);
-
-  // TODO(treib): Remove the legacy "2" histograms. See crbug.com/484102.
-  PermissionMessageIDs legacy_permissions =
-      extension->permissions_data()->GetLegacyPermissionMessageIDs();
-  if (legacy_permissions.empty()) {
-    legacy_counter->Add(PermissionMessage::kNone);
-  } else {
-    for (PermissionMessage::ID id : legacy_permissions)
-      legacy_counter->Add(id);
-  }
-
   base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
       base::StringPrintf("Extensions.Permissions_%s3", histogram),
       1,
@@ -1682,17 +1667,14 @@
   // Extension has changed permissions significantly. Disable it. A
   // notification should be sent by the caller. If the extension is already
   // disabled because it was installed remotely, don't add another disable
-  // reason, but instead always set the "did escalate permissions" flag, to
-  // ensure enabling it will always show a warning.
-  if (disable_reasons == Extension::DISABLE_REMOTE_INSTALL) {
-    extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
-  } else if (is_privilege_increase) {
+  // reason.
+  if (is_privilege_increase &&
+      disable_reasons != Extension::DISABLE_REMOTE_INSTALL) {
     disable_reasons |= Extension::DISABLE_PERMISSIONS_INCREASE;
     if (!extension_prefs_->DidExtensionEscalatePermissions(extension->id())) {
       RecordPermissionMessagesHistogram(extension, "AutoDisable");
     }
     extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
-    extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
 
 #if defined(ENABLE_SUPERVISED_USERS)
     // If a custodian-installed extension is disabled for a supervised user due
@@ -1799,7 +1781,7 @@
     // Installation of a blacklisted extension can happen from sync, policy,
     // etc, where to maintain consistency we need to install it, just never
     // load it (see AddExtension). Usually it should be the job of callers to
-    // incercept blacklisted extension earlier (e.g. CrxInstaller, before even
+    // intercept blacklisted extensions earlier (e.g. CrxInstaller, before even
     // showing the install dialogue).
     extension_prefs_->AcknowledgeBlacklistedExtension(id);
     UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.SilentInstall",
@@ -1827,8 +1809,7 @@
   }
 
   if (disable_reasons)
-    extension_prefs_->AddDisableReason(id,
-        static_cast<Extension::DisableReason>(disable_reasons));
+    extension_prefs_->AddDisableReasons(id, disable_reasons);
 
   const Extension::State initial_state =
       disable_reasons == Extension::DISABLE_NONE ? Extension::ENABLED
@@ -2124,7 +2105,6 @@
 
   const Extension* extension = GetInstalledExtension(extension_id);
   if (!extension) {
-    LOG(WARNING) << "Terminated extension is already removed.";
     return;
   }
 
@@ -2134,8 +2114,7 @@
 }
 
 void ExtensionService::TerminateExtension(const std::string& extension_id) {
-  const Extension* extension = GetInstalledExtension(extension_id);
-  TrackTerminatedExtension(extension->id());
+  TrackTerminatedExtension(extension_id);
 }
 
 void ExtensionService::UntrackTerminatedExtension(const std::string& id) {
@@ -2271,12 +2250,9 @@
       // at all, but never half-crashed.  We do it in a PostTask so
       // that other handlers of this notification will still have
       // access to the Extension and ExtensionHost.
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(
-              &ExtensionService::TrackTerminatedExtension,
-              AsWeakPtr(),
-              host->extension()->id()));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&ExtensionService::TrackTerminatedExtension,
+                                AsWeakPtr(), host->extension()->id()));
       break;
     }
     case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
@@ -2317,7 +2293,7 @@
         for (std::set<std::string>::const_iterator it = extension_ids.begin();
              it != extension_ids.end(); ++it) {
           if (delayed_installs_.Contains(*it)) {
-            base::MessageLoop::current()->PostDelayedTask(
+            base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
                 FROM_HERE,
                 base::Bind(&ExtensionService::MaybeFinishDelayedInstallation,
                            AsWeakPtr(), *it),
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index c6e47799..e213e77 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -16,15 +16,17 @@
 #include "base/json/json_file_value_serializer.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_string_value_serializer.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/prefs/scoped_user_pref_update.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/version.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -86,6 +88,7 @@
 #include "content/public/common/content_constants.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
@@ -2760,8 +2763,6 @@
   // over to the updated version.
   service()->DisableExtension(good->id(), Extension::DISABLE_USER_ACTION);
   extensions::util::SetIsIncognitoEnabled(good->id(), profile(), true);
-  ExtensionPrefs::Get(profile())
-      ->SetDidExtensionEscalatePermissions(good, true);
 
   path = data_dir().AppendASCII("good2.crx");
   UpdateExtension(good_crx, path, INSTALLED);
@@ -2769,8 +2770,8 @@
   const Extension* good2 = service()->GetExtensionById(good_crx, true);
   ASSERT_EQ("1.0.0.1", good2->version()->GetString());
   EXPECT_TRUE(extensions::util::IsIncognitoEnabled(good2->id(), profile()));
-  EXPECT_TRUE(ExtensionPrefs::Get(profile())
-                  ->DidExtensionEscalatePermissions(good2->id()));
+  EXPECT_EQ(Extension::DISABLE_USER_ACTION,
+            ExtensionPrefs::Get(profile())->GetDisableReasons(good2->id()));
 }
 
 // Tests that updating preserves extension location.
@@ -2851,8 +2852,9 @@
   service()->set_show_extensions_prompts(true);
 
   // Start by canceling any install prompts.
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::CANCEL;
+  scoped_ptr<extensions::ScopedTestDialogAutoConfirm> auto_confirm(
+      new extensions::ScopedTestDialogAutoConfirm(
+          extensions::ScopedTestDialogAutoConfirm::CANCEL));
 
   // The extension that has a plugin should not install.
   extensions::UnpackedInstaller::Create(service())
@@ -2875,8 +2877,9 @@
   EXPECT_TRUE(registry()->enabled_extensions().Contains(good2));
 
   // The plugin extension should install if we accept the dialog.
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
+  auto_confirm.reset();
+  auto_confirm.reset(new extensions::ScopedTestDialogAutoConfirm(
+      extensions::ScopedTestDialogAutoConfirm::ACCEPT));
 
   ExtensionErrorReporter::GetInstance()->ClearErrors();
   extensions::UnpackedInstaller::Create(service())
@@ -2899,8 +2902,9 @@
 
   // We should be able to reload the extension without getting another prompt.
   loaded_.clear();
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::CANCEL;
+  auto_confirm.reset();
+  auto_confirm.reset(new extensions::ScopedTestDialogAutoConfirm(
+      extensions::ScopedTestDialogAutoConfirm::CANCEL));
 
   service()->ReloadExtension(good1);
   base::RunLoop().RunUntilIdle();
@@ -4675,13 +4679,15 @@
       weak_factory_(base::MessageLoop::current()) {}
 
   void SetCookieCallback(bool result) {
-    base::MessageLoop::current()->PostTask(FROM_HERE,
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
         base::Bind(&base::MessageLoop::Quit, weak_factory_.GetWeakPtr()));
     result_ = result;
   }
 
   void GetAllCookiesCallback(const net::CookieList& list) {
-    base::MessageLoop::current()->PostTask(FROM_HERE,
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
         base::Bind(&base::MessageLoop::Quit, weak_factory_.GetWeakPtr()));
     list_ = list;
   }
@@ -4755,7 +4761,7 @@
   IndexedDBContext* idb_context = BrowserContext::GetDefaultStoragePartition(
                                       profile())->GetIndexedDBContext();
   idb_context->SetTaskRunnerForTesting(
-      base::MessageLoop::current()->message_loop_proxy().get());
+      base::MessageLoop::current()->task_runner().get());
   base::FilePath idb_path = idb_context->GetFilePathForTesting(origin_id);
   EXPECT_TRUE(base::CreateDirectory(idb_path));
   EXPECT_TRUE(base::DirectoryExists(idb_path));
@@ -4878,7 +4884,7 @@
   IndexedDBContext* idb_context = BrowserContext::GetDefaultStoragePartition(
                                       profile())->GetIndexedDBContext();
   idb_context->SetTaskRunnerForTesting(
-      base::MessageLoop::current()->message_loop_proxy().get());
+      base::MessageLoop::current()->task_runner().get());
   base::FilePath idb_path = idb_context->GetFilePathForTesting(origin_id);
   EXPECT_TRUE(base::CreateDirectory(idb_path));
   EXPECT_TRUE(base::DirectoryExists(idb_path));
@@ -6488,18 +6494,14 @@
           new syncer::FakeSyncChangeProcessor),
       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
 
-  sync_pb::EntitySpecifics specifics;
-  sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
-  ext_specifics->set_id(good_crx);
-  ext_specifics->set_version(base::Version("1").GetString());
-
   const base::FilePath path = data_dir().AppendASCII("good.crx");
   const ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
 
   struct TestCase {
     const char* name;  // For failure output only.
     bool sync_enabled;  // The "enabled" flag coming in from Sync.
-    int sync_disable_reasons;  // The disable reason(s) coming in from Sync.
+    // The disable reason(s) coming in from Sync, or -1 for "not set".
+    int sync_disable_reasons;
     // The disable reason(s) that should be set on the installed extension.
     // This will usually be the same as |sync_disable_reasons|, but see the
     // "Legacy" case.
@@ -6518,7 +6520,7 @@
     // Legacy case (<M45): No disable reasons come in from Sync (see
     // crbug.com/484214). After installation, the reason should be set to
     // DISABLE_UNKNOWN_FROM_SYNC.
-    { "Legacy", false, 0, Extension::DISABLE_UNKNOWN_FROM_SYNC, true },
+    { "Legacy", false, -1, Extension::DISABLE_UNKNOWN_FROM_SYNC, true },
     // If the extension came in disabled due to a permissions increase, then the
     // user has *not* approved the permissions, and they shouldn't be granted.
     // crbug.com/484214
@@ -6529,16 +6531,20 @@
   for (const TestCase& test_case : test_cases) {
     SCOPED_TRACE(test_case.name);
 
+    sync_pb::EntitySpecifics specifics;
+    sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
+    ext_specifics->set_id(good_crx);
+    ext_specifics->set_version(base::Version("1").GetString());
     ext_specifics->set_enabled(test_case.sync_enabled);
-    ext_specifics->set_disable_reasons(test_case.sync_disable_reasons);
+    if (test_case.sync_disable_reasons != -1)
+      ext_specifics->set_disable_reasons(test_case.sync_disable_reasons);
 
     syncer::SyncData sync_data =
         syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
     syncer::SyncChange sync_change(FROM_HERE,
                                    syncer::SyncChange::ACTION_UPDATE,
                                    sync_data);
-    syncer::SyncChangeList list(1);
-    list[0] = sync_change;
+    syncer::SyncChangeList list(1, sync_change);
     extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
 
     ASSERT_TRUE(service()->pending_extension_manager()->IsIdPending(good_crx));
@@ -6708,6 +6714,225 @@
   // TODO(akalin): Figure out a way to test |info.ShouldAllowInstall()|.
 }
 
+TEST_F(ExtensionServiceTest, ProcessSyncDataEnableDisable) {
+  InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
+  extension_sync_service()->MergeDataAndStartSyncing(
+      syncer::EXTENSIONS,
+      syncer::SyncDataList(),
+      scoped_ptr<syncer::SyncChangeProcessor>(
+          new syncer::FakeSyncChangeProcessor),
+      scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
+
+  const ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
+
+  struct TestCase {
+    const char* name;  // For failure output only.
+    // Set of disable reasons before any Sync data comes in. If this is != 0,
+    // the extension is disabled.
+    int previous_disable_reasons;
+    bool sync_enable;  // The enabled flag coming in from Sync.
+    // The disable reason(s) coming in from Sync, or -1 for "not set".
+    int sync_disable_reasons;
+    // The expected set of disable reasons after processing the Sync update. The
+    // extension should be disabled iff this is != 0.
+    int expect_disable_reasons;
+  } test_cases[] = {
+    { "NopEnable", 0, true, 0, 0 },
+    { "NopDisable", Extension::DISABLE_USER_ACTION, false,
+      Extension::DISABLE_USER_ACTION, Extension::DISABLE_USER_ACTION },
+    { "Disable", 0, false, Extension::DISABLE_USER_ACTION,
+      Extension::DISABLE_USER_ACTION },
+    { "DisableLegacy", 0, false, -1, Extension::DISABLE_UNKNOWN_FROM_SYNC },
+    { "AddDisableReason", Extension::DISABLE_REMOTE_INSTALL, false,
+      Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION,
+      Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION },
+    { "AddDisableReasonLegacy", Extension::DISABLE_USER_ACTION, false, -1,
+      Extension::DISABLE_USER_ACTION | Extension::DISABLE_UNKNOWN_FROM_SYNC},
+    { "RemoveDisableReason",
+      Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION, false,
+      Extension::DISABLE_USER_ACTION, Extension::DISABLE_USER_ACTION },
+    { "Enable", Extension::DISABLE_USER_ACTION, true, 0, 0 },
+    { "EnableLegacy", Extension::DISABLE_USER_ACTION, true, -1, 0 },
+  };
+
+  for (const TestCase& test_case : test_cases) {
+    SCOPED_TRACE(test_case.name);
+
+    std::string id;
+    std::string version;
+    // Don't keep |extension| around longer than necessary.
+    {
+      const Extension* extension =
+          InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
+      // The extension should now be installed and enabled.
+      ASSERT_TRUE(extension);
+      id = extension->id();
+      version = extension->VersionString();
+    }
+    ASSERT_TRUE(registry()->enabled_extensions().Contains(id));
+
+    // Disable it if the test case says so.
+    if (test_case.previous_disable_reasons) {
+      service()->DisableExtension(id, test_case.previous_disable_reasons);
+      ASSERT_TRUE(registry()->disabled_extensions().Contains(id));
+    }
+
+    // Now a sync update comes in.
+    sync_pb::EntitySpecifics specifics;
+    sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
+    ext_specifics->set_id(id);
+    ext_specifics->set_enabled(test_case.sync_enable);
+    ext_specifics->set_version(version);
+    if (test_case.sync_disable_reasons != -1)
+      ext_specifics->set_disable_reasons(test_case.sync_disable_reasons);
+
+    syncer::SyncData sync_data =
+        syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
+    syncer::SyncChange sync_change(FROM_HERE,
+                                   syncer::SyncChange::ACTION_UPDATE,
+                                   sync_data);
+    syncer::SyncChangeList list(1, sync_change);
+    extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
+
+    // Check expectations.
+    const bool expect_enabled = !test_case.expect_disable_reasons;
+    EXPECT_EQ(expect_enabled, service()->IsExtensionEnabled(id));
+    EXPECT_EQ(test_case.expect_disable_reasons, prefs->GetDisableReasons(id));
+
+    // Remove the extension again, so we can install it again for the next case.
+    UninstallExtension(id, false, expect_enabled ? Extension::ENABLED
+                                                 : Extension::DISABLED);
+  }
+}
+
+TEST_F(ExtensionServiceTest, ProcessSyncDataPermissionApproval) {
+  // This is the update URL specified in the test extension. Setting it here is
+  // necessary to make it considered syncable.
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kAppsGalleryUpdateURL,
+      "http://localhost/autoupdate/updates.xml");
+
+  InitializeEmptyExtensionService();
+  InitializeExtensionSyncService();
+  extension_sync_service()->MergeDataAndStartSyncing(
+      syncer::EXTENSIONS,
+      syncer::SyncDataList(),
+      scoped_ptr<syncer::SyncChangeProcessor>(
+          new syncer::FakeSyncChangeProcessor),
+      scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
+
+  const base::FilePath base_path =
+      data_dir().AppendASCII("permissions_increase");
+  const base::FilePath pem_path = base_path.AppendASCII("permissions.pem");
+  const base::FilePath path_v1 = base_path.AppendASCII("v1");
+  const base::FilePath path_v2 = base_path.AppendASCII("v2");
+
+  base::ScopedTempDir crx_dir;
+  ASSERT_TRUE(crx_dir.CreateUniqueTempDir());
+  const base::FilePath crx_path_v1 = crx_dir.path().AppendASCII("temp1.crx");
+  PackCRX(path_v1, pem_path, crx_path_v1);
+  const base::FilePath crx_path_v2 = crx_dir.path().AppendASCII("temp2.crx");
+  PackCRX(path_v2, pem_path, crx_path_v2);
+
+  const std::string v1("1");
+  const std::string v2("2");
+
+  const ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
+
+  struct TestCase {
+    const char* name;  // For failure output only.
+    const std::string& sync_version;  // The version coming in from Sync.
+    // The disable reason(s) coming in from Sync, or -1 for "not set".
+    int sync_disable_reasons;
+    // Whether the extension's permissions should be auto-granted.
+    bool expect_permissions_granted;
+  } test_cases[] = {
+    // Sync tells us to re-enable an older version. No permissions should be
+    // granted, since we can't be sure if the user actually approved the right
+    // set of permissions. Note that the extension will get disabled again the
+    // next time ExtensionService::CheckPermissionsIncrease runs because of the
+    // extra permissions.
+    { "OldVersion", v1, 0, false },
+    // Legacy case: Sync tells us to re-enable the extension, but doesn't
+    // specify disable reasons. No permissions should be granted.
+    { "Legacy", v2, -1, false },
+    // Sync tells us to re-enable the extension and explicitly removes the
+    // disable reasons. Now the extension should have its permissions granted.
+    { "GrantPermissions", v2, 0, true },
+  };
+
+  for (const TestCase& test_case : test_cases) {
+    SCOPED_TRACE(test_case.name);
+
+    std::string id;
+    // Don't keep |extension| around longer than necessary (it'll be destroyed
+    // during updating).
+    {
+      const Extension* extension = InstallCRX(crx_path_v1, INSTALL_NEW);
+      // The extension should now be installed and enabled.
+      ASSERT_TRUE(extension);
+      ASSERT_EQ(v1, extension->VersionString());
+      id = extension->id();
+    }
+    ASSERT_TRUE(registry()->enabled_extensions().Contains(id));
+
+    scoped_refptr<PermissionSet> granted_permissions_v1(
+        prefs->GetGrantedPermissions(id));
+
+    // Update to a new version with increased permissions.
+    UpdateExtension(id, crx_path_v2, DISABLED);
+
+    // Now the extension should be disabled due to a permissions increase.
+    {
+      const Extension* extension =
+          registry()->disabled_extensions().GetByID(id);
+      ASSERT_TRUE(extension);
+      ASSERT_EQ(v2, extension->VersionString());
+    }
+    ASSERT_TRUE(prefs->HasDisableReason(
+        id, Extension::DISABLE_PERMISSIONS_INCREASE));
+
+    // No new permissions should have been granted.
+    scoped_refptr<PermissionSet> granted_permissions_v2(
+        prefs->GetGrantedPermissions(id));
+    ASSERT_EQ(*granted_permissions_v1, *granted_permissions_v2);
+
+    // Now a sync update comes in.
+    sync_pb::EntitySpecifics specifics;
+    sync_pb::ExtensionSpecifics* ext_specifics = specifics.mutable_extension();
+    ext_specifics->set_id(id);
+    ext_specifics->set_enabled(true);
+    ext_specifics->set_version(test_case.sync_version);
+    if (test_case.sync_disable_reasons != -1)
+      ext_specifics->set_disable_reasons(test_case.sync_disable_reasons);
+
+    syncer::SyncData sync_data =
+        syncer::SyncData::CreateLocalData(good_crx, "Name", specifics);
+    syncer::SyncChange sync_change(FROM_HERE,
+                                   syncer::SyncChange::ACTION_UPDATE,
+                                   sync_data);
+    syncer::SyncChangeList list(1, sync_change);
+    extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
+
+    // Check expectations.
+    EXPECT_TRUE(registry()->GetExtensionById(id, ExtensionRegistry::ENABLED));
+    scoped_refptr<PermissionSet> granted_permissions(
+        prefs->GetGrantedPermissions(id));
+    if (test_case.expect_permissions_granted) {
+      scoped_refptr<PermissionSet> active_permissions(
+          prefs->GetActivePermissions(id));
+      EXPECT_EQ(*granted_permissions, *active_permissions);
+    } else {
+      EXPECT_EQ(*granted_permissions, *granted_permissions_v1);
+    }
+    EXPECT_EQ(Extension::DISABLE_NONE, prefs->GetDisableReasons(id));
+
+    // Remove the extension again, so we can install it again for the next case.
+    UninstallExtension(id, false);
+  }
+}
+
 #if defined(ENABLE_SUPERVISED_USERS)
 class ScopedSupervisedUserServiceDelegate
     : public SupervisedUserService::Delegate {
diff --git a/chrome/browser/extensions/extension_storage_monitor_browsertest.cc b/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
index f60adb65..295331d 100644
--- a/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
+++ b/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
@@ -323,8 +324,8 @@
 
   // Fake clicking the notification button to uninstall and accepting the
   // uninstall.
-  ExtensionUninstallDialog::ScopedAutoConfirm scoped_autoconfirm(
-      ExtensionUninstallDialog::ACCEPT);
+  ScopedTestDialogAutoConfirm scoped_autoconfirm(
+      ScopedTestDialogAutoConfirm::ACCEPT);
   TestExtensionRegistryObserver observer(ExtensionRegistry::Get(profile()),
                                          extension->id());
   message_center::MessageCenter::Get()->ClickOnNotificationButton(
diff --git a/chrome/browser/extensions/extension_sync_data.cc b/chrome/browser/extensions/extension_sync_data.cc
index 6914bc1d..17bb217 100644
--- a/chrome/browser/extensions/extension_sync_data.cc
+++ b/chrome/browser/extensions/extension_sync_data.cc
@@ -22,10 +22,13 @@
 
 std::string GetExtensionSpecificsLogMessage(
     const sync_pb::ExtensionSpecifics& specifics) {
-  return base::StringPrintf("id: %s\nversion: %s\nupdate_url: %s",
-                            specifics.id().c_str(),
-                            specifics.version().c_str(),
-                            specifics.update_url().c_str());
+  return base::StringPrintf(
+      "id: %s\nversion: %s\nupdate_url: %s\nenabled: %i\ndisable_reasons: %i",
+      specifics.id().c_str(),
+      specifics.version().c_str(),
+      specifics.update_url().c_str(),
+      specifics.enabled(),
+      specifics.disable_reasons());
 }
 
 enum BadSyncDataReason {
@@ -41,6 +44,9 @@
   // No ExtensionSpecifics in the EntitySpecifics.
   NO_EXTENSION_SPECIFICS,
 
+  // Enabled extensions can't have disable reasons.
+  BAD_DISABLE_REASONS,
+
   // Must be at the end.
   NUM_BAD_SYNC_DATA_REASONS
 };
@@ -55,6 +61,7 @@
 ExtensionSyncData::ExtensionSyncData()
     : uninstalled_(false),
       enabled_(false),
+      supports_disable_reasons_(false),
       disable_reasons_(Extension::DISABLE_NONE),
       incognito_enabled_(false),
       remote_install_(false),
@@ -71,6 +78,7 @@
     : id_(extension.id()),
       uninstalled_(false),
       enabled_(enabled),
+      supports_disable_reasons_(true),
       disable_reasons_(disable_reasons),
       incognito_enabled_(incognito_enabled),
       remote_install_(remote_install),
@@ -125,7 +133,8 @@
   specifics->set_update_url(update_url_.spec());
   specifics->set_version(version_.GetString());
   specifics->set_enabled(enabled_);
-  specifics->set_disable_reasons(disable_reasons_);
+  if (supports_disable_reasons_)
+    specifics->set_disable_reasons(disable_reasons_);
   specifics->set_incognito_enabled(incognito_enabled_);
   specifics->set_remote_install(remote_install_);
   if (all_urls_enabled_ != BOOLEAN_UNSET)
@@ -160,10 +169,22 @@
     return false;
   }
 
+  // Enabled extensions can't have disable reasons. (The proto field may be
+  // unset, in which case it defaults to DISABLE_NONE.)
+  if (specifics.enabled() &&
+      specifics.disable_reasons() != Extension::DISABLE_NONE) {
+    LOG(ERROR) << "Attempt to sync bad ExtensionSpecifics "
+               << "(enabled extension can't have disable reasons):\n"
+               << GetExtensionSpecificsLogMessage(specifics);
+    RecordBadSyncData(BAD_DISABLE_REASONS);
+    return false;
+  }
+
   id_ = specifics.id();
   update_url_ = specifics_update_url;
   version_ = specifics_version;
   enabled_ = specifics.enabled();
+  supports_disable_reasons_ = specifics.has_disable_reasons();
   disable_reasons_ = specifics.disable_reasons();
   incognito_enabled_ = specifics.incognito_enabled();
   if (specifics.has_all_urls_enabled()) {
diff --git a/chrome/browser/extensions/extension_sync_data.h b/chrome/browser/extensions/extension_sync_data.h
index 5a94eaba..03ce9bd 100644
--- a/chrome/browser/extensions/extension_sync_data.h
+++ b/chrome/browser/extensions/extension_sync_data.h
@@ -70,6 +70,7 @@
   // |version|).
   bool uninstalled() const { return uninstalled_; }
   bool enabled() const { return enabled_; }
+  bool supports_disable_reasons() const { return supports_disable_reasons_; }
   int disable_reasons() const { return disable_reasons_; }
   bool incognito_enabled() const { return incognito_enabled_; }
   bool remote_install() const { return remote_install_; }
@@ -90,6 +91,11 @@
   std::string id_;
   bool uninstalled_;
   bool enabled_;
+  // |supports_disable_reasons_| is true if the optional |disable_reasons_| was
+  // set to some value in the extension_specifics.proto. If not,
+  // |disable_reasons_| is given a default value and |supports_disable_reasons_|
+  // is false.
+  bool supports_disable_reasons_;
   int disable_reasons_;
   bool incognito_enabled_;
   bool remote_install_;
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
index 12769c6..90f679f 100644
--- a/chrome/browser/extensions/extension_sync_service.cc
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -491,8 +491,7 @@
   if (extension_sync_data.uninstalled()) {
     if (!extension_service_->UninstallExtensionHelper(
             extension_service_, id, extensions::UNINSTALL_REASON_SYNC)) {
-      LOG(WARNING) << "Could not uninstall extension " << id
-                   << " for sync";
+      LOG(WARNING) << "Could not uninstall extension " << id << " for sync";
     }
     return true;
   }
@@ -507,33 +506,43 @@
   }
 
   // Set user settings.
-  // If the extension has been disabled from sync, it may not have
-  // been installed yet, so we don't know if the disable reason was a
-  // permissions increase.  That will be updated once CheckPermissionsIncrease
-  // is called for it.
-  // However if the extension is marked as a remote install in sync, we know
-  // what the disable reason is, so set it to that directly. Note that when
-  // CheckPermissionsIncrease runs, it might still add permissions increase
-  // as a disable reason for the extension.
   if (extension_sync_data.enabled()) {
-    extension_service_->EnableExtension(id);
+    // Only grant permissions if the sync data explicitly sets the disable
+    // reasons to Extension::DISABLE_NONE (as opposed to the legacy (<M45) case
+    // where they're not set at all), and if the version from sync matches our
+    // local one. Otherwise we just enable it without granting permissions. If
+    // any permissions are missing, CheckPermissionsIncrease will soon disable
+    // it again.
+    DCHECK(!extension_sync_data.disable_reasons());
+    bool grant_permissions =
+        extension_sync_data.supports_disable_reasons() &&
+        extension &&
+        extension->version()->Equals(extension_sync_data.version());
+    if (grant_permissions)
+      extension_service_->GrantPermissionsAndEnableExtension(extension);
+    else
+      extension_service_->EnableExtension(id);
   } else if (!IsPendingEnable(id)) {
     int disable_reasons = extension_sync_data.disable_reasons();
     if (extension_sync_data.remote_install()) {
-      // In the non-legacy case (>=M45) where disable reasons are synced at all,
-      // DISABLE_REMOTE_INSTALL should be among them already.
-      DCHECK(!disable_reasons ||
-             (disable_reasons & Extension::DISABLE_REMOTE_INSTALL));
-      disable_reasons |= Extension::DISABLE_REMOTE_INSTALL;
-    }
-    if (!disable_reasons) {
+      if (!(disable_reasons & Extension::DISABLE_REMOTE_INSTALL)) {
+        // In the non-legacy case (>=M45) where disable reasons are synced at
+        // all, DISABLE_REMOTE_INSTALL should be among them already.
+        DCHECK(!extension_sync_data.supports_disable_reasons());
+        disable_reasons |= Extension::DISABLE_REMOTE_INSTALL;
+      }
+    } else if (!extension_sync_data.supports_disable_reasons()) {
       // Legacy case (<M45), from before we synced disable reasons (see
       // crbug.com/484214).
       disable_reasons = Extension::DISABLE_UNKNOWN_FROM_SYNC;
     }
 
-    extension_service_->DisableExtension(
-        id, Extension::DisableReason(disable_reasons));
+    // In the non-legacy case (>=M45), clear any existing disable reasons first.
+    // Otherwise sync can't remove just some of them.
+    if (extension_sync_data.supports_disable_reasons())
+      extensions::ExtensionPrefs::Get(profile_)->ClearDisableReasons(id);
+
+    extension_service_->DisableExtension(id, disable_reasons);
   }
 
   // We need to cache some version information here because setting the
diff --git a/chrome/browser/extensions/extension_system_impl.cc b/chrome/browser/extensions/extension_system_impl.cc
index 31a79a8..6011190 100644
--- a/chrome/browser/extensions/extension_system_impl.cc
+++ b/chrome/browser/extensions/extension_system_impl.cc
@@ -9,13 +9,11 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram.h"
 #include "base/strings/string_tokenizer.h"
-#include "base/strings/string_util.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/cookie_settings.h"
+#include "chrome/browser/extensions/chrome_content_verifier_delegate.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_error_reporter.h"
 #include "chrome/browser/extensions/extension_management.h"
@@ -33,29 +31,20 @@
 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
-#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/features/feature_channel.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/url_data_source.h"
 #include "extensions/browser/content_verifier.h"
-#include "extensions/browser/content_verifier_delegate.h"
 #include "extensions/browser/extension_pref_store.h"
 #include "extensions/browser/extension_pref_value_map.h"
 #include "extensions/browser/extension_pref_value_map_factory.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/info_map.h"
-#include "extensions/browser/management_policy.h"
 #include "extensions/browser/quota_service.h"
 #include "extensions/browser/runtime_data.h"
 #include "extensions/browser/state_store.h"
 #include "extensions/common/constants.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/extension_urls.h"
-#include "extensions/common/extensions_client.h"
-#include "extensions/common/manifest.h"
-#include "extensions/common/manifest_url_handlers.h"
-#include "net/base/escape.h"
 
 #if defined(ENABLE_NOTIFICATIONS)
 #include "chrome/browser/notifications/desktop_notification_service.h"
@@ -67,7 +56,6 @@
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
-#include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/login/login_state.h"
 #include "components/user_manager/user.h"
@@ -76,13 +64,6 @@
 
 using content::BrowserThread;
 
-namespace {
-
-const char kContentVerificationExperimentName[] =
-    "ExtensionContentVerification";
-
-}  // namespace
-
 namespace extensions {
 
 //
@@ -140,172 +121,6 @@
   management_policy_->RegisterProvider(InstallVerifier::Get(profile_));
 }
 
-namespace {
-
-class ContentVerifierDelegateImpl : public ContentVerifierDelegate {
- public:
-  explicit ContentVerifierDelegateImpl(content::BrowserContext* context)
-      : context_(context), default_mode_(GetDefaultMode()) {}
-
-  ~ContentVerifierDelegateImpl() override {}
-
-  Mode ShouldBeVerified(const Extension& extension) override {
-#if defined(OS_CHROMEOS)
-    if (ExtensionAssetsManagerChromeOS::IsSharedInstall(&extension))
-      return ContentVerifierDelegate::ENFORCE_STRICT;
-#endif
-
-    if (!extension.is_extension() && !extension.is_legacy_packaged_app())
-      return ContentVerifierDelegate::NONE;
-    if (!Manifest::IsAutoUpdateableLocation(extension.location()))
-      return ContentVerifierDelegate::NONE;
-
-    if (!ManifestURL::UpdatesFromGallery(&extension)) {
-      // It's possible that the webstore update url was overridden for testing
-      // so also consider extensions with the default (production) update url
-      // to be from the store as well.
-      GURL default_webstore_url = extension_urls::GetDefaultWebstoreUpdateUrl();
-      if (ManifestURL::GetUpdateURL(&extension) != default_webstore_url)
-        return ContentVerifierDelegate::NONE;
-    }
-
-    return default_mode_;
-  }
-
-  const ContentVerifierKey& PublicKey() override {
-    static ContentVerifierKey key(
-        extension_misc::kWebstoreSignaturesPublicKey,
-        extension_misc::kWebstoreSignaturesPublicKeySize);
-    return key;
-  }
-
-  GURL GetSignatureFetchUrl(const std::string& extension_id,
-                            const base::Version& version) override {
-    // TODO(asargent) Factor out common code from the extension updater's
-    // ManifestFetchData class that can be shared for use here.
-    std::vector<std::string> parts;
-    parts.push_back("uc");
-    parts.push_back("installsource=signature");
-    parts.push_back("id=" + extension_id);
-    parts.push_back("v=" + version.GetString());
-    std::string x_value =
-        net::EscapeQueryParamValue(JoinString(parts, "&"), true);
-    std::string query = "response=redirect&x=" + x_value;
-
-    GURL base_url = extension_urls::GetWebstoreUpdateUrl();
-    GURL::Replacements replacements;
-    replacements.SetQuery(query.c_str(), url::Component(0, query.length()));
-    return base_url.ReplaceComponents(replacements);
-  }
-
-  std::set<base::FilePath> GetBrowserImagePaths(
-      const extensions::Extension* extension) override {
-    return ExtensionsClient::Get()->GetBrowserImagePaths(extension);
-  }
-
-  void VerifyFailed(const std::string& extension_id,
-                    ContentVerifyJob::FailureReason reason) override {
-    ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
-    const Extension* extension =
-        registry->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
-    if (!extension)
-      return;
-    ExtensionSystem* system = ExtensionSystem::Get(context_);
-    Mode mode = ShouldBeVerified(*extension);
-    if (mode >= ContentVerifierDelegate::ENFORCE) {
-      if (!system->management_policy()->UserMayModifySettings(extension,
-                                                              NULL)) {
-        LogFailureForPolicyForceInstall(extension_id);
-        return;
-      }
-      system->extension_service()->DisableExtension(
-          extension_id, Extension::DISABLE_CORRUPTED);
-      ExtensionPrefs::Get(context_)->IncrementCorruptedDisableCount();
-      UMA_HISTOGRAM_BOOLEAN("Extensions.CorruptExtensionBecameDisabled", true);
-      UMA_HISTOGRAM_ENUMERATION("Extensions.CorruptExtensionDisabledReason",
-          reason, ContentVerifyJob::FAILURE_REASON_MAX);
-    } else if (!ContainsKey(would_be_disabled_ids_, extension_id)) {
-      UMA_HISTOGRAM_BOOLEAN("Extensions.CorruptExtensionWouldBeDisabled", true);
-      would_be_disabled_ids_.insert(extension_id);
-    }
-  }
-
-  static Mode GetDefaultMode() {
-    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-
-    Mode experiment_value = NONE;
-    const std::string group = base::FieldTrialList::FindFullName(
-        kContentVerificationExperimentName);
-    if (group == "EnforceStrict")
-      experiment_value = ContentVerifierDelegate::ENFORCE_STRICT;
-    else if (group == "Enforce")
-      experiment_value = ContentVerifierDelegate::ENFORCE;
-    else if (group == "Bootstrap")
-      experiment_value = ContentVerifierDelegate::BOOTSTRAP;
-
-    // The field trial value that normally comes from the server can be
-    // overridden on the command line, which we don't want to allow since
-    // malware can set chrome command line flags. There isn't currently a way
-    // to find out what the server-provided value is in this case, so we
-    // conservatively default to the strictest mode if we detect our experiment
-    // name being overridden.
-    if (command_line->HasSwitch(switches::kForceFieldTrials)) {
-      std::string forced_trials =
-          command_line->GetSwitchValueASCII(switches::kForceFieldTrials);
-      if (forced_trials.find(kContentVerificationExperimentName) !=
-              std::string::npos)
-        experiment_value = ContentVerifierDelegate::ENFORCE_STRICT;
-    }
-
-    Mode cmdline_value = NONE;
-    if (command_line->HasSwitch(switches::kExtensionContentVerification)) {
-      std::string switch_value = command_line->GetSwitchValueASCII(
-          switches::kExtensionContentVerification);
-      if (switch_value == switches::kExtensionContentVerificationBootstrap)
-        cmdline_value = ContentVerifierDelegate::BOOTSTRAP;
-      else if (switch_value == switches::kExtensionContentVerificationEnforce)
-        cmdline_value = ContentVerifierDelegate::ENFORCE;
-      else if (switch_value ==
-              switches::kExtensionContentVerificationEnforceStrict)
-        cmdline_value = ContentVerifierDelegate::ENFORCE_STRICT;
-      else
-        // If no value was provided (or the wrong one), just default to enforce.
-        cmdline_value = ContentVerifierDelegate::ENFORCE;
-    }
-
-    // We don't want to allow the command-line flags to eg disable enforcement
-    // if the experiment group says it should be on, or malware may just modify
-    // the command line flags. So return the more restrictive of the 2 values.
-    return std::max(experiment_value, cmdline_value);
-  }
-
- private:
-  void LogFailureForPolicyForceInstall(const std::string& extension_id) {
-    if (!ContainsKey(corrupt_policy_extensions_, extension_id)) {
-      corrupt_policy_extensions_.insert(extension_id);
-      UMA_HISTOGRAM_BOOLEAN("Extensions.CorruptPolicyExtensionWouldBeDisabled",
-                            true);
-    }
-  }
-
-  content::BrowserContext* context_;
-  ContentVerifierDelegate::Mode default_mode_;
-
-  // For reporting metrics in BOOTSTRAP mode, when an extension would be
-  // disabled if content verification was in ENFORCE mode.
-  std::set<std::string> would_be_disabled_ids_;
-
-  // Currently enterprise policy extensions that must remain enabled will not
-  // be disabled due to content verification failure, but we are considering
-  // changing this (crbug.com/447040), so for now we are tracking how often
-  // this happens to help inform the decision.
-  std::set<std::string> corrupt_policy_extensions_;
-
-  DISALLOW_COPY_AND_ASSIGN(ContentVerifierDelegateImpl);
-};
-
-}  // namespace
-
 void ExtensionSystemImpl::Shared::Init(bool extensions_enabled) {
   TRACE_EVENT0("browser,startup", "ExtensionSystemImpl::Shared::Init");
   const base::CommandLine* command_line =
@@ -338,9 +153,9 @@
   {
     InstallVerifier::Get(profile_)->Init();
     content_verifier_ = new ContentVerifier(
-        profile_, new ContentVerifierDelegateImpl(profile_));
+        profile_, new ChromeContentVerifierDelegate(profile_));
     ContentVerifierDelegate::Mode mode =
-        ContentVerifierDelegateImpl::GetDefaultMode();
+        ChromeContentVerifierDelegate::GetDefaultMode();
 #if defined(OS_CHROMEOS)
     mode = std::max(mode, ContentVerifierDelegate::BOOTSTRAP);
 #endif  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc
index 7012ffb..dcca35e 100644
--- a/chrome/browser/extensions/extension_toolbar_model.cc
+++ b/chrome/browser/extensions/extension_toolbar_model.cc
@@ -7,10 +7,12 @@
 #include <algorithm>
 #include <string>
 
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_base.h"
 #include "base/prefs/pref_service.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
@@ -135,7 +137,7 @@
     // overflow menu are considered "hidden". But it so happens that the times
     // we are likely to call SetVisibleIconCount() are also those when we are
     // in flux. So wait for things to cool down before setting the prefs.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ExtensionToolbarModel::MaybeUpdateVisibilityPrefs,
                    weak_ptr_factory_.GetWeakPtr()));
@@ -596,10 +598,9 @@
   if (last_known_positions_.size() > pref_position_size) {
     // Need to update pref because we have extra icons. But can't call
     // UpdatePrefs() directly within observation closure.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&ExtensionToolbarModel::UpdatePrefs,
-                   weak_ptr_factory_.GetWeakPtr()));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&ExtensionToolbarModel::UpdatePrefs,
+                              weak_ptr_factory_.GetWeakPtr()));
   }
 }
 
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.cc b/chrome/browser/extensions/extension_uninstall_dialog.cc
index 82d3487..16c6a72 100644
--- a/chrome/browser/extensions/extension_uninstall_dialog.cc
+++ b/chrome/browser/extensions/extension_uninstall_dialog.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/grit/generated_resources.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/image_loader.h"
@@ -48,21 +49,6 @@
 
 }  // namespace
 
-// static
-ExtensionUninstallDialog::AutoConfirmForTests
-ExtensionUninstallDialog::g_auto_confirm_for_testing =
-    ExtensionUninstallDialog::NONE;
-
-ExtensionUninstallDialog::ScopedAutoConfirm::ScopedAutoConfirm(
-    AutoConfirmForTests new_value)
-    : original_value_(g_auto_confirm_for_testing) {
-  g_auto_confirm_for_testing = new_value;
-}
-
-ExtensionUninstallDialog::ScopedAutoConfirm::~ScopedAutoConfirm() {
-  g_auto_confirm_for_testing = original_value_;
-}
-
 ExtensionUninstallDialog::ExtensionUninstallDialog(
     Profile* profile,
     ExtensionUninstallDialog::Delegate* delegate)
@@ -137,14 +123,14 @@
 
   SetIcon(image);
 
-  switch (g_auto_confirm_for_testing) {
-    case NONE:
+  switch (ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
+    case ScopedTestDialogAutoConfirm::NONE:
       Show();
       break;
-    case ACCEPT:
+    case ScopedTestDialogAutoConfirm::ACCEPT:
       OnDialogClosed(CLOSE_ACTION_UNINSTALL);
       break;
-    case CANCEL:
+    case ScopedTestDialogAutoConfirm::CANCEL:
       OnDialogClosed(CLOSE_ACTION_CANCELED);
       break;
   }
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.h b/chrome/browser/extensions/extension_uninstall_dialog.h
index e8039c3..9691906 100644
--- a/chrome/browser/extensions/extension_uninstall_dialog.h
+++ b/chrome/browser/extensions/extension_uninstall_dialog.h
@@ -34,24 +34,6 @@
     CLOSE_ACTION_LAST = 3,
   };
 
-  // A setting to cause extension/app installs from the webstore skip the normal
-  // confirmation dialog. This should only be used in tests.
-  enum AutoConfirmForTests {
-    NONE,    // The prompt will show normally.
-    ACCEPT,  // The prompt will always accept.
-    CANCEL,  // The prompt will always cancel.
-  };
-  class ScopedAutoConfirm {
-   public:
-    explicit ScopedAutoConfirm(AutoConfirmForTests new_value);
-    ~ScopedAutoConfirm();
-
-   private:
-    AutoConfirmForTests original_value_;
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedAutoConfirm);
-  };
-
   // TODO(devlin): For a single method like this, a callback is probably more
   // appropriate than a delegate.
   class Delegate {
@@ -111,8 +93,6 @@
   const gfx::ImageSkia& icon() const { return icon_; }
 
  private:
-  static AutoConfirmForTests g_auto_confirm_for_testing;
-
   // Handles the "report abuse" checkbox being checked at the close of the
   // dialog.
   void HandleReportAbuse();
diff --git a/chrome/browser/extensions/extension_user_script_loader_unittest.cc b/chrome/browser/extensions/extension_user_script_loader_unittest.cc
index 81a70ac..02de7812 100644
--- a/chrome/browser/extensions/extension_user_script_loader_unittest.cc
+++ b/chrome/browser/extensions/extension_user_script_loader_unittest.cc
@@ -10,7 +10,8 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/test/base/testing_profile.h"
@@ -96,7 +97,8 @@
       HostID(),
       true /* listen_for_extension_system_loaded */);
   loader.StartLoad();
-  message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+  message_loop_.task_runner()->PostTask(FROM_HERE,
+                                        base::MessageLoop::QuitClosure());
   message_loop_.Run();
 
   ASSERT_TRUE(shared_memory_ != NULL);
diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc
index 9d6526d..2b30e039 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -285,7 +285,7 @@
       std::string override;
       if (!(*it2)->GetAsString(&override))
         continue;
-      if (StartsWithASCII(url->spec(), override, true)) {
+      if (base::StartsWithASCII(url->spec(), override, true)) {
         GURL original_url(content::kChromeUIScheme + std::string("://") +
                           it.key() + url->spec().substr(override.length()));
         *url = original_url;
diff --git a/chrome/browser/extensions/external_pref_loader.cc b/chrome/browser/extensions/external_pref_loader.cc
index 366cab3..472d185 100644
--- a/chrome/browser/extensions/external_pref_loader.cc
+++ b/chrome/browser/extensions/external_pref_loader.cc
@@ -118,7 +118,7 @@
 void ExternalPrefLoader::StartLoading() {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if ((options_ & DELAY_LOAD_UNTIL_PRIORITY_SYNC) &&
-      (profile_ && profile_->IsSyncAccessible())) {
+      (profile_ && profile_->IsSyncAllowed())) {
     if (!PostLoadIfPrioritySyncReady()) {
       DCHECK(profile_);
       PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
diff --git a/chrome/browser/extensions/isolated_app_browsertest.cc b/chrome/browser/extensions/isolated_app_browsertest.cc
index c55f602..f7b1b1e4 100644
--- a/chrome/browser/extensions/isolated_app_browsertest.cc
+++ b/chrome/browser/extensions/isolated_app_browsertest.cc
@@ -42,7 +42,8 @@
 scoped_ptr<net::test_server::HttpResponse> HandleExpectAndSetCookieRequest(
     const net::test_server::EmbeddedTestServer* test_server,
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(request.relative_url, "/expect-and-set-cookie?", true))
+  if (!base::StartsWithASCII(request.relative_url, "/expect-and-set-cookie?",
+                             true))
     return scoped_ptr<net::test_server::HttpResponse>();
 
   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
diff --git a/chrome/browser/extensions/menu_manager_factory.cc b/chrome/browser/extensions/menu_manager_factory.cc
index 1d2aa746..2bfd3cbb 100644
--- a/chrome/browser/extensions/menu_manager_factory.cc
+++ b/chrome/browser/extensions/menu_manager_factory.cc
@@ -26,9 +26,9 @@
 }
 
 // static
-KeyedService* MenuManagerFactory::BuildServiceInstanceForTesting(
+scoped_ptr<KeyedService> MenuManagerFactory::BuildServiceInstanceForTesting(
     content::BrowserContext* context) {
-  return GetInstance()->BuildServiceInstanceFor(context);
+  return make_scoped_ptr(GetInstance()->BuildServiceInstanceFor(context));
 }
 
 MenuManagerFactory::MenuManagerFactory()
diff --git a/chrome/browser/extensions/menu_manager_factory.h b/chrome/browser/extensions/menu_manager_factory.h
index ae1693e5..5e71738 100644
--- a/chrome/browser/extensions/menu_manager_factory.h
+++ b/chrome/browser/extensions/menu_manager_factory.h
@@ -22,7 +22,7 @@
 
   static MenuManagerFactory* GetInstance();
 
-  static KeyedService* BuildServiceInstanceForTesting(
+  static scoped_ptr<KeyedService> BuildServiceInstanceForTesting(
       content::BrowserContext* context);
 
  private:
diff --git a/chrome/browser/extensions/menu_manager_unittest.cc b/chrome/browser/extensions/menu_manager_unittest.cc
index 8b1ec7d..2afb80b 100644
--- a/chrome/browser/extensions/menu_manager_unittest.cc
+++ b/chrome/browser/extensions/menu_manager_unittest.cc
@@ -6,8 +6,8 @@
 
 #include "base/files/scoped_temp_dir.h"
 #include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
-#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -52,7 +52,7 @@
         profile_(new TestingProfile()),
         manager_(profile_.get(),
                  ExtensionSystem::Get(profile_.get())->state_store()),
-        prefs_(message_loop_.message_loop_proxy().get()),
+        prefs_(message_loop_.task_runner().get()),
         next_id_(1) {}
 
   void TearDown() override {
@@ -483,8 +483,9 @@
 };
 
 // MockEventRouter factory function
-KeyedService* MockEventRouterFactoryFunction(content::BrowserContext* profile) {
-  return new MockEventRouter(static_cast<Profile*>(profile));
+scoped_ptr<KeyedService> MockEventRouterFactoryFunction(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(new MockEventRouter(static_cast<Profile*>(context)));
 }
 
 }  // namespace
diff --git a/chrome/browser/extensions/standard_management_policy_provider_unittest.cc b/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
index 55e3cc5..f6ab019 100644
--- a/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
+++ b/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
@@ -22,7 +22,7 @@
   StandardManagementPolicyProviderTest()
       : ui_thread_(content::BrowserThread::UI, &message_loop_),
         file_thread_(content::BrowserThread::FILE, &message_loop_),
-        prefs_(message_loop_.message_loop_proxy().get()),
+        prefs_(message_loop_.task_runner().get()),
         settings_(new ExtensionManagement(prefs()->pref_service())),
         provider_(settings_.get()) {}
 
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc
index 53c7127..00828eb1 100644
--- a/chrome/browser/extensions/tab_helper.cc
+++ b/chrome/browser/extensions/tab_helper.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/api/webstore/webstore_api.h"
 #include "chrome/browser/extensions/bookmark_app_helper.h"
+#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/extensions/error_console/error_console.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/extension_util.h"
@@ -50,6 +51,7 @@
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_web_contents_observer.h"
 #include "extensions/browser/image_loader.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
@@ -74,10 +76,8 @@
 
 TabHelper::TabHelper(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
+      profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
       extension_app_(NULL),
-      extension_function_dispatcher_(
-          Profile::FromBrowserContext(web_contents->GetBrowserContext()),
-          this),
       pending_web_app_action_(NONE),
       last_committed_nav_entry_unique_id_(0),
       update_shortcut_on_load_complete_(false),
@@ -97,14 +97,20 @@
   active_tab_permission_granter_.reset(new ActiveTabPermissionGranter(
       web_contents,
       SessionTabHelper::IdForTab(web_contents),
-      Profile::FromBrowserContext(web_contents->GetBrowserContext())));
-
-  // If more classes need to listen to global content script activity, then
-  // a separate routing class with an observer interface should be written.
-  profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
+      profile_));
 
   AddScriptExecutionObserver(ActivityLog::GetInstance(profile_));
 
+  InvokeForContentRulesRegistries([this](ContentRulesRegistry* registry) {
+    registry->MonitorWebContentsForRuleEvaluation(this->web_contents());
+  });
+
+  // We need an ExtensionWebContentsObserver, so make sure one exists (this is
+  // a no-op if one already does).
+  ChromeExtensionWebContentsObserver::CreateForWebContents(web_contents);
+  ExtensionWebContentsObserver::GetForWebContents(web_contents)->dispatcher()->
+      set_delegate(this);
+
   registrar_.Add(this,
                  content::NOTIFICATION_LOAD_STOP,
                  content::Source<NavigationController>(
@@ -192,6 +198,30 @@
   return &extension_app_icon_;
 }
 
+// Encapsulates the logic to decide which ContentRulesRegistries need to be
+// invoked, depending on whether this WebContents is associated with an Original
+// or OffTheRecord profile. In the latter case, we need to invoke on both the
+// Original and OffTheRecord ContentRulesRegistries since the Original registry
+// handles spanning-mode incognito extensions.
+template <class Func>
+void TabHelper::InvokeForContentRulesRegistries(const Func& func) {
+  RulesRegistryService* rules_registry_service =
+      RulesRegistryService::Get(profile_);
+  if (rules_registry_service) {
+    func(rules_registry_service->content_rules_registry());
+    if (profile_->IsOffTheRecord()) {
+      // The original profile's content rules registry handles rules for
+      // spanning extensions in incognito profiles, so invoke it also.
+      RulesRegistryService* original_profile_rules_registry_service =
+          RulesRegistryService::Get(profile_->GetOriginalProfile());
+      DCHECK_NE(rules_registry_service,
+                original_profile_rules_registry_service);
+      if (original_profile_rules_registry_service)
+        func(original_profile_rules_registry_service->content_rules_registry());
+    }
+  }
+}
+
 void TabHelper::FinishCreateBookmarkApp(
     const Extension* extension,
     const WebApplicationInfo& web_app_info) {
@@ -205,27 +235,10 @@
 void TabHelper::DidNavigateMainFrame(
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
-  RulesRegistryService* rules_registry_service =
-      RulesRegistryService::Get(profile_);
-  if (rules_registry_service) {
-    rules_registry_service->content_rules_registry()->
-        DidNavigateMainFrame(web_contents(), details, params);
-    // The original profile's content rules registry handles rules for spanning
-    // extensions in incognito profiles, so let it know about the navigation
-    // also.
-    if (profile_->IsOffTheRecord()) {
-      RulesRegistryService* incognito_rules_registry_service =
-          RulesRegistryService::Get(profile_->GetOriginalProfile());
-      // The content and web request rules registries depend on separate
-      // instances for original/incognito profiles. See the comment on
-      // ChromeContentRulesRegistry.
-      DCHECK_NE(rules_registry_service, incognito_rules_registry_service);
-      if (incognito_rules_registry_service) {
-        incognito_rules_registry_service->content_rules_registry()->
-            DidNavigateMainFrame(web_contents(), details, params);
-      }
-    }
-  }
+  InvokeForContentRulesRegistries(
+      [this, &details, &params](ContentRulesRegistry* registry) {
+    registry->DidNavigateMainFrame(web_contents(), details, params);
+  });
 
   content::BrowserContext* context = web_contents()->GetBrowserContext();
   ExtensionRegistry* registry = ExtensionRegistry::Get(context);
@@ -261,9 +274,6 @@
                         OnInlineWebstoreInstall)
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppInstallState,
                         OnGetAppInstallState);
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange,
-                        OnWatchedPageChange)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -356,12 +366,9 @@
   }
   // Inform the Webstore API that an inline install is happening, in case the
   // page requested status updates.
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
-
-  ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
+  ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
   if (registry->disabled_extensions().Contains(webstore_item_id) &&
-      (ExtensionPrefs::Get(profile)->GetDisableReasons(webstore_item_id) &
+      (ExtensionPrefs::Get(profile_)->GetDisableReasons(webstore_item_id) &
            Extension::DISABLE_PERMISSIONS_INCREASE) != 0) {
       // The extension was disabled due to permissions increase. Prompt for
       // re-enable.
@@ -371,7 +378,7 @@
       extension_reenabler_.reset();
       extension_reenabler_ = ExtensionReenabler::PromptForReenable(
           registry->disabled_extensions().GetByID(webstore_item_id),
-          profile,
+          profile_,
           web_contents(),
           requestor_url,
           base::Bind(&TabHelper::OnReenableComplete,
@@ -381,7 +388,7 @@
   } else {
     // TODO(devlin): We should adddress the case of the extension already
     // being installed and enabled.
-    WebstoreAPI::Get(profile)->OnInlineInstallStart(
+    WebstoreAPI::Get(profile_)->OnInlineInstallStart(
         return_route_id, this, webstore_item_id, listeners_mask);
 
     WebstoreStandaloneInstaller::Callback callback =
@@ -419,11 +426,6 @@
       return_route_id, state, callback_id));
 }
 
-void TabHelper::OnRequest(const ExtensionHostMsg_Request_Params& request) {
-  extension_function_dispatcher_.Dispatch(request,
-                                          web_contents()->GetRenderViewHost());
-}
-
 void TabHelper::OnContentScriptsExecuting(
     const ScriptExecutionObserver::ExecutingScriptsMap& executing_scripts_map,
     const GURL& on_url) {
@@ -433,15 +435,6 @@
       OnScriptsExecuted(web_contents(), executing_scripts_map, on_url));
 }
 
-void TabHelper::OnWatchedPageChange(
-    const std::vector<std::string>& css_selectors) {
-  if (ExtensionSystem::Get(profile_)->extension_service() &&
-      RulesRegistryService::Get(profile_)) {
-    RulesRegistryService::Get(profile_)->content_rules_registry()->Apply(
-        web_contents(), css_selectors);
-  }
-}
-
 void TabHelper::OnDetailedConsoleMessageAdded(
     const base::string16& message,
     const base::string16& source,
@@ -480,9 +473,7 @@
 
   // Enqueue OnImageLoaded callback.
   if (extension) {
-    Profile* profile =
-        Profile::FromBrowserContext(web_contents()->GetBrowserContext());
-    ImageLoader* loader = ImageLoader::Get(profile);
+    ImageLoader* loader = ImageLoader::Get(profile_);
     loader->LoadImageAsync(
         extension,
         IconsInfo::GetIconResource(extension,
diff --git a/chrome/browser/extensions/tab_helper.h b/chrome/browser/extensions/tab_helper.h
index 5564f914..b3088cb 100644
--- a/chrome/browser/extensions/tab_helper.h
+++ b/chrome/browser/extensions/tab_helper.h
@@ -7,7 +7,6 @@
 
 #include <set>
 #include <string>
-#include <vector>
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
@@ -67,8 +66,6 @@
   virtual void AddScriptExecutionObserver(ScriptExecutionObserver* observer);
   virtual void RemoveScriptExecutionObserver(ScriptExecutionObserver* observer);
 
-  // App extensions ------------------------------------------------------------
-
   // Sets the extension denoting this as an app. If |extension| is non-null this
   // tab becomes an app-tab. WebContents does not listen for unload events for
   // the extension. It's up to consumers of WebContents to do that.
@@ -125,6 +122,11 @@
       WebstoreInlineInstallerFactory* factory);
 
  private:
+  // Utility function to invoke member functions on all relevant
+  // ContentRulesRegistries.
+  template <class Func>
+  void InvokeForContentRulesRegistries(const Func& func);
+
   // Different types of action when web app info is available.
   // OnDidGetApplicationInfo uses this to dispatch calls.
   enum WebAppAction {
@@ -167,11 +169,9 @@
   void OnGetAppInstallState(const GURL& requestor_url,
                             int return_route_id,
                             int callback_id);
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
   void OnContentScriptsExecuting(
       const ScriptExecutionObserver::ExecutingScriptsMap& extension_ids,
       const GURL& on_url);
-  void OnWatchedPageChange(const std::vector<std::string>& css_selectors);
   void OnDetailedConsoleMessageAdded(const base::string16& message,
                                      const base::string16& source,
                                      const StackTrace& stack_trace,
@@ -212,7 +212,7 @@
   // Sends our tab ID to |render_frame_host|.
   void SetTabId(content::RenderFrameHost* render_frame_host);
 
-  // Data for app extensions ---------------------------------------------------
+  Profile* profile_;
 
   // Our content script observers. Declare at top so that it will outlive all
   // other members, since they might add themselves as observers.
@@ -226,9 +226,6 @@
   // non-extension apps.
   SkBitmap extension_app_icon_;
 
-  // Process any extension messages coming from the tab.
-  extensions::ExtensionFunctionDispatcher extension_function_dispatcher_;
-
   // Cached web app info data.
   WebApplicationInfo web_app_info_;
 
@@ -255,8 +252,6 @@
 
   scoped_ptr<BookmarkAppHelper> bookmark_app_helper_;
 
-  Profile* profile_;
-
   // Creates WebstoreInlineInstaller instances for inline install triggers.
   scoped_ptr<WebstoreInlineInstallerFactory> webstore_inline_installer_factory_;
 
diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc
index 11f8317..4867560a 100644
--- a/chrome/browser/extensions/test_extension_prefs.cc
+++ b/chrome/browser/extensions/test_extension_prefs.cc
@@ -9,12 +9,12 @@
 #include "base/files/file_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/prefs/json_pref_store.h"
 #include "base/prefs/pref_value_store.h"
 #include "base/run_loop.h"
 #include "base/sequenced_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/prefs/pref_service_mock_factory.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
diff --git a/chrome/browser/extensions/test_extension_system.cc b/chrome/browser/extensions/test_extension_system.cc
index 14835f1..4ba5e95 100644
--- a/chrome/browser/extensions/test_extension_system.cc
+++ b/chrome/browser/extensions/test_extension_system.cc
@@ -44,7 +44,7 @@
     extension_service_->Shutdown();
 }
 
-ExtensionPrefs* TestExtensionSystem::CreateExtensionPrefs(
+scoped_ptr<ExtensionPrefs> TestExtensionSystem::CreateExtensionPrefs(
     const base::CommandLine* command_line,
     const base::FilePath& install_directory) {
   bool extensions_disabled =
@@ -55,11 +55,11 @@
   // are not reflected in the pref service. One would need to
   // inject a new ExtensionPrefStore(extension_pref_value_map, false).
 
-  return ExtensionPrefs::Create(
+  return make_scoped_ptr(ExtensionPrefs::Create(
       profile_->GetPrefs(), install_directory,
       ExtensionPrefValueMapFactory::GetForBrowserContext(profile_),
       ExtensionsBrowserClient::Get()->CreateAppSorting().Pass(),
-      extensions_disabled, std::vector<ExtensionPrefsObserver*>());
+      extensions_disabled, std::vector<ExtensionPrefsObserver*>()));
 }
 
 ExtensionService* TestExtensionSystem::CreateExtensionService(
@@ -137,8 +137,10 @@
 }
 
 // static
-KeyedService* TestExtensionSystem::Build(content::BrowserContext* profile) {
-  return new TestExtensionSystem(static_cast<Profile*>(profile));
+scoped_ptr<KeyedService> TestExtensionSystem::Build(
+    content::BrowserContext* profile) {
+  return make_scoped_ptr(
+      new TestExtensionSystem(static_cast<Profile*>(profile)));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/test_extension_system.h b/chrome/browser/extensions/test_extension_system.h
index 7efd930..3605626 100644
--- a/chrome/browser/extensions/test_extension_system.h
+++ b/chrome/browser/extensions/test_extension_system.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_TEST_EXTENSION_SYSTEM_H_
 #define CHROME_BROWSER_EXTENSIONS_TEST_EXTENSION_SYSTEM_H_
 
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/one_shot_event.h"
@@ -41,8 +42,9 @@
   // Creates an ExtensionPrefs with the testing profile and returns it.
   // Useful for tests that need to modify prefs before creating the
   // ExtensionService.
-  ExtensionPrefs* CreateExtensionPrefs(const base::CommandLine* command_line,
-                                       const base::FilePath& install_directory);
+  scoped_ptr<ExtensionPrefs> CreateExtensionPrefs(
+      const base::CommandLine* command_line,
+      const base::FilePath& install_directory);
 
   // Creates an ExtensionService initialized with the testing profile and
   // returns it, and creates ExtensionPrefs if it hasn't been created yet.
@@ -74,7 +76,7 @@
   void SetReady() { ready_.Signal(); }
 
   // Factory method for tests to use with SetTestingProfile.
-  static KeyedService* Build(content::BrowserContext* profile);
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* profile);
 
  protected:
   Profile* profile_;
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc
index 36368aca..5f702b9b 100644
--- a/chrome/browser/extensions/unpacked_installer.cc
+++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -19,6 +19,7 @@
 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
 #include "components/crx_file/id_util.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/install/extension_install_ui.h"
@@ -79,18 +80,19 @@
 }
 
 void SimpleExtensionLoadPrompt::ShowPrompt() {
-  switch (ExtensionInstallPrompt::g_auto_confirm_for_tests) {
-    case ExtensionInstallPrompt::NONE:
+  switch (extensions::ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
+    case extensions::ScopedTestDialogAutoConfirm::NONE:
       install_ui_->ConfirmInstall(
           this,
           extension_.get(),
           ExtensionInstallPrompt::GetDefaultShowDialogCallback());
       break;
-    case ExtensionInstallPrompt::ACCEPT:
+    case extensions::ScopedTestDialogAutoConfirm::ACCEPT:
       InstallUIProceed();
       break;
-    case ExtensionInstallPrompt::CANCEL:
+    case extensions::ScopedTestDialogAutoConfirm::CANCEL:
       InstallUIAbort(false);
+      break;
   }
 }
 
diff --git a/chrome/browser/extensions/webstore_inline_installer_browsertest.cc b/chrome/browser/extensions/webstore_inline_installer_browsertest.cc
index 270d7cf..352f17f 100644
--- a/chrome/browser/extensions/webstore_inline_installer_browsertest.cc
+++ b/chrome/browser/extensions/webstore_inline_installer_browsertest.cc
@@ -167,8 +167,7 @@
 IN_PROC_BROWSER_TEST_F(WebstoreInlineInstallerTest,
                        ReinstallDisabledExtension) {
   // Install an extension via inline install, and confirm it is successful.
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
+  AutoAcceptInstall();
   ui_test_utils::NavigateToURL(
       browser(), GenerateTestServerUrl(kAppDomain, "install.html"));
   RunTest("runTest");
@@ -224,8 +223,7 @@
 
  protected:
   void RunTest(const std::string& file_name) {
-    ExtensionInstallPrompt::g_auto_confirm_for_tests =
-        ExtensionInstallPrompt::ACCEPT;
+    AutoAcceptInstall();
     ui_test_utils::NavigateToURL(browser(),
                                  GenerateTestServerUrl(kAppDomain, file_name));
     WebstoreInstallerTest::RunTest("runTest");
diff --git a/chrome/browser/extensions/webstore_install_helper.cc b/chrome/browser/extensions/webstore_install_helper.cc
index b487bf6..91292d6 100644
--- a/chrome/browser/extensions/webstore_install_helper.cc
+++ b/chrome/browser/extensions/webstore_install_helper.cc
@@ -64,10 +64,11 @@
     CHECK(!icon_fetcher_.get());
     AddRef();  // Balanced in OnFetchComplete().
     icon_fetcher_.reset(new chrome::BitmapFetcher(icon_url_, this));
-    icon_fetcher_->Start(
+    icon_fetcher_->Init(
         context_getter_, std::string(),
         net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
         net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES);
+    icon_fetcher_->Start();
   }
 }
 
diff --git a/chrome/browser/extensions/webstore_installer_test.cc b/chrome/browser/extensions/webstore_installer_test.cc
index cb3b790..73192e0 100644
--- a/chrome/browser/extensions/webstore_installer_test.cc
+++ b/chrome/browser/extensions/webstore_installer_test.cc
@@ -138,11 +138,13 @@
 }
 
 void WebstoreInstallerTest::AutoAcceptInstall() {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
+  install_auto_confirm_.reset();  // Destroy any old override first.
+  install_auto_confirm_.reset(new extensions::ScopedTestDialogAutoConfirm(
+      extensions::ScopedTestDialogAutoConfirm::ACCEPT));
 }
 
 void WebstoreInstallerTest::AutoCancelInstall() {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::CANCEL;
+  install_auto_confirm_.reset();  // Destroy any old override first.
+  install_auto_confirm_.reset(new extensions::ScopedTestDialogAutoConfirm(
+      extensions::ScopedTestDialogAutoConfirm::CANCEL));
 }
diff --git a/chrome/browser/extensions/webstore_installer_test.h b/chrome/browser/extensions/webstore_installer_test.h
index a70e35af..be226719 100644
--- a/chrome/browser/extensions/webstore_installer_test.h
+++ b/chrome/browser/extensions/webstore_installer_test.h
@@ -9,6 +9,7 @@
 
 #include "base/files/scoped_temp_dir.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "url/gurl.h"
 
 namespace base {
@@ -68,6 +69,10 @@
   std::string test_gallery_url_;
 
   base::ScopedTempDir download_directory_;
+
+  scoped_ptr<extensions::ScopedTestDialogAutoConfirm> install_auto_confirm_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebstoreInstallerTest);
 };
 
 #endif  // CHROME_BROWSER_EXTENSIONS_WEBSTORE_INSTALLER_TEST_H_
diff --git a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
index 1662694..2c142b4 100644
--- a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
+++ b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
@@ -5,7 +5,6 @@
 #include "base/command_line.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/startup_helper.h"
 #include "chrome/browser/extensions/webstore_installer_test.h"
@@ -57,8 +56,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, Install) {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
+  AutoAcceptInstall();
 
   ui_test_utils::NavigateToURL(
       browser(), GenerateTestServerUrl(kAppDomain, "install.html"));
@@ -74,8 +72,7 @@
 
 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest,
     InstallNotAllowedFromNonVerifiedDomains) {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::CANCEL;
+  AutoCancelInstall();
   ui_test_utils::NavigateToURL(
       browser(),
       GenerateTestServerUrl(kNonAppDomain, "install_non_verified_domain.html"));
@@ -94,8 +91,7 @@
 // Flakes on all platforms: http://crbug.com/95713, http://crbug.com/229947
 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest,
                        DISABLED_ArgumentValidation) {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::CANCEL;
+  AutoCancelInstall();
 
   // Each of these tests has to run separately, since one page/tab can
   // only have one in-progress install request. These tests don't all pass
@@ -111,8 +107,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, MultipleInstallCalls) {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::CANCEL;
+  AutoCancelInstall();
 
   ui_test_utils::NavigateToURL(
       browser(),
@@ -121,8 +116,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, InstallNotSupported) {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::CANCEL;
+  AutoCancelInstall();
   ui_test_utils::NavigateToURL(
       browser(),
       GenerateTestServerUrl(kAppDomain, "install_not_supported.html"));
@@ -141,8 +135,7 @@
 
 // Regression test for http://crbug.com/144991.
 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, InstallFromHostedApp) {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
+  AutoAcceptInstall();
 
   const GURL kInstallUrl = GenerateTestServerUrl(kAppDomain, "install.html");
 
@@ -195,8 +188,7 @@
     return;
 #endif
 
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
+  AutoAcceptInstall();
 
   ui_test_utils::NavigateToURL(
       browser(), GenerateTestServerUrl(kAppDomain, "install_prohibited.html"));
@@ -231,8 +223,7 @@
 
 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallUnpackFailureTest,
     WebstoreStartupInstallUnpackFailureTest) {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
+  AutoAcceptInstall();
 
   ui_test_utils::NavigateToURL(browser(),
       GenerateTestServerUrl(kAppDomain, "install_unpack_failure.html"));
@@ -295,8 +286,7 @@
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   command_line->AppendSwitchASCII(
       switches::kInstallEphemeralAppFromWebstore, kTestExtensionId);
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
+  AutoAcceptInstall();
   extensions::StartupHelper helper;
   EXPECT_FALSE(helper.InstallEphemeralApp(*command_line, browser()->profile()));
   EXPECT_FALSE(saw_install());
diff --git a/chrome/browser/favicon/chrome_favicon_client_factory.cc b/chrome/browser/favicon/chrome_favicon_client_factory.cc
deleted file mode 100644
index cb1fe81..0000000
--- a/chrome/browser/favicon/chrome_favicon_client_factory.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/favicon/chrome_favicon_client_factory.h"
-
-#include "base/memory/singleton.h"
-#include "chrome/browser/favicon/chrome_favicon_client.h"
-#include "chrome/browser/profiles/incognito_helpers.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-
-ChromeFaviconClientFactory::ChromeFaviconClientFactory()
-    : BrowserContextKeyedServiceFactory(
-          "ChromeFaviconClient",
-          BrowserContextDependencyManager::GetInstance()) {
-}
-
-ChromeFaviconClientFactory::~ChromeFaviconClientFactory() {
-}
-
-// static
-favicon::FaviconClient* ChromeFaviconClientFactory::GetForProfile(
-    Profile* profile) {
-  return static_cast<favicon::FaviconClient*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-}
-
-// static
-ChromeFaviconClientFactory* ChromeFaviconClientFactory::GetInstance() {
-  return Singleton<ChromeFaviconClientFactory>::get();
-}
-
-KeyedService* ChromeFaviconClientFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  return new ChromeFaviconClient(Profile::FromBrowserContext(context));
-}
-
-content::BrowserContext* ChromeFaviconClientFactory::GetBrowserContextToUse(
-    content::BrowserContext* context) const {
-  return chrome::GetBrowserContextRedirectedInIncognito(context);
-}
diff --git a/chrome/browser/favicon/chrome_favicon_client_factory.h b/chrome/browser/favicon/chrome_favicon_client_factory.h
deleted file mode 100644
index 83fdcc0..0000000
--- a/chrome/browser/favicon/chrome_favicon_client_factory.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_FAVICON_CHROME_FAVICON_CLIENT_FACTORY_H_
-#define CHROME_BROWSER_FAVICON_CHROME_FAVICON_CLIENT_FACTORY_H_
-
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-template <typename T>
-struct DefaultSingletonTraits;
-
-class Profile;
-
-namespace favicon {
-class FaviconClient;
-}
-
-// Singleton that owns all ChromeFaviconClients and associates them with
-// Profiles.
-class ChromeFaviconClientFactory : public BrowserContextKeyedServiceFactory {
- public:
-  // Returns the instance of favicon::FaviconClient associated with |profile|
-  // (creating one if none exists).
-  static favicon::FaviconClient* GetForProfile(Profile* profile);
-
-  // Returns an instance of the factory singleton.
-  static ChromeFaviconClientFactory* GetInstance();
-
- private:
-  friend struct DefaultSingletonTraits<ChromeFaviconClientFactory>;
-
-  ChromeFaviconClientFactory();
-  ~ChromeFaviconClientFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* profile) const override;
-  content::BrowserContext* GetBrowserContextToUse(
-      content::BrowserContext* context) const override;
-};
-
-#endif  // CHROME_BROWSER_FAVICON_CHROME_FAVICON_CLIENT_FACTORY_H_
diff --git a/chrome/browser/favicon/favicon_service_factory.cc b/chrome/browser/favicon/favicon_service_factory.cc
index cb0840cf..35da589 100644
--- a/chrome/browser/favicon/favicon_service_factory.cc
+++ b/chrome/browser/favicon/favicon_service_factory.cc
@@ -6,13 +6,25 @@
 
 #include "base/memory/singleton.h"
 #include "base/prefs/pref_service.h"
-#include "chrome/browser/favicon/chrome_favicon_client_factory.h"
+#include "chrome/browser/favicon/chrome_favicon_client.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 
+namespace {
+
+scoped_ptr<KeyedService> BuildFaviconService(content::BrowserContext* context) {
+  Profile* profile = Profile::FromBrowserContext(context);
+  return make_scoped_ptr(new favicon::FaviconService(
+      make_scoped_ptr(new ChromeFaviconClient(profile)),
+      HistoryServiceFactory::GetForProfile(
+          profile, ServiceAccessType::EXPLICIT_ACCESS)));
+}
+
+}  // namespace
+
 // static
 favicon::FaviconService* FaviconServiceFactory::GetForProfile(
     Profile* profile,
@@ -37,12 +49,17 @@
   return Singleton<FaviconServiceFactory>::get();
 }
 
+// static
+BrowserContextKeyedServiceFactory::TestingFactoryFunction
+FaviconServiceFactory::GetDefaultFactory() {
+  return &BuildFaviconService;
+}
+
 FaviconServiceFactory::FaviconServiceFactory()
     : BrowserContextKeyedServiceFactory(
         "FaviconService",
         BrowserContextDependencyManager::GetInstance()) {
   DependsOn(HistoryServiceFactory::GetInstance());
-  DependsOn(ChromeFaviconClientFactory::GetInstance());
 }
 
 FaviconServiceFactory::~FaviconServiceFactory() {
@@ -50,11 +67,7 @@
 
 KeyedService* FaviconServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  Profile* profile = Profile::FromBrowserContext(context);
-  return new favicon::FaviconService(
-      ChromeFaviconClientFactory::GetForProfile(profile),
-      HistoryServiceFactory::GetForProfile(profile,
-                                           ServiceAccessType::EXPLICIT_ACCESS));
+  return BuildFaviconService(context).release();
 }
 
 bool FaviconServiceFactory::ServiceIsNULLWhileTesting() const {
diff --git a/chrome/browser/favicon/favicon_service_factory.h b/chrome/browser/favicon/favicon_service_factory.h
index fd159de..6da30f4 100644
--- a/chrome/browser/favicon/favicon_service_factory.h
+++ b/chrome/browser/favicon/favicon_service_factory.h
@@ -25,8 +25,13 @@
   static favicon::FaviconService* GetForProfile(Profile* profile,
                                                 ServiceAccessType sat);
 
+  // Returns the FaviconServiceFactory singleton.
   static FaviconServiceFactory* GetInstance();
 
+  // Returns the default factory used to build FaviconService. Can be registered
+  // with SetTestingFactory to use the FaviconService instance during testing.
+  static TestingFactoryFunction GetDefaultFactory();
+
  private:
   friend struct DefaultSingletonTraits<FaviconServiceFactory>;
 
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc
index b3225106..894b683 100644
--- a/chrome/browser/geolocation/geolocation_browsertest.cc
+++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -832,10 +832,6 @@
 }
 
 IN_PROC_BROWSER_TEST_P(GeolocationBrowserTest, TabDestroyed) {
-  // This test triggers crbug.com/433877.
-  // TODO(felt): Reenable this test for permission bubbles once that's fixed.
-  if (PermissionBubbleManager::Enabled()) return;
-
   set_html_for_tests("/geolocation/tab_destroyed.html");
   ASSERT_TRUE(Initialize(INITIALIZATION_IFRAMES));
   LoadIFrames(3);
diff --git a/chrome/browser/google/google_brand.cc b/chrome/browser/google/google_brand.cc
index a452844..894efb5 100644
--- a/chrome/browser/google/google_brand.cc
+++ b/chrome/browser/google/google_brand.cc
@@ -103,9 +103,9 @@
   if (found != end)
     return true;
 
-  return StartsWithASCII(brand, "EUB", true) ||
-         StartsWithASCII(brand, "EUC", true) ||
-         StartsWithASCII(brand, "GGR", true);
+  return base::StartsWithASCII(brand, "EUB", true) ||
+         base::StartsWithASCII(brand, "EUC", true) ||
+         base::StartsWithASCII(brand, "GGR", true);
 }
 
 bool IsOrganicFirstRun(const std::string& brand) {
@@ -117,8 +117,8 @@
   }
 #endif
 
-  return StartsWithASCII(brand, "GG", true) ||
-         StartsWithASCII(brand, "EU", true);
+  return base::StartsWithASCII(brand, "GG", true) ||
+         base::StartsWithASCII(brand, "EU", true);
 }
 
 bool IsInternetCafeBrandCode(const std::string& brand) {
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc
index 664b8be1..ded32d60 100644
--- a/chrome/browser/google/google_update_win.cc
+++ b/chrome/browser/google/google_update_win.cc
@@ -82,28 +82,43 @@
   return GOOGLE_UPDATE_NO_ERROR;
 }
 
-// Creates an instance of a COM Local Server class using either plain vanilla
-// CoCreateInstance, or using the Elevation moniker if running on Vista.
-// hwnd must refer to a foregound window in order to get the UAC prompt
-// showing up in the foreground if running on Vista. It can also be NULL if
-// background UAC prompts are desired.
-HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id,
+// Explicitly allow the Google Update service to impersonate the client since
+// some COM code elsewhere in the browser process may have previously used
+// CoInitializeSecurity to set the impersonation level to something other than
+// the default. Ignore errors since an attempt to use Google Update may succeed
+// regardless.
+void ConfigureProxyBlanket(IUnknown* interface_pointer) {
+  ::CoSetProxyBlanket(interface_pointer,
+                      RPC_C_AUTHN_DEFAULT,
+                      RPC_C_AUTHZ_DEFAULT,
+                      COLE_DEFAULT_PRINCIPAL,
+                      RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+                      RPC_C_IMP_LEVEL_IMPERSONATE,
+                      nullptr,
+                      EOAC_DYNAMIC_CLOAKING);
+}
+
+// Creates a class factory for a COM Local Server class using either plain
+// vanilla CoGetClassObject, or using the Elevation moniker if running on
+// Vista+. |hwnd| must refer to a foregound window in order to get the UAC
+// prompt to appear in the foreground if running on Vista+. It can also be NULL
+// if background UAC prompts are desired.
+HRESULT CoGetClassObjectAsAdmin(REFCLSID class_id,
                                 REFIID interface_id,
                                 gfx::AcceleratedWidget hwnd,
                                 void** interface_ptr) {
   if (!interface_ptr)
     return E_POINTER;
 
-  // For Vista, need to instantiate the COM server via the elevation
+  // For Vista+, need to instantiate the class factory via the elevation
   // moniker. This ensures that the UAC dialog shows up.
   if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
     wchar_t class_id_as_string[MAX_PATH] = {};
     StringFromGUID2(class_id, class_id_as_string,
                     arraysize(class_id_as_string));
 
-    base::string16 elevation_moniker_name =
-        base::StringPrintf(L"Elevation:Administrator!new:%ls",
-                           class_id_as_string);
+    base::string16 elevation_moniker_name = base::StringPrintf(
+        L"Elevation:Administrator!clsid:%ls", class_id_as_string);
 
     BIND_OPTS3 bind_opts;
     // An explicit memset is needed rather than relying on value initialization
@@ -113,12 +128,12 @@
     bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
     bind_opts.hwnd = hwnd;
 
-    return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, interface_id,
-                       interface_ptr);
+    return ::CoGetObject(elevation_moniker_name.c_str(), &bind_opts,
+                         interface_id, interface_ptr);
   }
 
-  return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, interface_id,
-                          interface_ptr);
+  return ::CoGetClassObject(class_id, CLSCTX_LOCAL_SERVER, nullptr,
+                            interface_id, interface_ptr);
 }
 
 HRESULT CreateGoogleUpdate3WebClass(
@@ -129,21 +144,35 @@
   if (g_google_update_factory)
     return g_google_update_factory->Run(google_update);
 
+  const CLSID& google_update_clsid = system_level_install ?
+      CLSID_GoogleUpdate3WebMachineClass :
+      CLSID_GoogleUpdate3WebUserClass;
+  base::win::ScopedComPtr<IClassFactory> class_factory;
+  HRESULT hresult = S_OK;
+
   // For a user-level install, update checks and updates can both be done by a
-  // normal user with the UserClass.
-  if (!system_level_install)
-    return google_update->CreateInstance(CLSID_GoogleUpdate3WebUserClass);
+  // normal user with the UserClass. For a system-level install, update checks
+  // can be done by a normal user with the MachineClass.
+  if (!system_level_install || !install_update_if_possible) {
+    hresult = ::CoGetClassObject(google_update_clsid, CLSCTX_ALL, nullptr,
+                                 base::win::ScopedComPtr<IClassFactory>::iid(),
+                                 class_factory.ReceiveVoid());
+  } else {
+    // For a system-level install, an update requires Admin privileges for
+    // writing to %ProgramFiles%. Elevate while instantiating the MachineClass.
+    hresult = CoGetClassObjectAsAdmin(
+        google_update_clsid, base::win::ScopedComPtr<IClassFactory>::iid(),
+        elevation_window, class_factory.ReceiveVoid());
+  }
+  if (FAILED(hresult))
+    return hresult;
 
-  // For a system-level install, update checks can be done by a normal user with
-  // the MachineClass.
-  if (!install_update_if_possible)
-    return google_update->CreateInstance(CLSID_GoogleUpdate3WebMachineClass);
+  ConfigureProxyBlanket(class_factory.get());
 
-  // For a system-level install, an update requires Admin privileges for writing
-  // to %ProgramFiles%. Elevate while instantiating the MachineClass.
-  return CoCreateInstanceAsAdmin(CLSID_GoogleUpdate3WebMachineClass,
-                                 IID_IGoogleUpdate3Web, elevation_window,
-                                 google_update->ReceiveVoid());
+  return class_factory->CreateInstance(
+      nullptr,
+      base::win::ScopedComPtr<IGoogleUpdate3Web>::iid(),
+      google_update->ReceiveVoid());
 }
 
 // UpdateCheckDriver -----------------------------------------------------------
@@ -395,6 +424,8 @@
     return hresult;
   }
 
+  ConfigureProxyBlanket(google_update_.get());
+
   // The class was created, so all subsequent errors are reported as:
   *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
   base::string16 app_guid =
@@ -410,6 +441,7 @@
     if (FAILED(hresult))
       return hresult;
   }
+  ConfigureProxyBlanket(app_bundle_.get());
 
   if (!locale_.empty()) {
     // Ignore the result of this since, while setting the display language is
@@ -439,6 +471,7 @@
   hresult = dispatch.QueryInterface(app_.Receive());
   if (FAILED(hresult))
     return hresult;
+  ConfigureProxyBlanket(app_.get());
   return app_bundle_->checkForUpdate();
 }
 
@@ -453,6 +486,7 @@
   *hresult = dispatch.QueryInterface(current_state->Receive());
   if (FAILED(*hresult))
     return false;
+  ConfigureProxyBlanket(current_state->get());
   LONG value = 0;
   *hresult = (*current_state)->get_stateValue(&value);
   if (FAILED(*hresult))
diff --git a/chrome/browser/guest_view/extension_options/chrome_extension_options_guest_delegate.cc b/chrome/browser/guest_view/extension_options/chrome_extension_options_guest_delegate.cc
index 4fc170b..0685e2b04 100644
--- a/chrome/browser/guest_view/extension_options/chrome_extension_options_guest_delegate.cc
+++ b/chrome/browser/guest_view/extension_options/chrome_extension_options_guest_delegate.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/guest_view/extension_options/chrome_extension_options_guest_delegate.h"
 
-#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -21,11 +20,6 @@
 ChromeExtensionOptionsGuestDelegate::~ChromeExtensionOptionsGuestDelegate() {
 }
 
-void ChromeExtensionOptionsGuestDelegate::DidInitialize() {
-  ChromeExtensionWebContentsObserver::CreateForWebContents(
-      extension_options_guest()->web_contents());
-}
-
 bool ChromeExtensionOptionsGuestDelegate::HandleContextMenu(
     const content::ContextMenuParams& params) {
   ContextMenuDelegate* menu_delegate = ContextMenuDelegate::FromWebContents(
diff --git a/chrome/browser/guest_view/extension_options/chrome_extension_options_guest_delegate.h b/chrome/browser/guest_view/extension_options/chrome_extension_options_guest_delegate.h
index 7234149..007cdd9 100644
--- a/chrome/browser/guest_view/extension_options/chrome_extension_options_guest_delegate.h
+++ b/chrome/browser/guest_view/extension_options/chrome_extension_options_guest_delegate.h
@@ -19,8 +19,6 @@
   explicit ChromeExtensionOptionsGuestDelegate(ExtensionOptionsGuest* guest);
   ~ChromeExtensionOptionsGuestDelegate() override;
 
-  void DidInitialize() override;
-
   bool HandleContextMenu(const content::ContextMenuParams& params) override;
 
   content::WebContents* OpenURLInNewTab(
diff --git a/chrome/browser/guest_view/extension_view/chrome_extension_view_guest_delegate.cc b/chrome/browser/guest_view/extension_view/chrome_extension_view_guest_delegate.cc
deleted file mode 100644
index 3fd5e69..0000000
--- a/chrome/browser/guest_view/extension_view/chrome_extension_view_guest_delegate.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/guest_view/extension_view/chrome_extension_view_guest_delegate.h"
-
-#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
-#include "extensions/browser/guest_view/extension_view/extension_view_guest.h"
-
-namespace extensions {
-
-ChromeExtensionViewGuestDelegate::ChromeExtensionViewGuestDelegate(
-    ExtensionViewGuest* guest)
-    : ExtensionViewGuestDelegate(guest) {
-}
-
-ChromeExtensionViewGuestDelegate::~ChromeExtensionViewGuestDelegate() {
-}
-
-void ChromeExtensionViewGuestDelegate::DidInitialize() {
-  ChromeExtensionWebContentsObserver::CreateForWebContents(
-      extension_view_guest()->web_contents());
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/guest_view/extension_view/chrome_extension_view_guest_delegate.h b/chrome/browser/guest_view/extension_view/chrome_extension_view_guest_delegate.h
deleted file mode 100644
index 3cae365..0000000
--- a/chrome/browser/guest_view/extension_view/chrome_extension_view_guest_delegate.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_GUEST_VIEW_EXTENSION_VIEW_CHROME_EXTENSION_VIEW_GUEST_DELEGATE_H_
-#define CHROME_BROWSER_GUEST_VIEW_EXTENSION_VIEW_CHROME_EXTENSION_VIEW_GUEST_DELEGATE_H_
-
-#include "extensions/browser/guest_view/extension_view/extension_view_guest_delegate.h"
-
-namespace extensions {
-
-class ExtensionViewGuest;
-
-class ChromeExtensionViewGuestDelegate : public ExtensionViewGuestDelegate {
- public:
-  explicit ChromeExtensionViewGuestDelegate(ExtensionViewGuest* guest);
-  ~ChromeExtensionViewGuestDelegate() override;
-
-  void DidInitialize() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ChromeExtensionViewGuestDelegate);
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_GUEST_VIEW_EXTENSION_VIEW_CHROME_EXTENSION_VIEW_GUEST_DELEGATE_H_
diff --git a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.cc b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.cc
index 9a3d140..ce47743 100644
--- a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.cc
+++ b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.cc
@@ -4,52 +4,17 @@
 
 #include "chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.h"
 
-#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
-#include "chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.h"
-#include "components/pdf/browser/pdf_web_contents_helper.h"
 #include "components/renderer_context_menu/context_menu_delegate.h"
-#include "components/ui/zoom/page_zoom.h"
-#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
-
-#if defined(ENABLE_PRINTING)
-#if defined(ENABLE_PRINT_PREVIEW)
-#include "chrome/browser/printing/print_preview_message_handler.h"
-#include "chrome/browser/printing/print_view_manager.h"
-#else
-#include "chrome/browser/printing/print_view_manager_basic.h"
-#endif  // defined(ENABLE_PRINT_PREVIEW)
-#endif  // defined(ENABLE_PRINTING)
 
 namespace extensions {
 
-ChromeMimeHandlerViewGuestDelegate::ChromeMimeHandlerViewGuestDelegate(
-    MimeHandlerViewGuest* guest)
-    : MimeHandlerViewGuestDelegate(guest), guest_(guest) {
+ChromeMimeHandlerViewGuestDelegate::ChromeMimeHandlerViewGuestDelegate() {
 }
 
 ChromeMimeHandlerViewGuestDelegate::~ChromeMimeHandlerViewGuestDelegate() {
 }
 
-// TODO(lazyboy): Investigate ways to move this out to /extensions.
-void ChromeMimeHandlerViewGuestDelegate::AttachHelpers() {
-  content::WebContents* web_contents = guest_->web_contents();
-#if defined(ENABLE_PRINTING)
-#if defined(ENABLE_PRINT_PREVIEW)
-  printing::PrintViewManager::CreateForWebContents(web_contents);
-  printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents);
-#else
-  printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
-#endif  // defined(ENABLE_PRINT_PREVIEW)
-#endif  // defined(ENABLE_PRINTING)
-  pdf::PDFWebContentsHelper::CreateForWebContentsWithClient(
-      web_contents,
-      scoped_ptr<pdf::PDFWebContentsHelperClient>(
-          new ChromePDFWebContentsHelperClient()));
-  extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
-      web_contents);
-}
-
 bool ChromeMimeHandlerViewGuestDelegate::HandleContextMenu(
     content::WebContents* web_contents,
     const content::ContextMenuParams& params) {
diff --git a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.h b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.h
index d29168a..850e7bd 100644
--- a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.h
+++ b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.h
@@ -16,17 +16,14 @@
 
 class ChromeMimeHandlerViewGuestDelegate : public MimeHandlerViewGuestDelegate {
  public:
-  explicit ChromeMimeHandlerViewGuestDelegate(MimeHandlerViewGuest* guest);
+  ChromeMimeHandlerViewGuestDelegate();
   ~ChromeMimeHandlerViewGuestDelegate() override;
 
   // MimeHandlerViewGuestDelegate.
-  void AttachHelpers() override;
   bool HandleContextMenu(content::WebContents* web_contents,
                          const content::ContextMenuParams& params) override;
 
  private:
-  MimeHandlerViewGuest* guest_;  // Owns us.
-
   DISALLOW_COPY_AND_ASSIGN(ChromeMimeHandlerViewGuestDelegate);
 };
 
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
index 687f78e..ad34b5c 100644
--- a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
+++ b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
@@ -13,21 +13,11 @@
 #include "chrome/common/chrome_version_info.h"
 #include "components/browsing_data/storage_partition_http_cache_data_remover.h"
 #include "components/guest_view/browser/guest_view_event.h"
-#include "components/pdf/browser/pdf_web_contents_helper.h"
 #include "components/renderer_context_menu/context_menu_delegate.h"
 #include "content/public/browser/render_process_host.h"
 #include "extensions/browser/api/web_request/web_request_api.h"
 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
 
-#if defined(ENABLE_PRINTING)
-#if defined(ENABLE_PRINT_PREVIEW)
-#include "chrome/browser/printing/print_preview_message_handler.h"
-#include "chrome/browser/printing/print_view_manager.h"
-#else
-#include "chrome/browser/printing/print_view_manager_basic.h"
-#endif  // defined(ENABLE_PRINT_PREVIEW)
-#endif  // defined(ENABLE_PRINTING)
-
 using guest_view::GuestViewEvent;
 
 namespace extensions {
@@ -35,6 +25,7 @@
 ChromeWebViewGuestDelegate::ChromeWebViewGuestDelegate(
     WebViewGuest* web_view_guest)
     : pending_context_menu_request_id_(0),
+      chromevox_injected_(false),
       web_view_guest_(web_view_guest),
       weak_ptr_factory_(this) {
 }
@@ -67,24 +58,15 @@
   return true;
 }
 
-// TODO(hanxi) Investigate which of these observers should move to the
-// extension module in the future.
-void ChromeWebViewGuestDelegate::OnAttachWebViewHelpers(
-    content::WebContents* contents) {
-  favicon::CreateContentFaviconDriverForWebContents(contents);
-  ChromeExtensionWebContentsObserver::CreateForWebContents(contents);
-#if defined(ENABLE_PRINTING)
-#if defined(ENABLE_PRINT_PREVIEW)
-  printing::PrintViewManager::CreateForWebContents(contents);
-  printing::PrintPreviewMessageHandler::CreateForWebContents(contents);
-#else
-  printing::PrintViewManagerBasic::CreateForWebContents(contents);
-#endif  // defined(ENABLE_PRINT_PREVIEW)
-#endif  // defined(ENABLE_PRINTING)
-  pdf::PDFWebContentsHelper::CreateForWebContentsWithClient(
-      contents,
-      scoped_ptr<pdf::PDFWebContentsHelperClient>(
-          new ChromePDFWebContentsHelperClient()));
+void ChromeWebViewGuestDelegate::OnDidInitialize() {
+#if defined(OS_CHROMEOS)
+  chromeos::AccessibilityManager* accessibility_manager =
+      chromeos::AccessibilityManager::Get();
+  CHECK(accessibility_manager);
+  accessibility_subscription_ = accessibility_manager->RegisterCallback(
+      base::Bind(&ChromeWebViewGuestDelegate::OnAccessibilityStatusChanged,
+                 weak_ptr_factory_.GetWeakPtr()));
+#endif
 }
 
 void ChromeWebViewGuestDelegate::OnGuestDestroyed() {
@@ -130,4 +112,33 @@
   menu_delegate->ShowMenu(pending_menu_.Pass());
 }
 
+void ChromeWebViewGuestDelegate::InjectChromeVoxIfNeeded(
+    content::RenderViewHost* render_view_host) {
+#if defined(OS_CHROMEOS)
+  if (!chromevox_injected_) {
+    chromeos::AccessibilityManager* manager =
+        chromeos::AccessibilityManager::Get();
+    if (manager && manager->IsSpokenFeedbackEnabled()) {
+      manager->InjectChromeVox(render_view_host);
+      chromevox_injected_ = true;
+    }
+  }
+#endif
+}
+
+#if defined(OS_CHROMEOS)
+void ChromeWebViewGuestDelegate::OnAccessibilityStatusChanged(
+    const chromeos::AccessibilityStatusEventDetails& details) {
+  if (details.notification_type == chromeos::ACCESSIBILITY_MANAGER_SHUTDOWN) {
+    accessibility_subscription_.reset();
+  } else if (details.notification_type ==
+      chromeos::ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK) {
+    if (details.enabled)
+      InjectChromeVoxIfNeeded(guest_web_contents()->GetRenderViewHost());
+    else
+      chromevox_injected_ = false;
+  }
+}
+#endif
+
 }  // namespace extensions
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h
index d21d8a47..d467569 100644
--- a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h
+++ b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h
@@ -28,7 +28,7 @@
 
   // WebViewGuestDelegate implementation.
   bool HandleContextMenu(const content::ContextMenuParams& params) override;
-  void OnAttachWebViewHelpers(content::WebContents* contents) override;
+  void OnDidInitialize() override;
   void OnGuestDestroyed() override;
   void OnShowContextMenu(int request_id, const MenuItemVector* items) override;
 
@@ -43,14 +43,31 @@
   static scoped_ptr<base::ListValue> MenuModelToValue(
       const ui::SimpleMenuModel& menu_model);
 
+  void InjectChromeVoxIfNeeded(content::RenderViewHost* render_view_host);
+
+#if defined(OS_CHROMEOS)
+  // Notification of a change in the state of an accessibility setting.
+  void OnAccessibilityStatusChanged(
+      const chromeos::AccessibilityStatusEventDetails& details);
+#endif
+
   // A counter to generate a unique request id for a context menu request.
   // We only need the ids to be unique for a given WebViewGuest.
   int pending_context_menu_request_id_;
 
+  // Set to |true| if ChromeVox was already injected in main frame.
+  bool chromevox_injected_;
+
   // Holds the RenderViewContextMenuBase that has been built but yet to be
   // shown. This is .reset() after ShowContextMenu().
   scoped_ptr<RenderViewContextMenuBase> pending_menu_;
 
+#if defined(OS_CHROMEOS)
+  // Subscription to receive notifications on changes to a11y settings.
+  scoped_ptr<chromeos::AccessibilityStatusSubscription>
+      accessibility_subscription_;
+#endif
+
   WebViewGuest* const web_view_guest_;
 
   // This is used to ensure pending tasks will not fire after this object is
@@ -63,3 +80,4 @@
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_GUEST_VIEW_WEB_VIEW_CHROME_WEB_VIEW_GUEST_DELEGATE_H_
+
diff --git a/chrome/browser/history/web_history_service_unittest.cc b/chrome/browser/history/web_history_service_unittest.cc
index 6bbb54a5..3d20a89 100644
--- a/chrome/browser/history/web_history_service_unittest.cc
+++ b/chrome/browser/history/web_history_service_unittest.cc
@@ -195,12 +195,13 @@
   return "false";
 }
 
-static KeyedService* BuildWebHistoryService(content::BrowserContext* context) {
+static scoped_ptr<KeyedService> BuildWebHistoryService(
+    content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
-  return new TestingWebHistoryService(
+  return make_scoped_ptr(new TestingWebHistoryService(
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
       SigninManagerFactory::GetForProfile(profile),
-      profile->GetRequestContext());
+      profile->GetRequestContext()));
 }
 
 }  // namespace
diff --git a/chrome/browser/image_holder.cc b/chrome/browser/image_holder.cc
index 852f670..aeaec5ce 100644
--- a/chrome/browser/image_holder.cc
+++ b/chrome/browser/image_holder.cc
@@ -68,11 +68,12 @@
   // Now that we have queued them all, start the fetching.
   ScopedVector<chrome::BitmapFetcher>::iterator iter;
   for (iter = fetchers_.begin(); iter != fetchers_.end(); ++iter) {
-    (*iter)->Start(
+    (*iter)->Init(
         profile_->GetRequestContext(),
         std::string(),
         net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
         net::LOAD_NORMAL);
+    (*iter)->Start();
   }
 }
 
diff --git a/chrome/browser/infobars/infobar_responder.cc b/chrome/browser/infobars/infobar_responder.cc
index cddc89b..4fc225ec 100644
--- a/chrome/browser/infobars/infobar_responder.cc
+++ b/chrome/browser/infobars/infobar_responder.cc
@@ -11,8 +11,8 @@
 #include "components/infobars/core/infobar.h"
 
 InfoBarResponder::InfoBarResponder(InfoBarService* infobar_service,
-                                   bool should_accept)
-    : infobar_service_(infobar_service), should_accept_(should_accept) {
+                                   AutoResponseType response)
+    : infobar_service_(infobar_service), response_(response) {
   infobar_service_->AddObserver(this);
 }
 
@@ -33,9 +33,21 @@
       base::Bind(&InfoBarResponder::Respond, base::Unretained(this), delegate));
 }
 
+void InfoBarResponder::OnInfoBarReplaced(infobars::InfoBar* old_infobar,
+                                         infobars::InfoBar* new_infobar) {
+  OnInfoBarAdded(new_infobar);
+}
+
 void InfoBarResponder::Respond(ConfirmInfoBarDelegate* delegate) {
-  if (should_accept_)
-    delegate->Accept();
-  else
-    delegate->Cancel();
+  switch (response_) {
+    case ACCEPT:
+      delegate->Accept();
+      break;
+    case DENY:
+      delegate->Cancel();
+      break;
+    case DISMISS:
+      delegate->InfoBarDismissed();
+      break;
+  }
 }
diff --git a/chrome/browser/infobars/infobar_responder.h b/chrome/browser/infobars/infobar_responder.h
index 266a2be..2e68a06 100644
--- a/chrome/browser/infobars/infobar_responder.h
+++ b/chrome/browser/infobars/infobar_responder.h
@@ -22,19 +22,26 @@
 // The asynchronous response matches how real users will use the infobar.
 class InfoBarResponder : public infobars::InfoBarManager::Observer {
  public:
-  // If |should_accept| is true, the responder will asynchronously Accept() the
-  // infobar; otherwise it will Cancel() it.
-  InfoBarResponder(InfoBarService* infobar_service, bool should_accept);
+  enum AutoResponseType {
+    ACCEPT,
+    DENY,
+    DISMISS
+  };
+
+  // The responder will asynchronously perform the requested |response|.
+  InfoBarResponder(InfoBarService* infobar_service, AutoResponseType response);
   ~InfoBarResponder() override;
 
   // infobars::InfoBarManager::Observer:
   void OnInfoBarAdded(infobars::InfoBar* infobar) override;
+  void OnInfoBarReplaced(infobars::InfoBar* old_infobar,
+                         infobars::InfoBar* new_infobar) override;
 
  private:
   void Respond(ConfirmInfoBarDelegate* delegate);
 
   InfoBarService* infobar_service_;
-  bool should_accept_;
+  AutoResponseType response_;
 
   DISALLOW_COPY_AND_ASSIGN(InfoBarResponder);
 };
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index 175022b..db81e6e 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -18,6 +18,7 @@
 #include "chrome/test/base/test_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_service.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_system.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
@@ -48,8 +49,8 @@
 };
 
 IN_PROC_BROWSER_TEST_F(InfoBarsTest, TestInfoBarsCloseOnNewTheme) {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
+  extensions::ScopedTestDialogAutoConfirm auto_confirm(
+      extensions::ScopedTestDialogAutoConfirm::ACCEPT);
 
 #if defined(OS_WIN) && defined(USE_ASH)
   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
diff --git a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
index 39b401a6..4bc6171 100644
--- a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
+++ b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
@@ -95,7 +95,7 @@
 KeyedService* ProfileInvalidationProviderFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   if (testing_factory_)
-    return testing_factory_(context);
+    return testing_factory_(context).release();
 
 #if defined(OS_ANDROID)
   return new ProfileInvalidationProvider(scoped_ptr<InvalidationService>(
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index cb9f69e..27cde299 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -949,7 +949,6 @@
   }
 
   ConfigureTCPFastOpen(command_line);
-  ConfigureSdch();
 
   // TODO(rch): Make the client socket factory a per-network session
   // instance, constructed from a NetworkSession::Params, to allow us
@@ -969,26 +968,6 @@
   net::CheckSupportAndMaybeEnableTCPFastOpen(always_enable_if_supported);
 }
 
-void IOThread::ConfigureSdch() {
-  // Check SDCH field trial.  Default is now that everything is enabled,
-  // so provide options for disabling HTTPS or all of SDCH.
-  const char kSdchFieldTrialName[] = "SDCH";
-  const char kEnabledHttpOnlyGroupName[] = "EnabledHttpOnly";
-  const char kDisabledAllGroupName[] = "DisabledAll";
-
-  // Store in a string on return to keep underlying storage for
-  // StringPiece stable.
-  std::string sdch_trial_group_string =
-      base::FieldTrialList::FindFullName(kSdchFieldTrialName);
-  base::StringPiece sdch_trial_group(sdch_trial_group_string);
-  if (sdch_trial_group.starts_with(kEnabledHttpOnlyGroupName)) {
-    net::SdchManager::EnableSdchSupport(true);
-    net::SdchManager::EnableSecureSchemeSupport(false);
-  } else if (sdch_trial_group.starts_with(kDisabledAllGroupName)) {
-    net::SdchManager::EnableSdchSupport(false);
-  }
-}
-
 // static
 void IOThread::ConfigureSpdyGlobals(
     const base::CommandLine& command_line,
@@ -1036,17 +1015,17 @@
   }
   if (spdy_trial_group.starts_with(kSpdyFieldTrialParametrizedPrefix)) {
     bool spdy_enabled = false;
-    if (LowerCaseEqualsASCII(
+    if (base::LowerCaseEqualsASCII(
             GetVariationParam(spdy_trial_params, "enable_spdy31"), "true")) {
       globals->next_protos.push_back(net::kProtoSPDY31);
       spdy_enabled = true;
     }
-    if (LowerCaseEqualsASCII(
+    if (base::LowerCaseEqualsASCII(
             GetVariationParam(spdy_trial_params, "enable_http2_14"), "true")) {
       globals->next_protos.push_back(net::kProtoSPDY4_14);
       spdy_enabled = true;
     }
-    if (LowerCaseEqualsASCII(
+    if (base::LowerCaseEqualsASCII(
             GetVariationParam(spdy_trial_params, "enable_http2"), "true")) {
       globals->next_protos.push_back(net::kProtoSPDY4);
       spdy_enabled = true;
@@ -1174,6 +1153,7 @@
       &params->quic_enable_connection_racing);
   globals.quic_enable_non_blocking_io.CopyToIfSet(
       &params->quic_enable_non_blocking_io);
+  globals.quic_prefer_aes.CopyToIfSet(&params->quic_prefer_aes);
   globals.quic_disable_disk_cache.CopyToIfSet(
       &params->quic_disable_disk_cache);
   globals.quic_max_number_of_lossy_connections.CopyToIfSet(
@@ -1321,6 +1301,8 @@
         ShouldQuicEnableNonBlockingIO(quic_trial_params));
     globals->quic_disable_disk_cache.set(
         ShouldQuicDisableDiskCache(quic_trial_params));
+    globals->quic_prefer_aes.set(
+        ShouldQuicPreferAes(quic_trial_params));
     int max_number_of_lossy_connections = GetQuicMaxNumberOfLossyConnections(
         quic_trial_params);
     if (max_number_of_lossy_connections != 0) {
@@ -1412,7 +1394,7 @@
 // static
 bool IOThread::ShouldDisableInsecureQuic(
     const VariationParameters& quic_trial_params) {
-  return LowerCaseEqualsASCII(
+  return base::LowerCaseEqualsASCII(
       GetVariationParam(quic_trial_params, "disable_insecure_quic"),
       "true");
 }
@@ -1482,7 +1464,7 @@
 // static
 bool IOThread::ShouldQuicAlwaysRequireHandshakeConfirmation(
     const VariationParameters& quic_trial_params) {
-  return LowerCaseEqualsASCII(
+  return base::LowerCaseEqualsASCII(
       GetVariationParam(quic_trial_params,
                         "always_require_handshake_confirmation"),
       "true");
@@ -1491,7 +1473,7 @@
 // static
 bool IOThread::ShouldQuicDisableConnectionPooling(
     const VariationParameters& quic_trial_params) {
-  return LowerCaseEqualsASCII(
+  return base::LowerCaseEqualsASCII(
       GetVariationParam(quic_trial_params, "disable_connection_pooling"),
       "true");
 }
@@ -1511,7 +1493,7 @@
 // static
 bool IOThread::ShouldQuicEnableConnectionRacing(
     const VariationParameters& quic_trial_params) {
-  return LowerCaseEqualsASCII(
+  return base::LowerCaseEqualsASCII(
       GetVariationParam(quic_trial_params, "enable_connection_racing"),
       "true");
 }
@@ -1519,7 +1501,7 @@
 // static
 bool IOThread::ShouldQuicEnableNonBlockingIO(
     const VariationParameters& quic_trial_params) {
-  return LowerCaseEqualsASCII(
+  return base::LowerCaseEqualsASCII(
       GetVariationParam(quic_trial_params, "enable_non_blocking_io"),
       "true");
 }
@@ -1527,11 +1509,18 @@
 // static
 bool IOThread::ShouldQuicDisableDiskCache(
     const VariationParameters& quic_trial_params) {
-  return LowerCaseEqualsASCII(
+  return base::LowerCaseEqualsASCII(
       GetVariationParam(quic_trial_params, "disable_disk_cache"), "true");
 }
 
 // static
+bool IOThread::ShouldQuicPreferAes(
+    const VariationParameters& quic_trial_params) {
+  return base::LowerCaseEqualsASCII(
+      GetVariationParam(quic_trial_params, "prefer_aes"), "true");
+}
+
+// static
 int IOThread::GetQuicMaxNumberOfLossyConnections(
     const VariationParameters& quic_trial_params) {
   int value;
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index 7a02c5b..b165d4a6 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -189,6 +189,7 @@
     Optional<bool> quic_enable_connection_racing;
     Optional<bool> quic_enable_non_blocking_io;
     Optional<bool> quic_disable_disk_cache;
+    Optional<bool> quic_prefer_aes;
     Optional<int> quic_max_number_of_lossy_connections;
     Optional<float> quic_packet_loss_threshold;
     Optional<int> quic_socket_receive_buffer_size;
@@ -269,9 +270,6 @@
   // Sets up TCP FastOpen if enabled via field trials or via the command line.
   void ConfigureTCPFastOpen(const base::CommandLine& command_line);
 
-  // Sets up SDCH based on field trials.
-  void ConfigureSdch();
-
   // Configures available SPDY protocol versions in |globals| based on the flags
   // in |command_lin| as well as SPDY field trial group and parameters.  Must be
   // called after ConfigureQuicGlobals.
@@ -375,6 +373,9 @@
   static bool ShouldQuicDisableDiskCache(
       const VariationParameters& quic_trial_params);
 
+  // Returns true if QUIC should prefer AES-GCN even without hardware support.
+  static bool ShouldQuicPreferAes(const VariationParameters& quic_trial_params);
+
   // Returns the maximum number of QUIC connections with high packet loss in a
   // row after which QUIC should be disabled.  Returns 0 if the default value
   // should be used.
diff --git a/chrome/browser/io_thread_unittest.cc b/chrome/browser/io_thread_unittest.cc
index 03e3dc4..6f460bd 100644
--- a/chrome/browser/io_thread_unittest.cc
+++ b/chrome/browser/io_thread_unittest.cc
@@ -188,6 +188,7 @@
   EXPECT_FALSE(params.quic_enable_connection_racing);
   EXPECT_FALSE(params.quic_enable_non_blocking_io);
   EXPECT_FALSE(params.quic_disable_disk_cache);
+  EXPECT_FALSE(params.quic_prefer_aes);
   EXPECT_EQ(0, params.quic_max_number_of_lossy_connections);
   EXPECT_EQ(1.0f, params.quic_packet_loss_threshold);
   EXPECT_FALSE(IOThread::ShouldEnableQuicForDataReductionProxy());
@@ -363,6 +364,15 @@
   EXPECT_TRUE(params.quic_disable_disk_cache);
 }
 
+TEST_F(IOThreadTest, QuicPreferAes) {
+  field_trial_group_ = "Enabled";
+  field_trial_params_["prefer_aes"] = "true";
+  ConfigureQuicGlobals();
+  net::HttpNetworkSession::Params params;
+  InitializeNetworkSessionParams(&params);
+  EXPECT_TRUE(params.quic_prefer_aes);
+}
+
 TEST_F(IOThreadTest, QuicMaxNumberOfLossyConnectionsFieldTrialParams) {
   field_trial_group_ = "Enabled";
   field_trial_params_["max_number_of_lossy_connections"] = "5";
diff --git a/chrome/browser/jumplist_win.cc b/chrome/browser/jumplist_win.cc
index f1e8a87..bed6653d 100644
--- a/chrome/browser/jumplist_win.cc
+++ b/chrome/browser/jumplist_win.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
+#include "base/trace_event/trace_event.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/top_sites_factory.h"
@@ -46,6 +47,9 @@
 
 namespace {
 
+// Delay jumplist updates to allow collapsing of redundant update requests.
+const int kDelayForJumplistUpdateInMS = 3500;
+
 // Append the common switches to each shell link.
 void AppendCommonSwitches(ShellLinkItem* shell_link) {
   const char* kSwitchNames[] = { switches::kUserDataDir };
@@ -440,6 +444,23 @@
 }
 
 void JumpList::PostRunUpdate() {
+  TRACE_EVENT0("browser", "JumpList::PostRunUpdate");
+  // Initialize the one-shot timer to update the jumplists in a while.
+  // If there is already a request queued then cancel it and post the new
+  // request. This ensures that JumpListUpdates won't happen until there has
+  // been a brief quiet period, thus avoiding update storms.
+  if (timer_.IsRunning()) {
+    timer_.Reset();
+  } else {
+    timer_.Start(FROM_HERE,
+                 base::TimeDelta::FromMilliseconds(kDelayForJumplistUpdateInMS),
+                 this,
+                 &JumpList::DeferredRunUpdate);
+  }
+}
+
+void JumpList::DeferredRunUpdate() {
+  TRACE_EVENT0("browser", "JumpList::DeferredRunUpdate");
   // Check if incognito windows (or normal windows) are disabled by policy.
   IncognitoModePrefs::Availability incognito_availability =
       profile_ ? IncognitoModePrefs::GetAvailability(profile_->GetPrefs())
diff --git a/chrome/browser/jumplist_win.h b/chrome/browser/jumplist_win.h
index 72b6d02a..1c69165 100644
--- a/chrome/browser/jumplist_win.h
+++ b/chrome/browser/jumplist_win.h
@@ -14,6 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/jumplist_updater_win.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/sessions/tab_restore_service.h"
@@ -125,6 +126,10 @@
   // Helper for RunUpdate() that determines its parameters.
   void PostRunUpdate();
 
+  // Called on a timer to invoke RunUpdateOnFileThread() after requests storms
+  // have subsided.
+  void DeferredRunUpdate();
+
   // Runnable method that updates the jumplist, once all the data
   // has been fetched.
   void RunUpdateOnFileThread(
@@ -162,6 +167,9 @@
   // protected by the list_lock_.
   ShellLinkItemList recently_closed_pages_;
 
+  // Timer for requesting delayed updates of the jumplist.
+  base::OneShotTimer<JumpList> timer_;
+
   // A list of URLs we need to retrieve their favicons,
   // protected by the list_lock_.
   typedef std::pair<std::string, scoped_refptr<ShellLinkItem> > URLPair;
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
index 23071b9..ac98995a2 100644
--- a/chrome/browser/lifetime/browser_close_manager_browsertest.cc
+++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
@@ -601,8 +601,8 @@
   EXPECT_TRUE(chrome::BrowserIterator().done());
 }
 
-// Test is flaky on windows, disabled. See http://crbug.com/276366
-#if defined(OS_WIN)
+// Test is flaky on Windows and Mac. See http://crbug.com/276366.
+#if defined(OS_WIN) || defined(OS_MACOSX)
 #define MAYBE_TestOpenAndCloseWindowDuringShutdown \
     DISABLED_TestOpenAndCloseWindowDuringShutdown
 #else
diff --git a/chrome/browser/local_discovery/device_description.cc b/chrome/browser/local_discovery/device_description.cc
index 71e748db..b9a3dda6 100644
--- a/chrome/browser/local_discovery/device_description.cc
+++ b/chrome/browser/local_discovery/device_description.cc
@@ -19,7 +19,7 @@
                            const std::string& name) {
   std::string prefix(name + "=");
   for (const std::string& record : metadata) {
-    if (StartsWithASCII(record, prefix, false)) {
+    if (base::StartsWithASCII(record, prefix, false)) {
       return record.substr(prefix.size());
     }
   }
diff --git a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
index 059db34..9ae0d1f7 100644
--- a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
+++ b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
@@ -6,7 +6,6 @@
 #include "base/files/file_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/media/media_stream_devices_controller.h"
 #include "chrome/browser/media/webrtc_browsertest_base.h"
 #include "chrome/browser/media/webrtc_browsertest_common.h"
@@ -21,7 +20,6 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/infobars/core/infobar.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/media_stream_request.h"
 #include "content/public/test/browser_test_utils.h"
@@ -114,32 +112,29 @@
 
 // Actual tests ---------------------------------------------------------------
 
-IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       DISABLED_TestAllowingUserMedia) {
+IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest, TestAllowingUserMedia) {
   content::WebContents* tab_contents = LoadTestPageInTab();
   EXPECT_TRUE(GetUserMediaAndAccept(tab_contents));
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       DISABLED_TestDenyingUserMedia) {
+IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest, TestDenyingUserMedia) {
   content::WebContents* tab_contents = LoadTestPageInTab();
   GetUserMediaAndDeny(tab_contents);
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       DISABLED_TestDismissingInfobar) {
+IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest, TestDismissingRequest) {
   content::WebContents* tab_contents = LoadTestPageInTab();
   GetUserMediaAndDismiss(tab_contents);
 }
 
 IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       DISABLED_TestDenyingUserMediaIncognito) {
+                       TestDenyingUserMediaIncognito) {
   content::WebContents* tab_contents = LoadTestPageInIncognitoTab();
   GetUserMediaAndDeny(tab_contents);
 }
 
 IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       DISABLED_TestAcceptThenDenyWhichShouldBeSticky) {
+                       TestAcceptThenDenyWhichShouldBeSticky) {
 #if defined(OS_WIN) && defined(USE_ASH)
   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -152,38 +147,33 @@
   EXPECT_TRUE(GetUserMediaAndAccept(tab_contents));
   GetUserMediaAndDeny(tab_contents);
 
-  // Should fail with permission denied right away with no infobar popping up.
+  // Should fail with permission denied, instead of hanging.
   GetUserMedia(tab_contents, kAudioVideoCallConstraints);
   EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()",
                                      kFailedWithPermissionDeniedError,
                                      tab_contents));
-  InfoBarService* infobar_service =
-      InfoBarService::FromWebContents(tab_contents);
-  EXPECT_EQ(0u, infobar_service->infobar_count());
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       DISABLED_TestAcceptIsNotSticky) {
+IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest, TestAcceptIsNotSticky) {
   content::WebContents* tab_contents = LoadTestPageInTab();
 
   // If accept were sticky the second call would hang because it hangs if an
-  // infobar does not pop up.
+  // infobar or bubble does not pop up.
   EXPECT_TRUE(GetUserMediaAndAccept(tab_contents));
   EXPECT_TRUE(GetUserMediaAndAccept(tab_contents));
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       DISABLED_TestDismissIsNotSticky) {
+IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest, TestDismissIsNotSticky) {
   content::WebContents* tab_contents = LoadTestPageInTab();
 
   // If dismiss were sticky the second call would hang because it hangs if an
-  // infobar does not pop up.
+  // infobar or bubble does not pop up.
   GetUserMediaAndDismiss(tab_contents);
   GetUserMediaAndDismiss(tab_contents);
 }
 
 IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       DISABLED_TestDenyingThenClearingStickyException) {
+                       TestDenyingThenClearingStickyException) {
   content::WebContents* tab_contents = LoadTestPageInTab();
 
   GetUserMediaAndDeny(tab_contents);
@@ -195,7 +185,7 @@
   settings_map->ClearSettingsForOneType(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
 
-  // If an infobar is not launched now, this will hang.
+  // If an infobar or bubble is not launched now, this will hang.
   GetUserMediaAndDeny(tab_contents);
 }
 
@@ -219,7 +209,7 @@
 }
 
 IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       DISABLED_DenyingCameraDoesNotCauseStickyDenyForMics) {
+                       DenyingCameraDoesNotCauseStickyDenyForMics) {
   content::WebContents* tab_contents = LoadTestPageInTab();
 
   // If camera blocking also blocked mics, the second call here would hang.
diff --git a/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc b/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
index dbd7883e..102801c 100644
--- a/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_apprtc_browsertest.cc
@@ -9,11 +9,14 @@
 #include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/infobars/infobar_responder.h"
+#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/media/webrtc_browsertest_base.h"
 #include "chrome/browser/media/webrtc_browsertest_common.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/test/browser_test_utils.h"
@@ -246,11 +249,25 @@
   GURL room_url = GURL("http://localhost:9999/r/some_room"
                        "?wshpp=localhost:8089&wstls=false");
 
+  // Set up the left tab.
   chrome::AddTabAt(browser(), GURL(), -1, true);
-  content::WebContents* left_tab = OpenPageAndAcceptUserMedia(room_url);
+  content::WebContents* left_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  PermissionBubbleManager::FromWebContents(left_tab)
+      ->set_auto_response_for_test(PermissionBubbleManager::ACCEPT_ALL);
+  InfoBarResponder left_infobar_responder(
+      InfoBarService::FromWebContents(left_tab), InfoBarResponder::ACCEPT);
+  ui_test_utils::NavigateToURL(browser(), room_url);
 
+  // Set up the right tab.
   chrome::AddTabAt(browser(), GURL(), -1, true);
-  content::WebContents* right_tab = OpenPageAndAcceptUserMedia(room_url);
+  content::WebContents* right_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  PermissionBubbleManager::FromWebContents(right_tab)
+      ->set_auto_response_for_test(PermissionBubbleManager::ACCEPT_ALL);
+  InfoBarResponder right_infobar_responder(
+      InfoBarService::FromWebContents(right_tab), InfoBarResponder::ACCEPT);
+  ui_test_utils::NavigateToURL(browser(), room_url);
 
   ASSERT_TRUE(WaitForCallToComeUp(left_tab));
   ASSERT_TRUE(WaitForCallToComeUp(right_tab));
@@ -284,7 +301,14 @@
   GURL room_url = GURL("http://localhost:9999/r/some_room"
                        "?wshpp=localhost:8089&wstls=false"
                        "&firefox_fake_device=1");
-  content::WebContents* chrome_tab = OpenPageAndAcceptUserMedia(room_url);
+  chrome::AddTabAt(browser(), GURL(), -1, true);
+  content::WebContents* chrome_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  PermissionBubbleManager::FromWebContents(chrome_tab)
+      ->set_auto_response_for_test(PermissionBubbleManager::ACCEPT_ALL);
+  InfoBarResponder infobar_responder(
+      InfoBarService::FromWebContents(chrome_tab), InfoBarResponder::ACCEPT);
+  ui_test_utils::NavigateToURL(browser(), room_url);
 
   ASSERT_TRUE(LaunchFirefoxWithUrl(room_url));
 
diff --git a/chrome/browser/media/desktop_capture_access_handler.cc b/chrome/browser/media/desktop_capture_access_handler.cc
new file mode 100644
index 0000000..d240678e
--- /dev/null
+++ b/chrome/browser/media/desktop_capture_access_handler.cc
@@ -0,0 +1,386 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/desktop_capture_access_handler.h"
+
+#include "base/command_line.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/media/desktop_streams_registry.h"
+#include "chrome/browser/media/media_capture_devices_dispatcher.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/screen_capture_notification_ui.h"
+#include "chrome/browser/ui/simple_message_box.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/desktop_media_id.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/media_stream_request.h"
+#include "extensions/browser/app_window/app_window.h"
+#include "extensions/browser/app_window/app_window_registry.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "media/audio/audio_manager_base.h"
+#include "net/base/net_util.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h"
+#include "ui/base/l10n/l10n_util.h"
+
+#if defined(OS_CHROMEOS)
+#include "ash/shell.h"
+#include "base/sha1.h"
+#endif  // defined(OS_CHROMEOS)
+
+using content::BrowserThread;
+
+namespace {
+
+bool IsExtensionWhitelistedForScreenCapture(
+    const extensions::Extension* extension) {
+  if (!extension)
+    return false;
+
+#if defined(OS_CHROMEOS)
+  std::string hash = base::SHA1HashString(extension->id());
+  std::string hex_hash = base::HexEncode(hash.c_str(), hash.length());
+
+  // crbug.com/446688
+  return hex_hash == "4F25792AF1AA7483936DE29C07806F203C7170A0" ||
+         hex_hash == "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9" ||
+         hex_hash == "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB" ||
+         hex_hash == "81986D4F846CEDDDB962643FA501D1780DD441BB";
+#else
+  return false;
+#endif  // defined(OS_CHROMEOS)
+}
+
+bool IsBuiltInExtension(const GURL& origin) {
+  return
+      // Feedback Extension.
+      origin.spec() == "chrome-extension://gfdkimpbcpahaombhbimeihdjnejgicl/";
+}
+
+// Helper to get title of the calling application shown in the screen capture
+// notification.
+base::string16 GetApplicationTitle(content::WebContents* web_contents,
+                                   const extensions::Extension* extension) {
+  // Use extension name as title for extensions and host/origin for drive-by
+  // web.
+  std::string title;
+  if (extension) {
+    title = extension->name();
+    return base::UTF8ToUTF16(title);
+  }
+  GURL url = web_contents->GetURL();
+  title = url.SchemeIsSecure() ? net::GetHostAndOptionalPort(url)
+                               : url.GetOrigin().spec();
+  return base::UTF8ToUTF16(title);
+}
+
+// Helper to get list of media stream devices for desktop capture in |devices|.
+// Registers to display notification if |display_notification| is true.
+// Returns an instance of MediaStreamUI to be passed to content layer.
+scoped_ptr<content::MediaStreamUI> GetDevicesForDesktopCapture(
+    content::MediaStreamDevices* devices,
+    content::DesktopMediaID media_id,
+    bool capture_audio,
+    bool display_notification,
+    const base::string16& application_title,
+    const base::string16& registered_extension_name) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  scoped_ptr<content::MediaStreamUI> ui;
+
+  // Add selected desktop source to the list.
+  devices->push_back(content::MediaStreamDevice(
+      content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(), "Screen"));
+  if (capture_audio) {
+    // Use the special loopback device ID for system audio capture.
+    devices->push_back(content::MediaStreamDevice(
+        content::MEDIA_DESKTOP_AUDIO_CAPTURE,
+        media::AudioManagerBase::kLoopbackInputDeviceId, "System Audio"));
+  }
+
+  // If required, register to display the notification for stream capture.
+  if (display_notification) {
+    if (application_title == registered_extension_name) {
+      ui = ScreenCaptureNotificationUI::Create(l10n_util::GetStringFUTF16(
+          IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT, application_title));
+    } else {
+      ui = ScreenCaptureNotificationUI::Create(l10n_util::GetStringFUTF16(
+          IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT_DELEGATED,
+          registered_extension_name, application_title));
+    }
+  }
+
+  return ui.Pass();
+}
+
+#if !defined(OS_ANDROID)
+// Find browser or app window from a given |web_contents|.
+gfx::NativeWindow FindParentWindowForWebContents(
+    content::WebContents* web_contents) {
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+  if (browser && browser->window())
+    return browser->window()->GetNativeWindow();
+
+  const extensions::AppWindowRegistry::AppWindowList& window_list =
+      extensions::AppWindowRegistry::Get(web_contents->GetBrowserContext())
+          ->app_windows();
+  for (extensions::AppWindowRegistry::AppWindowList::const_iterator iter =
+           window_list.begin();
+       iter != window_list.end(); ++iter) {
+    if ((*iter)->web_contents() == web_contents)
+      return (*iter)->GetNativeWindow();
+  }
+
+  return NULL;
+}
+#endif
+
+}  // namespace
+
+DesktopCaptureAccessHandler::DesktopCaptureAccessHandler() {
+}
+
+DesktopCaptureAccessHandler::~DesktopCaptureAccessHandler() {
+}
+
+void DesktopCaptureAccessHandler::ProcessScreenCaptureAccessRequest(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    const content::MediaResponseCallback& callback,
+    const extensions::Extension* extension) {
+  content::MediaStreamDevices devices;
+  scoped_ptr<content::MediaStreamUI> ui;
+
+  DCHECK_EQ(request.video_type, content::MEDIA_DESKTOP_VIDEO_CAPTURE);
+
+  bool loopback_audio_supported = false;
+#if defined(USE_CRAS) || defined(OS_WIN)
+  // Currently loopback audio capture is supported only on Windows and ChromeOS.
+  loopback_audio_supported = true;
+#endif
+
+  bool component_extension = false;
+  component_extension =
+      extension && extension->location() == extensions::Manifest::COMPONENT;
+
+  bool screen_capture_enabled =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableUserMediaScreenCapturing) ||
+      MediaCaptureDevicesDispatcher::IsOriginForCasting(
+          request.security_origin) ||
+      IsExtensionWhitelistedForScreenCapture(extension) ||
+      IsBuiltInExtension(request.security_origin);
+
+  const bool origin_is_secure =
+      request.security_origin.SchemeIsSecure() ||
+      request.security_origin.SchemeIs(extensions::kExtensionScheme) ||
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kAllowHttpScreenCapture);
+
+  // If basic conditions (screen capturing is enabled and origin is secure)
+  // aren't fulfilled, we'll use "invalid state" as result. Otherwise, we set
+  // it after checking permission.
+  // TODO(grunell): It would be good to change this result for something else,
+  // probably a new one.
+  content::MediaStreamRequestResult result =
+      content::MEDIA_DEVICE_INVALID_STATE;
+
+  // Approve request only when the following conditions are met:
+  //  1. Screen capturing is enabled via command line switch or white-listed for
+  //     the given origin.
+  //  2. Request comes from a page with a secure origin or from an extension.
+  if (screen_capture_enabled && origin_is_secure) {
+    // Get title of the calling application prior to showing the message box.
+    // chrome::ShowMessageBox() starts a nested message loop which may allow
+    // |web_contents| to be destroyed on the UI thread before the message box
+    // is closed. See http://crbug.com/326690.
+    base::string16 application_title =
+        GetApplicationTitle(web_contents, extension);
+#if !defined(OS_ANDROID)
+    gfx::NativeWindow parent_window =
+        FindParentWindowForWebContents(web_contents);
+#else
+    gfx::NativeWindow parent_window = NULL;
+#endif
+    web_contents = NULL;
+
+    bool whitelisted_extension =
+        IsExtensionWhitelistedForScreenCapture(extension);
+
+    // For whitelisted or component extensions, bypass message box.
+    bool user_approved = false;
+    if (!whitelisted_extension && !component_extension) {
+      base::string16 application_name =
+          base::UTF8ToUTF16(request.security_origin.spec());
+      if (extension)
+        application_name = base::UTF8ToUTF16(extension->name());
+      base::string16 confirmation_text = l10n_util::GetStringFUTF16(
+          request.audio_type == content::MEDIA_NO_SERVICE
+              ? IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TEXT
+              : IDS_MEDIA_SCREEN_AND_AUDIO_CAPTURE_CONFIRMATION_TEXT,
+          application_name);
+      chrome::MessageBoxResult result = chrome::ShowMessageBox(
+          parent_window,
+          l10n_util::GetStringFUTF16(
+              IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TITLE, application_name),
+          confirmation_text, chrome::MESSAGE_BOX_TYPE_QUESTION);
+      user_approved = (result == chrome::MESSAGE_BOX_RESULT_YES);
+    }
+
+    if (user_approved || component_extension || whitelisted_extension) {
+      content::DesktopMediaID screen_id;
+#if defined(OS_CHROMEOS)
+      screen_id = content::DesktopMediaID::RegisterAuraWindow(
+          ash::Shell::GetInstance()->GetPrimaryRootWindow());
+#else   // defined(OS_CHROMEOS)
+      screen_id = content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
+                                          webrtc::kFullDesktopScreenId);
+#endif  // !defined(OS_CHROMEOS)
+
+      bool capture_audio =
+          (request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE &&
+           loopback_audio_supported);
+
+      // Unless we're being invoked from a component extension, register to
+      // display the notification for stream capture.
+      bool display_notification = !component_extension;
+
+      ui = GetDevicesForDesktopCapture(&devices, screen_id, capture_audio,
+                                       display_notification, application_title,
+                                       application_title);
+      DCHECK(!devices.empty());
+    }
+
+    // The only case when devices can be empty is if the user has denied
+    // permission.
+    result = devices.empty() ? content::MEDIA_DEVICE_PERMISSION_DENIED
+                             : content::MEDIA_DEVICE_OK;
+  }
+
+  callback.Run(devices, result, ui.Pass());
+}
+
+bool DesktopCaptureAccessHandler::SupportsStreamType(
+    const content::MediaStreamType type,
+    const extensions::Extension* extension) {
+  return type == content::MEDIA_DESKTOP_VIDEO_CAPTURE ||
+         type == content::MEDIA_DESKTOP_AUDIO_CAPTURE;
+}
+
+bool DesktopCaptureAccessHandler::CheckMediaAccessPermission(
+    content::WebContents* web_contents,
+    const GURL& security_origin,
+    content::MediaStreamType type,
+    const extensions::Extension* extension) {
+  return false;
+}
+
+void DesktopCaptureAccessHandler::HandleRequest(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    const content::MediaResponseCallback& callback,
+    const extensions::Extension* extension) {
+  content::MediaStreamDevices devices;
+  scoped_ptr<content::MediaStreamUI> ui;
+
+  if (request.video_type != content::MEDIA_DESKTOP_VIDEO_CAPTURE) {
+    callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass());
+    return;
+  }
+
+  // If the device id wasn't specified then this is a screen capture request
+  // (i.e. chooseDesktopMedia() API wasn't used to generate device id).
+  if (request.requested_video_device_id.empty()) {
+    ProcessScreenCaptureAccessRequest(web_contents, request, callback,
+                                      extension);
+    return;
+  }
+
+  // The extension name that the stream is registered with.
+  std::string original_extension_name;
+  // Resolve DesktopMediaID for the specified device id.
+  content::DesktopMediaID media_id;
+  // TODO(miu): Replace "main RenderFrame" IDs with the request's actual
+  // RenderFrame IDs once the desktop capture extension API implementation is
+  // fixed.  http://crbug.com/304341
+  content::WebContents* const web_contents_for_stream =
+      content::WebContents::FromRenderFrameHost(
+          content::RenderFrameHost::FromID(request.render_process_id,
+                                           request.render_frame_id));
+  content::RenderFrameHost* const main_frame =
+      web_contents_for_stream ? web_contents_for_stream->GetMainFrame() : NULL;
+  if (main_frame) {
+    media_id = MediaCaptureDevicesDispatcher::GetInstance()
+                   ->GetDesktopStreamsRegistry()
+                   ->RequestMediaForStreamId(request.requested_video_device_id,
+                                             main_frame->GetProcess()->GetID(),
+                                             main_frame->GetRoutingID(),
+                                             request.security_origin,
+                                             &original_extension_name);
+  }
+
+  // Received invalid device id.
+  if (media_id.type == content::DesktopMediaID::TYPE_NONE) {
+    callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass());
+    return;
+  }
+
+  bool loopback_audio_supported = false;
+#if defined(USE_CRAS) || defined(OS_WIN)
+  // Currently loopback audio capture is supported only on Windows and ChromeOS.
+  loopback_audio_supported = true;
+#endif
+
+  // Audio is only supported for screen capture streams.
+  bool capture_audio =
+      (media_id.type == content::DesktopMediaID::TYPE_SCREEN &&
+       request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE &&
+       loopback_audio_supported);
+
+  ui = GetDevicesForDesktopCapture(&devices, media_id, capture_audio, true,
+                                   GetApplicationTitle(web_contents, extension),
+                                   base::UTF8ToUTF16(original_extension_name));
+
+  callback.Run(devices, content::MEDIA_DEVICE_OK, ui.Pass());
+}
+
+void DesktopCaptureAccessHandler::UpdateMediaRequestState(
+    int render_process_id,
+    int render_frame_id,
+    int page_request_id,
+    content::MediaStreamType stream_type,
+    content::MediaRequestState state) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // Track desktop capture sessions.  Tracking is necessary to avoid unbalanced
+  // session counts since not all requests will reach MEDIA_REQUEST_STATE_DONE,
+  // but they will all reach MEDIA_REQUEST_STATE_CLOSING.
+  if (stream_type != content::MEDIA_DESKTOP_VIDEO_CAPTURE)
+    return;
+
+  if (state == content::MEDIA_REQUEST_STATE_DONE) {
+    DesktopCaptureSession session = {
+        render_process_id, render_frame_id, page_request_id};
+    desktop_capture_sessions_.push_back(session);
+  } else if (state == content::MEDIA_REQUEST_STATE_CLOSING) {
+    for (DesktopCaptureSessions::iterator it =
+             desktop_capture_sessions_.begin();
+         it != desktop_capture_sessions_.end(); ++it) {
+      if (it->render_process_id == render_process_id &&
+          it->render_frame_id == render_frame_id &&
+          it->page_request_id == page_request_id) {
+        desktop_capture_sessions_.erase(it);
+        break;
+      }
+    }
+  }
+}
+
+bool DesktopCaptureAccessHandler::IsCaptureInProgress() {
+  return desktop_capture_sessions_.size() > 0;
+}
diff --git a/chrome/browser/media/desktop_capture_access_handler.h b/chrome/browser/media/desktop_capture_access_handler.h
new file mode 100644
index 0000000..c0ab0ec
--- /dev/null
+++ b/chrome/browser/media/desktop_capture_access_handler.h
@@ -0,0 +1,60 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_DESKTOP_CAPTURE_ACCESS_HANDLER_H_
+#define CHROME_BROWSER_MEDIA_DESKTOP_CAPTURE_ACCESS_HANDLER_H_
+
+#include <list>
+
+#include "chrome/browser/media/media_access_handler.h"
+
+class DesktopStreamsRegistry;
+
+// MediaAccessHandler for DesktopCapture API.
+class DesktopCaptureAccessHandler : public MediaAccessHandler {
+ public:
+  DesktopCaptureAccessHandler();
+  ~DesktopCaptureAccessHandler() override;
+
+  // MediaAccessHandler implementation.
+  bool SupportsStreamType(const content::MediaStreamType type,
+                          const extensions::Extension* extension) override;
+  bool CheckMediaAccessPermission(
+      content::WebContents* web_contents,
+      const GURL& security_origin,
+      content::MediaStreamType type,
+      const extensions::Extension* extension) override;
+  void HandleRequest(content::WebContents* web_contents,
+                     const content::MediaStreamRequest& request,
+                     const content::MediaResponseCallback& callback,
+                     const extensions::Extension* extension) override;
+  void UpdateMediaRequestState(int render_process_id,
+                               int render_frame_id,
+                               int page_request_id,
+                               content::MediaStreamType stream_type,
+                               content::MediaRequestState state) override;
+
+  bool IsCaptureInProgress();
+
+ private:
+  // Tracks MEDIA_DESKTOP_VIDEO_CAPTURE sessions which reach the
+  // MEDIA_REQUEST_STATE_DONE state.  Sessions are remove when
+  // MEDIA_REQUEST_STATE_CLOSING is encountered.
+  struct DesktopCaptureSession {
+    int render_process_id;
+    int render_frame_id;
+    int page_request_id;
+  };
+  typedef std::list<DesktopCaptureSession> DesktopCaptureSessions;
+
+  void ProcessScreenCaptureAccessRequest(
+      content::WebContents* web_contents,
+      const content::MediaStreamRequest& request,
+      const content::MediaResponseCallback& callback,
+      const extensions::Extension* extension);
+
+  DesktopCaptureSessions desktop_capture_sessions_;
+};
+
+#endif  // CHROME_BROWSER_MEDIA_DESKTOP_CAPTURE_ACCESS_HANDLER_H_
diff --git a/chrome/browser/media/extension_media_access_handler.cc b/chrome/browser/media/extension_media_access_handler.cc
new file mode 100644
index 0000000..9b4e7db
--- /dev/null
+++ b/chrome/browser/media/extension_media_access_handler.cc
@@ -0,0 +1,147 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/extension_media_access_handler.h"
+
+#include "chrome/browser/media/media_capture_devices_dispatcher.h"
+#include "chrome/browser/media/media_stream_capture_indicator.h"
+#include "chrome/browser/media/media_stream_device_permissions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/permissions/permissions_data.h"
+
+namespace {
+
+// This is a short-term solution to grant camera and/or microphone access to
+// extensions:
+// 1. Virtual keyboard extension.
+// 2. Flutter gesture recognition extension.
+// 3. TODO(smus): Airbender experiment 1.
+// 4. TODO(smus): Airbender experiment 2.
+// 5. Hotwording component extension.
+// 6. XKB input method component extension.
+// 7. M17n/T13n/CJK input method component extension.
+// Once http://crbug.com/292856 is fixed, remove this whitelist.
+bool IsMediaRequestWhitelistedForExtension(
+    const extensions::Extension* extension) {
+  return extension->id() == "mppnpdlheglhdfmldimlhpnegondlapf" ||
+         extension->id() == "jokbpnebhdcladagohdnfgjcpejggllo" ||
+         extension->id() == "clffjmdilanldobdnedchkdbofoimcgb" ||
+         extension->id() == "nnckehldicaciogcbchegobnafnjkcne" ||
+         extension->id() == "nbpagnldghgfoolbancepceaanlmhfmd" ||
+         extension->id() == "jkghodnilhceideoidjikpgommlajknk" ||
+         extension->id() == "gjaehgfemfahhmlgpdfknkhdnemmolop";
+}
+
+}  // namespace
+
+ExtensionMediaAccessHandler::ExtensionMediaAccessHandler() {
+}
+
+ExtensionMediaAccessHandler::~ExtensionMediaAccessHandler() {
+}
+
+bool ExtensionMediaAccessHandler::SupportsStreamType(
+    const content::MediaStreamType type,
+    const extensions::Extension* extension) {
+  return extension && (extension->is_platform_app() ||
+                       IsMediaRequestWhitelistedForExtension(extension)) &&
+         (type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
+          type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
+}
+
+bool ExtensionMediaAccessHandler::CheckMediaAccessPermission(
+    content::WebContents* web_contents,
+    const GURL& security_origin,
+    content::MediaStreamType type,
+    const extensions::Extension* extension) {
+  return extension->permissions_data()->HasAPIPermission(
+      type == content::MEDIA_DEVICE_AUDIO_CAPTURE
+          ? extensions::APIPermission::kAudioCapture
+          : extensions::APIPermission::kVideoCapture);
+}
+
+void ExtensionMediaAccessHandler::HandleRequest(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    const content::MediaResponseCallback& callback,
+    const extensions::Extension* extension) {
+  // TODO(vrk): This code is largely duplicated in
+  // MediaStreamDevicesController::Accept(). Move this code into a shared method
+  // between the two classes.
+
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+
+  bool audio_allowed =
+      request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE &&
+      extension->permissions_data()->HasAPIPermission(
+          extensions::APIPermission::kAudioCapture) &&
+      GetDevicePolicy(profile, extension->url(), prefs::kAudioCaptureAllowed,
+                      prefs::kAudioCaptureAllowedUrls) != ALWAYS_DENY;
+  bool video_allowed =
+      request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE &&
+      extension->permissions_data()->HasAPIPermission(
+          extensions::APIPermission::kVideoCapture) &&
+      GetDevicePolicy(profile, extension->url(), prefs::kVideoCaptureAllowed,
+                      prefs::kVideoCaptureAllowedUrls) != ALWAYS_DENY;
+
+  bool get_default_audio_device = audio_allowed;
+  bool get_default_video_device = video_allowed;
+
+  content::MediaStreamDevices devices;
+
+  // Set an initial error result. If neither audio or video is allowed, we'll
+  // never try to get any device below but will just create |ui| and return an
+  // empty list with "invalid state" result. If at least one is allowed, we'll
+  // try to get device(s), and if failure, we want to return "no hardware"
+  // result.
+  // TODO(grunell): The invalid state result should be changed to a new denied
+  // result + a dcheck to ensure at least one of audio or video types is
+  // capture.
+  content::MediaStreamRequestResult result =
+      (audio_allowed || video_allowed) ? content::MEDIA_DEVICE_NO_HARDWARE
+                                       : content::MEDIA_DEVICE_INVALID_STATE;
+
+  // Get the exact audio or video device if an id is specified.
+  // We only set any error result here and before running the callback change
+  // it to OK if we have any device.
+  if (audio_allowed && !request.requested_audio_device_id.empty()) {
+    const content::MediaStreamDevice* audio_device =
+        MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedAudioDevice(
+            request.requested_audio_device_id);
+    if (audio_device) {
+      devices.push_back(*audio_device);
+      get_default_audio_device = false;
+    }
+  }
+  if (video_allowed && !request.requested_video_device_id.empty()) {
+    const content::MediaStreamDevice* video_device =
+        MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedVideoDevice(
+            request.requested_video_device_id);
+    if (video_device) {
+      devices.push_back(*video_device);
+      get_default_video_device = false;
+    }
+  }
+
+  // If either or both audio and video devices were requested but not
+  // specified by id, get the default devices.
+  if (get_default_audio_device || get_default_video_device) {
+    MediaCaptureDevicesDispatcher::GetInstance()->GetDefaultDevicesForProfile(
+        profile, get_default_audio_device, get_default_video_device, &devices);
+  }
+
+  scoped_ptr<content::MediaStreamUI> ui;
+  if (!devices.empty()) {
+    result = content::MEDIA_DEVICE_OK;
+    ui = MediaCaptureDevicesDispatcher::GetInstance()
+             ->GetMediaStreamCaptureIndicator()
+             ->RegisterMediaStream(web_contents, devices);
+  }
+
+  callback.Run(devices, result, ui.Pass());
+}
diff --git a/chrome/browser/media/extension_media_access_handler.h b/chrome/browser/media/extension_media_access_handler.h
new file mode 100644
index 0000000..3f6a1461
--- /dev/null
+++ b/chrome/browser/media/extension_media_access_handler.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_EXTENSION_MEDIA_ACCESS_HANDLER_H_
+#define CHROME_BROWSER_MEDIA_EXTENSION_MEDIA_ACCESS_HANDLER_H_
+
+#include "chrome/browser/media/media_access_handler.h"
+
+class MediaStreamCaptureIndicator;
+
+// MediaAccessHandler for extension capturing requests.
+class ExtensionMediaAccessHandler : public MediaAccessHandler {
+ public:
+  ExtensionMediaAccessHandler();
+  ~ExtensionMediaAccessHandler() override;
+
+  // MediaAccessHandler implementation.
+  bool SupportsStreamType(const content::MediaStreamType type,
+                          const extensions::Extension* extension) override;
+  bool CheckMediaAccessPermission(
+      content::WebContents* web_contents,
+      const GURL& security_origin,
+      content::MediaStreamType type,
+      const extensions::Extension* extension) override;
+  void HandleRequest(content::WebContents* web_contents,
+                     const content::MediaStreamRequest& request,
+                     const content::MediaResponseCallback& callback,
+                     const extensions::Extension* extension) override;
+};
+
+#endif  // CHROME_BROWSER_MEDIA_EXTENSION_MEDIA_ACCESS_HANDLER_H_
diff --git a/chrome/browser/media/media_access_handler.h b/chrome/browser/media/media_access_handler.h
new file mode 100644
index 0000000..bc7b855
--- /dev/null
+++ b/chrome/browser/media/media_access_handler.h
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_MEDIA_ACCESS_HANDLER_H_
+#define CHROME_BROWSER_MEDIA_MEDIA_ACCESS_HANDLER_H_
+
+#include "base/callback.h"
+#include "content/public/browser/media_request_state.h"
+#include "content/public/common/media_stream_request.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace extensions {
+class Extension;
+}
+
+// Interface for handling media access requests that are propagated from
+// MediaCaptureDevicesDispatcher.
+class MediaAccessHandler {
+ public:
+  MediaAccessHandler() {}
+  virtual ~MediaAccessHandler() {}
+
+  // Check if the media stream type is supported by MediaAccessHandler.
+  virtual bool SupportsStreamType(const content::MediaStreamType type,
+                                  const extensions::Extension* extension) = 0;
+  // Check media access permission. |extension| is set to NULL if request was
+  // made from a drive-by page.
+  virtual bool CheckMediaAccessPermission(
+      content::WebContents* web_contents,
+      const GURL& security_origin,
+      content::MediaStreamType type,
+      const extensions::Extension* extension) = 0;
+  // Process media access requests. |extension| is set to NULL if request was
+  // made from a drive-by page.
+  virtual void HandleRequest(content::WebContents* web_contents,
+                             const content::MediaStreamRequest& request,
+                             const content::MediaResponseCallback& callback,
+                             const extensions::Extension* extension) = 0;
+  // Update media request state. Called on UI thread.
+  virtual void UpdateMediaRequestState(int render_process_id,
+                                       int render_frame_id,
+                                       int page_request_id,
+                                       content::MediaStreamType stream_type,
+                                       content::MediaRequestState state) {}
+};
+
+#endif  // CHROME_BROWSER_MEDIA_MEDIA_ACCESS_HANDLER_H_
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc
index 79c93f5c..b64a2c7 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/media_capture_devices_dispatcher.cc
@@ -9,52 +9,38 @@
 #include "base/metrics/field_trial.h"
 #include "base/prefs/pref_service.h"
 #include "base/prefs/scoped_user_pref_update.h"
-#include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media/desktop_streams_registry.h"
+#include "chrome/browser/media/media_access_handler.h"
 #include "chrome/browser/media/media_stream_capture_indicator.h"
-#include "chrome/browser/media/media_stream_device_permissions.h"
-#include "chrome/browser/media/media_stream_infobar_delegate.h"
-#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/media/permission_bubble_media_access_handler.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/screen_capture_notification_ui.h"
-#include "chrome/browser/ui/simple_message_box.h"
-#include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/desktop_media_id.h"
 #include "content/public/browser/media_capture_devices.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/media_stream_request.h"
 #include "extensions/common/constants.h"
-#include "media/audio/audio_manager_base.h"
 #include "media/base/media_switches.h"
 #include "net/base/net_util.h"
-#include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h"
-#include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
 #include "ash/shell.h"
 #endif  // defined(OS_CHROMEOS)
 
 #if defined(ENABLE_EXTENSIONS)
-#include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
-#include "extensions/browser/app_window/app_window.h"
-#include "extensions/browser/app_window/app_window_registry.h"
+#include "chrome/browser/media/desktop_capture_access_handler.h"
+#include "chrome/browser/media/extension_media_access_handler.h"
+#include "chrome/browser/media/tab_capture_access_handler.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/permissions/permissions_data.h"
@@ -66,16 +52,6 @@
 
 namespace {
 
-// A finch experiment to enable the permission bubble for media requests only.
-bool MediaStreamPermissionBubbleExperimentEnabled() {
-  const std::string group =
-      base::FieldTrialList::FindFullName("MediaStreamPermissionBubble");
-  if (group == "enabled")
-    return true;
-
-  return false;
-}
-
 // Finds a device in |devices| that has |device_id|, or NULL if not found.
 const content::MediaStreamDevice* FindDeviceWithId(
     const content::MediaStreamDevices& devices,
@@ -90,35 +66,50 @@
 }
 
 #if defined(ENABLE_EXTENSIONS)
-// This is a short-term solution to grant camera and/or microphone access to
-// extensions:
-// 1. Virtual keyboard extension.
-// 2. Flutter gesture recognition extension.
-// 3. TODO(smus): Airbender experiment 1.
-// 4. TODO(smus): Airbender experiment 2.
-// 5. Hotwording component extension.
-// 6. XKB input method component extension.
-// 7. M17n/T13n/CJK input method component extension.
-// Once http://crbug.com/292856 is fixed, remove this whitelist.
-bool IsMediaRequestWhitelistedForExtension(
-    const extensions::Extension* extension) {
-  return extension->id() == "mppnpdlheglhdfmldimlhpnegondlapf" ||
-      extension->id() == "jokbpnebhdcladagohdnfgjcpejggllo" ||
-      extension->id() == "clffjmdilanldobdnedchkdbofoimcgb" ||
-      extension->id() == "nnckehldicaciogcbchegobnafnjkcne" ||
-      extension->id() == "nbpagnldghgfoolbancepceaanlmhfmd" ||
-      extension->id() == "jkghodnilhceideoidjikpgommlajknk" ||
-      extension->id() == "gjaehgfemfahhmlgpdfknkhdnemmolop";
+inline DesktopCaptureAccessHandler* ToDesktopCaptureAccessHandler(
+    MediaAccessHandler* handler) {
+  return static_cast<DesktopCaptureAccessHandler*>(handler);
+}
+#endif
+}  // namespace
+
+MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() {
+  return Singleton<MediaCaptureDevicesDispatcher>::get();
 }
 
-bool IsBuiltInExtension(const GURL& origin) {
-  return
-      // Feedback Extension.
-      origin.spec() == "chrome-extension://gfdkimpbcpahaombhbimeihdjnejgicl/";
+MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher()
+    : is_device_enumeration_disabled_(false),
+      media_stream_capture_indicator_(new MediaStreamCaptureIndicator()) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+#if defined(OS_MACOSX)
+  // AVFoundation is used for video/audio device monitoring and video capture.
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kForceQTKit)) {
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kEnableAVFoundation);
+  }
+#endif
+
+#if defined(ENABLE_EXTENSIONS)
+  media_access_handlers_.push_back(new ExtensionMediaAccessHandler());
+  media_access_handlers_.push_back(new DesktopCaptureAccessHandler());
+  media_access_handlers_.push_back(new TabCaptureAccessHandler());
+#endif
+  media_access_handlers_.push_back(new PermissionBubbleMediaAccessHandler());
 }
 
-// Returns true of the security origin is associated with casting.
-bool IsOriginForCasting(const GURL& origin) {
+MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {}
+
+void MediaCaptureDevicesDispatcher::RegisterProfilePrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterStringPref(prefs::kDefaultAudioCaptureDevice,
+                               std::string());
+  registry->RegisterStringPref(prefs::kDefaultVideoCaptureDevice,
+                               std::string());
+}
+
+bool MediaCaptureDevicesDispatcher::IsOriginForCasting(const GURL& origin) {
   // Whitelisted tab casting extensions.
   return
       // Dev
@@ -136,151 +127,6 @@
       origin.spec() == "chrome-extension://fjhoaacokmgbjemoflkofnenfaiekifl/";
 }
 
-bool IsExtensionWhitelistedForScreenCapture(
-    const extensions::Extension* extension) {
-#if defined(OS_CHROMEOS)
-  std::string hash = base::SHA1HashString(extension->id());
-  std::string hex_hash = base::HexEncode(hash.c_str(), hash.length());
-
-  // crbug.com/446688
-  return hex_hash == "4F25792AF1AA7483936DE29C07806F203C7170A0" ||
-         hex_hash == "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9" ||
-         hex_hash == "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB" ||
-         hex_hash == "81986D4F846CEDDDB962643FA501D1780DD441BB";
-#else
-  return false;
-#endif  // defined(OS_CHROMEOS)
-}
-#endif  // defined(ENABLE_EXTENSIONS)
-
-// Helper to get title of the calling application shown in the screen capture
-// notification.
-base::string16 GetApplicationTitle(content::WebContents* web_contents,
-                                   const extensions::Extension* extension) {
-  // Use extension name as title for extensions and host/origin for drive-by
-  // web.
-  std::string title;
-#if defined(ENABLE_EXTENSIONS)
-  if (extension) {
-    title = extension->name();
-    return base::UTF8ToUTF16(title);
-  }
-#endif
-  GURL url = web_contents->GetURL();
-  title = url.SchemeIsSecure() ? net::GetHostAndOptionalPort(url)
-                               : url.GetOrigin().spec();
-  return base::UTF8ToUTF16(title);
-}
-
-// Helper to get list of media stream devices for desktop capture in |devices|.
-// Registers to display notification if |display_notification| is true.
-// Returns an instance of MediaStreamUI to be passed to content layer.
-scoped_ptr<content::MediaStreamUI> GetDevicesForDesktopCapture(
-    content::MediaStreamDevices* devices,
-    content::DesktopMediaID media_id,
-    bool capture_audio,
-    bool display_notification,
-    const base::string16& application_title,
-    const base::string16& registered_extension_name) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  scoped_ptr<content::MediaStreamUI> ui;
-
-  // Add selected desktop source to the list.
-  devices->push_back(content::MediaStreamDevice(
-      content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(), "Screen"));
-  if (capture_audio) {
-    // Use the special loopback device ID for system audio capture.
-    devices->push_back(content::MediaStreamDevice(
-        content::MEDIA_DESKTOP_AUDIO_CAPTURE,
-        media::AudioManagerBase::kLoopbackInputDeviceId, "System Audio"));
-  }
-
-  // If required, register to display the notification for stream capture.
-  if (display_notification) {
-    if (application_title == registered_extension_name) {
-      ui = ScreenCaptureNotificationUI::Create(l10n_util::GetStringFUTF16(
-          IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT,
-          application_title));
-    } else {
-      ui = ScreenCaptureNotificationUI::Create(l10n_util::GetStringFUTF16(
-          IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT_DELEGATED,
-          registered_extension_name,
-          application_title));
-    }
-  }
-
-  return ui.Pass();
-}
-
-#if !defined(OS_ANDROID)
-// Find browser or app window from a given |web_contents|.
-gfx::NativeWindow FindParentWindowForWebContents(
-    content::WebContents* web_contents) {
-  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
-  if (browser && browser->window())
-    return browser->window()->GetNativeWindow();
-
-  const extensions::AppWindowRegistry::AppWindowList& window_list =
-      extensions::AppWindowRegistry::Get(
-          web_contents->GetBrowserContext())->app_windows();
-  for (extensions::AppWindowRegistry::AppWindowList::const_iterator iter =
-           window_list.begin();
-       iter != window_list.end(); ++iter) {
-    if ((*iter)->web_contents() == web_contents)
-      return (*iter)->GetNativeWindow();
-  }
-
-  return NULL;
-}
-#endif
-
-}  // namespace
-
-MediaCaptureDevicesDispatcher::PendingAccessRequest::PendingAccessRequest(
-    const content::MediaStreamRequest& request,
-    const content::MediaResponseCallback& callback)
-    : request(request),
-      callback(callback) {
-}
-
-MediaCaptureDevicesDispatcher::PendingAccessRequest::~PendingAccessRequest() {}
-
-MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() {
-  return Singleton<MediaCaptureDevicesDispatcher>::get();
-}
-
-MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher()
-    : is_device_enumeration_disabled_(false),
-      media_stream_capture_indicator_(new MediaStreamCaptureIndicator()) {
-  // MediaCaptureDevicesDispatcher is a singleton. It should be created on
-  // UI thread. Otherwise, it will not receive
-  // content::NOTIFICATION_WEB_CONTENTS_DESTROYED, and that will result in
-  // possible use after free.
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  notifications_registrar_.Add(
-      this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-      content::NotificationService::AllSources());
-
-#if defined(OS_MACOSX)
-  // AVFoundation is used for video/audio device monitoring and video capture.
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kForceQTKit)) {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kEnableAVFoundation);
-  }
-#endif
-}
-
-MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {}
-
-void MediaCaptureDevicesDispatcher::RegisterProfilePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterStringPref(prefs::kDefaultAudioCaptureDevice,
-                               std::string());
-  registry->RegisterStringPref(prefs::kDefaultVideoCaptureDevice,
-                               std::string());
-}
-
 void MediaCaptureDevicesDispatcher::AddObserver(Observer* observer) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!observers_.HasObserver(observer))
@@ -310,18 +156,6 @@
   return MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices();
 }
 
-void MediaCaptureDevicesDispatcher::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
-    content::WebContents* web_contents =
-        content::Source<content::WebContents>(source).ptr();
-    pending_requests_.erase(web_contents);
-  }
-}
-
 void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequest(
     content::WebContents* web_contents,
     const content::MediaStreamRequest& request,
@@ -329,28 +163,15 @@
     const extensions::Extension* extension) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE ||
-      request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE) {
-    ProcessDesktopCaptureAccessRequest(
-        web_contents, request, callback, extension);
-  } else if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE ||
-             request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE) {
-    ProcessTabCaptureAccessRequest(
-        web_contents, request, callback, extension);
-  } else {
-#if defined(ENABLE_EXTENSIONS)
-    bool is_whitelisted =
-        extension && (extension->is_platform_app() ||
-                      IsMediaRequestWhitelistedForExtension(extension));
-    if (is_whitelisted) {
-      // For extensions access is approved based on extension permissions.
-      ProcessMediaAccessRequestFromPlatformAppOrExtension(
-          web_contents, request, callback, extension);
+  for (MediaAccessHandler* handler : media_access_handlers_) {
+    if (handler->SupportsStreamType(request.video_type, extension) ||
+        handler->SupportsStreamType(request.audio_type, extension)) {
+      handler->HandleRequest(web_contents, request, callback, extension);
       return;
     }
-#endif
-    ProcessRegularMediaAccessRequest(web_contents, request, callback);
   }
+  callback.Run(content::MediaStreamDevices(),
+               content::MEDIA_DEVICE_NOT_SUPPORTED, nullptr);
 }
 
 bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission(
@@ -358,487 +179,23 @@
     const GURL& security_origin,
     content::MediaStreamType type) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
-         type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
-
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-
-  ContentSettingsType contentSettingsType =
-      type == content::MEDIA_DEVICE_AUDIO_CAPTURE
-          ? CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
-          : CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA;
-
-  if (CheckAllowAllMediaStreamContentForOrigin(
-          profile, security_origin, contentSettingsType)) {
-    return true;
-  }
-
-  const char* policy_name = type == content::MEDIA_DEVICE_AUDIO_CAPTURE
-                                ? prefs::kAudioCaptureAllowed
-                                : prefs::kVideoCaptureAllowed;
-  const char* list_policy_name = type == content::MEDIA_DEVICE_AUDIO_CAPTURE
-                                     ? prefs::kAudioCaptureAllowedUrls
-                                     : prefs::kVideoCaptureAllowedUrls;
-  if (GetDevicePolicy(
-          profile, security_origin, policy_name, list_policy_name) ==
-      ALWAYS_ALLOW) {
-    return true;
-  }
-
-  // There's no secondary URL for these content types, hence duplicating
-  // |security_origin|.
-  if (profile->GetHostContentSettingsMap()->GetContentSetting(
-          security_origin,
-          security_origin,
-          contentSettingsType,
-          content_settings::ResourceIdentifier()) == CONTENT_SETTING_ALLOW) {
-    return true;
-  }
-
-  return false;
+  return CheckMediaAccessPermission(web_contents, security_origin, type,
+                                    nullptr);
 }
 
-#if defined(ENABLE_EXTENSIONS)
 bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission(
     content::WebContents* web_contents,
     const GURL& security_origin,
     content::MediaStreamType type,
     const extensions::Extension* extension) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
-         type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
-
-  if (extension->is_platform_app() ||
-      IsMediaRequestWhitelistedForExtension(extension)) {
-    return extension->permissions_data()->HasAPIPermission(
-        type == content::MEDIA_DEVICE_AUDIO_CAPTURE
-            ? extensions::APIPermission::kAudioCapture
-            : extensions::APIPermission::kVideoCapture);
-  }
-
-  return CheckMediaAccessPermission(web_contents, security_origin, type);
-}
-#endif
-
-void MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest(
-    content::WebContents* web_contents,
-    const content::MediaStreamRequest& request,
-    const content::MediaResponseCallback& callback,
-    const extensions::Extension* extension) {
-  content::MediaStreamDevices devices;
-  scoped_ptr<content::MediaStreamUI> ui;
-
-  if (request.video_type != content::MEDIA_DESKTOP_VIDEO_CAPTURE) {
-    callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass());
-    return;
-  }
-
-  // If the device id wasn't specified then this is a screen capture request
-  // (i.e. chooseDesktopMedia() API wasn't used to generate device id).
-  if (request.requested_video_device_id.empty()) {
-    ProcessScreenCaptureAccessRequest(
-        web_contents, request, callback, extension);
-    return;
-  }
-
-  // The extension name that the stream is registered with.
-  std::string original_extension_name;
-  // Resolve DesktopMediaID for the specified device id.
-  content::DesktopMediaID media_id;
-  // TODO(miu): Replace "main RenderFrame" IDs with the request's actual
-  // RenderFrame IDs once the desktop capture extension API implementation is
-  // fixed.  http://crbug.com/304341
-  content::WebContents* const web_contents_for_stream =
-      content::WebContents::FromRenderFrameHost(
-          content::RenderFrameHost::FromID(request.render_process_id,
-                                           request.render_frame_id));
-  content::RenderFrameHost* const main_frame = web_contents_for_stream ?
-      web_contents_for_stream->GetMainFrame() : NULL;
-  if (main_frame) {
-    media_id = GetDesktopStreamsRegistry()->RequestMediaForStreamId(
-        request.requested_video_device_id,
-        main_frame->GetProcess()->GetID(),
-        main_frame->GetRoutingID(),
-        request.security_origin,
-        &original_extension_name);
-  }
-
-  // Received invalid device id.
-  if (media_id.type == content::DesktopMediaID::TYPE_NONE) {
-    callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass());
-    return;
-  }
-
-  bool loopback_audio_supported = false;
-#if defined(USE_CRAS) || defined(OS_WIN)
-  // Currently loopback audio capture is supported only on Windows and ChromeOS.
-  loopback_audio_supported = true;
-#endif
-
-  // Audio is only supported for screen capture streams.
-  bool capture_audio =
-      (media_id.type == content::DesktopMediaID::TYPE_SCREEN &&
-       request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE &&
-       loopback_audio_supported);
-
-  ui = GetDevicesForDesktopCapture(
-      &devices, media_id, capture_audio, true,
-      GetApplicationTitle(web_contents, extension),
-      base::UTF8ToUTF16(original_extension_name));
-
-  callback.Run(devices, content::MEDIA_DEVICE_OK, ui.Pass());
-}
-
-void MediaCaptureDevicesDispatcher::ProcessScreenCaptureAccessRequest(
-    content::WebContents* web_contents,
-    const content::MediaStreamRequest& request,
-    const content::MediaResponseCallback& callback,
-    const extensions::Extension* extension) {
-  content::MediaStreamDevices devices;
-  scoped_ptr<content::MediaStreamUI> ui;
-
-  DCHECK_EQ(request.video_type, content::MEDIA_DESKTOP_VIDEO_CAPTURE);
-
-  bool loopback_audio_supported = false;
-#if defined(USE_CRAS) || defined(OS_WIN)
-  // Currently loopback audio capture is supported only on Windows and ChromeOS.
-  loopback_audio_supported = true;
-#endif
-
-  bool component_extension = false;
-#if defined(ENABLE_EXTENSIONS)
-  component_extension =
-      extension && extension->location() == extensions::Manifest::COMPONENT;
-#endif
-
-  bool screen_capture_enabled =
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableUserMediaScreenCapturing);
-#if defined(ENABLE_EXTENSIONS)
-  screen_capture_enabled |=
-      IsOriginForCasting(request.security_origin) ||
-      IsExtensionWhitelistedForScreenCapture(extension) ||
-      IsBuiltInExtension(request.security_origin);
-#endif
-
-  const bool origin_is_secure =
-      request.security_origin.SchemeIsSecure() ||
-      request.security_origin.SchemeIs(extensions::kExtensionScheme) ||
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kAllowHttpScreenCapture);
-
-  // If basic conditions (screen capturing is enabled and origin is secure)
-  // aren't fulfilled, we'll use "invalid state" as result. Otherwise, we set
-  // it after checking permission.
-  // TODO(grunell): It would be good to change this result for something else,
-  // probably a new one.
-  content::MediaStreamRequestResult result =
-      content::MEDIA_DEVICE_INVALID_STATE;
-
-  // Approve request only when the following conditions are met:
-  //  1. Screen capturing is enabled via command line switch or white-listed for
-  //     the given origin.
-  //  2. Request comes from a page with a secure origin or from an extension.
-  if (screen_capture_enabled && origin_is_secure) {
-    // Get title of the calling application prior to showing the message box.
-    // chrome::ShowMessageBox() starts a nested message loop which may allow
-    // |web_contents| to be destroyed on the UI thread before the message box
-    // is closed. See http://crbug.com/326690.
-    base::string16 application_title =
-        GetApplicationTitle(web_contents, extension);
-#if !defined(OS_ANDROID)
-    gfx::NativeWindow parent_window =
-        FindParentWindowForWebContents(web_contents);
-#else
-    gfx::NativeWindow parent_window = NULL;
-#endif
-    web_contents = NULL;
-
-    bool whitelisted_extension = false;
-#if defined(ENABLE_EXTENSIONS)
-    whitelisted_extension = IsExtensionWhitelistedForScreenCapture(
-        extension);
-#endif
-
-    // For whitelisted or component extensions, bypass message box.
-    bool user_approved = false;
-    if (!whitelisted_extension && !component_extension) {
-      base::string16 application_name =
-          base::UTF8ToUTF16(request.security_origin.spec());
-#if defined(ENABLE_EXTENSIONS)
-      if (extension)
-        application_name = base::UTF8ToUTF16(extension->name());
-#endif
-      base::string16 confirmation_text = l10n_util::GetStringFUTF16(
-          request.audio_type == content::MEDIA_NO_SERVICE ?
-              IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TEXT :
-              IDS_MEDIA_SCREEN_AND_AUDIO_CAPTURE_CONFIRMATION_TEXT,
-          application_name);
-      chrome::MessageBoxResult result = chrome::ShowMessageBox(
-          parent_window,
-          l10n_util::GetStringFUTF16(
-              IDS_MEDIA_SCREEN_CAPTURE_CONFIRMATION_TITLE, application_name),
-          confirmation_text,
-          chrome::MESSAGE_BOX_TYPE_QUESTION);
-      user_approved = (result == chrome::MESSAGE_BOX_RESULT_YES);
-    }
-
-    if (user_approved || component_extension || whitelisted_extension) {
-      content::DesktopMediaID screen_id;
-#if defined(OS_CHROMEOS)
-      screen_id = content::DesktopMediaID::RegisterAuraWindow(
-          ash::Shell::GetInstance()->GetPrimaryRootWindow());
-#else  // defined(OS_CHROMEOS)
-      screen_id =
-          content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
-                                  webrtc::kFullDesktopScreenId);
-#endif  // !defined(OS_CHROMEOS)
-
-      bool capture_audio =
-          (request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE &&
-           loopback_audio_supported);
-
-      // Unless we're being invoked from a component extension, register to
-      // display the notification for stream capture.
-      bool display_notification = !component_extension;
-
-      ui = GetDevicesForDesktopCapture(&devices, screen_id, capture_audio,
-                                       display_notification, application_title,
-                                       application_title);
-      DCHECK(!devices.empty());
-    }
-
-    // The only case when devices can be empty is if the user has denied
-    // permission.
-    result = devices.empty() ? content::MEDIA_DEVICE_PERMISSION_DENIED
-                             : content::MEDIA_DEVICE_OK;
-  }
-
-  callback.Run(devices, result, ui.Pass());
-}
-
-void MediaCaptureDevicesDispatcher::ProcessTabCaptureAccessRequest(
-    content::WebContents* web_contents,
-    const content::MediaStreamRequest& request,
-    const content::MediaResponseCallback& callback,
-    const extensions::Extension* extension) {
-  content::MediaStreamDevices devices;
-  scoped_ptr<content::MediaStreamUI> ui;
-
-#if defined(ENABLE_EXTENSIONS)
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  extensions::TabCaptureRegistry* tab_capture_registry =
-      extensions::TabCaptureRegistry::Get(profile);
-  if (!tab_capture_registry) {
-    NOTREACHED();
-    callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass());
-    return;
-  }
-  const bool tab_capture_allowed = tab_capture_registry->VerifyRequest(
-      request.render_process_id, request.render_frame_id, extension->id());
-
-  if (request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE &&
-      tab_capture_allowed &&
-      extension->permissions_data()->HasAPIPermission(
-          extensions::APIPermission::kTabCapture)) {
-    devices.push_back(content::MediaStreamDevice(
-        content::MEDIA_TAB_AUDIO_CAPTURE, std::string(), std::string()));
-  }
-
-  if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE &&
-      tab_capture_allowed &&
-      extension->permissions_data()->HasAPIPermission(
-          extensions::APIPermission::kTabCapture)) {
-    devices.push_back(content::MediaStreamDevice(
-        content::MEDIA_TAB_VIDEO_CAPTURE, std::string(), std::string()));
-  }
-
-  if (!devices.empty()) {
-    ui = media_stream_capture_indicator_->RegisterMediaStream(
-        web_contents, devices);
-  }
-  callback.Run(
-    devices,
-    devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE :
-                      content::MEDIA_DEVICE_OK,
-    ui.Pass());
-#else  // defined(ENABLE_EXTENSIONS)
-  callback.Run(devices, content::MEDIA_DEVICE_TAB_CAPTURE_FAILURE, ui.Pass());
-#endif  // defined(ENABLE_EXTENSIONS)
-}
-
-#if defined(ENABLE_EXTENSIONS)
-void MediaCaptureDevicesDispatcher::
-    ProcessMediaAccessRequestFromPlatformAppOrExtension(
-        content::WebContents* web_contents,
-        const content::MediaStreamRequest& request,
-        const content::MediaResponseCallback& callback,
-        const extensions::Extension* extension) {
-  // TODO(vrk): This code is largely duplicated in
-  // MediaStreamDevicesController::Accept(). Move this code into a shared method
-  // between the two classes.
-
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-
-  bool audio_allowed =
-      request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE &&
-      extension->permissions_data()->HasAPIPermission(
-          extensions::APIPermission::kAudioCapture) &&
-      GetDevicePolicy(profile, extension->url(),
-                      prefs::kAudioCaptureAllowed,
-                      prefs::kAudioCaptureAllowedUrls) != ALWAYS_DENY;
-  bool video_allowed =
-      request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE &&
-      extension->permissions_data()->HasAPIPermission(
-          extensions::APIPermission::kVideoCapture) &&
-      GetDevicePolicy(profile, extension->url(),
-                      prefs::kVideoCaptureAllowed,
-                      prefs::kVideoCaptureAllowedUrls) != ALWAYS_DENY;
-
-  bool get_default_audio_device = audio_allowed;
-  bool get_default_video_device = video_allowed;
-
-  content::MediaStreamDevices devices;
-
-  // Set an initial error result. If neither audio or video is allowed, we'll
-  // never try to get any device below but will just create |ui| and return an
-  // empty list with "invalid state" result. If at least one is allowed, we'll
-  // try to get device(s), and if failure, we want to return "no hardware"
-  // result.
-  // TODO(grunell): The invalid state result should be changed to a new denied
-  // result + a dcheck to ensure at least one of audio or video types is
-  // capture.
-  content::MediaStreamRequestResult result =
-      (audio_allowed || video_allowed) ? content::MEDIA_DEVICE_NO_HARDWARE
-                                       : content::MEDIA_DEVICE_INVALID_STATE;
-
-  // Get the exact audio or video device if an id is specified.
-  // We only set any error result here and before running the callback change
-  // it to OK if we have any device.
-  if (audio_allowed && !request.requested_audio_device_id.empty()) {
-    const content::MediaStreamDevice* audio_device =
-        GetRequestedAudioDevice(request.requested_audio_device_id);
-    if (audio_device) {
-      devices.push_back(*audio_device);
-      get_default_audio_device = false;
+  for (MediaAccessHandler* handler : media_access_handlers_) {
+    if (handler->SupportsStreamType(type, extension)) {
+      return handler->CheckMediaAccessPermission(web_contents, security_origin,
+                                                 type, extension);
     }
   }
-  if (video_allowed && !request.requested_video_device_id.empty()) {
-    const content::MediaStreamDevice* video_device =
-        GetRequestedVideoDevice(request.requested_video_device_id);
-    if (video_device) {
-      devices.push_back(*video_device);
-      get_default_video_device = false;
-    }
-  }
-
-  // If either or both audio and video devices were requested but not
-  // specified by id, get the default devices.
-  if (get_default_audio_device || get_default_video_device) {
-    GetDefaultDevicesForProfile(profile,
-                                get_default_audio_device,
-                                get_default_video_device,
-                                &devices);
-  }
-
-  scoped_ptr<content::MediaStreamUI> ui;
-  if (!devices.empty()) {
-    result = content::MEDIA_DEVICE_OK;
-    ui = media_stream_capture_indicator_->RegisterMediaStream(
-        web_contents, devices);
-  }
-
-  callback.Run(devices, result, ui.Pass());
-}
-#endif
-
-void MediaCaptureDevicesDispatcher::ProcessRegularMediaAccessRequest(
-    content::WebContents* web_contents,
-    const content::MediaStreamRequest& request,
-    const content::MediaResponseCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  RequestsQueue& queue = pending_requests_[web_contents];
-  queue.push_back(PendingAccessRequest(request, callback));
-
-  // If this is the only request then show the infobar.
-  if (queue.size() == 1)
-    ProcessQueuedAccessRequest(web_contents);
-}
-
-void MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest(
-    content::WebContents* web_contents) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  std::map<content::WebContents*, RequestsQueue>::iterator it =
-      pending_requests_.find(web_contents);
-
-  if (it == pending_requests_.end() || it->second.empty()) {
-    // Don't do anything if the tab was closed.
-    return;
-  }
-
-  DCHECK(!it->second.empty());
-
-  if (PermissionBubbleManager::Enabled() ||
-      MediaStreamPermissionBubbleExperimentEnabled()) {
-    scoped_ptr<MediaStreamDevicesController> controller(
-        new MediaStreamDevicesController(web_contents,
-            it->second.front().request,
-            base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse,
-                       base::Unretained(this), web_contents)));
-    if (controller->DismissInfoBarAndTakeActionOnSettings())
-      return;
-    PermissionBubbleManager* bubble_manager =
-        PermissionBubbleManager::FromWebContents(web_contents);
-    if (bubble_manager)
-      bubble_manager->AddRequest(controller.release());
-    return;
-  }
-
-  // TODO(gbillock): delete this block and the MediaStreamInfoBarDelegate
-  // when we've transitioned to bubbles. (crbug/337458)
-  MediaStreamInfoBarDelegate::Create(
-      web_contents, it->second.front().request,
-      base::Bind(&MediaCaptureDevicesDispatcher::OnAccessRequestResponse,
-                 base::Unretained(this), web_contents));
-}
-
-void MediaCaptureDevicesDispatcher::OnAccessRequestResponse(
-    content::WebContents* web_contents,
-    const content::MediaStreamDevices& devices,
-    content::MediaStreamRequestResult result,
-    scoped_ptr<content::MediaStreamUI> ui) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  std::map<content::WebContents*, RequestsQueue>::iterator it =
-      pending_requests_.find(web_contents);
-  if (it == pending_requests_.end()) {
-    // WebContents has been destroyed. Don't need to do anything.
-    return;
-  }
-
-  RequestsQueue& queue(it->second);
-  if (queue.empty())
-    return;
-
-  content::MediaResponseCallback callback = queue.front().callback;
-  queue.pop_front();
-
-  if (!queue.empty()) {
-    // Post a task to process next queued request. It has to be done
-    // asynchronously to make sure that calling infobar is not destroyed until
-    // after this function returns.
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest,
-                   base::Unretained(this), web_contents));
-  }
-
-  callback.Run(devices, result, ui.Pass());
+  return false;
 }
 
 void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile(
@@ -990,47 +347,11 @@
     const GURL& security_origin,
     content::MediaStreamType stream_type,
     content::MediaRequestState state) {
-  // Track desktop capture sessions.  Tracking is necessary to avoid unbalanced
-  // session counts since not all requests will reach MEDIA_REQUEST_STATE_DONE,
-  // but they will all reach MEDIA_REQUEST_STATE_CLOSING.
-  if (stream_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) {
-    if (state == content::MEDIA_REQUEST_STATE_DONE) {
-      DesktopCaptureSession session = { render_process_id, render_frame_id,
-                                        page_request_id };
-      desktop_capture_sessions_.push_back(session);
-    } else if (state == content::MEDIA_REQUEST_STATE_CLOSING) {
-      for (DesktopCaptureSessions::iterator it =
-               desktop_capture_sessions_.begin();
-           it != desktop_capture_sessions_.end();
-           ++it) {
-        if (it->render_process_id == render_process_id &&
-            it->render_frame_id == render_frame_id &&
-            it->page_request_id == page_request_id) {
-          desktop_capture_sessions_.erase(it);
-          break;
-        }
-      }
-    }
-  }
-
-  // Cancel the request.
-  if (state == content::MEDIA_REQUEST_STATE_CLOSING) {
-    bool found = false;
-    for (RequestsQueues::iterator rqs_it = pending_requests_.begin();
-         rqs_it != pending_requests_.end(); ++rqs_it) {
-      RequestsQueue& queue = rqs_it->second;
-      for (RequestsQueue::iterator it = queue.begin();
-           it != queue.end(); ++it) {
-        if (it->request.render_process_id == render_process_id &&
-            it->request.render_frame_id == render_frame_id &&
-            it->request.page_request_id == page_request_id) {
-          queue.erase(it);
-          found = true;
-          break;
-        }
-      }
-      if (found)
-        break;
+  for (MediaAccessHandler* handler : media_access_handlers_) {
+    if (handler->SupportsStreamType(stream_type, nullptr)) {
+      handler->UpdateMediaRequestState(render_process_id, render_frame_id,
+                                       page_request_id, stream_type, state);
+      break;
     }
   }
 
@@ -1062,7 +383,15 @@
 
 bool MediaCaptureDevicesDispatcher::IsDesktopCaptureInProgress() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  return desktop_capture_sessions_.size() > 0;
+#if defined(ENABLE_EXTENSIONS)
+  for (MediaAccessHandler* handler : media_access_handlers_) {
+    if (handler->SupportsStreamType(content::MEDIA_DESKTOP_VIDEO_CAPTURE,
+                                    NULL)) {
+      return ToDesktopCaptureAccessHandler(handler)->IsCaptureInProgress();
+    }
+  }
+#endif
+  return false;
 }
 
 void MediaCaptureDevicesDispatcher::SetTestAudioCaptureDevices(
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.h b/chrome/browser/media/media_capture_devices_dispatcher.h
index a428b61..e036f60 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.h
+++ b/chrome/browser/media/media_capture_devices_dispatcher.h
@@ -11,15 +11,15 @@
 
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
 #include "base/memory/singleton.h"
 #include "base/observer_list.h"
 #include "content/public/browser/media_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/media_stream_request.h"
 
 class DesktopStreamsRegistry;
+class MediaAccessHandler;
 class MediaStreamCaptureIndicator;
 class Profile;
 
@@ -33,8 +33,7 @@
 
 // This singleton is used to receive updates about media events from the content
 // layer.
-class MediaCaptureDevicesDispatcher : public content::MediaObserver,
-                                      public content::NotificationObserver {
+class MediaCaptureDevicesDispatcher : public content::MediaObserver {
  public:
   class Observer {
    public:
@@ -67,6 +66,9 @@
   // Registers the preferences related to Media Stream default devices.
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
+  // Returns true if the security origin is associated with casting.
+  static bool IsOriginForCasting(const GURL& origin);
+
   // Methods for observers. Called on UI thread.
   // Observers should add themselves on construction and remove themselves
   // on destruction.
@@ -91,12 +93,10 @@
                                   content::MediaStreamType type);
 
   // Same as above but for an |extension|, which may not be NULL.
-#if defined(ENABLE_EXTENSIONS)
   bool CheckMediaAccessPermission(content::WebContents* web_contents,
                                   const GURL& security_origin,
                                   content::MediaStreamType type,
                                   const extensions::Extension* extension);
-#endif
 
   // Helper to get the default devices which can be used by the media request.
   // Uses the first available devices if the default devices are not available.
@@ -150,60 +150,9 @@
  private:
   friend struct DefaultSingletonTraits<MediaCaptureDevicesDispatcher>;
 
-  struct PendingAccessRequest {
-    PendingAccessRequest(const content::MediaStreamRequest& request,
-                         const content::MediaResponseCallback& callback);
-    ~PendingAccessRequest();
-
-    // TODO(gbillock): make the MediaStreamDevicesController owned by
-    // this object when we're using bubbles.
-    content::MediaStreamRequest request;
-    content::MediaResponseCallback callback;
-  };
-  typedef std::deque<PendingAccessRequest> RequestsQueue;
-  typedef std::map<content::WebContents*, RequestsQueue> RequestsQueues;
-
   MediaCaptureDevicesDispatcher();
   ~MediaCaptureDevicesDispatcher() override;
 
-  // content::NotificationObserver implementation.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
-  // Helpers for ProcessMediaAccessRequest().
-  void ProcessDesktopCaptureAccessRequest(
-      content::WebContents* web_contents,
-      const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback,
-      const extensions::Extension* extension);
-  void ProcessScreenCaptureAccessRequest(
-      content::WebContents* web_contents,
-      const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback,
-      const extensions::Extension* extension);
-  void ProcessTabCaptureAccessRequest(
-      content::WebContents* web_contents,
-      const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback,
-      const extensions::Extension* extension);
-#if defined(ENABLE_EXTENSIONS)
-  void ProcessMediaAccessRequestFromPlatformAppOrExtension(
-      content::WebContents* web_contents,
-      const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback,
-      const extensions::Extension* extension);
-#endif
-  void ProcessRegularMediaAccessRequest(
-      content::WebContents* web_contents,
-      const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback);
-  void ProcessQueuedAccessRequest(content::WebContents* web_contents);
-  void OnAccessRequestResponse(content::WebContents* web_contents,
-                               const content::MediaStreamDevices& devices,
-                               content::MediaStreamRequestResult result,
-                               scoped_ptr<content::MediaStreamUI> ui);
-
   // Called by the MediaObserver() functions, executed on UI thread.
   void NotifyAudioDevicesChangedOnUIThread();
   void NotifyVideoDevicesChangedOnUIThread();
@@ -229,24 +178,12 @@
   // Flag used by unittests to disable device enumeration.
   bool is_device_enumeration_disabled_;
 
-  RequestsQueues pending_requests_;
-
   scoped_refptr<MediaStreamCaptureIndicator> media_stream_capture_indicator_;
 
   scoped_ptr<DesktopStreamsRegistry> desktop_streams_registry_;
 
-  content::NotificationRegistrar notifications_registrar_;
-
-  // Tracks MEDIA_DESKTOP_VIDEO_CAPTURE sessions which reach the
-  // MEDIA_REQUEST_STATE_DONE state.  Sessions are remove when
-  // MEDIA_REQUEST_STATE_CLOSING is encountered.
-  struct DesktopCaptureSession {
-    int render_process_id;
-    int render_frame_id;
-    int page_request_id;
-  };
-  typedef std::list<DesktopCaptureSession> DesktopCaptureSessions;
-  DesktopCaptureSessions desktop_capture_sessions_;
+  // Handlers for processing media access requests.
+  ScopedVector<MediaAccessHandler> media_access_handlers_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaCaptureDevicesDispatcher);
 };
diff --git a/chrome/browser/media/media_stream_infobar_delegate.cc b/chrome/browser/media/media_stream_infobar_delegate.cc
index 6cc451b7..6c9c1c0 100644
--- a/chrome/browser/media/media_stream_infobar_delegate.cc
+++ b/chrome/browser/media/media_stream_infobar_delegate.cc
@@ -66,6 +66,14 @@
   return true;
 }
 
+bool MediaStreamInfoBarDelegate::IsRequestingVideoAccess() const {
+  return controller_->HasVideo();
+}
+
+bool MediaStreamInfoBarDelegate::IsRequestingMicrophoneAccess() const {
+  return controller_->HasAudio();
+}
+
 MediaStreamInfoBarDelegate::MediaStreamInfoBarDelegate(
     scoped_ptr<MediaStreamDevicesController> controller)
     : ConfirmInfoBarDelegate(),
diff --git a/chrome/browser/media/media_stream_infobar_delegate.h b/chrome/browser/media/media_stream_infobar_delegate.h
index e055289..4f86c71 100644
--- a/chrome/browser/media/media_stream_infobar_delegate.h
+++ b/chrome/browser/media/media_stream_infobar_delegate.h
@@ -30,6 +30,9 @@
                      const content::MediaStreamRequest& request,
                      const content::MediaResponseCallback& callback);
 
+  bool IsRequestingVideoAccess() const;
+  bool IsRequestingMicrophoneAccess() const;
+
  private:
   friend class WebRtcTestBase;
 
diff --git a/chrome/browser/media/permission_bubble_media_access_handler.cc b/chrome/browser/media/permission_bubble_media_access_handler.cc
new file mode 100644
index 0000000..09d16c1a
--- /dev/null
+++ b/chrome/browser/media/permission_bubble_media_access_handler.cc
@@ -0,0 +1,235 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/permission_bubble_media_access_handler.h"
+
+#include "base/metrics/field_trial.h"
+#include "chrome/browser/media/media_stream_device_permissions.h"
+#include "chrome/browser/media/media_stream_infobar_delegate.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
+#include "chrome/common/pref_names.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/web_contents.h"
+
+using content::BrowserThread;
+
+namespace {
+
+// A finch experiment to enable the permission bubble for media requests only.
+bool MediaStreamPermissionBubbleExperimentEnabled() {
+  const std::string group =
+      base::FieldTrialList::FindFullName("MediaStreamPermissionBubble");
+  if (group == "enabled")
+    return true;
+
+  return false;
+}
+
+}  // namespace
+
+struct PermissionBubbleMediaAccessHandler::PendingAccessRequest {
+  PendingAccessRequest(const content::MediaStreamRequest& request,
+                       const content::MediaResponseCallback& callback)
+      : request(request), callback(callback) {}
+  ~PendingAccessRequest() {}
+
+  // TODO(gbillock): make the MediaStreamDevicesController owned by
+  // this object when we're using bubbles.
+  content::MediaStreamRequest request;
+  content::MediaResponseCallback callback;
+};
+
+PermissionBubbleMediaAccessHandler::PermissionBubbleMediaAccessHandler() {
+  // PermissionBubbleMediaAccessHandler should be created on UI thread.
+  // Otherwise, it will not receive
+  // content::NOTIFICATION_WEB_CONTENTS_DESTROYED, and that will result in
+  // possible use after free.
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  notifications_registrar_.Add(this,
+                               content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+                               content::NotificationService::AllSources());
+}
+
+PermissionBubbleMediaAccessHandler::~PermissionBubbleMediaAccessHandler() {
+}
+
+bool PermissionBubbleMediaAccessHandler::SupportsStreamType(
+    const content::MediaStreamType type,
+    const extensions::Extension* extension) {
+  return type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
+         type == content::MEDIA_DEVICE_AUDIO_CAPTURE;
+}
+
+bool PermissionBubbleMediaAccessHandler::CheckMediaAccessPermission(
+    content::WebContents* web_contents,
+    const GURL& security_origin,
+    content::MediaStreamType type,
+    const extensions::Extension* extension) {
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+
+  ContentSettingsType content_settings_type =
+      type == content::MEDIA_DEVICE_AUDIO_CAPTURE
+          ? CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
+          : CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA;
+
+  if (CheckAllowAllMediaStreamContentForOrigin(profile, security_origin,
+                                               content_settings_type)) {
+    return true;
+  }
+
+  const char* policy_name = type == content::MEDIA_DEVICE_AUDIO_CAPTURE
+                                ? prefs::kAudioCaptureAllowed
+                                : prefs::kVideoCaptureAllowed;
+  const char* list_policy_name = type == content::MEDIA_DEVICE_AUDIO_CAPTURE
+                                     ? prefs::kAudioCaptureAllowedUrls
+                                     : prefs::kVideoCaptureAllowedUrls;
+  if (GetDevicePolicy(profile, security_origin, policy_name,
+                      list_policy_name) == ALWAYS_ALLOW) {
+    return true;
+  }
+
+  // There's no secondary URL for these content types, hence duplicating
+  // |security_origin|.
+  if (profile->GetHostContentSettingsMap()->GetContentSetting(
+          security_origin, security_origin, content_settings_type,
+          content_settings::ResourceIdentifier()) == CONTENT_SETTING_ALLOW) {
+    return true;
+  }
+
+  return false;
+}
+
+void PermissionBubbleMediaAccessHandler::HandleRequest(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    const content::MediaResponseCallback& callback,
+    const extensions::Extension* extension) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  RequestsQueue& queue = pending_requests_[web_contents];
+  queue.push_back(PendingAccessRequest(request, callback));
+
+  // If this is the only request then show the infobar.
+  if (queue.size() == 1)
+    ProcessQueuedAccessRequest(web_contents);
+}
+
+void PermissionBubbleMediaAccessHandler::ProcessQueuedAccessRequest(
+    content::WebContents* web_contents) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  std::map<content::WebContents*, RequestsQueue>::iterator it =
+      pending_requests_.find(web_contents);
+
+  if (it == pending_requests_.end() || it->second.empty()) {
+    // Don't do anything if the tab was closed.
+    return;
+  }
+
+  DCHECK(!it->second.empty());
+
+  if (PermissionBubbleManager::Enabled() ||
+      MediaStreamPermissionBubbleExperimentEnabled()) {
+    scoped_ptr<MediaStreamDevicesController> controller(
+        new MediaStreamDevicesController(
+            web_contents, it->second.front().request,
+            base::Bind(
+                &PermissionBubbleMediaAccessHandler::OnAccessRequestResponse,
+                base::Unretained(this), web_contents)));
+    if (controller->DismissInfoBarAndTakeActionOnSettings())
+      return;
+    PermissionBubbleManager* bubble_manager =
+        PermissionBubbleManager::FromWebContents(web_contents);
+    if (bubble_manager)
+      bubble_manager->AddRequest(controller.release());
+    return;
+  }
+
+  // TODO(gbillock): delete this block and the MediaStreamInfoBarDelegate
+  // when we've transitioned to bubbles. (crbug/337458)
+  MediaStreamInfoBarDelegate::Create(
+      web_contents, it->second.front().request,
+      base::Bind(&PermissionBubbleMediaAccessHandler::OnAccessRequestResponse,
+                 base::Unretained(this), web_contents));
+}
+
+void PermissionBubbleMediaAccessHandler::UpdateMediaRequestState(
+    int render_process_id,
+    int render_frame_id,
+    int page_request_id,
+    content::MediaStreamType stream_type,
+    content::MediaRequestState state) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (state != content::MEDIA_REQUEST_STATE_CLOSING)
+    return;
+
+  bool found = false;
+  for (RequestsQueues::iterator rqs_it = pending_requests_.begin();
+       rqs_it != pending_requests_.end(); ++rqs_it) {
+    RequestsQueue& queue = rqs_it->second;
+    for (RequestsQueue::iterator it = queue.begin(); it != queue.end(); ++it) {
+      if (it->request.render_process_id == render_process_id &&
+          it->request.render_frame_id == render_frame_id &&
+          it->request.page_request_id == page_request_id) {
+        queue.erase(it);
+        found = true;
+        break;
+      }
+    }
+    if (found)
+      break;
+  }
+}
+
+void PermissionBubbleMediaAccessHandler::OnAccessRequestResponse(
+    content::WebContents* web_contents,
+    const content::MediaStreamDevices& devices,
+    content::MediaStreamRequestResult result,
+    scoped_ptr<content::MediaStreamUI> ui) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  std::map<content::WebContents*, RequestsQueue>::iterator it =
+      pending_requests_.find(web_contents);
+  if (it == pending_requests_.end()) {
+    // WebContents has been destroyed. Don't need to do anything.
+    return;
+  }
+
+  RequestsQueue& queue(it->second);
+  if (queue.empty())
+    return;
+
+  content::MediaResponseCallback callback = queue.front().callback;
+  queue.pop_front();
+
+  if (!queue.empty()) {
+    // Post a task to process next queued request. It has to be done
+    // asynchronously to make sure that calling infobar is not destroyed until
+    // after this function returns.
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::Bind(
+            &PermissionBubbleMediaAccessHandler::ProcessQueuedAccessRequest,
+            base::Unretained(this), web_contents));
+  }
+
+  callback.Run(devices, result, ui.Pass());
+}
+
+void PermissionBubbleMediaAccessHandler::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
+    content::WebContents* web_contents =
+        content::Source<content::WebContents>(source).ptr();
+    pending_requests_.erase(web_contents);
+  }
+}
diff --git a/chrome/browser/media/permission_bubble_media_access_handler.h b/chrome/browser/media/permission_bubble_media_access_handler.h
new file mode 100644
index 0000000..0f6514d
--- /dev/null
+++ b/chrome/browser/media/permission_bubble_media_access_handler.h
@@ -0,0 +1,60 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_PERMISSION_BUBBLE_MEDIA_ACCESS_HANDLER_H_
+#define CHROME_BROWSER_MEDIA_PERMISSION_BUBBLE_MEDIA_ACCESS_HANDLER_H_
+
+#include <deque>
+#include <map>
+
+#include "chrome/browser/media/media_access_handler.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+// MediaAccessHandler for permission bubble requests.
+class PermissionBubbleMediaAccessHandler
+    : public MediaAccessHandler,
+      public content::NotificationObserver {
+ public:
+  PermissionBubbleMediaAccessHandler();
+  ~PermissionBubbleMediaAccessHandler() override;
+
+  // MediaAccessHandler implementation.
+  bool SupportsStreamType(const content::MediaStreamType type,
+                          const extensions::Extension* extension) override;
+  bool CheckMediaAccessPermission(
+      content::WebContents* web_contents,
+      const GURL& security_origin,
+      content::MediaStreamType type,
+      const extensions::Extension* extension) override;
+  void HandleRequest(content::WebContents* web_contents,
+                     const content::MediaStreamRequest& request,
+                     const content::MediaResponseCallback& callback,
+                     const extensions::Extension* extension) override;
+  void UpdateMediaRequestState(int render_process_id,
+                               int render_frame_id,
+                               int page_request_id,
+                               content::MediaStreamType stream_type,
+                               content::MediaRequestState state) override;
+
+ private:
+  struct PendingAccessRequest;
+  typedef std::deque<PendingAccessRequest> RequestsQueue;
+  typedef std::map<content::WebContents*, RequestsQueue> RequestsQueues;
+
+  void ProcessQueuedAccessRequest(content::WebContents* web_contents);
+  void OnAccessRequestResponse(content::WebContents* web_contents,
+                               const content::MediaStreamDevices& devices,
+                               content::MediaStreamRequestResult result,
+                               scoped_ptr<content::MediaStreamUI> ui);
+
+  // content::NotificationObserver implementation.
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
+  RequestsQueues pending_requests_;
+  content::NotificationRegistrar notifications_registrar_;
+};
+#endif  // CHROME_BROWSER_MEDIA_PERMISSION_BUBBLE_MEDIA_ACCESS_HANDLER_H_
diff --git a/chrome/browser/media/router/media_router.h b/chrome/browser/media/router/media_router.h
index 0699d3f8..946dd127 100644
--- a/chrome/browser/media/router/media_router.h
+++ b/chrome/browser/media/router/media_router.h
@@ -35,6 +35,8 @@
 // posting messages or closing).
 class MediaRouter {
  public:
+  using SendRouteMessageCallback = base::Callback<void(bool sent)>;
+
   virtual ~MediaRouter() {}
 
   // Creates a media route from |source_id| to |sink_id|.
@@ -49,8 +51,9 @@
   // Posts |message| to a MediaSink connected via MediaRoute with |route_id|.
   // TODO(imcheng): Support additional data types: Blob, ArrayBuffer,
   // ArrayBufferView.
-  virtual void PostMessage(const MediaRoute::Id& route_id,
-                           const std::string& message) = 0;
+  virtual void SendRouteMessage(const MediaRoute::Id& route_id,
+                                const std::string& message,
+                                const SendRouteMessageCallback& callback) = 0;
 
   // Clears the issue with the id |issue_id|.
   virtual void ClearIssue(const Issue::Id& issue_id) = 0;
diff --git a/chrome/browser/media/router/media_router.mojom b/chrome/browser/media/router/media_router.mojom
index e67b327f..bf459870 100644
--- a/chrome/browser/media/router/media_router.mojom
+++ b/chrome/browser/media/router/media_router.mojom
@@ -94,9 +94,9 @@
   // Closes the route specified by |route_id|.
   CloseRoute(string route_id);
 
-  // Sends |message| with optional |extra_info_json| via the media route
-  // |media_route_id|.
-  PostMessage(string media_route_id, string message);
+  // Sends |message| via the media route |media_route_id|.
+  // If the operation was successful, |sent| is true; otherwise it is false.
+  SendRouteMessage(string media_route_id, string message) => (bool sent);
 
   // Starts querying for sinks capable of displaying |media_source|.
   StartObservingMediaSinks(string media_source);
diff --git a/chrome/browser/media/router/media_router_mojo_impl.cc b/chrome/browser/media/router/media_router_mojo_impl.cc
index c65700d..4824c69 100644
--- a/chrome/browser/media/router/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/media_router_mojo_impl.cc
@@ -174,12 +174,14 @@
                         base::Unretained(this), route_id));
 }
 
-void MediaRouterMojoImpl::PostMessage(const MediaRoute::Id& route_id,
-                                      const std::string& message) {
+void MediaRouterMojoImpl::SendRouteMessage(
+    const MediaRoute::Id& route_id,
+    const std::string& message,
+    const SendRouteMessageCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoPostMessage,
-                        base::Unretained(this), route_id, message));
+  RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoSendSessionMessage,
+                        base::Unretained(this), route_id, message, callback));
 }
 
 void MediaRouterMojoImpl::ClearIssue(const Issue::Id& issue_id) {
@@ -281,10 +283,12 @@
   mojo_media_router_->CloseRoute(route_id);
 }
 
-void MediaRouterMojoImpl::DoPostMessage(const MediaRoute::Id& route_id,
-                                        const std::string& message) {
-  DVLOG_WITH_INSTANCE(1) << "PostMessage " << route_id;
-  mojo_media_router_->PostMessage(route_id, message);
+void MediaRouterMojoImpl::DoSendSessionMessage(
+    const MediaRoute::Id& route_id,
+    const std::string& message,
+    const SendRouteMessageCallback& callback) {
+  DVLOG_WITH_INSTANCE(1) << "SendRouteMessage " << route_id;
+  mojo_media_router_->SendRouteMessage(route_id, message, callback);
 }
 
 void MediaRouterMojoImpl::DoClearIssue(const Issue::Id& issue_id) {
diff --git a/chrome/browser/media/router/media_router_mojo_impl.h b/chrome/browser/media/router/media_router_mojo_impl.h
index f3bd8e36..417ab80 100644
--- a/chrome/browser/media/router/media_router_mojo_impl.h
+++ b/chrome/browser/media/router/media_router_mojo_impl.h
@@ -63,8 +63,9 @@
                    const MediaSink::Id& sink_id,
                    const MediaRouteResponseCallback& callback) override;
   void CloseRoute(const MediaRoute::Id& route_id) override;
-  void PostMessage(const MediaRoute::Id& route_id,
-                   const std::string& message) override;
+  void SendRouteMessage(const MediaRoute::Id& route_id,
+                        const std::string& message,
+                        const SendRouteMessageCallback& callback) override;
   void ClearIssue(const Issue::Id& issue_id) override;
   void RegisterMediaSinksObserver(MediaSinksObserver* observer) override;
   void UnregisterMediaSinksObserver(MediaSinksObserver* observer) override;
@@ -111,8 +112,9 @@
                      const MediaSink::Id& sink_id,
                      const MediaRouteResponseCallback& callback);
   void DoCloseRoute(const MediaRoute::Id& route_id);
-  void DoPostMessage(const MediaRoute::Id& route_id,
-                     const std::string& message);
+  void DoSendSessionMessage(const MediaRoute::Id& route_id,
+                            const std::string& message,
+                            const SendRouteMessageCallback& callback);
   void DoClearIssue(const Issue::Id& issue_id);
   void DoStartObservingMediaSinks(const std::string& source_id);
   void DoStopObservingMediaSinks(const std::string& source_id);
diff --git a/chrome/browser/media/router/media_router_mojo_impl_unittest.cc b/chrome/browser/media/router/media_router_mojo_impl_unittest.cc
index 810bdb7..87ad5115 100644
--- a/chrome/browser/media/router/media_router_mojo_impl_unittest.cc
+++ b/chrome/browser/media/router/media_router_mojo_impl_unittest.cc
@@ -60,6 +60,11 @@
                void(MediaRoute* route, const std::string& error_text));
 };
 
+class SendMessageCallbackHandler {
+ public:
+  MOCK_METHOD1(Invoke, void(bool));
+};
+
 template <typename T>
 void StoreAndRun(T* result, const base::Closure& closure, const T& result_val) {
   *result = result_val;
@@ -83,8 +88,8 @@
             extensions::ExtensionRegistry::Get(context)) {}
   ~TestProcessManager() override {}
 
-  static KeyedService* Create(content::BrowserContext* context) {
-    return new TestProcessManager(context);
+  static scoped_ptr<KeyedService> Create(content::BrowserContext* context) {
+    return make_scoped_ptr(new TestProcessManager(context));
   }
 
   MOCK_METHOD1(IsEventPageSuspended, bool(const std::string& ext_id));
@@ -273,10 +278,21 @@
   ProcessEventLoop();
 }
 
-TEST_F(MediaRouterMojoImplTest, PostMessage) {
-  EXPECT_CALL(mock_mojo_media_router_service_,
-              PostMessage(mojo::String(kRouteId), mojo::String(kMessage)));
-  router()->PostMessage(kRouteId, kMessage);
+TEST_F(MediaRouterMojoImplTest, SendRouteMessage) {
+  EXPECT_CALL(
+      mock_mojo_media_router_service_,
+      SendRouteMessage(mojo::String(kRouteId), mojo::String(kMessage), _))
+      .WillOnce(Invoke(
+          [](const MediaRoute::Id& route_id, const std::string& message,
+             const interfaces::MediaRouter::SendRouteMessageCallback& cb) {
+            cb.Run(true);
+          }));
+
+  SendMessageCallbackHandler handler;
+  EXPECT_CALL(handler, Invoke(true));
+  router()->SendRouteMessage(kRouteId, kMessage,
+                             base::Bind(&SendMessageCallbackHandler::Invoke,
+                                        base::Unretained(&handler)));
   ProcessEventLoop();
 }
 
diff --git a/chrome/browser/media/router/media_source_helper.cc b/chrome/browser/media/router/media_source_helper.cc
index 47c717a..a5d1288a 100644
--- a/chrome/browser/media/router/media_source_helper.cc
+++ b/chrome/browser/media/router/media_source_helper.cc
@@ -34,13 +34,13 @@
 }
 
 bool IsMirroringMediaSource(const MediaSource& source) {
-  return StartsWithASCII(source.id(), kDesktopMediaUrn, true) ||
-    StartsWithASCII(source.id(), kTabMediaUrnPrefix, true);
+  return base::StartsWithASCII(source.id(), kDesktopMediaUrn, true) ||
+         base::StartsWithASCII(source.id(), kTabMediaUrnPrefix, true);
 }
 
 bool IsValidMediaSource(const MediaSource& source) {
   if (IsMirroringMediaSource(source) ||
-      StartsWithASCII(source.id(), kCastUrnPrefix, true)) {
+      base::StartsWithASCII(source.id(), kCastUrnPrefix, true)) {
     return true;
   }
   GURL url(source.id());
diff --git a/chrome/browser/media/router/mock_media_router.h b/chrome/browser/media/router/mock_media_router.h
index c093a0e9..9ea22bd 100644
--- a/chrome/browser/media/router/mock_media_router.h
+++ b/chrome/browser/media/router/mock_media_router.h
@@ -28,9 +28,10 @@
                     const MediaSink::Id& sink_id,
                     const MediaRouteResponseCallback& callback));
   MOCK_METHOD1(CloseRoute, void(const MediaRoute::Id& route_id));
-  MOCK_METHOD2(PostMessage,
+  MOCK_METHOD3(SendRouteMessage,
                void(const MediaRoute::Id& route_id,
-                    const std::string& message));
+                    const std::string& message,
+                    const SendRouteMessageCallback& callback));
   MOCK_METHOD1(ClearIssue, void(const Issue::Id& issue_id));
   MOCK_METHOD1(AddIssuesObserver, void(IssuesObserver* observer));
   MOCK_METHOD1(RemoveIssuesObserver, void(IssuesObserver* observer));
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.cc b/chrome/browser/media/router/presentation_service_delegate_impl.cc
index 30b1c8a..a148496 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.cc
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/media/router/media_source_helper.h"
 #include "chrome/browser/media/router/presentation_media_sinks_observer.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
+#include "chrome/browser/ui/webui/media_router/media_router_dialog_controller.h"
 #include "content/public/browser/presentation_screen_availability_listener.h"
 #include "content/public/browser/presentation_session.h"
 #include "content/public/browser/render_frame_host.h"
@@ -43,13 +44,12 @@
   return RenderFrameHostId(render_process_id, render_frame_id);
 }
 
-std::string GetDisplayNameForFrame(RenderFrameHostId render_frame_host_id) {
-  RenderFrameHost* render_view_host = RenderFrameHost::FromID(
+// Gets the last committed URL for the render frame specified by
+// |render_frame_host_id|.
+GURL GetLastCommittedURLForFrame(RenderFrameHostId render_frame_host_id) {
+  RenderFrameHost* render_frame_host = RenderFrameHost::FromID(
       render_frame_host_id.first, render_frame_host_id.second);
-  std::string host = render_view_host->GetLastCommittedURL().host();
-  if (StartsWithASCII(host, "www.", false))
-    host = host.substr(4);
-  return host;
+  return render_frame_host->GetLastCommittedURL();
 }
 
 }  // namespace
@@ -387,7 +387,7 @@
   RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
   frame_manager_->Reset(render_frame_host_id);
   if (IsMainFrame(render_process_id, render_frame_id))
-    UpdateDefaultMediaSourceAndNotifyObservers(MediaSource(), std::string());
+    UpdateDefaultMediaSourceAndNotifyObservers(MediaSource(), GURL());
 }
 
 void PresentationServiceDelegateImpl::SetDefaultPresentationUrl(
@@ -405,10 +405,9 @@
     if (!default_presentation_url.empty())
       default_source = MediaSourceForPresentationUrl(default_presentation_url);
 
-    std::string default_frame_display_name(
-        GetDisplayNameForFrame(render_frame_host_id));
+    GURL default_frame_url = GetLastCommittedURLForFrame(render_frame_host_id);
     UpdateDefaultMediaSourceAndNotifyObservers(default_source,
-                                               default_frame_display_name);
+                                               default_frame_url);
   }
 }
 
@@ -423,15 +422,14 @@
 void PresentationServiceDelegateImpl::
     UpdateDefaultMediaSourceAndNotifyObservers(
         const MediaSource& default_source,
-        const std::string& default_frame_display_name) {
+        const GURL& default_frame_url) {
   if (!default_source.Equals(default_source_) ||
-      default_frame_display_name != default_frame_display_name_) {
+      default_frame_url != default_frame_url_) {
     default_source_ = default_source;
-    default_frame_display_name_ = default_frame_display_name;
-    FOR_EACH_OBSERVER(DefaultMediaSourceObserver,
-                      default_media_source_observers_,
-                      OnDefaultMediaSourceChanged(default_source_,
-                                                  default_frame_display_name_));
+    default_frame_url_ = default_frame_url;
+    FOR_EACH_OBSERVER(
+        DefaultMediaSourceObserver, default_media_source_observers_,
+        OnDefaultMediaSourceChanged(default_source_, default_frame_url_));
   }
 }
 
@@ -442,8 +440,36 @@
     const std::string& presentation_id,
     const PresentationSessionSuccessCallback& success_cb,
     const PresentationSessionErrorCallback& error_cb) {
-  // BUG=464205
-  NOTIMPLEMENTED();
+  if (presentation_url.empty() || !IsValidPresentationUrl(presentation_url)) {
+    error_cb.Run(content::PresentationError(content::PRESENTATION_ERROR_UNKNOWN,
+                                            "Invalid presentation arguments."));
+    return;
+  }
+  RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id);
+  std::string final_presentation_id =
+      presentation_id.empty()
+          ? frame_manager_->GetDefaultPresentationId(render_frame_host_id)
+          : presentation_id;
+  if (final_presentation_id.empty())
+    // TODO(imcheng): Remove presentation_id argument entirely if required
+    // by Presentation API spec.
+    final_presentation_id = base::GenerateGUID();
+  scoped_ptr<CreateSessionRequest> context(new CreateSessionRequest(
+      presentation_url, final_presentation_id,
+      GetLastCommittedURLForFrame(render_frame_host_id), success_cb, error_cb));
+  // NOTE: Currently this request is ignored if a dialog is already open, e.g.
+  // via browser action. In practice, this should rarely happen, but log
+  // an error message in case it does.
+  MediaRouterDialogController::CreateForWebContents(web_contents_);
+  MediaRouterDialogController* controller =
+      MediaRouterDialogController::FromWebContents(web_contents_);
+
+  if (!controller->ShowMediaRouterDialogForPresentation(context.Pass())) {
+    LOG(ERROR) << "Media router dialog already exists. Ignoring StartSession.";
+    error_cb.Run(content::PresentationError(content::PRESENTATION_ERROR_UNKNOWN,
+                                            "Unable to create dialog."));
+    return;
+  }
 }
 
 void PresentationServiceDelegateImpl::JoinSession(
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.h b/chrome/browser/media/router/presentation_service_delegate_impl.h
index 43d34c00..f3bd53f 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.h
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.h
@@ -106,6 +106,9 @@
   // Returns an empty MediaSource otherwise.
   MediaSource default_source() const { return default_source_; }
 
+  content::WebContents* web_contents() const { return web_contents_; }
+  const GURL& default_frame_url() const { return default_frame_url_; }
+
   // Observer interface for listening to default MediaSource changes for the
   // WebContents.
   class DefaultMediaSourceObserver {
@@ -115,11 +118,11 @@
     // Called when default media source for the corresponding WebContents has
     // changed.
     // |source|: New default MediaSource, or empty if default was removed.
-    // |frame_display_name|: Display Name of the frame that contains the default
-    // media source, or empty if there is no default media source.
+    // |frame_url|: URL of the frame that contains the default
+    //     media source, or empty if there is no default media source.
     virtual void OnDefaultMediaSourceChanged(
         const MediaSource& source,
-        const std::string& frame_display_name) = 0;
+        const GURL& frame_url) = 0;
   };
 
   // Adds / removes an observer for listening to default MediaSource changes.
@@ -153,10 +156,10 @@
   // changed, notify the observers.
   void UpdateDefaultMediaSourceAndNotifyObservers(
       const MediaSource& new_default_source,
-      const std::string& new_default_source_host);
+      const GURL& new_default_frame_url);
 
   MediaSource default_source_;
-  std::string default_frame_display_name_;
+  GURL default_frame_url_;
 
   // References to the observers listening for changes to default media source.
   base::ObserverList<
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc b/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc
index 1a11b80..4011f41 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc
+++ b/chrome/browser/media/router/presentation_service_delegate_impl_unittest.cc
@@ -40,7 +40,7 @@
     : public PresentationServiceDelegateImpl::DefaultMediaSourceObserver {
  public:
   MOCK_METHOD2(OnDefaultMediaSourceChanged,
-               void(const MediaSource&, const std::string&));
+               void(const MediaSource&, const GURL&));
 };
 
 class PresentationServiceDelegateImplTest
@@ -158,10 +158,10 @@
   std::string url1("http://foo");
   EXPECT_CALL(observer1, OnDefaultMediaSourceChanged(
                              Equals(MediaSourceForPresentationUrl(url1)),
-                             "google.com")).Times(1);
+                             GURL("http://www.google.com"))).Times(1);
   EXPECT_CALL(observer2, OnDefaultMediaSourceChanged(
                              Equals(MediaSourceForPresentationUrl(url1)),
-                             "google.com")).Times(1);
+                             GURL("http://www.google.com"))).Times(1);
   delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id, url1,
                                             "defaultPresentationId");
 
@@ -172,14 +172,15 @@
   std::string url2("http://youtube.com");
   EXPECT_CALL(observer1, OnDefaultMediaSourceChanged(
                              Equals(MediaSourceForPresentationUrl(url2)),
-                             "google.com")).Times(1);
+                             GURL("http://www.google.com"))).Times(1);
   delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id, url2,
                                             "defaultPresentationId");
 
   EXPECT_TRUE(Mock::VerifyAndClearExpectations(&observer1));
   // Remove default presentation URL.
-  EXPECT_CALL(observer1, OnDefaultMediaSourceChanged(Equals(MediaSource()),
-                                                     "google.com")).Times(1);
+  EXPECT_CALL(observer1, OnDefaultMediaSourceChanged(
+                             Equals(MediaSource()),
+                             GURL("http://www.google.com"))).Times(1);
   delegate_impl_->SetDefaultPresentationUrl(render_process_id, routing_id, "",
                                             "");
 }
diff --git a/chrome/browser/media/router/test_helper.h b/chrome/browser/media/router/test_helper.h
index f7cca19..fd00424 100644
--- a/chrome/browser/media/router/test_helper.h
+++ b/chrome/browser/media/router/test_helper.h
@@ -48,9 +48,10 @@
   MOCK_METHOD1(CloseRoute, void(const mojo::String& route_id));
   MOCK_METHOD1(StartObservingMediaSinks, void(const mojo::String& source));
   MOCK_METHOD1(StopObservingMediaSinks, void(const mojo::String& source));
-  MOCK_METHOD2(PostMessage,
+  MOCK_METHOD3(SendRouteMessage,
                void(const mojo::String& media_route_id,
-                    const mojo::String& message));
+                    const mojo::String& message,
+                    const SendRouteMessageCallback& callback));
   MOCK_METHOD1(ClearIssue, void(const mojo::String& issue_id));
   MOCK_METHOD0(StartObservingMediaRoutes, void());
   MOCK_METHOD0(StopObservingMediaRoutes, void());
diff --git a/chrome/browser/media/tab_capture_access_handler.cc b/chrome/browser/media/tab_capture_access_handler.cc
new file mode 100644
index 0000000..d0cc06a
--- /dev/null
+++ b/chrome/browser/media/tab_capture_access_handler.cc
@@ -0,0 +1,82 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media/tab_capture_access_handler.h"
+
+#include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
+#include "chrome/browser/media/media_capture_devices_dispatcher.h"
+#include "chrome/browser/media/media_stream_capture_indicator.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/common/permissions/permissions_data.h"
+
+TabCaptureAccessHandler::TabCaptureAccessHandler() {
+}
+
+TabCaptureAccessHandler::~TabCaptureAccessHandler() {
+}
+
+bool TabCaptureAccessHandler::SupportsStreamType(
+    const content::MediaStreamType type,
+    const extensions::Extension* extension) {
+  return type == content::MEDIA_TAB_VIDEO_CAPTURE ||
+         type == content::MEDIA_TAB_AUDIO_CAPTURE;
+}
+
+bool TabCaptureAccessHandler::CheckMediaAccessPermission(
+    content::WebContents* web_contents,
+    const GURL& security_origin,
+    content::MediaStreamType type,
+    const extensions::Extension* extension) {
+  return false;
+}
+
+void TabCaptureAccessHandler::HandleRequest(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    const content::MediaResponseCallback& callback,
+    const extensions::Extension* extension) {
+  content::MediaStreamDevices devices;
+  scoped_ptr<content::MediaStreamUI> ui;
+
+  if (!extension)
+    callback.Run(devices, content::MEDIA_DEVICE_TAB_CAPTURE_FAILURE, ui.Pass());
+
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  extensions::TabCaptureRegistry* tab_capture_registry =
+      extensions::TabCaptureRegistry::Get(profile);
+  if (!tab_capture_registry) {
+    NOTREACHED();
+    callback.Run(devices, content::MEDIA_DEVICE_INVALID_STATE, ui.Pass());
+    return;
+  }
+  const bool tab_capture_allowed = tab_capture_registry->VerifyRequest(
+      request.render_process_id, request.render_frame_id, extension->id());
+
+  if (request.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE &&
+      tab_capture_allowed &&
+      extension->permissions_data()->HasAPIPermission(
+          extensions::APIPermission::kTabCapture)) {
+    devices.push_back(content::MediaStreamDevice(
+        content::MEDIA_TAB_AUDIO_CAPTURE, std::string(), std::string()));
+  }
+
+  if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE &&
+      tab_capture_allowed &&
+      extension->permissions_data()->HasAPIPermission(
+          extensions::APIPermission::kTabCapture)) {
+    devices.push_back(content::MediaStreamDevice(
+        content::MEDIA_TAB_VIDEO_CAPTURE, std::string(), std::string()));
+  }
+
+  if (!devices.empty()) {
+    ui = MediaCaptureDevicesDispatcher::GetInstance()
+             ->GetMediaStreamCaptureIndicator()
+             ->RegisterMediaStream(web_contents, devices);
+  }
+  callback.Run(devices, devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE
+                                        : content::MEDIA_DEVICE_OK,
+               ui.Pass());
+}
diff --git a/chrome/browser/media/tab_capture_access_handler.h b/chrome/browser/media/tab_capture_access_handler.h
new file mode 100644
index 0000000..8c526a7
--- /dev/null
+++ b/chrome/browser/media/tab_capture_access_handler.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_TAB_CAPTURE_ACCESS_HANDLER_H_
+#define CHROME_BROWSER_MEDIA_TAB_CAPTURE_ACCESS_HANDLER_H_
+
+#include "chrome/browser/media/media_access_handler.h"
+
+class MediaStreamCaptureIndicator;
+
+// MediaAccessHandler for TabCapture API.
+class TabCaptureAccessHandler : public MediaAccessHandler {
+ public:
+  TabCaptureAccessHandler();
+  ~TabCaptureAccessHandler() override;
+
+  // MediaAccessHandler implementation.
+  bool SupportsStreamType(const content::MediaStreamType type,
+                          const extensions::Extension* extension) override;
+  bool CheckMediaAccessPermission(
+      content::WebContents* web_contents,
+      const GURL& security_origin,
+      content::MediaStreamType type,
+      const extensions::Extension* extension) override;
+  void HandleRequest(content::WebContents* web_contents,
+                     const content::MediaStreamRequest& request,
+                     const content::MediaResponseCallback& callback,
+                     const extensions::Extension* extension) override;
+};
+
+#endif  // CHROME_BROWSER_MEDIA_TAB_CAPTURE_ACCESS_HANDLER_H_
diff --git a/chrome/browser/media/webrtc_browsertest_base.cc b/chrome/browser/media/webrtc_browsertest_base.cc
index 2953503..20241c2 100644
--- a/chrome/browser/media/webrtc_browsertest_base.cc
+++ b/chrome/browser/media/webrtc_browsertest_base.cc
@@ -7,18 +7,15 @@
 #include "base/lazy_instance.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/infobars/infobar_responder.h"
 #include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/media/media_stream_infobar_delegate.h"
 #include "chrome/browser/media/webrtc_browsertest_common.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/website_settings/mock_permission_bubble_view.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/infobars/core/infobar.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
@@ -112,30 +109,22 @@
 bool WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndAccept(
     content::WebContents* tab_contents,
     const std::string& constraints) const {
+  std::string result;
   if (PermissionBubbleManager::Enabled()) {
-    scoped_ptr<MockPermissionBubbleView> mock_bubble_view(
-        new MockPermissionBubbleView());
     PermissionBubbleManager::FromWebContents(tab_contents)
-        ->SetView(mock_bubble_view.get());
-    mock_bubble_view->SetBrowserTest(true);
+        ->set_auto_response_for_test(PermissionBubbleManager::ACCEPT_ALL);
     GetUserMedia(tab_contents, constraints);
-    if (!mock_bubble_view->IsVisible())
-      content::RunMessageLoop();
-    mock_bubble_view->Accept();
-    // Wait for WebRTC to call the success callback, then remove the view.
-    const bool result = test::PollingWaitUntil("obtainGetUserMediaResult()",
-                                               kOkGotStream, tab_contents);
-    PermissionBubbleManager::FromWebContents(tab_contents)->SetView(NULL);
-    return result;
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
   } else {
-    infobars::InfoBar* infobar =
-        GetUserMediaAndWaitForInfoBar(tab_contents, constraints);
-    infobar->delegate()->AsConfirmInfoBarDelegate()->Accept();
-    CloseInfoBarInTab(tab_contents, infobar);
-    // Wait for WebRTC to call the success callback.
-    return test::PollingWaitUntil("obtainGetUserMediaResult()", kOkGotStream,
-                                  tab_contents);
+    InfoBarResponder infobar_accept_responder(
+        InfoBarService::FromWebContents(tab_contents),
+        InfoBarResponder::ACCEPT);
+    GetUserMedia(tab_contents, constraints);
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
   }
+  return kOkGotStream == result;
 }
 
 void WebRtcTestBase::GetUserMediaAndDeny(content::WebContents* tab_contents) {
@@ -146,87 +135,53 @@
 void WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndDeny(
     content::WebContents* tab_contents,
     const std::string& constraints) const {
+  std::string result;
   if (PermissionBubbleManager::Enabled()) {
-    scoped_ptr<MockPermissionBubbleView> mock_bubble_view(
-        new MockPermissionBubbleView());
     PermissionBubbleManager::FromWebContents(tab_contents)
-        ->SetView(mock_bubble_view.get());
-    mock_bubble_view->SetBrowserTest(true);
+        ->set_auto_response_for_test(PermissionBubbleManager::DENY_ALL);
     GetUserMedia(tab_contents, constraints);
-    if (!mock_bubble_view->IsVisible())
-      content::RunMessageLoop();
-    mock_bubble_view->Deny();
-    // Wait for WebRTC to call the fail callback, then remove the view.
-    EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()",
-                                       kFailedWithPermissionDeniedError,
-                                       tab_contents));
-    PermissionBubbleManager::FromWebContents(tab_contents)->SetView(NULL);
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
   } else {
-    infobars::InfoBar* infobar =
-        GetUserMediaAndWaitForInfoBar(tab_contents, constraints);
-    infobar->delegate()->AsConfirmInfoBarDelegate()->Cancel();
-    CloseInfoBarInTab(tab_contents, infobar);
-    // Wait for WebRTC to call the fail callback.
-    EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()",
-                                       kFailedWithPermissionDeniedError,
-                                       tab_contents));
+    InfoBarResponder infobar_deny_responder(
+        InfoBarService::FromWebContents(tab_contents), InfoBarResponder::DENY);
+    GetUserMedia(tab_contents, constraints);
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
   }
+  EXPECT_EQ(kFailedWithPermissionDeniedError, result);
 }
 
 void WebRtcTestBase::GetUserMediaAndDismiss(
     content::WebContents* tab_contents) const {
+  std::string result;
   if (PermissionBubbleManager::Enabled()) {
-    scoped_ptr<MockPermissionBubbleView> mock_bubble_view(
-        new MockPermissionBubbleView());
     PermissionBubbleManager::FromWebContents(tab_contents)
-        ->SetView(mock_bubble_view.get());
-    mock_bubble_view->SetBrowserTest(true);
+        ->set_auto_response_for_test(PermissionBubbleManager::DISMISS);
     GetUserMedia(tab_contents, kAudioVideoCallConstraints);
-    if (!mock_bubble_view->IsVisible())
-      content::RunMessageLoop();
-    mock_bubble_view->Close();
     // A dismiss should be treated like a deny.
-    EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()",
-                                       kFailedWithPermissionDismissedError,
-                                       tab_contents));
-    PermissionBubbleManager::FromWebContents(tab_contents)->SetView(NULL);
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
   } else {
-    infobars::InfoBar* infobar =
-        GetUserMediaAndWaitForInfoBar(tab_contents, kAudioVideoCallConstraints);
-    infobar->delegate()->InfoBarDismissed();
-    CloseInfoBarInTab(tab_contents, infobar);
+    InfoBarResponder infobar_dismiss_responder(
+        InfoBarService::FromWebContents(tab_contents),
+        InfoBarResponder::DISMISS);
+    GetUserMedia(tab_contents, kAudioVideoCallConstraints);
     // A dismiss should be treated like a deny.
-    EXPECT_TRUE(test::PollingWaitUntil("obtainGetUserMediaResult()",
-                                       kFailedWithPermissionDismissedError,
-                                       tab_contents));
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result));
   }
+  EXPECT_EQ(kFailedWithPermissionDismissedError, result);
 }
 
 void WebRtcTestBase::GetUserMedia(content::WebContents* tab_contents,
                                   const std::string& constraints) const {
-  // Request user media: this will launch the media stream info bar.
+  // Request user media: this will launch the media stream info bar or bubble.
   std::string result;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
       tab_contents, "doGetUserMedia(" + constraints + ");", &result));
-  EXPECT_EQ("ok-requested", result);
-}
-
-infobars::InfoBar* WebRtcTestBase::GetUserMediaAndWaitForInfoBar(
-    content::WebContents* tab_contents,
-    const std::string& constraints) const {
-  content::WindowedNotificationObserver infobar_added(
-      chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
-      content::NotificationService::AllSources());
-
-  // Request user media: this will launch the media stream info bar.
-  GetUserMedia(tab_contents, constraints);
-
-  // Wait for the bar to pop up, then return it.
-  infobar_added.Wait();
-  content::Details<infobars::InfoBar::AddedDetails> details(
-      infobar_added.details());
-  EXPECT_TRUE(details->delegate()->AsMediaStreamInfoBarDelegate());
-  return details.ptr();
+  EXPECT_TRUE(result == "request-callback-denied" ||
+              result == "request-callback-granted");
 }
 
 content::WebContents* WebRtcTestBase::OpenPageAndGetUserMediaInNewTab(
@@ -254,55 +209,6 @@
       embedded_test_server()->GetURL(test_page));
 }
 
-content::WebContents* WebRtcTestBase::OpenPageAndAcceptUserMedia(
-    const GURL& url) const {
-  content::WebContents* tab_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  if (PermissionBubbleManager::Enabled()) {
-    scoped_ptr<MockPermissionBubbleView> mock_bubble_view(
-        new MockPermissionBubbleView());
-    PermissionBubbleManager::FromWebContents(tab_contents)
-        ->SetView(mock_bubble_view.get());
-    mock_bubble_view->SetBrowserTest(true);
-    ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(browser(), url,
-                                                              1);
-    if (!mock_bubble_view->IsVisible())
-      content::RunMessageLoop();
-    mock_bubble_view->Accept();
-    // Wait to make sure the callback is fired before deleting the bubble view.
-    test::PollingWaitUntil("obtainGetUserMediaResult()", kOkGotStream,
-                           tab_contents);
-    PermissionBubbleManager::FromWebContents(tab_contents)->SetView(NULL);
-  } else {
-    content::WindowedNotificationObserver nav(
-        chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
-        content::NotificationService::AllSources());
-    ui_test_utils::NavigateToURL(browser(), url);
-    nav.Wait();
-
-    content::Details<infobars::InfoBar::AddedDetails> details(nav.details());
-    infobars::InfoBar* infobar = details.ptr();
-    EXPECT_TRUE(infobar);
-    infobar->delegate()->AsMediaStreamInfoBarDelegate()->Accept();
-
-    CloseInfoBarInTab(tab_contents, infobar);
-  }
-  return tab_contents;
-}
-
-void WebRtcTestBase::CloseInfoBarInTab(content::WebContents* tab_contents,
-                                       infobars::InfoBar* infobar) const {
-  content::WindowedNotificationObserver infobar_removed(
-      chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
-      content::NotificationService::AllSources());
-
-  InfoBarService* infobar_service =
-      InfoBarService::FromWebContents(tab_contents);
-  infobar_service->RemoveInfoBar(infobar);
-
-  infobar_removed.Wait();
-}
-
 void WebRtcTestBase::CloseLastLocalStream(
     content::WebContents* tab_contents) const {
   EXPECT_EQ("ok-stopped",
@@ -416,7 +322,7 @@
   std::string javascript =
       base::StringPrintf("getStreamSize('%s')", video_element.c_str());
   std::string result = ExecuteJavascript(javascript, tab_contents);
-  EXPECT_TRUE(StartsWithASCII(result, "ok-", true));
+  EXPECT_TRUE(base::StartsWithASCII(result, "ok-", true));
   return result.substr(3);
 }
 
diff --git a/chrome/browser/media/webrtc_browsertest_common.cc b/chrome/browser/media/webrtc_browsertest_common.cc
index 635b818..61f967e 100644
--- a/chrome/browser/media/webrtc_browsertest_common.cc
+++ b/chrome/browser/media/webrtc_browsertest_common.cc
@@ -40,7 +40,7 @@
 const int kDefaultPollIntervalMsec = 250;
 
 bool IsErrorResult(const std::string& result) {
-  return StartsWithASCII(result, "failed-", false);
+  return base::StartsWithASCII(result, "failed-", false);
 }
 
 base::FilePath GetReferenceFilesDir() {
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc b/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
index b7f629c0..5c65f96 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
@@ -91,9 +91,8 @@
         MediaFileSystemBackend::ConstructMountName(
             profile->GetPath(), storage_domain, kInvalidMediaGalleryPrefId);
     MediaGalleryPrefId pref_id = kInvalidMediaGalleryPrefId;
-    if (extension &&
-        extension->id() == storage_domain &&
-        StartsWithASCII(mount_point, expected_mount_prefix, true) &&
+    if (extension && extension->id() == storage_domain &&
+        base::StartsWithASCII(mount_point, expected_mount_prefix, true) &&
         base::StringToUint64(mount_point.substr(expected_mount_prefix.size()),
                              &pref_id) &&
         pref_id != kInvalidMediaGalleryPrefId) {
@@ -197,7 +196,7 @@
   if (components.empty())
     return false;
   std::string mount_point = base::FilePath(components[0]).AsUTF8Unsafe();
-  if (!StartsWithASCII(mount_point, kMediaGalleryMountPrefix, true))
+  if (!base::StartsWithASCII(mount_point, kMediaGalleryMountPrefix, true))
     return false;
 
   const content::ResourceRequestInfo* request_info =
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util.cc b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
index 79dc4f0d..87acf8c 100644
--- a/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
@@ -37,9 +37,9 @@
   if (!net::SniffMimeTypeFromLocalData(buf, length, &mime_type))
     return base::File::FILE_ERROR_SECURITY;
 
-  if (StartsWithASCII(mime_type, "image/", true) ||
-      StartsWithASCII(mime_type, "audio/", true) ||
-      StartsWithASCII(mime_type, "video/", true) ||
+  if (base::StartsWithASCII(mime_type, "image/", true) ||
+      base::StartsWithASCII(mime_type, "audio/", true) ||
+      base::StartsWithASCII(mime_type, "video/", true) ||
       mime_type == "application/x-shockwave-flash") {
     return base::File::FILE_OK;
   }
diff --git a/chrome/browser/media_galleries/media_folder_finder.cc b/chrome/browser/media_galleries/media_folder_finder.cc
index 1d72012..b80b1bfd 100644
--- a/chrome/browser/media_galleries/media_folder_finder.cc
+++ b/chrome/browser/media_galleries/media_folder_finder.cc
@@ -98,8 +98,8 @@
   return mount_point.IsParent(path);
 #elif defined(OS_LINUX)
   // /media and /mnt are likely the only places with interesting mount points.
-  if (StartsWithASCII(path.value(), "/media", true) ||
-      StartsWithASCII(path.value(), "/mnt", true)) {
+  if (base::StartsWithASCII(path.value(), "/media", true) ||
+      base::StartsWithASCII(path.value(), "/mnt", true)) {
     return false;
   }
   return true;
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc
index 784cd21..c6a7e7c 100644
--- a/chrome/browser/memory_details.cc
+++ b/chrome/browser/memory_details.cc
@@ -343,11 +343,13 @@
       const NavigationEntry* last_committed_entry =
           contents->GetController().GetLastCommittedEntry();
       if ((last_committed_entry &&
-           LowerCaseEqualsASCII(last_committed_entry->GetVirtualURL().spec(),
-                                chrome::kChromeUIMemoryURL)) ||
+           base::LowerCaseEqualsASCII(
+               last_committed_entry->GetVirtualURL().spec(),
+               chrome::kChromeUIMemoryURL)) ||
           (pending_entry &&
-           LowerCaseEqualsASCII(pending_entry->GetVirtualURL().spec(),
-                                chrome::kChromeUIMemoryURL))) {
+           base::LowerCaseEqualsASCII(
+               pending_entry->GetVirtualURL().spec(),
+               chrome::kChromeUIMemoryURL))) {
         process.is_diagnostics = true;
       }
     }
diff --git a/chrome/browser/metrics/omnibox_metrics_provider.cc b/chrome/browser/metrics/omnibox_metrics_provider.cc
index 6fc3589..ca2f466 100644
--- a/chrome/browser/metrics/omnibox_metrics_provider.cc
+++ b/chrome/browser/metrics/omnibox_metrics_provider.cc
@@ -144,13 +144,8 @@
   // (as explained in omnibox_event.proto) even if it was not, because such
   // actions ignore the contents of the popup so it doesn't matter that it was
   // open.
-  const bool consider_popup_open = log.is_popup_open && !log.is_paste_and_go;
-  omnibox_event->set_is_popup_open(consider_popup_open);
+  omnibox_event->set_is_popup_open(log.is_popup_open && !log.is_paste_and_go);
   omnibox_event->set_is_paste_and_go(log.is_paste_and_go);
-  if (consider_popup_open) {
-    omnibox_event->set_is_top_result_hidden_in_dropdown(
-        log.result.ShouldHideTopMatch());
-  }
 
   for (AutocompleteResult::const_iterator i(log.result.begin());
        i != log.result.end(); ++i) {
diff --git a/chrome/browser/metrics/variations/variations_service_unittest.cc b/chrome/browser/metrics/variations/variations_service_unittest.cc
index 1b98cd16..17415729 100644
--- a/chrome/browser/metrics/variations/variations_service_unittest.cc
+++ b/chrome/browser/metrics/variations/variations_service_unittest.cc
@@ -243,18 +243,18 @@
 
   std::string value;
   GURL url = VariationsService::GetVariationsServerURL(prefs, std::string());
-  EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
+  EXPECT_TRUE(base::StartsWithASCII(url.spec(), default_variations_url, true));
   EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
 
   prefs_store.SetVariationsRestrictParameterPolicyValue("restricted");
   url = VariationsService::GetVariationsServerURL(prefs, std::string());
-  EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
+  EXPECT_TRUE(base::StartsWithASCII(url.spec(), default_variations_url, true));
   EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
   EXPECT_EQ("restricted", value);
 
   // The override value should take precedence over what's in prefs.
   url = VariationsService::GetVariationsServerURL(prefs, "override");
-  EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
+  EXPECT_TRUE(base::StartsWithASCII(url.spec(), default_variations_url, true));
   EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
   EXPECT_EQ("override", value);
 }
diff --git a/chrome/browser/net/async_dns_field_trial.cc b/chrome/browser/net/async_dns_field_trial.cc
index 7e98d13..ab4f704f 100644
--- a/chrome/browser/net/async_dns_field_trial.cc
+++ b/chrome/browser/net/async_dns_field_trial.cc
@@ -79,8 +79,8 @@
   // otherwise (trial absent): return default.
   std::string group_name = base::FieldTrialList::FindFullName("AsyncDns");
   if (!group_name.empty()) {
-    const bool enabled = StartsWithASCII(
-        group_name, "AsyncDns", false /* case_sensitive */);
+    const bool enabled = base::StartsWithASCII(group_name, "AsyncDns",
+                                               false /* case_sensitive */);
     HistogramPrefDefaultSource(FIELD_TRIAL, enabled);
     return enabled;
   }
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 4953a72..50f83bb 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -187,7 +187,7 @@
   for (size_t i = 0; i < arraysize(kEligibleMasks); i++) {
     const char *prefix = kEligibleMasks[i].prefix;
     const char *suffix = kEligibleMasks[i].suffix;
-    if (prefix && !StartsWithASCII(mime_type, prefix, kCaseSensitive))
+    if (prefix && !base::StartsWithASCII(mime_type, prefix, kCaseSensitive))
       continue;
     if (suffix && !EndsWith(mime_type, suffix, kCaseSensitive))
       continue;
diff --git a/chrome/browser/net/firefox_proxy_settings.cc b/chrome/browser/net/firefox_proxy_settings.cc
index 7b135b9f..39dd5f1 100644
--- a/chrome/browser/net/firefox_proxy_settings.cc
+++ b/chrome/browser/net/firefox_proxy_settings.cc
@@ -106,8 +106,8 @@
                                     stop_value - start_value - 1);
     base::TrimWhitespace(value, base::TRIM_ALL, &value);
     // Value could be a boolean.
-    bool is_value_true = LowerCaseEqualsASCII(value, "true");
-    if (is_value_true || LowerCaseEqualsASCII(value, "false")) {
+    bool is_value_true = base::LowerCaseEqualsASCII(value, "true");
+    if (is_value_true || base::LowerCaseEqualsASCII(value, "false")) {
       prefs->SetBoolean(key, is_value_true);
       continue;
     }
diff --git a/chrome/browser/net/proxy_browsertest.cc b/chrome/browser/net/proxy_browsertest.cc
index e777249..5ffd0f7ed 100644
--- a/chrome/browser/net/proxy_browsertest.cc
+++ b/chrome/browser/net/proxy_browsertest.cc
@@ -136,7 +136,7 @@
                                    .ReplaceComponents(replacements));
 
   const base::string16 result = watcher.WaitAndGetTitle();
-  EXPECT_TRUE(EqualsASCII(result, "PASS"));
+  EXPECT_TRUE(base::EqualsASCII(result, "PASS"));
   EXPECT_TRUE(observer.auth_handled());
 }
 
diff --git a/chrome/browser/net/safe_search_util.cc b/chrome/browser/net/safe_search_util.cc
index 29f095d..86862cd 100644
--- a/chrome/browser/net/safe_search_util.cc
+++ b/chrome/browser/net/safe_search_util.cc
@@ -38,7 +38,7 @@
   // Prefix for "foo=bar" is "foo=".
   std::string parameter_prefix = second_parameter.substr(
       0, second_parameter.find("=") + 1);
-  return StartsWithASCII(first_parameter, parameter_prefix, false);
+  return base::StartsWithASCII(first_parameter, parameter_prefix, false);
 }
 
 // Examines the query string containing parameters and adds the necessary ones
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
index 80404d9..7a639fa 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
@@ -67,7 +67,7 @@
   DCHECK(pac_script);
   const std::string kPacURLPrefix =
       "data:application/x-ns-proxy-autoconfig;base64,";
-  return StartsWithASCII(pac_url, kPacURLPrefix, true) &&
+  return base::StartsWithASCII(pac_url, kPacURLPrefix, true) &&
          base::Base64Decode(pac_url.substr(kPacURLPrefix.size()), pac_script);
 }
 
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
index d3f7461..ea07712 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
@@ -76,6 +76,11 @@
   return Settings()->IsDataReductionProxyManaged();
 }
 
+void DataReductionProxySettingsAndroid::IncrementLoFiUserRequestsForImages(
+    JNIEnv* env, jobject obj) {
+  Settings()->IncrementLoFiUserRequestsForImages();
+}
+
 void DataReductionProxySettingsAndroid::SetDataReductionProxyEnabled(
     JNIEnv* env,
     jobject obj,
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
index 439c3a49..8dfcf06 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
@@ -43,6 +43,7 @@
   jboolean WasLoFiShowImageRequestedBefore(JNIEnv* env, jobject obj);
   void SetLoFiShowImageRequested(JNIEnv* env, jobject obj);
   jboolean IsDataReductionProxyManaged(JNIEnv* env, jobject obj);
+  void IncrementLoFiUserRequestsForImages(JNIEnv* env, jobject obj);
   void SetDataReductionProxyEnabled(JNIEnv* env, jobject obj, jboolean enabled);
 
   jlong GetDataReductionLastUpdateTime(JNIEnv* env, jobject obj);
diff --git a/chrome/browser/net/websocket_browsertest.cc b/chrome/browser/net/websocket_browsertest.cc
index ed1fa0b9..a226f8d 100644
--- a/chrome/browser/net/websocket_browsertest.cc
+++ b/chrome/browser/net/websocket_browsertest.cc
@@ -185,7 +185,7 @@
     connected_title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("CLOSED"));
     NavigateToHTTP("counted_connection.html");
     const base::string16 result = connected_title_watcher.WaitAndGetTitle();
-    EXPECT_TRUE(EqualsASCII(result, "CONNECTED"));
+    EXPECT_TRUE(base::EqualsASCII(result, "CONNECTED"));
 
     content::WebContentsDestroyedWatcher destroyed_watcher(new_tab);
     browser()->tab_strip_model()->CloseWebContentsAt(1, 0);
@@ -325,7 +325,7 @@
   ui_test_utils::NavigateToURL(
       browser(), https_server.GetURL("files/websocket/set-hsts.html"));
   const base::string16 result = title_watcher.WaitAndGetTitle();
-  EXPECT_TRUE(EqualsASCII(result, "SET"));
+  EXPECT_TRUE(base::EqualsASCII(result, "SET"));
 
   // Verify that it applies to WebSockets.
   ASSERT_TRUE(wss_server.BlockUntilStarted());
diff --git a/chrome/browser/notifications/platform_notification_service_browsertest.cc b/chrome/browser/notifications/platform_notification_service_browsertest.cc
index 587f545f1..631670f 100644
--- a/chrome/browser/notifications/platform_notification_service_browsertest.cc
+++ b/chrome/browser/notifications/platform_notification_service_browsertest.cc
@@ -158,7 +158,8 @@
                        DisplayPersistentNotificationWithoutPermission) {
   std::string script_result;
 
-  InfoBarResponder cancelling_responder(GetInfoBarService(), false);
+  InfoBarResponder cancelling_responder(GetInfoBarService(),
+                                        InfoBarResponder::DENY);
   ASSERT_TRUE(RunScript("RequestPermission()", &script_result));
   EXPECT_EQ("denied", script_result);
 
@@ -174,7 +175,8 @@
                        DisplayPersistentNotificationWithPermission) {
   std::string script_result;
 
-  InfoBarResponder accepting_responder(GetInfoBarService(), true);
+  InfoBarResponder accepting_responder(GetInfoBarService(),
+                                       InfoBarResponder::ACCEPT);
   ASSERT_TRUE(RunScript("RequestPermission()", &script_result));
   EXPECT_EQ("granted", script_result);
 
@@ -199,7 +201,8 @@
 
   // TODO(peter): It doesn't add much value if we use the InfoBarResponder for
   // each test. Rather, we should just toggle the content setting.
-  InfoBarResponder accepting_responder(GetInfoBarService(), true);
+  InfoBarResponder accepting_responder(GetInfoBarService(),
+                                       InfoBarResponder::ACCEPT);
   ASSERT_TRUE(RunScript("RequestPermission()", &script_result));
   EXPECT_EQ("granted", script_result);
 
@@ -225,7 +228,8 @@
                        WebNotificationOptionsVibrationPattern) {
   std::string script_result;
 
-  InfoBarResponder accepting_responder(GetInfoBarService(), true);
+  InfoBarResponder accepting_responder(GetInfoBarService(),
+                                       InfoBarResponder::ACCEPT);
   ASSERT_TRUE(RunScript("RequestPermission()", &script_result));
   EXPECT_EQ("granted", script_result);
 
@@ -247,7 +251,8 @@
                        CloseDisplayedPersistentNotification) {
   std::string script_result;
 
-  InfoBarResponder accepting_responder(GetInfoBarService(), true);
+  InfoBarResponder accepting_responder(GetInfoBarService(),
+                                       InfoBarResponder::ACCEPT);
   ASSERT_TRUE(RunScript("RequestPermission()", &script_result));
   EXPECT_EQ("granted", script_result);
 
@@ -271,7 +276,8 @@
   std::string script_result;
 
   // Creates a simple notification.
-  InfoBarResponder accepting_responder(GetInfoBarService(), true);
+  InfoBarResponder accepting_responder(GetInfoBarService(),
+                                       InfoBarResponder::ACCEPT);
   ASSERT_TRUE(RunScript("RequestPermission()", &script_result));
   ASSERT_EQ("granted", script_result);
   ASSERT_TRUE(RunScript("DisplayPersistentNotification()", &script_result));
@@ -293,7 +299,8 @@
   // See crbug.com/402191.
   std::string script_result;
 
-  InfoBarResponder accepting_responder_web(GetInfoBarService(), true);
+  InfoBarResponder accepting_responder_web(GetInfoBarService(),
+                                           InfoBarResponder::ACCEPT);
 
   DesktopNotificationService* notification_service =
       DesktopNotificationServiceFactory::GetForProfile(browser()->profile());
@@ -315,7 +322,8 @@
   message_center::NotifierId file_notifier(file_url);
   EXPECT_FALSE(notification_service->IsNotifierEnabled(file_notifier));
 
-  InfoBarResponder accepting_responder_file(GetInfoBarService(), true);
+  InfoBarResponder accepting_responder_file(GetInfoBarService(),
+                                            InfoBarResponder::ACCEPT);
   ASSERT_TRUE(RunScript("RequestPermission()", &script_result));
   EXPECT_EQ("granted", script_result);
 
diff --git a/chrome/browser/password_manager/mock_password_store_service.cc b/chrome/browser/password_manager/mock_password_store_service.cc
index f3acb90..e33ea04 100644
--- a/chrome/browser/password_manager/mock_password_store_service.cc
+++ b/chrome/browser/password_manager/mock_password_store_service.cc
@@ -7,13 +7,13 @@
 #include "components/password_manager/core/browser/mock_password_store.h"
 
 // static
-KeyedService* MockPasswordStoreService::Build(
+scoped_ptr<KeyedService> MockPasswordStoreService::Build(
     content::BrowserContext* /*profile*/) {
   scoped_refptr<password_manager::PasswordStore> store(
       new password_manager::MockPasswordStore);
   if (!store.get() || !store->Init(syncer::SyncableService::StartSyncFlare()))
     return nullptr;
-  return new MockPasswordStoreService(store);
+  return scoped_ptr<KeyedService>(new MockPasswordStoreService(store));
 }
 
 MockPasswordStoreService::MockPasswordStoreService(
diff --git a/chrome/browser/password_manager/mock_password_store_service.h b/chrome/browser/password_manager/mock_password_store_service.h
index bad233ee..9b335bd 100644
--- a/chrome/browser/password_manager/mock_password_store_service.h
+++ b/chrome/browser/password_manager/mock_password_store_service.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_PASSWORD_MANAGER_MOCK_PASSWORD_STORE_SERVICE_H_
 #define CHROME_BROWSER_PASSWORD_MANAGER_MOCK_PASSWORD_STORE_SERVICE_H_
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 
 namespace content {
@@ -17,7 +18,7 @@
 
 class MockPasswordStoreService : public PasswordStoreService {
  public:
-  static KeyedService* Build(content::BrowserContext* profile);
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* profile);
 
  private:
   explicit MockPasswordStoreService(
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 3a41c29..6a6416b1 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -271,7 +271,7 @@
 // serves a Basic Auth challenge.
 scoped_ptr<net::test_server::HttpResponse> HandleTestAuthRequest(
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(request.relative_url, "/basic_auth", true))
+  if (!base::StartsWithASCII(request.relative_url, "/basic_auth", true))
     return scoped_ptr<net::test_server::HttpResponse>();
 
   if (ContainsKey(request.headers, "Authorization")) {
diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc
index 46ba4d02..6d448d4 100644
--- a/chrome/browser/password_manager/password_store_mac.cc
+++ b/chrome/browser/password_manager/password_store_mac.cc
@@ -413,7 +413,7 @@
   // practice, other browsers seem to use a "" or " " password (and a special
   // user name) to indicated blacklist entries.
   if (extract_password_data && (form->password_value.empty() ||
-                                EqualsASCII(form->password_value, " "))) {
+                                base::EqualsASCII(form->password_value, " "))) {
     form->blacklisted_by_user = true;
   }
 
diff --git a/chrome/browser/password_manager/test_password_store_service.cc b/chrome/browser/password_manager/test_password_store_service.cc
index af96bc3b..ef5ad24 100644
--- a/chrome/browser/password_manager/test_password_store_service.cc
+++ b/chrome/browser/password_manager/test_password_store_service.cc
@@ -7,13 +7,13 @@
 #include "components/password_manager/core/browser/test_password_store.h"
 
 // static
-KeyedService* TestPasswordStoreService::Build(
+scoped_ptr<KeyedService> TestPasswordStoreService::Build(
     content::BrowserContext* /*profile*/) {
   scoped_refptr<password_manager::PasswordStore> store(
       new password_manager::TestPasswordStore);
   if (!store.get() || !store->Init(syncer::SyncableService::StartSyncFlare()))
     return nullptr;
-  return new TestPasswordStoreService(store);
+  return scoped_ptr<KeyedService>(new TestPasswordStoreService(store));
 }
 
 TestPasswordStoreService::TestPasswordStoreService(
diff --git a/chrome/browser/password_manager/test_password_store_service.h b/chrome/browser/password_manager/test_password_store_service.h
index 9e28cc7..3660f25 100644
--- a/chrome/browser/password_manager/test_password_store_service.h
+++ b/chrome/browser/password_manager/test_password_store_service.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_PASSWORD_MANAGER_TEST_PASSWORD_STORE_SERVICE_H_
 #define CHROME_BROWSER_PASSWORD_MANAGER_TEST_PASSWORD_STORE_SERVICE_H_
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 
 namespace content {
@@ -17,7 +18,7 @@
 
 class TestPasswordStoreService : public PasswordStoreService {
  public:
-  static KeyedService* Build(content::BrowserContext* profile);
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* profile);
 
  private:
   explicit TestPasswordStoreService(
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index fb1b65b..d6718e79 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -67,18 +67,21 @@
     extensions::ResultCatcher catcher;
 
     GURL url(embedded_test_server()->GetURL("/pdf/" + pdf_filename));
-    ui_test_utils::NavigateToURL(browser(), url);
+
+    // It should be good enough to just navigate to the URL. But loading up the
+    // BrowserPluginGuest seems to happen asynchronously as there was flakiness
+    // being seen due to the BrowserPluginGuest not being available yet (see
+    // crbug.com/498077). So instead use |LoadPdf| which ensures that the PDF is
+    // loaded before continuing.
+    ASSERT_TRUE(LoadPdf(url));
 
     content::WebContents* contents =
         browser()->tab_strip_model()->GetActiveWebContents();
-    ASSERT_TRUE(content::WaitForLoadStop(contents));
-
     content::BrowserPluginGuestManager* guest_manager =
         contents->GetBrowserContext()->GetGuestManager();
     content::WebContents* guest_contents =
         guest_manager->GetFullPageGuest(contents);
     ASSERT_TRUE(guest_contents);
-    EXPECT_TRUE(content::WaitForLoadStop(guest_contents));
 
     base::FilePath test_data_dir;
     PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
diff --git a/chrome/browser/plugins/plugin_info_message_filter.cc b/chrome/browser/plugins/plugin_info_message_filter.cc
index 72e09c4..b0337f2 100644
--- a/chrome/browser/plugins/plugin_info_message_filter.cc
+++ b/chrome/browser/plugins/plugin_info_message_filter.cc
@@ -129,8 +129,8 @@
   if (!rappor_service)
     return;
 
-  if (StartsWithASCII(mime_type, content::kSilverlightPluginMimeTypePrefix,
-                      false)) {
+  if (base::StartsWithASCII(mime_type,
+                            content::kSilverlightPluginMimeTypePrefix, false)) {
     rappor_service->RecordSample(
         "Plugins.SilverlightOriginUrl", rappor::ETLD_PLUS_ONE_RAPPOR_TYPE,
         net::registry_controlled_domains::GetDomainAndRegistry(
diff --git a/chrome/browser/plugins/plugin_power_saver_browsertest.cc b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
index d7ace2a..acbe7ba 100644
--- a/chrome/browser/plugins/plugin_power_saver_browsertest.cc
+++ b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
@@ -170,10 +170,14 @@
 
 IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest, LargeCrossOrigin) {
   LoadHTML(
-      "<object id='plugin' data='http://otherorigin.com/fake.swf' "
+      "<object id='large' data='http://otherorigin.com/fake.swf' "
       "    type='application/x-ppapi-tests' width='400' height='500'>"
+      "</object>"
+      "<object id='medium_16_9' data='http://otherorigin.com/fake.swf' "
+      "    type='application/x-ppapi-tests' width='480' height='270'>"
       "</object>");
-  VerifyPluginMarkedEssential(GetActiveWebContents(), "plugin");
+  VerifyPluginMarkedEssential(GetActiveWebContents(), "large");
+  VerifyPluginMarkedEssential(GetActiveWebContents(), "medium_16_9");
 }
 
 IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest,
@@ -224,12 +228,31 @@
 
 IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest, LargeCrossOriginObscured) {
   LoadHTML(
-      "<div style='width: 100px; height: 100px; overflow: hidden;'>"
+      "<div id='container' "
+      "    style='width: 400px; height: 100px; overflow: hidden;'>"
       "  <object id='plugin' data='http://otherorigin.com/fake.swf' "
       "      type='application/x-ppapi-tests' width='400' height='500'>"
       "  </object>"
       "</div>");
   VerifyPluginIsThrottled(GetActiveWebContents(), "plugin");
+
+  // Test that's unthrottled if it is unobscured.
+  std::string script =
+      "var container = window.document.getElementById('container');"
+      "container.setAttribute('style', 'width: 400px; height: 400px;');";
+  ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), script));
+  VerifyPluginMarkedEssential(GetActiveWebContents(), "plugin");
+}
+
+IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest, ExpandingSmallPlugin) {
+  LoadHTML(
+      "<object id='plugin' data='http://otherorigin.com/fake.swf' "
+      "    type='application/x-ppapi-tests' width='400' height='80'></object>");
+  VerifyPluginIsThrottled(GetActiveWebContents(), "plugin");
+
+  std::string script = "window.document.getElementById('plugin').height = 400;";
+  ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), script));
+  VerifyPluginMarkedEssential(GetActiveWebContents(), "plugin");
 }
 
 IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest, BackgroundTabPlugins) {
diff --git a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
index ebce294..8958e7bb 100644
--- a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
@@ -77,11 +77,11 @@
 
 namespace {
 
-KeyedService* BuildFakeProfileInvalidationProvider(
+scoped_ptr<KeyedService> BuildFakeProfileInvalidationProvider(
     content::BrowserContext* context) {
-  return new invalidation::ProfileInvalidationProvider(
+  return make_scoped_ptr(new invalidation::ProfileInvalidationProvider(
       scoped_ptr<invalidation::InvalidationService>(
-          new invalidation::FakeInvalidationService));
+          new invalidation::FakeInvalidationService)));
 }
 
 #if !defined(OS_CHROMEOS)
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
index 047dcd96..af496a0 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/run_loop.h"
 #include "base/thread_task_runner_handle.h"
@@ -95,8 +96,9 @@
     SignOut(signin_metrics::SIGNOUT_TEST);
   }
 
-  static KeyedService* Build(content::BrowserContext* profile) {
-    return new SigninManagerFake(static_cast<Profile*>(profile));
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* profile) {
+    return make_scoped_ptr(
+        new SigninManagerFake(static_cast<Profile*>(profile)));
   }
 };
 
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 32c83e5..0b0aec1 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -132,6 +132,7 @@
 #include "content/public/test/mock_notification_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
@@ -1968,8 +1969,8 @@
 #define MAYBE_ExtensionInstallSources ExtensionInstallSources
 #endif
 IN_PROC_BROWSER_TEST_F(PolicyTest, MAYBE_ExtensionInstallSources) {
-  ExtensionInstallPrompt::g_auto_confirm_for_tests =
-      ExtensionInstallPrompt::ACCEPT;
+  extensions::ScopedTestDialogAutoConfirm auto_confirm(
+      extensions::ScopedTestDialogAutoConfirm::ACCEPT);
 
   const GURL install_source_url(URLRequestMockHTTPJob::GetMockUrl(
       base::FilePath(FILE_PATH_LITERAL("extensions/*"))));
@@ -3779,7 +3780,7 @@
   const GURL url =
       chrome_variations::VariationsService::GetVariationsServerURL(
           g_browser_process->local_state(), std::string());
-  EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
+  EXPECT_TRUE(base::StartsWithASCII(url.spec(), default_variations_url, true));
   std::string value;
   EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
   EXPECT_EQ("restricted", value);
diff --git a/chrome/browser/policy/policy_prefs_browsertest.cc b/chrome/browser/policy/policy_prefs_browsertest.cc
index e34a06f..bd53790 100644
--- a/chrome/browser/policy/policy_prefs_browsertest.cc
+++ b/chrome/browser/policy/policy_prefs_browsertest.cc
@@ -559,7 +559,8 @@
            ++pref_mapping) {
         // Skip Chrome OS preferences that use a different backend and cannot be
         // retrieved through the prefs mechanism.
-        if (StartsWithASCII((*pref_mapping)->pref(), kCrosSettingsPrefix, true))
+        if (base::StartsWithASCII((*pref_mapping)->pref(), kCrosSettingsPrefix,
+                                  true))
           continue;
 
         // Skip preferences that should not be checked when the policy is set to
diff --git a/chrome/browser/precache/OWNERS b/chrome/browser/precache/OWNERS
deleted file mode 100644
index 38f02cc1..0000000
--- a/chrome/browser/precache/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-bengr@chromium.org
-sclittle@chromium.org
diff --git a/chrome/browser/precache/most_visited_urls_provider.cc b/chrome/browser/precache/most_visited_urls_provider.cc
deleted file mode 100644
index 3f7736f..0000000
--- a/chrome/browser/precache/most_visited_urls_provider.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/precache/most_visited_urls_provider.h"
-
-#include <list>
-
-#include "base/bind.h"
-#include "components/history/core/browser/history_types.h"
-#include "components/history/core/browser/top_sites.h"
-#include "url/gurl.h"
-
-using history::MostVisitedURLList;
-
-namespace {
-
-void OnMostVisitedURLsReceived(
-    const precache::URLListProvider::GetURLsCallback& callback,
-    const MostVisitedURLList& most_visited_urls) {
-  std::list<GURL> urls;
-  for (MostVisitedURLList::const_iterator it = most_visited_urls.begin();
-       it != most_visited_urls.end(); ++it) {
-    if (it->url.SchemeIs("http")) {
-      urls.push_back(it->url);
-    }
-  }
-  callback.Run(urls);
-}
-
-}  // namespace
-
-namespace precache {
-
-MostVisitedURLsProvider::MostVisitedURLsProvider(history::TopSites* top_sites)
-    : top_sites_(top_sites) {}
-
-MostVisitedURLsProvider::~MostVisitedURLsProvider() {}
-
-void MostVisitedURLsProvider::GetURLs(const GetURLsCallback& callback) {
-  top_sites_->GetMostVisitedURLs(
-      base::Bind(&OnMostVisitedURLsReceived, callback), false);
-}
-
-}  // namespace precache
diff --git a/chrome/browser/precache/most_visited_urls_provider.h b/chrome/browser/precache/most_visited_urls_provider.h
deleted file mode 100644
index 253181c..0000000
--- a/chrome/browser/precache/most_visited_urls_provider.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PRECACHE_MOST_VISITED_URLS_PROVIDER_H_
-#define CHROME_BROWSER_PRECACHE_MOST_VISITED_URLS_PROVIDER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "components/precache/core/url_list_provider.h"
-
-namespace history {
-class TopSites;
-}
-
-namespace precache {
-
-// A URLListProvider that provides a list of the user's most visited URLs.
-class MostVisitedURLsProvider : public URLListProvider {
- public:
-  explicit MostVisitedURLsProvider(history::TopSites* top_sites);
-  ~MostVisitedURLsProvider();
-
-  // Returns a list of the user's most visited URLs via a callback. May be
-  // called from any thread. The callback may be run before the call to GetURLs
-  // returns.
-  void GetURLs(const GetURLsCallback& callback) override;
-
- private:
-  scoped_refptr<history::TopSites> top_sites_;
-
-  DISALLOW_COPY_AND_ASSIGN(MostVisitedURLsProvider);
-};
-
-}  // namespace precache
-
-#endif  // CHROME_BROWSER_PRECACHE_MOST_VISITED_URLS_PROVIDER_H_
diff --git a/chrome/browser/predictors/autocomplete_action_predictor.cc b/chrome/browser/predictors/autocomplete_action_predictor.cc
index 0104895c..51a22c1 100644
--- a/chrome/browser/predictors/autocomplete_action_predictor.cc
+++ b/chrome/browser/predictors/autocomplete_action_predictor.cc
@@ -344,7 +344,7 @@
   for (std::vector<TransitionalMatch>::const_iterator it =
         transitional_matches_.begin(); it != transitional_matches_.end();
         ++it) {
-    if (!StartsWith(lower_user_text, it->user_text, true))
+    if (!base::StartsWith(lower_user_text, it->user_text, true))
       continue;
 
     // Add entries to the database for those matches.
diff --git a/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc b/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc
index 707a650..00562c6 100644
--- a/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc
+++ b/chrome/browser/predictors/autocomplete_action_predictor_unittest.cc
@@ -321,7 +321,8 @@
     std::string row_id = AddRow(test_url_db[i]);
     all_ids.push_back(row_id);
 
-    bool exclude_url = StartsWithASCII(test_url_db[i].url.path(), "/d", true) ||
+    bool exclude_url =
+        base::StartsWithASCII(test_url_db[i].url.path(), "/d", true) ||
         (test_url_db[i].days_from_now > maximum_days_to_keep_entry());
 
     if (exclude_url)
diff --git a/chrome/browser/prefetch/prefetch_field_trial.cc b/chrome/browser/prefetch/prefetch_field_trial.cc
index abdb112..e51dcb33 100644
--- a/chrome/browser/prefetch/prefetch_field_trial.cc
+++ b/chrome/browser/prefetch/prefetch_field_trial.cc
@@ -14,7 +14,7 @@
 
 bool DisableForFieldTrial() {
   std::string experiment = base::FieldTrialList::FindFullName("Prefetch");
-  return StartsWithASCII(experiment, "ExperimentDisable", false);
+  return base::StartsWithASCII(experiment, "ExperimentDisable", false);
 }
 
 }  // namespace prefetch
diff --git a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
index 3608606..48d4bfec 100644
--- a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
+++ b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
@@ -309,9 +309,8 @@
  private:
   // Returns true if this is the PRE_ phase of the test.
   bool IsPRETest() {
-    return StartsWithASCII(
-        testing::UnitTest::GetInstance()->current_test_info()->name(),
-        "PRE_",
+    return base::StartsWithASCII(
+        testing::UnitTest::GetInstance()->current_test_info()->name(), "PRE_",
         true /* case_sensitive */);
   }
 
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index ebe6549f..fb7daa9 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -90,11 +90,11 @@
                               const OpenURLParams& params) override {
     // |OpenURLFromTab| is typically called when a frame performs a navigation
     // that requires the browser to perform the transition instead of WebKit.
-    // Examples include prerendering a site that redirects to an app URL,
-    // or if --enable-strict-site-isolation is specified and the prerendered
-    // frame redirects to a different origin.
-    // TODO(cbentzel): Consider supporting this if it is a common case during
-    // prerenders.
+    // Examples include prerendering a site that redirects to an app URL, or if
+    // --site-per-process is specified and the prerendered frame redirects to a
+    // different origin.
+    // TODO(cbentzel): Consider supporting this for CURRENT_TAB dispositions, if
+    // it is a common case during prerenders.
     prerender_contents_->Destroy(FINAL_STATUS_OPEN_URL);
     return NULL;
   }
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 30fde0f5..58d6215 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -740,7 +740,7 @@
 bool PrerenderManager::IsValidHttpMethod(const std::string& method) {
   // method has been canonicalized to upper case at this point so we can just
   // compare them.
-  DCHECK_EQ(method, StringToUpperASCII(method));
+  DCHECK_EQ(method, base::StringToUpperASCII(method));
   for (size_t i = 0; i < arraysize(kValidHttpMethods); ++i) {
     if (method.compare(kValidHttpMethods[i]) == 0)
       return true;
diff --git a/chrome/browser/prerender/prerender_util.cc b/chrome/browser/prerender/prerender_util.cc
index 45266ee..1b60fcb 100644
--- a/chrome/browser/prerender/prerender_util.cc
+++ b/chrome/browser/prerender/prerender_util.cc
@@ -72,16 +72,16 @@
 }
 
 bool IsGoogleDomain(const GURL& url) {
-  return StartsWithASCII(url.host(), std::string("www.google."), true);
+  return base::StartsWithASCII(url.host(), std::string("www.google."), true);
 }
 
 bool IsGoogleSearchResultURL(const GURL& url) {
   if (!IsGoogleDomain(url))
     return false;
   return (url.path().empty() ||
-          StartsWithASCII(url.path(), std::string("/search"), true) ||
+          base::StartsWithASCII(url.path(), std::string("/search"), true) ||
           (url.path() == "/") ||
-          StartsWithASCII(url.path(), std::string("/webhp"), true));
+          base::StartsWithASCII(url.path(), std::string("/webhp"), true));
 }
 
 void ReportPrerenderExternalURL() {
diff --git a/chrome/browser/printing/print_dialog_cloud.cc b/chrome/browser/printing/print_dialog_cloud.cc
index a708193..d2118fc 100644
--- a/chrome/browser/printing/print_dialog_cloud.cc
+++ b/chrome/browser/printing/print_dialog_cloud.cc
@@ -126,7 +126,7 @@
 
 bool IsSimilarUrl(const GURL& url, const GURL& cloud_print_url) {
   return url.host() == cloud_print_url.host() &&
-         StartsWithASCII(url.path(), cloud_print_url.path(), false) &&
+         base::StartsWithASCII(url.path(), cloud_print_url.path(), false) &&
          url.scheme() == cloud_print_url.scheme();
 }
 
diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc
index 05e14995..28946f4f 100644
--- a/chrome/browser/process_singleton_posix.cc
+++ b/chrome/browser/process_singleton_posix.cc
@@ -62,8 +62,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/posix/eintr_wrapper.h"
+#include "base/posix/safe_strerror.h"
 #include "base/rand_util.h"
-#include "base/safe_strerror_posix.h"
 #include "base/sequenced_task_runner_helpers.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -135,7 +135,7 @@
 // Close a socket and check return value.
 void CloseSocket(int fd) {
   int rv = IGNORE_EINTR(close(fd));
-  DCHECK_EQ(0, rv) << "Error closing socket: " << safe_strerror(errno);
+  DCHECK_EQ(0, rv) << "Error closing socket: " << base::safe_strerror(errno);
 }
 
 // Write a message to a socket fd.
@@ -1010,7 +1010,7 @@
   }
 
   if (listen(sock, 5) < 0)
-    NOTREACHED() << "listen failed: " << safe_strerror(errno);
+    NOTREACHED() << "listen failed: " << base::safe_strerror(errno);
 
   DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
   BrowserThread::PostTask(
@@ -1069,5 +1069,5 @@
   // ESRCH = No Such Process (can happen if the other process is already in
   // progress of shutting down and finishes before we try to kill it).
   DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: "
-                                    << safe_strerror(errno);
+                                    << base::safe_strerror(errno);
 }
diff --git a/chrome/browser/profile_resetter/automatic_profile_resetter.cc b/chrome/browser/profile_resetter/automatic_profile_resetter.cc
index 9dead81c..f932946a 100644
--- a/chrome/browser/profile_resetter/automatic_profile_resetter.cc
+++ b/chrome/browser/profile_resetter/automatic_profile_resetter.cc
@@ -85,14 +85,14 @@
 
 // Returns whether or not a dry-run shall be performed.
 bool ShouldPerformDryRun() {
-  return StartsWithASCII(
+  return base::StartsWithASCII(
       base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName),
       kAutomaticProfileResetStudyDryRunGroupName, true);
 }
 
 // Returns whether or not a live-run shall be performed.
 bool ShouldPerformLiveRun() {
-  return StartsWithASCII(
+  return base::StartsWithASCII(
       base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName),
       kAutomaticProfileResetStudyEnabledGroupName, true);
 }
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index cb56e11..6d255a5 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/profile_resetter/profile_resetter.h"
 
 #include "base/json/json_string_value_serializer.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_path_override.h"
@@ -107,7 +108,7 @@
 
   TestingProfile* profile() { return profile_.get(); }
 
-  static KeyedService* CreateTemplateURLService(
+  static scoped_ptr<KeyedService> CreateTemplateURLService(
       content::BrowserContext* context);
 
  private:
@@ -144,15 +145,15 @@
 }
 
 // static
-KeyedService* ProfileResetterTest::CreateTemplateURLService(
+scoped_ptr<KeyedService> ProfileResetterTest::CreateTemplateURLService(
     content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
-  return new TemplateURLService(
+  return make_scoped_ptr(new TemplateURLService(
       profile->GetPrefs(),
       scoped_ptr<SearchTermsData>(new UIThreadSearchTermsData(profile)),
       WebDataServiceFactory::GetKeywordWebDataForProfile(
           profile, ServiceAccessType::EXPLICIT_ACCESS),
-      scoped_ptr<TemplateURLServiceClient>(), NULL, NULL, base::Closure());
+      scoped_ptr<TemplateURLServiceClient>(), NULL, NULL, base::Closure()));
 }
 
 
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 808e534..aa10c07 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -182,9 +182,10 @@
       PrefService::INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE;
 }
 
-bool Profile::IsSyncAccessible() {
-  if (ProfileSyncServiceFactory::HasProfileSyncService(this))
-    return !ProfileSyncServiceFactory::GetForProfile(this)->IsManaged();
+bool Profile::IsSyncAllowed() {
+  if (ProfileSyncServiceFactory::HasProfileSyncService(this)) {
+    return ProfileSyncServiceFactory::GetForProfile(this)->IsSyncAllowed();
+  }
 
   // No ProfileSyncService created yet - we don't want to create one, so just
   // infer the accessible state by looking at prefs/command line flags.
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index dcdd679..03c7491 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -356,8 +356,8 @@
   bool IsNewProfile();
 
   // Checks whether sync is configurable by the user. Returns false if sync is
-  // disabled or controlled by configuration management.
-  bool IsSyncAccessible();
+  // disallowed by the command line or controlled by configuration management.
+  bool IsSyncAllowed();
 
   // Send NOTIFICATION_PROFILE_DESTROYED for this Profile, if it has not
   // already been sent. It is necessary because most Profiles are destroyed by
diff --git a/chrome/browser/profiles/profile_avatar_downloader.cc b/chrome/browser/profiles/profile_avatar_downloader.cc
index fad384a..69f4a4c 100644
--- a/chrome/browser/profiles/profile_avatar_downloader.cc
+++ b/chrome/browser/profiles/profile_avatar_downloader.cc
@@ -35,12 +35,14 @@
   // In unit tests, the browser process can return a NULL request context.
   net::URLRequestContextGetter* request_context =
       g_browser_process->system_request_context();
-  if (request_context)
-    fetcher_->Start(
+  if (request_context) {
+    fetcher_->Init(
         request_context,
         std::string(),
         net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
         net::LOAD_NORMAL);
+    fetcher_->Start();
+  }
 }
 
 // BitmapFetcherDelegate overrides.
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index ff53d44..42a2276 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -23,8 +23,6 @@
 #include "chrome/browser/profiles/chrome_version_service.h"
 #include "chrome/browser/profiles/profile_impl.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/profiles/startup_task_runner_service.h"
-#include "chrome/browser/profiles/startup_task_runner_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_constants.h"
@@ -32,6 +30,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/bookmarks/browser/startup_task_runner_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_utils.h"
 #include "net/base/net_errors.h"
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 6eb96e91..b61964d1 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -88,7 +88,6 @@
 #include "components/metrics/metrics_service.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/signin/core/browser/signin_manager.h"
-#include "components/startup_metric_utils/startup_metric_utils.h"
 #include "components/ui/zoom/zoom_event_manager.h"
 #include "components/url_fixer/url_fixer.h"
 #include "components/user_prefs/user_prefs.h"
@@ -451,10 +450,6 @@
   }
 
   {
-    // On startup, preference loading is always synchronous so a scoped timer
-    // will work here.
-    startup_metric_utils::ScopedSlowStartupUMA
-        scoped_timer("Startup.SlowStartupPreferenceLoading");
     prefs_ = chrome_prefs::CreateProfilePrefs(
         path_,
         sequenced_task_runner,
@@ -468,8 +463,6 @@
     user_prefs::UserPrefs::Set(this, prefs_.get());
   }
 
-  startup_metric_utils::ScopedSlowStartupUMA
-      scoped_timer("Startup.SlowStartupFinalProfileInit");
   if (async_prefs) {
     // Wait for the notification that prefs has been loaded
     // (successfully or not).  Note that we can use base::Unretained
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 8bf401e..c7bdfdcc 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -74,9 +74,9 @@
   if (command_line.HasSwitch(switches::kUseSimpleCacheBackend)) {
     const std::string opt_value =
         command_line.GetSwitchValueASCII(switches::kUseSimpleCacheBackend);
-    if (LowerCaseEqualsASCII(opt_value, "off"))
+    if (base::LowerCaseEqualsASCII(opt_value, "off"))
       return net::CACHE_BACKEND_BLOCKFILE;
-    if (opt_value.empty() || LowerCaseEqualsASCII(opt_value, "on"))
+    if (opt_value.empty() || base::LowerCaseEqualsASCII(opt_value, "on"))
       return net::CACHE_BACKEND_SIMPLE;
   }
   const std::string experiment_name =
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index e6251781..5e3185e 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -56,7 +56,6 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/dom_distiller/core/url_constants.h"
-#include "components/startup_metric_utils/startup_metric_utils.h"
 #include "components/sync_driver/pref_names.h"
 #include "components/url_fixer/url_fixer.h"
 #include "content/public/browser/browser_thread.h"
@@ -160,7 +159,7 @@
 
   if (!url.SchemeIs(content::kChromeDevToolsScheme) ||
       url.host() != chrome::kChromeUIDevToolsHost ||
-      !StartsWithASCII(url.path(), bundled_path_prefix, false)) {
+      !base::StartsWithASCII(url.path(), bundled_path_prefix, false)) {
     return false;
   }
 
@@ -982,9 +981,6 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(!initialized_);
 
-  startup_metric_utils::ScopedSlowStartupUMA
-      scoped_timer("Startup.SlowStartupProfileIODataInit");
-
   // TODO(jhawkins): Remove once crbug.com/102004 is fixed.
   CHECK(initialized_on_UI_thread_);
 
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 1a7ef7d7..ada1797 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -21,6 +21,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/bookmarks/startup_task_runner_service_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/download/download_service.h"
@@ -35,8 +36,6 @@
 #include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profiles_state.h"
-#include "chrome/browser/profiles/startup_task_runner_service.h"
-#include "chrome/browser/profiles/startup_task_runner_service_factory.h"
 #include "chrome/browser/signin/account_reconcilor_factory.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/cross_device_promo.h"
@@ -56,6 +55,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/startup_task_runner_service.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/signin/core/browser/account_tracker_service.h"
diff --git a/chrome/browser/push_messaging/push_messaging_app_identifier.cc b/chrome/browser/push_messaging/push_messaging_app_identifier.cc
index 8d84fa2..325081a 100644
--- a/chrome/browser/push_messaging/push_messaging_app_identifier.cc
+++ b/chrome/browser/push_messaging/push_messaging_app_identifier.cc
@@ -75,8 +75,8 @@
 // static
 PushMessagingAppIdentifier PushMessagingAppIdentifier::FindByAppId(
     Profile* profile, const std::string& app_id) {
-  if (!StartsWithASCII(app_id, kPushMessagingAppIdentifierPrefix,
-                       false /* case_sensitive */)) {
+  if (!base::StartsWithASCII(app_id, kPushMessagingAppIdentifierPrefix,
+                             false /* case_sensitive */)) {
     return PushMessagingAppIdentifier();
   }
 
@@ -85,7 +85,8 @@
   DCHECK_EQ(kPushMessagingAppIdentifierPrefix, app_id.substr(0, kPrefixLength));
   DCHECK_GE(app_id.size(), kPrefixLength + kGuidLength);
   DCHECK_EQ(app_id.substr(app_id.size() - kGuidLength),
-            StringToUpperASCII(app_id.substr(app_id.size() - kGuidLength)));
+            base::StringToUpperASCII(
+                app_id.substr(app_id.size() - kGuidLength)));
 
   const base::DictionaryValue* map =
       profile->GetPrefs()->GetDictionary(prefs::kPushMessagingAppIdentifierMap);
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc
index a9acc332..0cd1a74 100644
--- a/chrome/browser/push_messaging/push_messaging_browsertest.cc
+++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -243,7 +243,8 @@
         PermissionBubbleManager::ACCEPT_ALL);
     EXPECT_TRUE(RunScript("requestNotificationPermission();", &script_result));
   } else {
-    InfoBarResponder infobar_accept_responder(GetInfoBarService(), true);
+    InfoBarResponder infobar_accept_responder(GetInfoBarService(),
+                                              InfoBarResponder::ACCEPT);
     EXPECT_TRUE(RunScript("requestNotificationPermission();", &script_result));
   }
   EXPECT_EQ("permission status - granted", script_result);
@@ -257,7 +258,8 @@
         PermissionBubbleManager::DENY_ALL);
     EXPECT_TRUE(RunScript("requestNotificationPermission();", &script_result));
   } else {
-    InfoBarResponder infobar_deny_responder(GetInfoBarService(), false);
+    InfoBarResponder infobar_deny_responder(GetInfoBarService(),
+                                            InfoBarResponder::DENY);
     EXPECT_TRUE(RunScript("requestNotificationPermission();", &script_result));
   }
   EXPECT_EQ("permission status - denied", script_result);
@@ -319,7 +321,8 @@
         PermissionBubbleManager::ACCEPT_ALL);
     ASSERT_TRUE(RunScript("subscribePush()", &script_result));
   } else {
-    InfoBarResponder infobar_accept_responder(GetInfoBarService(), true);
+    InfoBarResponder infobar_accept_responder(GetInfoBarService(),
+                                              InfoBarResponder::ACCEPT);
     ASSERT_TRUE(RunScript("subscribePush()", &script_result));
   }
   EXPECT_EQ(GetEndpointForSubscriptionId("1-0"), script_result);
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
index 736f1af4..5375e1e 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
@@ -574,7 +574,7 @@
           MaybeCreate(
               request, resource_type, io_data->data_reduction_proxy_io_data());
   if (data_reduction_proxy_throttle)
-    throttles->push_back(data_reduction_proxy_throttle.release());
+    throttles->push_back(data_reduction_proxy_throttle.Pass());
 #endif
 
 #if defined(ENABLE_SUPERVISED_USERS)
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc
index 36159bcb..98e86d31 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc
@@ -30,7 +30,7 @@
 
 scoped_ptr<net::test_server::HttpResponse> HandleTestRequest(
     const net::test_server::HttpRequest& request) {
-  if (StartsWithASCII(request.relative_url, kServerRedirectUrl, true)) {
+  if (base::StartsWithASCII(request.relative_url, kServerRedirectUrl, true)) {
     // Extract the target URL and redirect there.
     size_t query_string_pos = request.relative_url.find('?');
     std::string redirect_target =
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js b/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js
index d48d7da..8c48e1d 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/tabs_api_handler.js
@@ -135,9 +135,10 @@
       return;
     }
     chrome.windows.get(windowId, function(window) {
-      chrome.tabs.query({active: true, windowId: windowId}, function(tab) {
+      chrome.tabs.query({active: true, windowId: windowId}, function(tabs) {
         var msgId = window.incognito ? 'chrome_incognito_window_selected' :
-          'chrome_normal_window_selected';
+            'chrome_normal_window_selected';
+        var tab = tabs[0] || {};
         var title = tab.title ? tab.title : tab.url;
         this.tts_.speak(this.msg_(msgId, [title]),
                        cvox.QueueMode.FLUSH,
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/live_regions_test.unitjs b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/live_regions_test.unitjs
index ded94e0..e43e82a4 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/live_regions_test.unitjs
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/live_regions_test.unitjs
@@ -51,7 +51,8 @@
 /**
  * Test inserting an 'alert' live region.
  */
-TEST_F('CvoxLiveRegionsUnitTest', 'InsertAlertLiveRegion', function() {
+// Flaky on Chromium OS: crbug.com/498881.
+TEST_F('CvoxLiveRegionsUnitTest', 'DISABLED_InsertAlertLiveRegion', function() {
   var region = document.createElement('div');
   region.innerHTML = '<div role="alert">Alpha</div>';
   document.body.appendChild(region);
@@ -93,7 +94,8 @@
 /**
  * Test inserting a 'polite' live region.
  */
-TEST_F('CvoxLiveRegionsUnitTest', 'InsertPoliteLiveRegion', function() {
+// Flaky on Chromium OS: crbug.com/498881.
+TEST_F('CvoxLiveRegionsUnitTest', 'DISABLED_InsertPoliteLiveRegion', function() {
   var region = document.createElement('div');
   region.innerHTML = '<div aria-live="polite">Beta</div>';
   document.body.appendChild(region);
@@ -160,7 +162,8 @@
 /**
  * Test removing elements from live regions.
  */
-TEST_F('CvoxLiveRegionsUnitTest', 'RemoveFromLiveRegion', function() {
+// Flaky on Chromium OS: crbug.com/498881.
+TEST_F('CvoxLiveRegionsUnitTest', 'DISABLED_RemoveFromLiveRegion', function() {
   this.loadDoc(function() {/*!
     <div>
       <div id="buddylist2" aria-relevant="removals">
@@ -252,7 +255,8 @@
 /**
  * Test focus followed by live region change, make sure both are spoken.
  */
-TEST_F('CvoxLiveRegionsUnitTest', 'FocusThenLiveRegion', function() {
+// Flaky on Chromium OS: crbug.com/498881.
+TEST_F('CvoxLiveRegionsUnitTest', 'DISABLED_FocusThenLiveRegion', function() {
   this.loadDoc(function() {/*!
     <button id="button_to_focus">Button To Focus</button>
     <div id="live" aria-live="polite"></div>
@@ -272,7 +276,8 @@
 /**
  * Test live region change followed by focus, make sure both are spoken.
  */
-TEST_F('CvoxLiveRegionsUnitTest', 'LiveRegionThenFocus', function() {
+// Flaky on Chromium OS: crbug.com/498881.
+TEST_F('CvoxLiveRegionsUnitTest', 'DISABLED_LiveRegionThenFocus', function() {
   this.loadDoc(function() {/*!
     <button id="button_to_focus">Button To Focus</button>
     <div id="live" aria-live="polite"></div>
@@ -295,7 +300,8 @@
  * Two elements inside a live region. These are all combined into
  * one utterance until this bug is fixed: http://crbug.com/415679
  */
-TEST_F('CvoxLiveRegionsUnitTest', 'TwoElementsInLiveRegion', function() {
+// Flaky on Chromium OS: crbug.com/498881.
+TEST_F('CvoxLiveRegionsUnitTest', 'DISABLED_TwoElementsInLiveRegion', function() {
   this.loadDoc(function() {/*!
     <div id="live" aria-live="polite">
       <div id="hidden" style="display:none">
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index b34e176..2afbfd8 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -436,7 +436,7 @@
     },
     textField: {
       speak: '$name $value $if(' +
-          '$textInputType, @input_type_+$textInputType, @input_type_text)',
+          '$type, @input_type_+$type, @input_type_text)',
       braille: ''
     },
     toolbar: {
diff --git a/chrome/browser/resources/chromeos/network_ui/compiled_resources.gyp b/chrome/browser/resources/chromeos/network_ui/compiled_resources.gyp
index b92a04b8..cee42de 100644
--- a/chrome/browser/resources/chromeos/network_ui/compiled_resources.gyp
+++ b/chrome/browser/resources/chromeos/network_ui/compiled_resources.gyp
@@ -14,7 +14,6 @@
         ],
         'externs': [
           '../../../../../ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon_externs.js',
-          '../../../../../ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data_externs.js',
           '../../../../../third_party/closure_compiler/externs/chrome_extensions.js'
         ],
       },
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.html b/chrome/browser/resources/chromeos/network_ui/network_ui.html
index bfa9fc9..1152a19 100644
--- a/chrome/browser/resources/chromeos/network_ui/network_ui.html
+++ b/chrome/browser/resources/chromeos/network_ui/network_ui.html
@@ -7,7 +7,7 @@
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="chrome://network/network_ui.css">
   <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html">
-  <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+  <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_types.html">
   <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 
   <script src="chrome://resources/js/load_time_data.js"></script>
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.js b/chrome/browser/resources/chromeos/network_ui/network_ui.js
index 8fcf934..467e3c2c 100644
--- a/chrome/browser/resources/chromeos/network_ui/network_ui.js
+++ b/chrome/browser/resources/chromeos/network_ui/network_ui.js
@@ -110,7 +110,7 @@
     var icon = /** @type {!CrNetworkIconElement} */(
         document.createElement('cr-network-icon'));
     icon.isListItem = true;
-    icon.networkState = CrOncDataElement.create(networkState);
+    icon.networkState = networkState;
     cell.appendChild(icon);
     return cell;
   };
@@ -207,7 +207,7 @@
           loadTimeData.getStringF('defaultNetworkText',
                                   defaultState.Name,
                                   defaultState.ConnectionState);
-      icon.networkState = CrOncDataElement.create(defaultState);
+      icon.networkState = defaultState;
     } else {
       $('default-network-text').textContent =
           loadTimeData.getString('noNetworkText');
diff --git a/chrome/browser/resources/gaia_auth/background.js b/chrome/browser/resources/gaia_auth/background.js
index 3b529f3..482a4d1 100644
--- a/chrome/browser/resources/gaia_auth/background.js
+++ b/chrome/browser/resources/gaia_auth/background.js
@@ -28,13 +28,14 @@
  * the associated tab id.
  */
 function BackgroundBridgeManager() {
+  this.bridges_ = {};
 }
 
 BackgroundBridgeManager.prototype = {
   CONTINUE_URL_BASE: 'chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik' +
                      '/success.html',
   // Maps a tab id to its associated BackgroundBridge.
-  bridges_: {},
+  bridges_: null,
 
   run: function() {
     chrome.runtime.onConnect.addListener(this.onConnect_.bind(this));
@@ -103,6 +104,7 @@
  */
 function BackgroundBridge(tabId) {
   this.tabId_ = tabId;
+  this.passwordStore_ = {};
 }
 
 BackgroundBridge.prototype = {
@@ -148,7 +150,7 @@
   // Whether SAML flow is going.
   isSAML_: false,
 
-  passwordStore_: {},
+  passwordStore_: null,
 
   channelMain_: null,
   channelInjected_: null,
diff --git a/chrome/browser/resources/gaia_auth/channel.js b/chrome/browser/resources/gaia_auth/channel.js
index 52094b9d..2f6ce21 100644
--- a/chrome/browser/resources/gaia_auth/channel.js
+++ b/chrome/browser/resources/gaia_auth/channel.js
@@ -6,6 +6,8 @@
  * Channel to the background script.
  */
 function Channel() {
+  this.messageCallbacks_ = {};
+  this.internalRequestCallbacks_ = {};
 }
 
 /** @const */
@@ -19,13 +21,13 @@
   port_: null,
 
   // Registered message callbacks.
-  messageCallbacks_: {},
+  messageCallbacks_: null,
 
   // Internal request id to track pending requests.
   nextInternalRequestId_: 0,
 
   // Pending internal request callbacks.
-  internalRequestCallbacks_: {},
+  internalRequestCallbacks_: null,
 
   /**
    * Initialize the channel with given port for the background script.
diff --git a/chrome/browser/resources/gaia_auth/main.js b/chrome/browser/resources/gaia_auth/main.js
index e00869c..1a59e08 100644
--- a/chrome/browser/resources/gaia_auth/main.js
+++ b/chrome/browser/resources/gaia_auth/main.js
@@ -224,6 +224,9 @@
 
     window.setTimeout(function() {
       if (!this.supportChannel_) {
+        // Give up previous channel and bind its 'channelConnected' to a no-op.
+        supportChannel.registerMessage('channelConnected', function() {});
+
         // Re-initialize the channel if it is not connected properly, e.g.
         // connect may be called before background script started running.
         this.initSupportChannel_();
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js
index c5a1da2..870b368 100644
--- a/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -185,6 +185,7 @@
    * @param {Object} data Parameters for the authorization flow.
    */
   Authenticator.prototype.load = function(authMode, data) {
+    this.authMode = authMode;
     this.clearCredentials_();
     this.loaded_ = false;
     this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN;
@@ -322,7 +323,8 @@
    * @private
    */
   Authenticator.prototype.onFocus_ = function(e) {
-    this.webview_.focus();
+    if (this.authMode == AuthMode.DESKTOP)
+      this.webview_.focus();
   };
 
   /**
diff --git a/chrome/browser/resources/gaia_auth_host/post_message_channel.js b/chrome/browser/resources/gaia_auth_host/post_message_channel.js
index 5ab4c79..0b2b6e7 100644
--- a/chrome/browser/resources/gaia_auth_host/post_message_channel.js
+++ b/chrome/browser/resources/gaia_auth_host/post_message_channel.js
@@ -324,6 +324,7 @@
    * @constructor
    */
   function PostMessageChannel() {
+    Channel.apply(this, arguments);
   };
 
   PostMessageChannel.prototype = {
diff --git a/chrome/browser/resources/hotword/nacl_manager.js b/chrome/browser/resources/hotword/nacl_manager.js
index fef432d4..96da06fb 100644
--- a/chrome/browser/resources/hotword/nacl_manager.js
+++ b/chrome/browser/resources/hotword/nacl_manager.js
@@ -292,6 +292,7 @@
   assert(this.recognizerState_ == ManagerState_.UNINITIALIZED,
          'Recognizer not in uninitialized state. State: ' +
          this.recognizerState_);
+  assert(this.plugin_ == null);
   var langs = this.getPossibleLanguages_();
   var i, j;
   // For country-lang variations. For example, when combined with path it will
@@ -308,12 +309,12 @@
     }
 
     var plugin = this.createPlugin_(pluginSrc);
-    this.plugin_ = plugin;
-    if (!this.plugin_ || !this.plugin_.postMessage) {
-      document.body.removeChild(this.plugin_);
+    if (!plugin || !plugin.postMessage) {
+      document.body.removeChild(plugin);
       this.recognizerState_ = ManagerState_.ERROR;
       return false;
     }
+    this.plugin_ = plugin;
     this.modelUrl_ = chrome.extension.getURL(dataSrc);
     this.stream_ = stream;
     this.recognizerState_ = ManagerState_.LOADING;
diff --git a/chrome/browser/resources/hotword/state_manager.js b/chrome/browser/resources/hotword/state_manager.js
index 782939a..a7939b1 100644
--- a/chrome/browser/resources/hotword/state_manager.js
+++ b/chrome/browser/resources/hotword/state_manager.js
@@ -628,7 +628,8 @@
      * @private
      */
     handleStartup_: function() {
-      updateStatus();
+      // Nothing specific needs to be done here. This function exists solely to
+      // be registered on the startup event.
     }
   };
 
diff --git a/chrome/browser/resources/net_internals/sdch_view.html b/chrome/browser/resources/net_internals/sdch_view.html
index 2cbfca5..0288d968 100644
--- a/chrome/browser/resources/net_internals/sdch_view.html
+++ b/chrome/browser/resources/net_internals/sdch_view.html
@@ -3,10 +3,6 @@
     <li>SDCH Enabled:
       <span jscontent="!!sdch_enabled" id=sdch-view-sdch-enabled></span>
     </li>
-    <li>Secure Scheme Support Enabled:
-      <span jscontent="!!secure_scheme_support"
-            id=sdch-view-secure-scheme-support></span>
-    </li>
   </ul>
 
   <p>SDCH Errors:
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html
index 297095b6..4b30aab 100644
--- a/chrome/browser/resources/options/browser_options.html
+++ b/chrome/browser/resources/options/browser_options.html
@@ -6,7 +6,7 @@
   <include src="automatic_settings_reset_banner.html">
 <if expr="chromeos">
   <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html">
-  <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+  <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_types.html">
   <include src="secondary_user_banner.html">
   <section>
     <div id="network-section-header" class="section-header">
diff --git a/chrome/browser/resources/options/chromeos/internet_detail.js b/chrome/browser/resources/options/chromeos/internet_detail.js
index fa636df9..fa4e643 100644
--- a/chrome/browser/resources/options/chromeos/internet_detail.js
+++ b/chrome/browser/resources/options/chromeos/internet_detail.js
@@ -1284,7 +1284,10 @@
 
   DetailsInternetPage.configureNetwork = function() {
     var detailsPage = DetailsInternetPage.getInstance();
-    chrome.send('configureNetwork', [detailsPage.onc_.guid()]);
+    // This is an explicit request to show the configure dialog; do not show
+    // the enrollment dialog for networks missing a certificate.
+    var forceShow = true;
+    chrome.send('configureNetwork', [detailsPage.onc_.guid(), forceShow]);
     PageManager.closeOverlay();
   };
 
diff --git a/chrome/browser/resources/options/chromeos/network_list.js b/chrome/browser/resources/options/chromeos/network_list.js
index 318d96d..efba2b99 100644
--- a/chrome/browser/resources/options/chromeos/network_list.js
+++ b/chrome/browser/resources/options/chromeos/network_list.js
@@ -4,6 +4,8 @@
 
 /**
  * Partial definition of the result of networkingPrivate.getProperties()).
+ * TODO(stevenjb): Replace with chrome.networkingPrivate.NetworkStateProperties
+ * once that is fully speced.
  * @typedef {{
  *   ConnectionState: string,
  *   Cellular: {
@@ -211,9 +213,8 @@
       if (!isNetworkType(data.Type))
         return;
       var networkIcon = this.getNetworkIcon();
-      networkIcon.networkState = CrOncDataElement.create(
-          /** @type {chrome.networkingPrivate.NetworkStateProperties} */ (
-              data));
+      networkIcon.networkState =
+          /** @type {chrome.networkingPrivate.NetworkStateProperties} */ (data);
     },
 
     /**
@@ -827,7 +828,8 @@
           document.createElement('cr-network-icon'));
       buttonIconDiv.appendChild(networkIcon);
       networkIcon.isListItem = true;
-      networkIcon.networkState = CrOncDataElement.create(data);
+      networkIcon.networkState =
+          /** @type {chrome.networkingPrivate.NetworkStateProperties} */ (data);
     }
 
     var buttonLabel = menu.ownerDocument.createElement('span');
diff --git a/chrome/browser/resources/options/compiled_resources.gyp b/chrome/browser/resources/options/compiled_resources.gyp
index 88bb559a..270b340 100644
--- a/chrome/browser/resources/options/compiled_resources.gyp
+++ b/chrome/browser/resources/options/compiled_resources.gyp
@@ -50,7 +50,6 @@
 	  '../../../../third_party/closure_compiler/externs/chrome_extensions.js',
 	  '../../../../third_party/closure_compiler/externs/chrome_send_externs.js',
           '../../../../ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon_externs.js',
-          '../../../../ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data_externs.js',
 	],
       },
       'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'],
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.css b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.css
index a37cb4776..71e5b64 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.css
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.css
@@ -2,12 +2,6 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
-/* We introduce a wrapper animatable element and set the overflow since
- * core-transition interferes with the box-shadow from paper-shadow. */
-#animatable {
-  overflow: visible;
-}
-
 /* We introduce a wrapper aligner element as setting the relevant attributes
  * (horizontal justified layout center) have no effect on the core-toolbar. */
 #aligner {
@@ -49,16 +43,13 @@
   z-index: 3;
 }
 
-paper-progress::shadow #activeProgress {
-  background-color: rgb(50, 54, 57);
-}
-
-paper-progress::shadow #progressContainer {
-  background-color: rgba(0, 0, 0, 0.3);
+paper-progress {
+  --paper-progress-active-color: rgb(50, 54, 57);
+  --paper-progress-container-color: rgb(34, 36, 38);
 }
 
 paper-toolbar {
-  background-color: rgb(50, 54, 57);
+  background-color: transparent;
   color: rgb(241, 241, 241);
   font-size: 1.5em;
   height: 56px;
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
index 5e5586ea..3ba0ceb2 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
@@ -2,46 +2,46 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-shadow-flex-layout.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/image-icons.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/slide-down-animation.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/slide-up-animation.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animation-runner-behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-material/paper-material.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-progress/paper-progress.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-toolbar/paper-toolbar.html">
 <link rel="import" href="../viewer-page-selector/viewer-page-selector.html">
 
 <dom-module id="viewer-pdf-toolbar">
   <link rel="import" type="css" href="viewer-pdf-toolbar.css">
   <template>
-    <div id="animatable">
-      <paper-material class="fit"></paper-material>
+    <paper-material class="fit"></paper-material>
 
-      <!-- TODO(tsergeant): Re-enable once paper-progress is available in Polymer
-        0.8 -->
-      <!--<paper-progress value="{{loadProgress}}"></paper-progress>-->
+    <paper-progress value="{{loadProgress}}"></paper-progress>
 
-      <paper-toolbar class="core-narrow">
-        <div id="aligner" class="horizontal layout center">
-          <span id="title" class="invisible flex-5" title="{{docTitle}}">
-            <span>{{docTitle}}</span>
-          </span>
+    <paper-toolbar class="core-narrow">
+      <div id="aligner" class="horizontal layout center">
+        <span id="title" class="invisible flex-5" title="{{docTitle}}">
+          <span>{{docTitle}}</span>
+        </span>
 
-          <div class="flex-1" id="pageselector-container">
-            <viewer-page-selector id="pageselector" class="invisible"
-                doc-length="{{docLength}}" page-no="{{pageNo}}">
-            </viewer-page-selector>
-          </div>
-
-          <div id="buttons" class="invisible flex-5">
-            <paper-icon-button icon="image:rotate-right"
-                on-click="rotateRight"></paper-icon-button>
-            <paper-icon-button icon="bookmark-outline"
-                on-click="toggleBookmarks" hidden></paper-icon-button>
-            <paper-icon-button icon="save"
-                on-click="save"></paper-icon-button>
-            <paper-icon-button icon="print"
-                on-click="print"></paper-icon-button>
-          </div>
+        <div class="flex-1" id="pageselector-container">
+          <viewer-page-selector id="pageselector" class="invisible"
+              doc-length="{{docLength}}" page-no="{{pageNo}}">
+          </viewer-page-selector>
         </div>
-      </paper-toolbar>
-    </div>
+
+        <div id="buttons" class="invisible flex-5">
+          <paper-icon-button icon="image:rotate-right"
+              on-click="rotateRight"></paper-icon-button>
+          <paper-icon-button icon="bookmark-outline"
+              on-click="toggleBookmarks" hidden></paper-icon-button>
+          <paper-icon-button icon="save"
+              on-click="save"></paper-icon-button>
+          <paper-icon-button icon="print"
+              on-click="print"></paper-icon-button>
+        </div>
+      </div>
+    </paper-toolbar>
   </template>
 </dom-module>
 <script src="viewer-pdf-toolbar.js"></script>
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
index d4058d7..0e16409 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
@@ -5,6 +5,10 @@
   Polymer({
     is: 'viewer-pdf-toolbar',
 
+    behaviors: [
+      Polymer.NeonAnimationRunnerBehavior
+    ],
+
     properties: {
       /**
        * The current loading progress of the PDF document (0 - 100).
@@ -33,16 +37,46 @@
        * The number of pages in the PDF document.
        */
       docLength: Number,
+
+      /**
+       * Whether the toolbar is opened and visible.
+       */
+      opened: {
+        type: Boolean,
+        value: true
+      },
+
+      animationConfig: {
+        value: function() {
+          return {
+            'entry': {
+              name: 'slide-down-animation',
+              node: this,
+              timing: {
+                easing: 'cubic-bezier(0, 0, 0.2, 1)',
+                duration: 250
+              }
+            },
+            'exit': {
+              name: 'slide-up-animation',
+              node: this,
+              timing: {
+                easing: 'cubic-bezier(0.4, 0, 1, 1)',
+                duration: 250
+              }
+            }
+          };
+        }
+      }
     },
 
-    ready: function() {
-      /**
-       * @type {Object}
-       * Used in core-transition to determine whether the animatable is open.
-       * TODO(tsergeant): Add core-transition back in once it is in Polymer 0.8.
-       */
-      this.state_ = { opened: false };
-      this.show();
+    listeners: {
+      'neon-animation-finish': '_onAnimationFinished'
+    },
+
+    _onAnimationFinished: function() {
+      if (!this.opened)
+        this.style.visibility = 'hidden';
     },
 
     loadProgressChanged: function() {
@@ -54,17 +88,21 @@
     },
 
     hide: function() {
-      if (this.state_.opened)
+      if (this.opened)
         this.toggleVisibility();
     },
 
     show: function() {
-      if (!this.state_.opened)
+      if (!this.opened) {
         this.toggleVisibility();
+        this.style.visibility = 'initial';
+      }
     },
 
     toggleVisibility: function() {
-      this.state_.opened = !this.state_.opened;
+      this.opened = !this.opened;
+      this.cancelAnimation();
+      this.playAnimation(this.opened ? 'entry' : 'exit');
     },
 
     selectPageNumber: function() {
diff --git a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.html b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.html
index fd3f5bd5..84e5da1b 100644
--- a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.html
+++ b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.html
@@ -1,5 +1,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/transform-animation.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animation-runner-behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-fab/paper-fab.html">
 
 <dom-module id="viewer-zoom-button">
diff --git a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.js b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.js
index 823ca56..76b519f 100644
--- a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.js
+++ b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-button.js
@@ -4,27 +4,78 @@
 
 Polymer({
   is: 'viewer-zoom-button',
-  ready: function() {
-    this.state_ = { opened: true };
+
+  behaviors: [
+    Polymer.NeonAnimationRunnerBehavior
+  ],
+
+  properties: {
+    icon: String,
+
+    opened: {
+      type: Boolean,
+      value: true
+    },
+
+    delay: Number,
+
+    animationConfig: {
+      type: Object,
+      computed: 'computeAnimationConfig(delay)'
+    }
   },
 
-  show: function(delay) {
-    if (!this.state_.opened)
-      this.toggle_(delay);
+  computeAnimationConfig: function(delay) {
+    return {
+      'entry': {
+        name: 'transform-animation',
+        node: this,
+        timing: {
+          easing: 'cubic-bezier(0, 0, 0.2, 1)',
+          duration: 250,
+          delay: delay
+        },
+        transformFrom: 'translateX(150%)'
+      },
+      'exit': {
+        name: 'transform-animation',
+        node: this,
+        timing: {
+          easing: 'cubic-bezier(0.4, 0, 1, 1)',
+          duration: 250,
+          delay: delay
+        },
+        transformTo: 'translateX(150%)'
+      }
+    };
   },
 
-  hide: function(delay) {
-    if (this.state_.opened)
-      this.toggle_(delay);
+  listeners: {
+    'neon-animation-finish': '_onAnimationFinished'
   },
 
-  toggle_: function(delay) {
-    delay = delay || 0;
-    this.state_.opened = !this.state_.opened;
+  _onAnimationFinished: function() {
+    // Must use visibility: hidden so that the buttons do not change layout as
+    // they are hidden.
+    if (!this.opened)
+      this.style.visibility = 'hidden';
   },
 
-  activeChanged: function() {
-    if (this.active)
-      this.active = false;
-  }
+  show: function() {
+    if (!this.opened) {
+      this.toggle_();
+      this.style.visibility = 'initial';
+    }
+  },
+
+  hide: function() {
+    if (this.opened)
+      this.toggle_();
+  },
+
+  toggle_: function() {
+    this.opened = !this.opened;
+    this.cancelAnimation();
+    this.playAnimation(this.opened ? 'entry' : 'exit');
+  },
 });
diff --git a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.html b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.html
index 69b52df..9475dbb 100644
--- a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.html
+++ b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.html
@@ -10,9 +10,9 @@
       <div id="buttons">
         <!-- TODO(alexandrec): Replace with custom icons. -->
         <viewer-zoom-button id="fit-to-page-button" icon="fullscreen-exit"
-            on-click="fitToPage"></viewer-zoom-button>
+            on-click="fitToPage" delay="0"></viewer-zoom-button>
         <viewer-zoom-button id="fit-to-width-button" icon="fullscreen"
-            on-click="fitToWidth"></viewer-zoom-button>
+            on-click="fitToWidth" delay="50"></viewer-zoom-button>
       </div>
     </div>
   </template>
diff --git a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.js b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.js
index f3ace96..ea85bcb 100644
--- a/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.js
+++ b/chrome/browser/resources/pdf/elements/viewer-zoom-toolbar/viewer-zoom-toolbar.js
@@ -22,7 +22,7 @@
   },
 
   ready: function() {
-    this.visible_ = false;
+    this.visible_ = true;
   },
 
   zoomValueChanged: function() {
@@ -41,7 +41,7 @@
     if (!this.visible) {
       this.visible_ = true;
       this.$['fit-to-width-button'].show();
-      this.$['fit-to-page-button'].show(ANIMATION_INTERVAL);
+      this.$['fit-to-page-button'].show();
     }
   },
 
@@ -49,7 +49,7 @@
     if (this.visible) {
       this.visible_ = false;
       this.$['fit-to-page-button'].hide();
-      this.$['fit-to-width-button'].hide(ANIMATION_INTERVAL);
+      this.$['fit-to-width-button'].hide();
     }
   },
 });
diff --git a/chrome/browser/resources/pdf/ui_manager.js b/chrome/browser/resources/pdf/ui_manager.js
index 2f06a41..29bc322 100644
--- a/chrome/browser/resources/pdf/ui_manager.js
+++ b/chrome/browser/resources/pdf/ui_manager.js
@@ -4,7 +4,35 @@
 
 'use strict';
 
+/** Idle time in ms before the UI is hidden. */
 var HIDE_TIMEOUT = 2000;
+/** Velocity required in a mousemove to reveal the UI (pixels/sample). */
+var SHOW_VELOCITY = 20;
+/** Distance from the top or right of the screen required to reveal the UI. */
+var EDGE_REVEAL = 100;
+
+/**
+ * Whether a mousemove event is high enough velocity to reveal the toolbars.
+ * @param {MouseEvent} e Event to test.
+ * @return {boolean} true if the event is a high velocity mousemove, false
+ * otherwise.
+ */
+function isHighVelocityMouseMove(e) {
+  return e.type == 'mousemove' &&
+         e.movementX * e.movementX + e.movementY * e.movementY >
+             SHOW_VELOCITY * SHOW_VELOCITY;
+}
+
+/**
+ * Whether the mouse is close enough to the edge of the screen to keep the
+ * toolbars open.
+ * @param {Event} e Event to test.
+ * @return {boolean} true if the mouse is close to the top or right of the
+ * screen.
+ */
+function shouldKeepUiOpen(e) {
+  return (e.y < EDGE_REVEAL || e.x > window.innerWidth - EDGE_REVEAL);
+}
 
 /**
  * Creates a UI Manager to handle transitioning of toolbars.
@@ -19,13 +47,20 @@
   this.zoomToolbar_ = zoomToolbar;
 
   this.uiTimeout_ = null;
+  this.keepOpen_ = false;
 
-  var userInputs = ['click', 'keydown', 'mousemove', 'scroll'];
+  var userInputs = ['keydown', 'mousemove'];
   for (var i = 0; i < userInputs.length; i++)
-    this.window_.addEventListener(userInputs[i], this.showUi_.bind(this));
+    this.window_.addEventListener(userInputs[i], this.handleEvent.bind(this));
 }
 
 UiManager.prototype = {
+  handleEvent: function(e) {
+    this.keepOpen_ = shouldKeepUiOpen(e);
+    if (e.type != 'mousemove' || this.keepOpen_ || isHighVelocityMouseMove(e))
+      this.showUi_();
+  },
+
   /**
    * @private
    * Display the toolbar and any pane that was previously opened.
@@ -33,7 +68,6 @@
   showUi_: function() {
     this.toolbar_.show();
     this.zoomToolbar_.show();
-
     this.hideUiAfterTimeout();
   },
 
@@ -42,8 +76,10 @@
    * Hide the toolbar and any pane that was previously opened.
    */
   hideUi_: function() {
-    this.toolbar_.hide();
-    this.zoomToolbar_.hide();
+    if (!this.keepOpen_) {
+      this.toolbar_.hide();
+      this.zoomToolbar_.hide();
+    }
   },
 
   /**
diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js
index edce220a..9e9c88c 100644
--- a/chrome/browser/resources/print_preview/data/destination.js
+++ b/chrome/browser/resources/print_preview/data/destination.js
@@ -54,6 +54,8 @@
    *          lastAccessTime: (number|undefined),
    *          isTosAccepted: (boolean|undefined),
    *          cloudID: (string|undefined),
+   *          provisionalType:
+   *              (print_preview.Destination.ProvisionalType|undefined),
    *          extensionId: (string|undefined),
    *          extensionName: (string|undefined),
    *          description: (string|undefined)}=} opt_params Optional parameters
@@ -167,6 +169,23 @@
      * @private {string}
      */
     this.extensionName_ = (opt_params && opt_params.extensionName) || '';
+
+    /**
+     * Different from {@code Destination.ProvisionalType.NONE} if the
+     * destination is provisional. Provisional destinations cannot be selected
+     * as they are, but have to be resolved first (i.e. extra steps have to be
+     * taken to get actual destination properties, which should replace the
+     * provisional ones). Provisional destination resolvment flow will be
+     * started when the user attempts to select the destination in search UI.
+     * @private {Destination.ProvisionalType}
+     */
+    this.provisionalType_ = (opt_params && opt_params.provisionalType) ||
+                            Destination.ProvisionalType.NONE;
+
+    assert(this.provisionalType_ !=
+               Destination.ProvisionalType.NEEDS_USB_PERMISSON ||
+           this.isExtension,
+           'Provisional USB destination only supprted with extension origin.');
   };
 
   /**
@@ -226,6 +245,21 @@
   };
 
   /**
+   * Enumeration specifying whether a destination is provisional and the reason
+   * the destination is provisional.
+   * @enum {string
+   */
+  Destination.ProvisionalType = {
+    /** Destination is not provisional. */
+    NONE: 'NONE',
+    /**
+     * User has to grant USB access for the destination to its provider.
+     * Used for destinations with extension origin.
+     */
+    NEEDS_USB_PERMISSION: 'NEEDS_USB_PERMISSION'
+  };
+
+  /**
    * Enumeration of relative icon URLs for various types of destinations.
    * @enum {string}
    * @private
@@ -501,6 +535,22 @@
           this.extraPropertiesToMatch.some(function(property) {
             return property.match(query);
           });
+    },
+
+    /**
+     * Gets the destination's provisional type.
+     * @return {Destination.ProvisionalType}
+     */
+    get provisionalType() {
+      return this.provisionalType_;
+    },
+
+    /**
+     * Whether the destinaion is provisional.
+     * @return {boolean}
+     */
+    get isProvisional() {
+      return this.provisionalType_ != Destination.ProvisionalType.NONE;
     }
   };
 
diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js
index 3ed368e..5aeaffe2c 100644
--- a/chrome/browser/resources/print_preview/data/destination_store.js
+++ b/chrome/browser/resources/print_preview/data/destination_store.js
@@ -199,6 +199,8 @@
     DESTINATION_SELECT: 'print_preview.DestinationStore.DESTINATION_SELECT',
     DESTINATIONS_INSERTED:
         'print_preview.DestinationStore.DESTINATIONS_INSERTED',
+    PROVISIONAL_DESTINATION_RESOLVED:
+        'print_preview.DestinationStore.PROVISIONAL_DESTINATION_RESOLVED',
     CACHED_SELECTED_DESTINATION_INFO_READY:
         'print_preview.DestinationStore.CACHED_SELECTED_DESTINATION_INFO_READY',
     SELECTED_DESTINATION_CAPABILITIES_READY:
@@ -461,6 +463,10 @@
             this, DestinationStore.EventType.DESTINATION_SELECT);
         return;
       }
+
+      assert(!destination.isProvisional,
+             'Unable to select provisonal destinations');
+
       // Update and persist selected destination.
       this.selectedDestination_ = destination;
       this.selectedDestination_.isRecent = true;
@@ -512,6 +518,19 @@
     },
 
     /**
+     * Attempts to resolve a provisional destination.
+     * @param {!print_preview.Destination} destinaion Provisional destination
+     *     that should be resolved.
+     */
+    resolveProvisionalDestination: function(destination) {
+      assert(
+          destination.provisionalType ==
+              print_preview.Destination.ProvisionalType.NEEDS_USB_PERMISSION,
+          'Provisional type cannot be resolved.');
+      this.nativeLayer_.grantExtensionPrinterAccess(destination.id);
+    },
+
+    /**
      * Selects 'Save to PDF' destination (since it always exists).
      * @private
      */
@@ -614,6 +633,53 @@
     },
 
     /**
+     * Event handler for {@code
+     * print_preview.NativeLayer.EventType.PROVISIONAL_DESTINATION_RESOLVED}.
+     * Currently assumes the provisional destination is an extension
+     * destination.
+     * Called when a provisional destination resolvement attempt finishes.
+     * The provisional destination is removed from the store and replaced with
+     * a destination created from the resolved destination properties, if any
+     * are reported.
+     * Emits {@code DestinationStore.EventType.PROVISIONAL_DESTINATION_RESOLVED}
+     * event.
+     * @param {!Event} The event containing the provisional destination ID and
+     *     resolved destination description. If the destination was not
+     *     successfully resolved, the description will not be set.
+     * @private
+     */
+    handleProvisionalDestinationResolved_: function(evt) {
+      var provisionalDestinationIndex = -1;
+      var provisionalDestination = null;
+      for (var i = 0; i < this.destinations_.length; ++i) {
+        if (evt.provisionalId == this.destinations_[i].id) {
+          provisionalDestinationIndex = i;
+          provisionalDestination = this.destinations_[i];
+          break;
+        }
+      }
+
+      if (!provisionalDestination)
+        return;
+
+      this.destinations_.splice(provisionalDestinationIndex, 1);
+      delete this.destinationMap_[this.getKey_(provisionalDestination)];
+
+      var destination = evt.destination ?
+          print_preview.ExtensionDestinationParser.parse(evt.destination) :
+          null;
+
+      if (destination)
+        this.insertIntoStore_(destination);
+
+      var event = new Event(
+          DestinationStore.EventType.PROVISIONAL_DESTINATION_RESOLVED);
+      event.provisionalId = evt.provisionalId;
+      event.destination = destination;
+      this.dispatchEvent(event);
+    },
+
+    /**
      * Inserts {@code destination} to the data store and dispatches a
      * DESTINATIONS_INSERTED event.
      * @param {!print_preview.Destination} destination Print destination to
@@ -782,6 +848,10 @@
           this.nativeLayer_,
           print_preview.NativeLayer.EventType.EXTENSION_CAPABILITIES_SET,
           this.onExtensionCapabilitiesSet_.bind(this));
+      this.tracker_.add(
+          this.nativeLayer_,
+          print_preview.NativeLayer.EventType.PROVISIONAL_DESTINATION_RESOLVED,
+          this.handleProvisionalDestinationResolved_.bind(this));
     },
 
     /**
diff --git a/chrome/browser/resources/print_preview/data/local_parsers.js b/chrome/browser/resources/print_preview/data/local_parsers.js
index d367134..f6b4c73 100644
--- a/chrome/browser/resources/print_preview/data/local_parsers.js
+++ b/chrome/browser/resources/print_preview/data/local_parsers.js
@@ -75,6 +75,11 @@
    * @return {!print_preview.Destination} Parsed destination.
    */
   ExtensionDestinationParser.parse = function(destinationInfo) {
+    var provisionalType =
+        destinationInfo.provisional ?
+            print_preview.Destination.ProvisionalType.NEEDS_USB_PERMISSION :
+            print_preview.Destination.ProvisionalType.NONE;
+
     return new print_preview.Destination(
         destinationInfo.id,
         print_preview.Destination.Type.LOCAL,
@@ -84,7 +89,8 @@
         print_preview.Destination.ConnectionStatus.ONLINE,
         {description: destinationInfo.description || '',
          extensionId: destinationInfo.extensionId,
-         extensionName: destinationInfo.extensionName || ''});
+         extensionName: destinationInfo.extensionName || '',
+         provisionalType: provisionalType});
   };
 
   // Export
diff --git a/chrome/browser/resources/print_preview/native_layer.js b/chrome/browser/resources/print_preview/native_layer.js
index 8c72a53..d9289ff 100644
--- a/chrome/browser/resources/print_preview/native_layer.js
+++ b/chrome/browser/resources/print_preview/native_layer.js
@@ -67,6 +67,10 @@
         this.onEnableManipulateSettingsForTest_.bind(this);
     global.printPresetOptionsFromDocument =
         this.onPrintPresetOptionsFromDocument_.bind(this);
+    global.onProvisionalPrinterResolved =
+        this.onProvisionalDestinationResolved_.bind(this);
+    global.failedToResolveProvisionalPrinter =
+        this.failedToResolveProvisionalDestination_.bind(this);
   };
 
   /**
@@ -106,6 +110,8 @@
     EXTENSION_CAPABILITIES_SET:
         'print_preview.NativeLayer.EXTENSION_CAPABILITIES_SET',
     PRINT_PRESET_OPTIONS: 'print_preview.NativeLayer.PRINT_PRESET_OPTIONS',
+    PROVISIONAL_DESTINATION_RESOLVED:
+        'print_preview.NativeLayer.PROVISIONAL_DESTINATION_RESOLVED'
   };
 
   /**
@@ -214,6 +220,18 @@
     },
 
     /**
+     * Requests Chrome to resolve provisional extension destination by granting
+     * the provider extension access to the printer. Chrome will respond with
+     * the resolved destination properties by calling
+     * {@code onProvisionalPrinterResolved}, or in case of an error
+     * {@code failedToResolveProvisionalPrinter}
+     * @param {string} provisionalDestinationId
+     */
+    grantExtensionPrinterAccess: function(provisionalDestinationId) {
+      chrome.send('grantExtensionPrinterAccess', [provisionalDestinationId]);
+    },
+
+    /**
      * @param {!print_preview.Destination} destination Destination to print to.
      * @param {!print_preview.ticket_items.Color} color Color ticket item.
      * @return {number} Native layer color model.
@@ -770,7 +788,8 @@
      *                 extensionName: string,
      *                 id: string,
      *                 name: string,
-     *                 description: (string|undefined)}>} printers The list
+     *                 description: (string|undefined),
+     *                 provisional: (boolean|undefined)}>} printers The list
      *     containing information about printers added by an extension.
      * @param {boolean} done Whether this is the final list of extension
      *     managed printers.
@@ -796,6 +815,42 @@
       this.dispatchEvent(event);
     },
 
+    /**
+     * Called when Chrome reports that attempt to resolve a provisional
+     * destination failed.
+     * @param {string} destinationId The provisional destination ID.
+     * @private
+     */
+    failedToResolveProvisionalDestination_: function(destinationId) {
+      var evt = new Event(
+          NativeLayer.EventType.PROVISIONAL_DESTINATION_RESOLVED);
+      evt.provisionalId = destinationId;
+      evt.destination = null;
+      this.dispatchEvent(evt);
+    },
+
+    /**
+     * Called when Chrome reports that a provisional destination has been
+     * successfully resolved.
+     * Currently used only for extension provided destinations.
+     * @param {string} provisionalDestinationId The provisional destination id.
+     * @param {!{extensionId: string,
+     *           extensionName: string,
+     *           id: string,
+     *           name: string,
+     *           description: (string|undefined)}} destinationInfo The resolved
+     *     destination info.
+     * @private
+     */
+    onProvisionalDestinationResolved_: function(provisionalDestinationId,
+                                                destinationInfo) {
+      var evt = new Event(
+          NativeLayer.EventType.PROVISIONAL_DESTINATION_RESOLVED);
+      evt.provisionalId = provisionalDestinationId;
+      evt.destination = destinationInfo;
+      this.dispatchEvent(evt);
+    },
+
    /**
      * Allows for onManipulateSettings to be called
      * from the native layer.
diff --git a/chrome/browser/resources/print_preview/print_preview.html b/chrome/browser/resources/print_preview/print_preview.html
index 2c8e44e..bbcb5a1 100644
--- a/chrome/browser/resources/print_preview/print_preview.html
+++ b/chrome/browser/resources/print_preview/print_preview.html
@@ -36,6 +36,7 @@
   <link rel="stylesheet" href="search/destination_list_item.css">
   <link rel="stylesheet" href="search/destination_search.css">
   <link rel="stylesheet" href="search/fedex_tos.css">
+  <link rel="stylesheet" href="search/provisional_destination_resolver.css">
 
   <script src="chrome://resources/js/action_link.js"></script>
   <script src="chrome://resources/js/cr.js"></script>
@@ -103,6 +104,7 @@
   <include src="search/destination_list.html">
   <include src="search/destination_list_item.html">
   <include src="search/fedex_tos.html">
+  <include src="search/provisional_destination_resolver.html">
 
   <script src="chrome://resources/js/i18n_template.js"></script>
 </body>
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js
index cb24341..96336e8 100644
--- a/chrome/browser/resources/print_preview/print_preview.js
+++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -1314,6 +1314,7 @@
 <include src="search/destination_list_item.js">
 <include src="search/destination_search.js">
 <include src="search/fedex_tos.js">
+<include src="search/provisional_destination_resolver.js">
 
 window.addEventListener('DOMContentLoaded', function() {
   printPreview = new print_preview.PrintPreview();
diff --git a/chrome/browser/resources/print_preview/print_preview_focus_manager.js b/chrome/browser/resources/print_preview/print_preview_focus_manager.js
index be4c22d..b5d74ef 100644
--- a/chrome/browser/resources/print_preview/print_preview_focus_manager.js
+++ b/chrome/browser/resources/print_preview/print_preview_focus_manager.js
@@ -21,8 +21,11 @@
 
     /** @override */
     getFocusParent: function() {
-      return document.querySelector('.overlay:not([hidden])') ||
-          document.body;
+      var el = document.body;
+      var newEl = null;
+      while (newEl = el.querySelector('.overlay:not([hidden])'))
+        el = newEl;
+      return el;
     }
   };
 
diff --git a/chrome/browser/resources/print_preview/search/destination_search.css b/chrome/browser/resources/print_preview/search/destination_search.css
index ea76b84..113fd652 100644
--- a/chrome/browser/resources/print_preview/search/destination_search.css
+++ b/chrome/browser/resources/print_preview/search/destination_search.css
@@ -12,7 +12,7 @@
   pointer-events: none;
 }
 
-#destination-search .page {
+#destination-search > .page {
   width: 640px;
 }
 
diff --git a/chrome/browser/resources/print_preview/search/destination_search.js b/chrome/browser/resources/print_preview/search/destination_search.js
index 60102240..0922bca 100644
--- a/chrome/browser/resources/print_preview/search/destination_search.js
+++ b/chrome/browser/resources/print_preview/search/destination_search.js
@@ -66,6 +66,14 @@
     this.registerPromoShownMetricRecorded_ = false;
 
     /**
+     * Child overlay used for resolving a provisional destination. The overlay
+     * is shown when the user attempts to select a provisional destination.
+     * Set only when a destination is being resolved.
+     * @private {?print_preview.ProvisionalDestinationResolver}
+     */
+    this.provisionalDestinationResolver_ = null;
+
+    /**
      * Search box used to search through the destination lists.
      * @type {!print_preview.SearchBox}
      * @private
@@ -153,6 +161,8 @@
         // Collapse all destination lists
         this.localList_.setIsShowAll(false);
         this.cloudList_.setIsShowAll(false);
+        if (this.provisionalDestinationResolver_)
+          this.provisionalDestinationResolver_.cancel();
         this.resetSearch_();
       }
     },
@@ -232,6 +242,11 @@
           this.destinationStore_,
           print_preview.DestinationStore.EventType.DESTINATION_SEARCH_DONE,
           this.onDestinationSearchDone_.bind(this));
+      this.tracker.add(
+          this.destinationStore_,
+          print_preview.DestinationStore.EventType
+              .PROVISIONAL_DESTINATION_RESOLVED,
+          this.onDestinationsInserted_.bind(this));
 
       this.tracker.add(
           this.invitationStore_,
@@ -544,14 +559,68 @@
     },
 
     /**
-     * Called when a destination is selected. Clears the search and hides the
-     * widget.
+     * Handler for {@code print_preview.DestinationListItem.EventType.SELECT}
+     * event, which is called when a destinationi list item is selected.
      * @param {Event} evt Contains the selected destination.
      * @private
      */
     onDestinationSelect_: function(evt) {
+      this.handleOnDestinationSelect_(evt.destination);
+    },
+
+    /**
+     * Called when a destination is selected. Clears the search and hides the
+     * widget. If The destination is provisional, it runs provisional
+     * destination resolver first.
+     * @param {!print_preview.Destination} destination The selected destination.
+     * @private
+     */
+    handleOnDestinationSelect_: function(destination) {
+      if (destination.isProvisional) {
+        assert(!this.provisionalDestinationResolver_,
+               'Provisional destination resolver already exists.');
+        this.provisionalDestinationResolver_ =
+            print_preview.ProvisionalDestinationResolver.create(
+                this.destinationStore_, destination);
+        assert(!!this.provisionalDestinationResolver_,
+               'Unable to create provisional destination resolver');
+
+        var lastFocusedElement = document.activeElement;
+        this.addChild(this.provisionalDestinationResolver_);
+        this.provisionalDestinationResolver_.run(this.getElement())
+            .then(
+                /**
+                 * @param {!print_preview.Destination} resolvedDestination
+                 *    Destination to which the provisional destination was
+                 *    resolved.
+                 */
+                function(resolvedDestination) {
+                  this.handleOnDestinationSelect_(resolvedDestination);
+                }.bind(this))
+            .catch(
+                function() {
+                  console.log('Failed to resolve provisional destination: ' +
+                              destination.id);
+                })
+            .then(
+                function() {
+                  this.removeChild(this.provisionalDestinationResolver_);
+                  this.provisionalDestinationResolver_ = null;
+
+                  // Restore focus to the previosly focused element if it's
+                  // still shown in the search.
+                  if (lastFocusedElement &&
+                      this.getIsVisible() &&
+                      getIsVisible(lastFocusedElement) &&
+                      this.getElement().contains(lastFocusedElement)) {
+                    lastFocusedElement.focus();
+                  }
+                }.bind(this));
+        return;
+      }
+
       this.setIsVisible(false);
-      this.destinationStore_.selectDestination(evt.destination);
+      this.destinationStore_.selectDestination(destination);
       this.metrics_.record(print_preview.Metrics.DestinationSearchBucket.
           DESTINATION_CLOSED_CHANGED);
     },
diff --git a/chrome/browser/resources/print_preview/search/provisional_destination_resolver.css b/chrome/browser/resources/print_preview/search/provisional_destination_resolver.css
new file mode 100644
index 0000000..4d487aa2
--- /dev/null
+++ b/chrome/browser/resources/print_preview/search/provisional_destination_resolver.css
@@ -0,0 +1,40 @@
+/* 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. */
+
+.usb-permission-page .throbber-placeholder {
+  height: 16px;
+  margin: 4px;
+  width: 16px;
+}
+
+.usb-permission-message {
+  margin: 0;
+  padding-bottom: 35px;
+}
+
+.usb-permission-prompt {
+  padding: 35px 20px;
+  width: 360px;
+}
+
+.usb-permission-extension-desc {
+  display: flex;
+}
+
+.usb-permission-extension-icon {
+  background-position: center;
+  background-repeat: none;
+  height: 24px;
+  width: 24px;
+}
+
+.usb-permission-extension-name {
+  flex: 1;
+  line-height: 24px;
+  overflow-wrap: break-word;
+}
+
+.usb-permission-page > .action-area {
+  margin: 0 3px 10px;
+}
diff --git a/chrome/browser/resources/print_preview/search/provisional_destination_resolver.html b/chrome/browser/resources/print_preview/search/provisional_destination_resolver.html
new file mode 100644
index 0000000..f0e141d4
--- /dev/null
+++ b/chrome/browser/resources/print_preview/search/provisional_destination_resolver.html
@@ -0,0 +1,22 @@
+<div id="extension-usb-resolver" class="overlay transparent" hidden>
+  <div class="page usb-permission-page">
+    <div class="close-button"></div>
+    <div class="usb-permission-prompt">
+      <p class="usb-permission-message"></p>
+      <div class="usb-permission-extension-desc">
+        <div class="throbber-placeholder" role="img" alt=""></div>
+        <div class="usb-permission-extension-icon" role="img" alt=""></div>
+        <div class="usb-permission-extension-name"></div>
+      </div>
+    </div>
+    <div class="action-area">
+      <div class="button-strip">
+        <button class="cancel" i18n-content="goBackButton">
+        </button>
+        <button class="usb-permission-ok-button default"
+                i18n-content="selectButton">
+        </button>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/chrome/browser/resources/print_preview/search/provisional_destination_resolver.js b/chrome/browser/resources/print_preview/search/provisional_destination_resolver.js
new file mode 100644
index 0000000..a78732f
--- /dev/null
+++ b/chrome/browser/resources/print_preview/search/provisional_destination_resolver.js
@@ -0,0 +1,252 @@
+// 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.
+
+cr.define('print_preview', function() {
+  'use strict';
+
+  /** @enum {string} */
+  var ResolverState = {
+    INITIAL: 'INITIAL',
+    ACTIVE: 'ACTIVE',
+    GRANTING_PERMISSION: 'GRANTING_PERMISSION',
+    ERROR: 'ERROR',
+    DONE: 'DONE'
+  };
+
+  /**
+   * Utility class for bundling a promise object with it's resolver methods.
+   * @param {!Promise<!print_preview.Destination>} promise A promise returning
+   *     a destination.
+   * @param {function(!print_preview.Destination)} resolve Function resolving
+   *     the promise.
+   * @param {function()} reject Function for rejecting the promise.
+   * @constructor @struct
+   */
+  function PromiseResolver(promise, resolve, reject) {
+    /** @type {!Promise<!print_preview.Destination>} */
+    this.promise = promise;
+    /** @type {function(!print_preview.Destination)} */
+    this.resolve = resolve;
+    /** @type {function()} */
+    this.reject = reject;
+  }
+
+  /**
+   * Create a Promise and an associated PromiseResolver.
+   * @return {!PromiseResolver}
+   */
+  PromiseResolver.create = function() {
+    var reject = null;
+    var resolve = null;
+    /** @type {!Promise<!print_preview.Destination>} */
+    var promise = new Promise(function(resolvePromise, rejectPromise) {
+      resolve = /** @type {function(!print_preview.Destination)}*/(
+          resolvePromise);
+      reject = /** @type {function()} */(rejectPromise);
+    });
+
+    return new PromiseResolver(promise, resolve, reject);
+  };
+
+  /**
+   * Overlay used to resolve a provisional extension destination. The user is
+   * prompted to allow print preview to grant a USB device access to an
+   * extension associated with the destination. If user agrees destination
+   * resolvement is attempted (which includes granting the extension USB access
+   * and requesting destination description from the extension). The overlay is
+   * hidden when destination resolving is done.
+   *
+   * @param {!print_preview.DestinationStore} destinationStore The destination
+   *    store containing the destination. Used as a proxy to native layer for
+   *    resolving the destination.
+   * @param {!print_preview.Destination} destination The destination that has
+   *     to be resolved.
+   * @constructor
+   * @extends {print_preview.Overlay}
+   */
+  function ProvisionalDestinationResolver(destinationStore, destination) {
+    print_preview.Overlay.call(this);
+
+    /** @private {!print_preview.DestinationStore} */
+    this.destinationStore_ = destinationStore;
+    /** @private {!print_preview.Destination} */
+    this.destination_ = destination;
+
+    /** @private {ResolverState} */
+    this.state_ = ResolverState.INITIAL;
+
+    /**
+     * Promise resolver for promise returned by {@code this.run}.
+     * @private {?PromiseResolver}
+     */
+    this.promiseResolver_ = null;
+  }
+
+  /**
+   * @param {!print_preview.DestinationStore} store
+   * @param {!print_preview.Destination} destination
+   * @return {?ProvisionalDestinationResolver}
+   */
+  ProvisionalDestinationResolver.create = function(store, destination) {
+    if (destination.provisionalType !=
+            print_preview.Destination.ProvisionalType.NEEDS_USB_PERMISSION) {
+      return null;
+    }
+    return new ProvisionalDestinationResolver(store, destination);
+  };
+
+  ProvisionalDestinationResolver.prototype = {
+    __proto__: print_preview.Overlay.prototype,
+
+    /** @override */
+    enterDocument: function() {
+      print_preview.Overlay.prototype.enterDocument.call(this);
+
+      this.tracker.add(
+          this.getChildElement('.usb-permission-ok-button'),
+          'click',
+          this.startResolveDestination_.bind(this));
+      this.tracker.add(
+          this.getChildElement('.cancel'),
+          'click',
+          this.cancel.bind(this));
+
+      this.tracker.add(
+          this.destinationStore_,
+          print_preview.DestinationStore.EventType
+              .PROVISIONAL_DESTINATION_RESOLVED,
+          this.onDestinationResolved_.bind(this));
+    },
+
+    /** @override */
+    onSetVisibleInternal: function(visible) {
+      if (visible) {
+        assert(this.state_ == ResolverState.INITIAL,
+               'Showing overlay while not in initial state.');
+        assert(!this.promiseResolver_, 'Promise resolver already set.');
+        this.setState_(ResolverState.ACTIVE);
+        this.promiseResolver_ = PromiseResolver.create();
+        this.getChildElement('.default').focus();
+      } else if (this.state_ != ResolverState.DONE) {
+        assert(this.state_ != ResolverState.INITIAL, 'Hiding in initial state');
+        this.setState_(ResolverState.DONE);
+        this.promiseResolver_.reject();
+        this.promiseResolver_ = null;
+      }
+    },
+
+    /** @override */
+    createDom: function() {
+      this.setElementInternal(this.cloneTemplateInternal(
+          'extension-usb-resolver'));
+
+      var extNameEl = this.getChildElement('.usb-permission-extension-name');
+      extNameEl.title = this.destination_.extensionName;
+      extNameEl.textContent = this.destination_.extensionName;
+
+      var extIconEl = this.getChildElement('.usb-permission-extension-icon');
+      extIconEl.style.backgroundImage = '-webkit-image-set(' +
+          'url(chrome://extension-icon/' +
+               this.destination_.extensionId + '/24/1) 1x,' +
+          'url(chrome://extension-icon/' +
+               this.destination_.extensionId + '/48/1) 2x)';
+    },
+
+    /**
+     * Handler for click on OK button. It initiates destination resolving.
+     * @private
+     */
+    startResolveDestination_: function() {
+      assert(this.state_ == ResolverState.ACTIVE,
+             'Invalid state in request grant permission');
+
+      this.setState_(ResolverState.GRANTING_PERMISSION);
+      this.destinationStore_.resolveProvisionalDestination(this.destination_);
+    },
+
+    /**
+     * Handler for PROVISIONAL_DESTINATION_RESOLVED event. It finalizes the
+     * resolver state once the destination associated with the resolver gets
+     * resolved.
+     * @param {Event} event
+     * @private
+     */
+    onDestinationResolved_: function(event) {
+      if (this.state_ == ResolverState.DONE)
+        return;
+
+      if (event.provisionalId != this.destination_.id)
+        return;
+
+      if (event.destination) {
+        this.setState_(ResolverState.DONE);
+        this.promiseResolver_.resolve(event.destination);
+        this.promiseResolver_ = null;
+        this.setIsVisible(false);
+      } else {
+        this.setState_(ResolverState.ERROR);
+      }
+    },
+
+    /**
+     * Sets new resolver state and updates the UI accordingly.
+     * @param {ResolverState} state
+     * @private
+     */
+    setState_: function(state) {
+      if (this.state_ == state)
+        return;
+
+      this.state_ = state;
+      this.updateUI_();
+    },
+
+    /**
+     * Updates the resolver overlay UI to match the resolver state.
+     * @private
+     */
+    updateUI_: function() {
+      this.getChildElement('.usb-permission-ok-button').hidden =
+          this.state_ == ResolverState.ERROR;
+      this.getChildElement('.usb-permission-ok-button').disabled =
+          this.state_ != ResolverState.ACTIVE;
+
+      // If OK button is disabled, make sure Cancel button gets focus.
+      if (this.state_ != ResolverState.ACTIVE)
+        this.getChildElement('.cancel').focus();
+
+      this.getChildElement('.throbber-placeholder').classList.toggle(
+          'throbber',
+          this.state_ == ResolverState.GRANTING_PERMISSION);
+
+      this.getChildElement('.usb-permission-extension-desc').hidden =
+          this.state_ == ResolverState.ERROR;
+
+      this.getChildElement('.usb-permission-message').textContent =
+          this.state_ == ResolverState.ERROR ?
+              loadTimeData.getStringF('resolveExtensionUSBErrorMessage',
+                                      this.destination_.extensionName) :
+              loadTimeData.getString('resolveExtensionUSBPermissionMessage');
+    },
+
+    /**
+     * Initiates and shows the resolver overlay.
+     * @param {!HTMLElement} parent The element that should parent the resolver
+     *     UI.
+     * @return {!Promise<!print_preview.Destination>} Promise that will be
+     * fulfilled when the destination resolving is finished.
+     */
+    run: function(parent) {
+      this.render(parent);
+      this.setIsVisible(true);
+
+      assert(this.promiseResolver_, 'Promise resolver not created.');
+      return this.promiseResolver_.promise;
+    }
+  };
+
+  return {
+    ProvisionalDestinationResolver: ProvisionalDestinationResolver
+  };
+});
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html
index 7ebb033..a0e67bf 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -41,7 +41,7 @@
       </cr-settings-checkbox>
 
       <div class="autoclick-delay-label"
-          hidden$="{{!prefs.settings.a11y.autoclick}}">
+          hidden$="[[!prefs.settings.a11y.autoclick]]">
         <span i18n-content="delayBeforeClickLabel"></span>
         <select id="autoclickDropdown"
             value="{{prefs.settings.a11y.autoclick_delay_ms::change}}">
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.html b/chrome/browser/resources/settings/appearance_page/appearance_page.html
index 19c746c2..0727be8 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_page.html
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.html
@@ -16,7 +16,9 @@
         <cr-button id="get-themes" i18n-content="getThemes"
             on-click="openThemesGallery_">
         </cr-button>
-        <cr-button i18n-content="resetToDefaultTheme" disabled></cr-button>
+        <cr-button id="resetTheme" i18n-content="resetToDefaultTheme" disabled
+            on-click="resetTheme_">
+        </cr-button>
       </div>
       <hr>
       <cr-settings-checkbox pref="{{prefs.browser.show_home_button}}"
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.js b/chrome/browser/resources/settings/appearance_page/appearance_page.js
index 612c999c..0323065 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_page.js
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.js
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+
+
 /**
- * @fileoverview
  * 'cr-settings-appearance-page' is the settings page containing appearance
  * settings.
  *
@@ -21,6 +22,17 @@
 Polymer({
   is: 'cr-settings-appearance-page',
 
+  /** @override */
+  attached: function() {
+    // Query the initial state.
+    cr.sendWithCallback('getResetThemeEnabled', undefined,
+                        this.setResetThemeEnabled.bind(this));
+
+    // Set up the change event listener.
+    cr.addWebUIListener('reset-theme-enabled-changed',
+                        this.setResetThemeEnabled.bind(this));
+  },
+
   properties: {
     /**
      * Preferences state.
@@ -73,8 +85,17 @@
     },
   },
 
+  setResetThemeEnabled: function(enabled) {
+    this.$.resetTheme.disabled = !enabled;
+  },
+
   /** @private */
   openThemesGallery_: function() {
     window.open(loadTimeData.getString('themesGalleryUrl'));
   },
+
+  /** @private */
+  resetTheme_: function() {
+    chrome.send('resetTheme');
+  },
 });
diff --git a/chrome/browser/resources/settings/checkbox/checkbox.js b/chrome/browser/resources/settings/checkbox/checkbox.js
index 40d9fde..d4bdeb4 100644
--- a/chrome/browser/resources/settings/checkbox/checkbox.js
+++ b/chrome/browser/resources/settings/checkbox/checkbox.js
@@ -19,7 +19,7 @@
   properties: {
     /**
      * The boolean preference object to control.
-     * @type {?chrome.settingsPrivate.PrefObject}
+     * @type {?PrefObject}
      */
     pref: {
       type: Object,
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
index 2e15737..327d49021 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -1,5 +1,5 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_types.html">
 <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html">
 
 <dom-module id="cr-settings-internet-detail-page">
@@ -10,7 +10,8 @@
       <div class="layout vertical">
         <div id="titleDiv" class="layout horizontal">
           <div class="layout center horizontal flex">
-            <cr-network-icon id="networkIcon"></cr-network-icon>
+            <cr-network-icon id="networkIcon" network-state="[[networkState]]">
+            </cr-network-icon>
             <span id="networkName">[[getStateName_(networkState)]]</span>
             <span id="networkState" class="[[getStateClass_(networkState)]]"
                 >[[getStateText_(networkState)]]</span>
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
index 114cccd..17f0526 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -12,9 +12,6 @@
  */
 (function() {
 
-/** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
-var NetworkStateProperties;
-
 Polymer({
   is: 'cr-settings-internet-detail-page',
 
@@ -92,7 +89,7 @@
     /**
      * The current state for the network matching |guid|.
      *
-     * @type {?NetworkStateProperties}
+     * @type {?CrOnc.NetworkStateProperties}
      */
     networkState: {
       type: Object,
@@ -143,18 +140,6 @@
   },
 
   /**
-   * Polymer networkState changed method.
-   */
-  networkStateChanged_: function() {
-    if (!this.networkState)
-      return;
-    // Set networkIcon.networkState explicitly since networkState is an element.
-    // TODO(stevenjb): Remove this function when CrOncDataElement is removed.
-    this.$.networkIcon.networkState =
-        CrOncDataElement.create(this.networkState);
-  },
-
-  /**
    * networkingPrivate.onNetworksChanged event callback.
    * @param {!Array<string>} networkIds The list of changed network GUIDs.
    * @private
@@ -177,7 +162,7 @@
 
   /**
    * networkingPrivate.getProperties callback.
-   * @param {!NetworkStateProperties} state The network state properties.
+   * @param {!CrOnc.NetworkStateProperties} state The network state properties.
    * @private
    */
   getPropertiesCallback_: function(state) {
@@ -185,16 +170,16 @@
   },
 
   /**
-   * @param {?NetworkStateProperties} state The network state properties.
+   * @param {?CrOnc.NetworkStateProperties} state The network state properties.
    * @return {string} The text to display for the network name.
    * @private
    */
   getStateName_: function(state) {
-    return state && state.Name;
+    return (state && state.Name) || '';
   },
 
   /**
-   * @param {?NetworkStateProperties} state The network state properties.
+   * @param {?CrOnc.NetworkStateProperties} state The network state properties.
    * @return {string} The text to display for the network name.
    * @private
    */
@@ -203,17 +188,17 @@
   },
 
   /**
-   * @param {?NetworkStateProperties} state The network state properties.
+   * @param {?CrOnc.NetworkStateProperties} state The network state properties.
    * @return {string} The text to display for the network connection state.
    * @private
    */
   getStateText_: function(state) {
     // TODO(stevenjb): Localize.
-    return state && state.ConnectionState;
+    return (state && state.ConnectionState) || '';
   },
 
   /**
-   * @param {?NetworkStateProperties} state The network state properties.
+   * @param {?CrOnc.NetworkStateProperties} state The network state properties.
    * @param {string} property The property name.
    * @return {string} The text to display for the property, including the label.
    * @private
@@ -227,7 +212,7 @@
   },
 
   /**
-   * @param {?NetworkStateProperties} state The network state properties.
+   * @param {?CrOnc.NetworkStateProperties} state The network state properties.
    * @return {boolean} True if the state is connected.
    * @private
    */
@@ -236,7 +221,7 @@
   },
 
   /**
-   * @param {?NetworkStateProperties} state The network state properties.
+   * @param {?CrOnc.NetworkStateProperties} state The network state properties.
    * @return {boolean} Whether or not the network can be connected.
    * @private
    */
@@ -246,7 +231,7 @@
   },
 
   /**
-   * @param {?NetworkStateProperties} state The network state properties.
+   * @param {?CrOnc.NetworkStateProperties} state The network state properties.
    * @return {boolean} Whether or not the network can be disconnected.
    * @private
    */
@@ -256,7 +241,7 @@
   },
 
   /**
-   * @param {?NetworkStateProperties} state The network state properties.
+   * @param {?CrOnc.NetworkStateProperties} state The network state properties.
    * @param {string} type The network type to match.
    * @return {boolean} Whether or not the type of 'state' matches 'type'.
    * @private
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.html b/chrome/browser/resources/settings/internet_page/network_summary.html
index dacdc19..cc5dfe7a 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary.html
@@ -1,6 +1,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/more-routing/more-routing.html">
-<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_types.html">
 <link rel="import" href="network_summary_item.html">
 
 <dom-module id="cr-network-summary">
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.js b/chrome/browser/resources/settings/internet_page/network_summary.js
index 2b9e4cc..7f1aa692 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary.js
@@ -11,9 +11,6 @@
 /** @typedef {chrome.networkingPrivate.DeviceStateProperties} */
 var DeviceStateProperties;
 
-/** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
-var NetworkStateProperties;
-
 /**
  * @typedef {{
  *   Ethernet: (DeviceStateProperties|undefined),
@@ -27,22 +24,22 @@
 
 /**
  * @typedef {{
- *   Ethernet: (?NetworkStateProperties|undefined),
- *   WiFi: (?NetworkStateProperties|undefined),
- *   Cellular: (?NetworkStateProperties|undefined),
- *   WiMAX: (?NetworkStateProperties|undefined),
- *   VPN: (?NetworkStateProperties|undefined)
+ *   Ethernet: (?CrOnc.NetworkStateProperties|undefined),
+ *   WiFi: (?CrOnc.NetworkStateProperties|undefined),
+ *   Cellular: (?CrOnc.NetworkStateProperties|undefined),
+ *   WiMAX: (?CrOnc.NetworkStateProperties|undefined),
+ *   VPN: (?CrOnc.NetworkStateProperties|undefined)
  * }}
  */
 var NetworkStateObject;
 
 /**
  * @typedef {{
- *   Ethernet: (Array<NetworkStateProperties>|undefined),
- *   WiFi: (Array<NetworkStateProperties>|undefined),
- *   Cellular: (Array<NetworkStateProperties>|undefined),
- *   WiMAX: (Array<NetworkStateProperties>|undefined),
- *   VPN: (Array<NetworkStateProperties>|undefined)
+ *   Ethernet: (Array<CrOnc.NetworkStateProperties>|undefined),
+ *   WiFi: (Array<CrOnc.NetworkStateProperties>|undefined),
+ *   Cellular: (Array<CrOnc.NetworkStateProperties>|undefined),
+ *   WiMAX: (Array<CrOnc.NetworkStateProperties>|undefined),
+ *   VPN: (Array<CrOnc.NetworkStateProperties>|undefined)
  * }}
  */
 var NetworkStateListObject;
@@ -159,7 +156,7 @@
 
   /**
    * Event triggered when a cr-network-summary-item is selected.
-   * @param {!{detail: !NetworkStateProperties}} event
+   * @param {!{detail: !CrOnc.NetworkStateProperties}} event
    * @private
    */
   onSelected_: function(event) {
@@ -213,7 +210,7 @@
   /**
    * Handles UI requests to connect to a network.
    * TODO(stevenjb): Handle Cellular activation, etc.
-   * @param {!NetworkStateProperties} state The network state.
+   * @param {!CrOnc.NetworkStateProperties} state The network state.
    * @private
    */
   connectToNetwork_: function(state) {
@@ -265,8 +262,8 @@
 
   /**
    * networkingPrivate.getNetworksState callback.
-   * @param {!Array<!NetworkStateProperties>} states The state properties for
-   *     all visible networks.
+   * @param {!Array<!CrOnc.NetworkStateProperties>} states The state properties
+   *     for all visible networks.
    * @private
    */
   getNetworksCallback_: function(states) {
@@ -294,7 +291,7 @@
     // Set any types not found to a default value or null.
     NETWORK_TYPES.forEach(function(type) {
       if (!foundTypes[type]) {
-        /** @type {NetworkStateProperties} */ var defaultState = null;
+        /** @type {CrOnc.NetworkStateProperties} */ var defaultState = null;
         if (this.deviceStates[type])
           defaultState = { GUID: '', Type: type };
         this.updateNetworkState_(type, defaultState);
@@ -312,7 +309,7 @@
 
   /**
    * networkingPrivate.getState callback.
-   * @param {!NetworkStateProperties} state The network state properties.
+   * @param {!CrOnc.NetworkStateProperties} state The network state properties.
    * @private
    */
   getStateCallback_: function(state) {
@@ -326,9 +323,9 @@
    * Sets 'networkStates[type]' which will update the cr-network-list-item
    * associated with 'type'.
    * @param {string} type The network type.
-   * @param {?NetworkStateProperties} state The state properties for the network
-   *     to associate with |type|. May be null if there are no networks matching
-   *     |type|.
+   * @param {?CrOnc.NetworkStateProperties} state The state properties for the
+   *     network to associate with |type|. May be null if there are no networks
+   *     matching |type|.
    * @private
    */
   updateNetworkState_: function(type, state) {
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.js b/chrome/browser/resources/settings/internet_page/network_summary_item.js
index cf8512b..f01c4db 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.js
@@ -11,9 +11,6 @@
 /** @typedef {chrome.networkingPrivate.DeviceStateProperties} */
 var DeviceStateProperties;
 
-/** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
-var NetworkStateProperties;
-
 Polymer({
   is: 'cr-network-summary-item',
 
@@ -60,7 +57,7 @@
     /**
      * Network state for the active network.
      *
-     * @type {?NetworkStateProperties}
+     * @type {?CrOnc.NetworkStateProperties}
      */
     networkState: {
       type: Object,
@@ -70,7 +67,7 @@
     /**
      * List of all network state data for the network type.
      *
-     * @type {!Array<!NetworkStateProperties>}
+     * @type {!Array<!CrOnc.NetworkStateProperties>}
      */
     networkStateList: {
       type: Array,
@@ -134,7 +131,7 @@
 
   /**
    * @param {?DeviceStateProperties} deviceState The device state.
-   * @param {!Array<!NetworkStateProperties>} networkList A list of networks.
+   * @param {!Array<!CrOnc.NetworkStateProperties>} networkList
    * @return {string} The class value for the expand button.
    * @private
    */
@@ -145,7 +142,7 @@
 
   /**
    * @param {?DeviceStateProperties} deviceState The device state.
-   * @param {!Array<!NetworkStateProperties>} networkList A list of networks.
+   * @param {!Array<!CrOnc.NetworkStateProperties>} networkList
    * @return {boolean} Whether or not to show the UI to expand the list.
    * @private
    */
diff --git a/chrome/browser/resources/settings/pref_tracker/pref_tracker.js b/chrome/browser/resources/settings/pref_tracker/pref_tracker.js
index 0e372bea..1d692ab 100644
--- a/chrome/browser/resources/settings/pref_tracker/pref_tracker.js
+++ b/chrome/browser/resources/settings/pref_tracker/pref_tracker.js
@@ -41,7 +41,7 @@
     properties: {
       /**
        * The Preference object being tracked.
-       * @type {?chrome.settingsPrivate.PrefObject}
+       * @type {?PrefObject}
        */
       pref: {
         type: Object,
diff --git a/chrome/browser/resources/settings/prefs/prefs.js b/chrome/browser/resources/settings/prefs/prefs.js
index 59ce83c1..b68ccea 100644
--- a/chrome/browser/resources/settings/prefs/prefs.js
+++ b/chrome/browser/resources/settings/prefs/prefs.js
@@ -44,8 +44,7 @@
 
     /**
      * Called when prefs in the underlying Chrome pref store are changed.
-     * @param {!Array<!chrome.settingsPrivate.PrefObject>} prefs The prefs that
-     *     changed.
+     * @param {!Array<!PrefObject>} prefs The prefs that changed.
      * @private
      */
     onPrefsChanged_: function(prefs) {
@@ -54,7 +53,7 @@
 
     /**
      * Called when prefs are fetched from settingsPrivate.
-     * @param {!Array<!chrome.settingsPrivate.PrefObject>} prefs
+     * @param {!Array<!PrefObject>} prefs
      * @private
      */
     onPrefsFetched_: function(prefs) {
@@ -67,7 +66,7 @@
 
     /**
      * Updates the settings model with the given prefs.
-     * @param {!Array<!chrome.settingsPrivate.PrefObject>} prefs
+     * @param {!Array<!PrefObject>} prefs
      * @param {boolean} shouldObserve Whether each of the prefs should be
      *     observed.
      * @private
@@ -93,6 +92,17 @@
         // observer fires.
         for (let objKey in prefObj) {
           let path = 'prefStore.' + prefObj.key + '.' + objKey;
+
+          // Handle lists specially. We don't want to call this.set()
+          // unconditionally upon updating a list value, since even its contents
+          // are the same as the old list, doing this set() may cause an
+          // infinite update cycle (http://crbug.com/498586).
+          if (objKey == 'value' &&
+              prefObj.type == chrome.settingsPrivate.PrefType.LIST &&
+              !this.shouldUpdateListPrefValue_(root, prefObj['value'])) {
+            continue;
+          }
+
           this.set(path, prefObj[objKey]);
         }
 
@@ -102,6 +112,29 @@
       }, this);
     },
 
+
+    /**
+     * @param {Object} root The root object for a pref that contains a list
+     *     value.
+     * @param {!Array} newValue The new list value.
+     * @return {boolean} Whether the new value is different from the one in
+     *     root, thus necessitating a pref update.
+     */
+    shouldUpdateListPrefValue_: function(root, newValue) {
+      if (root.value == null ||
+          root.value.length != newValue.length) {
+        return true;
+      }
+
+      for (let i = 0; i < newValue.length; i++) {
+        if (root.value != null && root.value[i] != newValue[i]) {
+          return true;
+        }
+      }
+
+      return false;
+    },
+
     /**
      * Called when a property of a pref changes.
      * @param {!Array<!Object>} changes An array of objects describing changes.
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.css b/chrome/browser/resources/settings/privacy_page/privacy_page.css
new file mode 100644
index 0000000..bcd874e
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.css
@@ -0,0 +1,7 @@
+/* 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. */
+
+.privacy-buttons {
+  margin-top: 25px;
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
new file mode 100644
index 0000000..b6c4a492
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -0,0 +1,69 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-material/paper-material.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_button/cr_button.html">
+<link rel="import" href="chrome://md-settings/checkbox/checkbox.html">
+
+<dom-module id="cr-settings-privacy-page">
+  <link rel="import" type="css"
+      href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="privacy_page.css">
+  <template>
+    <paper-material>
+      <p class="privacy-explanation"
+          i18n-values=".innerHTML:improveBrowsingExperience">
+      </p>
+      <cr-settings-checkbox
+          pref="{{prefs.alternate_error_pages.enabled}}"
+          i18n-values="label:linkDoctorPref">
+      </cr-settings-checkbox>
+      <cr-settings-checkbox
+          pref="{{prefs.search.suggest_enabled}}"
+          i18n-values="label:searchSuggestPref">
+      </cr-settings-checkbox>
+      <cr-settings-checkbox
+          pref="{{prefs.net.network_prediction_options}}"
+          i18n-values="label:networkPredictionEnabled">
+      </cr-settings-checkbox>
+      <cr-settings-checkbox
+          pref="{{prefs.safebrowsing.extended_reporting_enabled}}"
+          i18n-values="label:safeBrowsingEnableExtendedReporting">
+      </cr-settings-checkbox>
+      <cr-settings-checkbox pref="{{prefs.safebrowsing.enabled}}"
+          i18n-values="label:safeBrowsingEnableProtection">
+      </cr-settings-checkbox>
+<if expr="_google_chrome">
+      <cr-settings-checkbox
+          pref="{{prefs.spellcheck.use_spelling_service}}"
+          i18n-values="label:spellingPref">
+      </cr-settings-checkbox>
+<if expr="chromeos">
+      <cr-settings-checkbox
+          pref="{{prefs.cros.metrics.reportingEnabled}}"
+          i18n-values="label:enableLogging">
+      </cr-settings-checkbox>
+</if>
+      <!-- TODO(jlklein): Add non-chromeos metrics box. -->
+</if>
+      <cr-settings-checkbox pref="{{prefs.enable_do_not_track}}"
+          i18n-values="label:doNotTrack">
+      </cr-settings-checkbox>
+<if expr="chromeos">
+      <cr-settings-checkbox
+          pref="{{prefs.cros.device.attestation_for_content_protection_enabled}}"
+          i18n-values="label:enableContentProtectionAttestation">
+      </cr-settings-checkbox>
+      <cr-settings-checkbox
+          pref="{{prefs.settings.internet.wake_on_wifi_ssid}}"
+          i18n-values="label:wakeOnWifi">
+      </cr-settings-checkbox>
+</if>
+      <div class="privacy-buttons layout horizontal end-justified">
+        <cr-button i18n-content="siteSettingsLabel"></cr-button>
+        <cr-button raised i18n-content="clearBrowsingDataLabel">
+        </cr-button>
+      </div>
+    </paper-material>
+  </template>
+  <script src="privacy_page.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js
new file mode 100644
index 0000000..1dce8a8
--- /dev/null
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -0,0 +1,75 @@
+// 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.
+
+/**
+ * @fileoverview
+ * 'cr-settings-privacy-page' is the settings page containing privacy and
+ * security settings.
+ *
+ * Example:
+ *
+ *    <iron-animated-pages>
+ *      <cr-settings-privacy-page prefs="{{prefs}}">
+ *      </cr-settings-privacy-page>
+ *      ... other pages ...
+ *    </iron-animated-pages>
+ *
+ * @group Chrome Settings Elements
+ * @element cr-settings-privacy-page
+ */
+Polymer({
+  is: 'cr-settings-privacy-page',
+
+  properties: {
+    /**
+     * Preferences state.
+     */
+    prefs: {
+      type: Object,
+      notify: true,
+    },
+
+    /**
+     * Route for the page.
+     */
+    route: String,
+
+    /**
+     * Whether the page is a subpage.
+     */
+    subpage: {
+      type: Boolean,
+      value: false,
+      readOnly: true,
+    },
+
+    /**
+     * ID of the page.
+     */
+    PAGE_ID: {
+      type: String,
+      value: 'privacy',
+      readOnly: true,
+    },
+
+    /**
+     * Title for the page header and navigation menu.
+     */
+    pageTitle: {
+      type: String,
+      value: function() {
+        return loadTimeData.getString('privacyPageTitle');
+      },
+    },
+
+    /**
+     * Name of the 'iron-icon' to show.
+     */
+    icon: {
+      type: String,
+      value: 'lock',
+      readOnly: true,
+    },
+  },
+});
diff --git a/chrome/browser/resources/settings/routes.html b/chrome/browser/resources/settings/routes.html
index a2c70c48..5d5328e1 100644
--- a/chrome/browser/resources/settings/routes.html
+++ b/chrome/browser/resources/settings/routes.html
@@ -13,6 +13,7 @@
 <more-route name="internet" path="/internet">
   <more-route name="internet-detail" path="/detail/:guid"></more-route>
 </more-route>
+<more-route name="privacy" path="/privacy"></more-route>
 <more-route name="search" path="/search">
   <more-route name="search-engines" path="/engines"></more-route>
 </more-route>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html
index 4b814bb0..b20e386 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -7,6 +7,7 @@
 <link rel="import" href="chrome://md-settings/appearance_page/appearance_page.html">
 <link rel="import" href="chrome://md-settings/date_time_page/date_time_page.html">
 <link rel="import" href="chrome://md-settings/downloads_page/downloads_page.html">
+<link rel="import" href="chrome://md-settings/privacy_page/privacy_page.html">
 <link rel="import" href="chrome://md-settings/search_engines_page/search_engines_page.html">
 <link rel="import" href="chrome://md-settings/search_page/search_page.html">
 <link rel="import" href="chrome://md-settings/sync_page/sync_page.html">
@@ -40,6 +41,8 @@
           <cr-settings-date-time-page prefs="{{prefs}}" route="dateTime">
           </cr-settings-date-time-page>
 </if>
+          <cr-settings-privacy-page prefs="{{prefs}}" route="privacy">
+          </cr-settings-privacy-page>
           <cr-settings-downloads-page prefs="{{prefs}}" route="downloads">
           </cr-settings-downloads-page>
           <cr-settings-search-page route="search"></cr-settings-search-page>
diff --git a/chrome/browser/resources/settings/settings_page/settings_page.css b/chrome/browser/resources/settings/settings_page/settings_page.css
index 0dd8579..25dd0d8 100644
--- a/chrome/browser/resources/settings/settings_page/settings_page.css
+++ b/chrome/browser/resources/settings/settings_page/settings_page.css
@@ -11,8 +11,7 @@
   background-color: white;
   display: flex;
   flex-direction: column;
-  padding-bottom: 40px;
-  padding-top: 40px;
+  padding: 40px;
 }
 
 .soft-border {
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index f9003fd..ea135caf 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -126,6 +126,17 @@
       <structure name="IDR_SETTINGS_PREF_TRACKER_JS"
                  file="pref_tracker/pref_tracker.js"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_PRIVACY_PAGE_CSS"
+                 file="privacy_page/privacy_page.css"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_PRIVACY_PAGE_HTML"
+                 file="privacy_page/privacy_page.html"
+                 type="chrome_html"
+                 flattenhtml="true"
+                 allowexternalscript="true" />
+      <structure name="IDR_SETTINGS_PRIVACY_PAGE_JS"
+                 file="privacy_page/privacy_page.js"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_POLYMER_CONFIG_JS"
                  file="polymer_config.js"
                  type="chrome_html" />
diff --git a/chrome/browser/safe_browsing/android_safe_browsing_api_handler.cc b/chrome/browser/safe_browsing/android_safe_browsing_api_handler.cc
deleted file mode 100644
index 1a6c107..0000000
--- a/chrome/browser/safe_browsing/android_safe_browsing_api_handler.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/safe_browsing/android_safe_browsing_api_handler.h"
-
-#include <string>
-
-#include "base/android/jni_android.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/safe_browsing/safe_browsing_util.h"
-#include "content/public/browser/browser_thread.h"
-// TODO(nparker): Include JNI-generated file
-
-using content::BrowserThread;
-
-AndroidSafeBrowsingAPIHandler::AndroidSafeBrowsingAPIHandler() {
-  j_context_ = base::android::GetApplicationContext();
-  DCHECK(j_context_);
-
-  // TODO(nparker): Fetch API key pertaining to Chrome.
-  api_key_ = "<todo-get-appropriate-api-key>";
-}
-
-bool AndroidSafeBrowsingAPIHandler::StartURLCheck(
-    const URLCheckCallback& callback,
-    const GURL& url,
-    const std::vector<SBThreatType>& threat_types) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  // Make copy on the heap so we can pass the pointer through JNI.
-  URLCheckCallback* callback_ptr = new URLCheckCallback(callback);
-  intptr_t callback_id_int = reinterpret_cast<intptr_t>(callback_ptr);
-  jlong callback_id = static_cast<jlong>(callback_id_int);
-
-  // TODO(nparker): Reduce logging before launch of this feature.
-  VLOG(1) << "Starting check " << callback_id << " for URL " << url;
-
-  // TODO(nparker): Implement this.
-  // Convert threat types to API's enums.
-  // Call JNI method.
-
-  // Until we have the Java implementation, just invoke the callback in 500ms
-  // for testing.
-  return BrowserThread::PostDelayedTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&OnURLCheckDone, callback_id, true, jstring()),
-      base::TimeDelta::FromMilliseconds(500));
-}
-
-// static
-void AndroidSafeBrowsingAPIHandler::OnURLCheckDone(jlong callback_id,
-                                                   jboolean isSuccessful,
-                                                   jstring metadata) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(callback_id);
-
-  VLOG(1) << "URLCheckDone invoked for check " << callback_id;
-
-  // Convert java long long int to c++ pointer, take ownership.
-  scoped_ptr<URLCheckCallback> callback(
-      reinterpret_cast<URLCheckCallback*>(callback_id));
-
-  // TODO(nparker):
-  // 1) Convert metadata to binary proto of MalwarePatternType so
-  //    SafeBrowsingUIManager::DisplayBlockingPage() can unmarshal it.
-  // 2) Pick the "worst" threat type from metadata and map to SBThreatType.
-
-  callback->Run(SB_THREAT_TYPE_SAFE, std::string());
-  VLOG(1) << "Done with check " << callback_id;
-}
diff --git a/chrome/browser/safe_browsing/android_safe_browsing_api_handler.h b/chrome/browser/safe_browsing/android_safe_browsing_api_handler.h
deleted file mode 100644
index 5adc650..0000000
--- a/chrome/browser/safe_browsing/android_safe_browsing_api_handler.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// Glue to pass Safe Browsing API requests between
-// RemoteSafeBrowsingDatabaseManager and Java-based API to check URLs.
-
-#ifndef CHROME_BROWSER_SAFE_BROWSING_ANDROID_SAFE_BROWSING_API_HANDLER_H_
-#define CHROME_BROWSER_SAFE_BROWSING_ANDROID_SAFE_BROWSING_API_HANDLER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/android/jni_android.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "chrome/browser/safe_browsing/safe_browsing_util.h"
-#include "url/gurl.h"
-
-typedef base::Callback<void(SBThreatType sb_threat_type,
-                            const std::string& metadata)> URLCheckCallback;
-
-class AndroidSafeBrowsingAPIHandler {
- public:
-  AndroidSafeBrowsingAPIHandler();
-
-  // Makes Native->Java call and invokes callback when check is done.
-  // Returns false if it fails to start.
-  bool StartURLCheck(
-      const URLCheckCallback& callback,
-      const GURL& url,
-      const std::vector<SBThreatType>& threat_types);
-
-  // Java->Native call, invoked when a check is done.  |callback_id| is an
-  // int form of pointer to a URLCheckCallback that will be called and then
-  // deleted here.
-  static void OnURLCheckDone(jlong callback_id,
-                             jboolean isSuccessful,
-                             jstring metadata);
-
- protected:
-  jobject j_context_;
-  std::string api_key_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AndroidSafeBrowsingAPIHandler);
-};
-#endif  // CHROME_BROWSER_SAFE_BROWSING_ANDROID_SAFE_BROWSING_API_HANDLER_H_
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.cc b/chrome/browser/safe_browsing/client_side_detection_service.cc
index e7fab2f..191e00e 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service.cc
@@ -15,6 +15,7 @@
 #include "base/metrics/sparse_histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
@@ -24,6 +25,7 @@
 #include "chrome/common/safe_browsing/client_model.pb.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
 #include "chrome/common/safe_browsing/safebrowsing_messages.h"
+#include "components/variations/variations_associated_data.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
@@ -79,8 +81,17 @@
     "https://sb-ssl.google.com/safebrowsing/clientreport/phishing";
 const char ClientSideDetectionService::kClientReportMalwareUrl[] =
     "https://sb-ssl.google.com/safebrowsing/clientreport/malware-check";
-const char ClientSideDetectionService::kClientModelUrl[] =
-    "https://ssl.gstatic.com/safebrowsing/csd/client_model_v5.pb";
+const char ClientSideDetectionService::kClientModelUrlPrefix[] =
+    "https://ssl.gstatic.com/safebrowsing/csd/";
+const char ClientSideDetectionService::kClientModelNamePattern[] =
+    "client_model_v5%s_variation_%d.pb";
+
+// Finch names
+const char ClientSideDetectionService::kClientModelFinchExperiment[] =
+    "ClientSideDetectionModel";
+const char ClientSideDetectionService::kClientModelFinchParam[] =
+    "ModelNum";
+
 
 struct ClientSideDetectionService::ClientReportInfo {
   ClientReportPhishingRequestCallback callback;
@@ -269,12 +280,37 @@
       base::TimeDelta::FromMilliseconds(delay_ms));
 }
 
+// static
+std::string ClientSideDetectionService::MakeModelName() {
+  std::string num_str = variations::GetVariationParamValue(
+      kClientModelFinchExperiment, kClientModelFinchParam);
+  int model_number = 0;
+  if (!base::StringToInt(num_str, &model_number)) {
+    model_number = 0;  // Default model
+  }
+
+  // TODO(nparker): Factor out the model-fetching so we can have
+  // up to two models: One for extended reporting, and one for not.
+  // Until then, we'll use the non-extended reporting model.
+  return FillInModelName(false /* is_extended_reporting */, model_number);
+}
+
+// static
+std::string ClientSideDetectionService::FillInModelName(
+    bool is_extended_reporting,
+    int model_number) {
+  return base::StringPrintf(kClientModelNamePattern,
+                            is_extended_reporting ? "_ext" : "", model_number);
+}
+
 void ClientSideDetectionService::StartFetchModel() {
   if (enabled_) {
     // Start fetching the model either from the cache or possibly from the
     // network if the model isn't in the cache.
+    fetching_model_name_ = MakeModelName();
+    std::string model_url = kClientModelUrlPrefix + fetching_model_name_;
     model_fetcher_ = net::URLFetcher::Create(0 /* ID used for testing */,
-                                             GURL(kClientModelUrl),
+                                             GURL(model_url),
                                              net::URLFetcher::GET, this);
     model_fetcher_->SetRequestContext(request_context_getter_.get());
     model_fetcher_->Start();
@@ -317,6 +353,8 @@
     return;
   }
 
+  request->set_model_filename(model_name_);
+
   std::string request_data;
   if (!request->SerializeToString(&request_data)) {
     UMA_HISTOGRAM_COUNTS("SBClientPhishing.RequestNotSerialized", 1);
@@ -429,6 +467,8 @@
     // The model is valid => replace the existing model with the new one.
     model_str_.assign(data);
     model_.swap(model);
+    model_name_ = fetching_model_name_;
+    fetching_model_name_ = "";
     model_status = MODEL_SUCCESS;
   }
   EndFetchModel(model_status);
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.h b/chrome/browser/safe_browsing/client_side_detection_service.h
index 671ba1a..5ed0f117 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service.h
+++ b/chrome/browser/safe_browsing/client_side_detection_service.h
@@ -180,6 +180,9 @@
   FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest, IsBadIpAddress);
   FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest,
                            ModelHasValidHashIds);
+  FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest, ModelNamesTest);
+  FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest,
+                           FetchExperimentalModelTest);
 
   // CacheState holds all information necessary to respond to a caller without
   // actually making a HTTP request.
@@ -202,7 +205,10 @@
 
   static const char kClientReportMalwareUrl[];
   static const char kClientReportPhishingUrl[];
-  static const char kClientModelUrl[];
+  static const char kClientModelUrlPrefix[];
+  static const char kClientModelNamePattern[];
+  static const char kClientModelFinchExperiment[];
+  static const char kClientModelFinchParam[];
   static const size_t kMaxModelSizeBytes;
   static const int kMaxReportsPerInterval;
   static const int kClientModelFetchIntervalMs;
@@ -281,6 +287,13 @@
   // Returns the URL that will be used for phishing requests.
   static GURL GetClientReportUrl(const std::string& report_url);
 
+  // Construct a model name from parameters.
+  static std::string FillInModelName(bool is_extended_reporting,
+                                     int model_number);
+
+  // Construct a model name from client state.
+  static std::string MakeModelName();
+
   // Whether the service is running or not.  When the service is not running,
   // it won't download the model nor report detected phishing URLs.
   bool enabled_;
@@ -290,6 +303,11 @@
   scoped_ptr<base::TimeDelta> model_max_age_;
   scoped_ptr<net::URLFetcher> model_fetcher_;
 
+  // Name of the model in model_.  This is the last component of the URL path.
+  std::string model_name_;
+  // Name of the model currently being fetched.
+  std::string fetching_model_name_;
+
   // Map of client report phishing request to the corresponding callback that
   // has to be invoked when the request is done.
   struct ClientReportInfo;
diff --git a/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
index 275409ff..0bd2371 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
@@ -11,10 +11,13 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
 #include "chrome/common/safe_browsing/client_model.pb.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
+#include "components/variations/variations_associated_data.h"
 #include "content/public/test/test_browser_thread.h"
 #include "crypto/sha2.h"
 #include "net/http/http_status_code.h"
@@ -62,7 +65,15 @@
 
 class ClientSideDetectionServiceTest : public testing::Test {
  protected:
+  ClientSideDetectionServiceTest() {
+    // Needed to set the singlton.
+    field_trials_.reset(new base::FieldTrialList(NULL));
+  }
+
   void SetUp() override {
+    variations::testing::ClearAllVariationIDs();
+    variations::testing::ClearAllVariationParams();
+
     file_thread_.reset(new content::TestBrowserThread(BrowserThread::FILE,
                                                       &msg_loop_));
 
@@ -106,11 +117,35 @@
     return is_malware_;
   }
 
+  std::string MakeModelUrl() {
+    return ClientSideDetectionService::kClientModelUrlPrefix +
+           ClientSideDetectionService::MakeModelName();
+  }
+
+  // Set up the finch experiment to control the model number
+  // used in the model URL.
+  void SetFinchModelNumber(int model_number) {
+    variations::testing::ClearAllVariationIDs();
+    variations::testing::ClearAllVariationParams();
+
+    const std::string group_name = "ModelFoo";  // Not used in CSD code.
+    base::FieldTrialList::CreateFieldTrial(
+        ClientSideDetectionService::kClientModelFinchExperiment, group_name);
+
+    std::map<std::string, std::string> params;
+    params[ClientSideDetectionService::kClientModelFinchParam] =
+        base::IntToString(model_number);
+
+    variations::AssociateVariationParams(
+        ClientSideDetectionService::kClientModelFinchExperiment, group_name,
+        params);
+  }
+
   void SetModelFetchResponse(std::string response_data,
                              net::HttpStatusCode response_code,
                              net::URLRequestStatus::Status status) {
-    factory_->SetFakeResponse(GURL(ClientSideDetectionService::kClientModelUrl),
-                              response_data, response_code, status);
+    factory_->SetFakeResponse(GURL(MakeModelUrl()), response_data,
+                              response_code, status);
   }
 
   void SetClientReportPhishingResponse(std::string response_data,
@@ -244,6 +279,7 @@
 
   scoped_ptr<content::TestBrowserThread> browser_thread_;
   scoped_ptr<content::TestBrowserThread> file_thread_;
+  scoped_ptr<base::FieldTrialList> field_trials_;
 
   GURL phishing_url_;
   GURL confirmed_malware_url_;
@@ -372,6 +408,49 @@
   Mock::VerifyAndClearExpectations(&service);
 }
 
+TEST_F(ClientSideDetectionServiceTest, ModelNamesTest) {
+  // Test the name-templating.
+  EXPECT_EQ(ClientSideDetectionService::FillInModelName(true, 3),
+            "client_model_v5_ext_variation_3.pb");
+  EXPECT_EQ(ClientSideDetectionService::FillInModelName(false, 5),
+            "client_model_v5_variation_5.pb");
+
+  // Use Finch.  Should default to 0.
+  EXPECT_EQ(ClientSideDetectionService::MakeModelName(),
+            "client_model_v5_variation_0.pb");
+
+  SetFinchModelNumber(2);
+  EXPECT_EQ(ClientSideDetectionService::MakeModelName(),
+            "client_model_v5_variation_2.pb");
+
+  SetFinchModelNumber(0);
+  EXPECT_EQ(ClientSideDetectionService::MakeModelName(),
+            "client_model_v5_variation_0.pb");
+}
+
+// Like FetchModelTest, but we vary the finch params.
+TEST_F(ClientSideDetectionServiceTest, FetchExperimentalModelTest) {
+  MockClientSideDetectionService service;
+  EXPECT_CALL(service, ScheduleFetchModel(_)).Times(1);
+  service.SetEnabledAndRefreshState(true);
+
+  ClientSideModel model;
+  model.set_max_words_per_term(0);
+  model.set_version(10);
+  model.add_hashes("bla");
+  model.add_page_term(0);
+
+  SetFinchModelNumber(1);
+  SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
+                        net::URLRequestStatus::SUCCESS);
+  EXPECT_CALL(service, EndFetchModel(
+      ClientSideDetectionService::MODEL_SUCCESS))
+      .WillOnce(QuitCurrentMessageLoop());
+  service.StartFetchModel();
+  msg_loop_.Run();  // EndFetchModel will quit the message loop.
+  Mock::VerifyAndClearExpectations(&service);
+}
+
 TEST_F(ClientSideDetectionServiceTest, ServiceObjectDeletedBeforeCallbackDone) {
   SetModelFetchResponse("bogus model", net::HTTP_OK,
                         net::URLRequestStatus::SUCCESS);
diff --git a/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc
index c9d2f8a..e128511 100644
--- a/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -42,7 +43,7 @@
 
 // A BrowserContextKeyedServiceFactory::TestingFactoryFunction that creates a
 // HistoryService for a TestingProfile.
-KeyedService* BuildHistoryService(content::BrowserContext* context) {
+scoped_ptr<KeyedService> BuildHistoryService(content::BrowserContext* context) {
   TestingProfile* profile = static_cast<TestingProfile*>(context);
 
   // Delete the file before creating the service.
@@ -52,21 +53,21 @@
       base::PathExists(history_path)) {
     ADD_FAILURE() << "failed to delete history db file "
                   << history_path.value();
-    return NULL;
+    return nullptr;
   }
 
-  history::HistoryService* history_service = new history::HistoryService(
-      ChromeHistoryClientFactory::GetForProfile(profile),
-      scoped_ptr<history::VisitDelegate>());
+  scoped_ptr<history::HistoryService> history_service(
+      new history::HistoryService(
+          ChromeHistoryClientFactory::GetForProfile(profile),
+          scoped_ptr<history::VisitDelegate>()));
   if (history_service->Init(
           profile->GetPrefs()->GetString(prefs::kAcceptLanguages),
           history::HistoryDatabaseParamsForPath(profile->GetPath()))) {
-    return history_service;
+    return history_service.Pass();
   }
 
   ADD_FAILURE() << "failed to initialize history service";
-  delete history_service;
-  return NULL;
+  return nullptr;
 }
 
 }  // namespace
diff --git a/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector_unittest.cc
index 22d7cf8..862a657 100644
--- a/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector_unittest.cc
@@ -56,7 +56,7 @@
 
 // A BrowserContextKeyedServiceFactory::TestingFactoryFunction that creates a
 // HistoryService for a TestingProfile.
-KeyedService* BuildHistoryService(content::BrowserContext* context) {
+scoped_ptr<KeyedService> BuildHistoryService(content::BrowserContext* context) {
   TestingProfile* profile = static_cast<TestingProfile*>(context);
 
   // Delete the file before creating the service.
@@ -66,21 +66,21 @@
       base::PathExists(history_path)) {
     ADD_FAILURE() << "failed to delete history db file "
                   << history_path.value();
-    return NULL;
+    return nullptr;
   }
 
-  history::HistoryService* history_service = new history::HistoryService(
-      ChromeHistoryClientFactory::GetForProfile(profile),
-      scoped_ptr<history::VisitDelegate>());
+  scoped_ptr<history::HistoryService> history_service(
+      new history::HistoryService(
+          ChromeHistoryClientFactory::GetForProfile(profile),
+          scoped_ptr<history::VisitDelegate>()));
   if (history_service->Init(
           profile->GetPrefs()->GetString(prefs::kAcceptLanguages),
           history::HistoryDatabaseParamsForPath(profile->GetPath()))) {
-    return history_service;
+    return history_service.Pass();
   }
 
   ADD_FAILURE() << "failed to initialize history service";
-  delete history_service;
-  return NULL;
+  return nullptr;
 }
 
 }  // namespace
diff --git a/chrome/browser/safe_browsing/local_database_manager.cc b/chrome/browser/safe_browsing/local_database_manager.cc
index a19eac9..e02db2d7 100644
--- a/chrome/browser/safe_browsing/local_database_manager.cc
+++ b/chrome/browser/safe_browsing/local_database_manager.cc
@@ -27,7 +27,6 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
-#include "components/startup_metric_utils/startup_metric_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "url/url_constants.h"
@@ -750,10 +749,8 @@
 
   if (database_)
     return database_;
-  startup_metric_utils::ScopedSlowStartupUMA
-      scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
-  const base::TimeTicks before = base::TimeTicks::Now();
 
+  const base::TimeTicks before = base::TimeTicks::Now();
   SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create(
       safe_browsing_task_runner_, enable_download_protection_,
       enable_csd_whitelist_, enable_download_whitelist_,
diff --git a/chrome/browser/safe_browsing/malware_details_cache.cc b/chrome/browser/safe_browsing/malware_details_cache.cc
index 4e8ae12..d70fb11 100644
--- a/chrome/browser/safe_browsing/malware_details_cache.cc
+++ b/chrome/browser/safe_browsing/malware_details_cache.cc
@@ -156,7 +156,7 @@
         pb_response->add_headers();
     pb_header->set_name(name);
     // Strip any Set-Cookie headers.
-    if (LowerCaseEqualsASCII(name, "set-cookie")) {
+    if (base::LowerCaseEqualsASCII(name, "set-cookie")) {
       pb_header->set_value("");
     } else {
       pb_header->set_value(value);
diff --git a/chrome/browser/safe_browsing/protocol_manager.cc b/chrome/browser/safe_browsing/protocol_manager.cc
index b1910d14..01aece1 100644
--- a/chrome/browser/safe_browsing/protocol_manager.cc
+++ b/chrome/browser/safe_browsing/protocol_manager.cc
@@ -749,10 +749,10 @@
 GURL SafeBrowsingProtocolManager::NextChunkUrl(const std::string& url) const {
   DCHECK(CalledOnValidThread());
   std::string next_url;
-  if (!StartsWithASCII(url, "http://", false) &&
-      !StartsWithASCII(url, "https://", false)) {
+  if (!base::StartsWithASCII(url, "http://", false) &&
+      !base::StartsWithASCII(url, "https://", false)) {
     // Use https if we updated via https, otherwise http (useful for testing).
-    if (StartsWithASCII(url_prefix_, "https://", false))
+    if (base::StartsWithASCII(url_prefix_, "https://", false))
       next_url.append("https://");
     else
       next_url.append("http://");
diff --git a/chrome/browser/safe_browsing/remote_database_manager.cc b/chrome/browser/safe_browsing/remote_database_manager.cc
index fed264a..b62dd782 100644
--- a/chrome/browser/safe_browsing/remote_database_manager.cc
+++ b/chrome/browser/safe_browsing/remote_database_manager.cc
@@ -6,7 +6,8 @@
 
 #include <vector>
 
-#include "chrome/browser/safe_browsing/android_safe_browsing_api_handler.h"
+#include "base/timer/elapsed_timer.h"
+#include "chrome/browser/safe_browsing/safe_browsing_api_handler.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
@@ -37,6 +38,7 @@
   Client* client_;
   RemoteSafeBrowsingDatabaseManager* db_manager_;
   GURL url_;
+  base::ElapsedTimer timer_;
   base::WeakPtrFactory<ClientRequest> weak_factory_;
 };
 
@@ -61,7 +63,8 @@
 void RemoteSafeBrowsingDatabaseManager::ClientRequest::OnRequestDone(
     SBThreatType matched_threat_type,
     const std::string& metadata) {
-  VLOG(1) << "OnRequestDone for client " << client_ << " and URL " << url_;
+  DVLOG(1) << "OnRequestDone took " << timer_.Elapsed().InMilliseconds()
+           << " ms for client " << client_ << " and URL " << url_;
   client_->OnCheckBrowseUrlResult(url_, matched_threat_type, metadata);
   db_manager_->CancelCheck(client_);
 }
@@ -74,9 +77,6 @@
 RemoteSafeBrowsingDatabaseManager::RemoteSafeBrowsingDatabaseManager()
     : enabled_(false) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // TODO(nparker): Implement the initialization glue.
-  // Check flag to see if this is enabled.
-  // Ask AndroidSafeBrowsingAPIHandler if Java API is correct version.
 }
 
 RemoteSafeBrowsingDatabaseManager::~RemoteSafeBrowsingDatabaseManager() {
@@ -156,17 +156,16 @@
     return true;  // Safe, continue right away.
 
   scoped_ptr<ClientRequest> req(new ClientRequest(client, this, url));
-  std::vector<SBThreatType> threat_types;
-  threat_types.push_back(SB_THREAT_TYPE_URL_MALWARE);
+  std::vector<SBThreatType> threat_types;  // Not currently used.
 
-  VLOG(1) << "Checking for client " << client << " and URL " << url;
-  bool started = api_handler_.StartURLCheck(
+  DVLOG(1) << "Checking for client " << client << " and URL " << url;
+  SafeBrowsingApiHandler* api_handler = SafeBrowsingApiHandler::GetInstance();
+  // If your build hits this at run time, then you should have either no built
+  // with safe_browsing=3, or set a SafeBrowingApiHandler singleton at startup.
+  DCHECK(api_handler) << "SafeBrowsingApiHandler was never constructed";
+  api_handler->StartURLCheck(
       base::Bind(&ClientRequest::OnRequestDoneWeak, req->GetWeakPtr()), url,
       threat_types);
-  if (!started) {
-    LOG(DFATAL) << "Failed to start Safe Browsing request";
-    return true;
-  }
 
   current_requests_.push_back(req.release());
 
@@ -180,7 +179,7 @@
   for (auto itr = current_requests_.begin(); itr != current_requests_.end();
        ++itr) {
     if ((*itr)->client() == client) {
-      VLOG(1) << "Canceling check for URL " << (*itr)->url();
+      DVLOG(2) << "Canceling check for URL " << (*itr)->url();
       delete *itr;
       current_requests_.erase(itr);
       return;
@@ -190,20 +189,20 @@
 }
 
 void RemoteSafeBrowsingDatabaseManager::StartOnIOThread() {
-  VLOG(1) << "RemoteSafeBrowsing starting";
+  VLOG(1) << "RemoteSafeBrowsingDatabaseManager starting";
   enabled_ = true;
 }
 
 void RemoteSafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
   // |shutdown| is not used.
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  VLOG(1) << "RemoteSafeBrowsing stopping";
+  DVLOG(1) << "RemoteSafeBrowsingDatabaseManager stopping";
 
   // Call back and delete any remaining clients. OnRequestDone() modifies
   // |current_requests_|, so we make a copy first.
   std::vector<ClientRequest*> to_callback(current_requests_);
   for (auto req : to_callback) {
-    VLOG(1) << "Stopping: Invoking unfinished req for URL " << req->url();
+    DVLOG(1) << "Stopping: Invoking unfinished req for URL " << req->url();
     req->OnRequestDone(SB_THREAT_TYPE_SAFE, std::string());
   }
   enabled_ = false;
diff --git a/chrome/browser/safe_browsing/remote_database_manager.h b/chrome/browser/safe_browsing/remote_database_manager.h
index 3a762c45b..329a77d 100644
--- a/chrome/browser/safe_browsing/remote_database_manager.h
+++ b/chrome/browser/safe_browsing/remote_database_manager.h
@@ -14,7 +14,6 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/safe_browsing/android_safe_browsing_api_handler.h"
 #include "chrome/browser/safe_browsing/database_manager.h"
 #include "url/gurl.h"
 
@@ -61,7 +60,6 @@
 
   // Requests currently outstanding.  This owns the ptrs.
   std::vector<ClientRequest*> current_requests_;
-  AndroidSafeBrowsingAPIHandler api_handler_;
   bool enabled_;
 
   friend class base::RefCountedThreadSafe<RemoteSafeBrowsingDatabaseManager>;
diff --git a/chrome/browser/safe_browsing/safe_browsing_api_handler.cc b/chrome/browser/safe_browsing/safe_browsing_api_handler.cc
new file mode 100644
index 0000000..dfa5a70
--- /dev/null
+++ b/chrome/browser/safe_browsing/safe_browsing_api_handler.cc
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/safe_browsing/safe_browsing_api_handler.h"
+
+SafeBrowsingApiHandler* SafeBrowsingApiHandler::instance_ = NULL;
+
+// static
+void SafeBrowsingApiHandler::SetInstance(SafeBrowsingApiHandler* instance) {
+  instance_ = instance;
+}
+
+// static
+SafeBrowsingApiHandler* SafeBrowsingApiHandler::GetInstance() {
+  return instance_;
+}
diff --git a/chrome/browser/safe_browsing/safe_browsing_api_handler.h b/chrome/browser/safe_browsing/safe_browsing_api_handler.h
new file mode 100644
index 0000000..90d4314
--- /dev/null
+++ b/chrome/browser/safe_browsing/safe_browsing_api_handler.h
@@ -0,0 +1,38 @@
+// 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.
+//
+// Glue to pass Safe Browsing API requests between
+// RemoteSafeBrowsingDatabaseManager and Java-based API to check URLs.
+
+#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_API_HANDLER_H_
+#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_API_HANDLER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "chrome/browser/safe_browsing/safe_browsing_util.h"
+#include "url/gurl.h"
+
+class SafeBrowsingApiHandler {
+ public:
+  // Singleton interface.
+  static void SetInstance(SafeBrowsingApiHandler* instance);
+  static SafeBrowsingApiHandler* GetInstance();
+
+  typedef base::Callback<void(SBThreatType sb_threat_type,
+                              const std::string& metadata)> URLCheckCallback;
+
+  // Makes Native->Java call and invokes callback when check is done.
+  virtual void StartURLCheck(const URLCheckCallback& callback,
+                             const GURL& url,
+                             const std::vector<SBThreatType>& threat_types) = 0;
+
+  virtual ~SafeBrowsingApiHandler() {}
+
+ private:
+  // Pointer not owned.
+  static SafeBrowsingApiHandler* instance_;
+};
+#endif  // CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_API_HANDLER_H_
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index 0d7f7da..162e6c2 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -37,7 +37,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
-#include "components/startup_metric_utils/startup_metric_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/cookie_store_factory.h"
 #include "content/public/browser/notification_service.h"
@@ -218,9 +217,6 @@
 }
 
 void SafeBrowsingService::Initialize() {
-  startup_metric_utils::ScopedSlowStartupUMA
-      scoped_timer("Startup.SlowStartupSafeBrowsingServiceInitialize");
-
   url_request_context_getter_ =
       new SafeBrowsingURLRequestContextGetter(this);
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 4379465..7a69139 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -20,13 +20,12 @@
 #include "base/strings/string_util.h"
 #include "base/test/thread_test_helper.h"
 #include "base/time/time.h"
+#include "chrome/browser/bookmarks/startup_task_runner_service_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/prerender/prerender_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/profiles/startup_task_runner_service.h"
-#include "chrome/browser/profiles/startup_task_runner_service_factory.h"
 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
 #include "chrome/browser/safe_browsing/database_manager.h"
 #include "chrome/browser/safe_browsing/local_database_manager.h"
@@ -43,6 +42,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/bookmarks/browser/startup_task_runner_service.h"
 #include "content/public/browser/web_contents.h"
 #include "net/cookies/cookie_store.h"
 #include "net/cookies/cookie_util.h"
@@ -1303,7 +1303,7 @@
  private:
   static scoped_ptr<net::test_server::HttpResponse> HandleRequest(
       const net::test_server::HttpRequest& request) {
-    if (!StartsWithASCII(request.relative_url, "/testpath/", true)) {
+    if (!base::StartsWithASCII(request.relative_url, "/testpath/", true)) {
       ADD_FAILURE() << "bad path";
       return nullptr;
     }
diff --git a/chrome/browser/safe_browsing/srt_fetcher_win.cc b/chrome/browser/safe_browsing/srt_fetcher_win.cc
index bbb40bb7..e29ed1e 100644
--- a/chrome/browser/safe_browsing/srt_fetcher_win.cc
+++ b/chrome/browser/safe_browsing/srt_fetcher_win.cc
@@ -99,14 +99,21 @@
       }
     }
 
-    // Even if the fetch could not be completed, still display the prompt. In
-    // this case, the prompt will fall back to visiting the download page.
+    // As long as the fetch didn't fail due to HTTP_NOT_FOUND, show a prompt
+    // (either offering the tool directly or pointing to the download page).
+    // If the fetch failed to find the file, don't prompt the user since the
+    // tool is not currently available.
     // TODO(mad): Consider implementing another layer of retries / alternate
     //            fetching mechanisms. http://crbug.com/460293
     // TODO(mad): In the event the browser is closed before the prompt displays,
     //            we will wait until the next scanner run to re-display it.
     //            Improve this. http://crbug.com/460295
-    DisplaySRTPrompt(download_path);
+    if (source->GetResponseCode() != net::HTTP_NOT_FOUND) {
+      DisplaySRTPrompt(download_path);
+    } else {
+      safe_browsing::RecordSRTPromptHistogram(
+          safe_browsing::SRT_PROMPT_DOWNLOAD_UNAVAILABLE);
+    }
 
     // Explicitly destroy the url_fetcher_ to avoid destruction races.
     url_fetcher_.reset();
diff --git a/chrome/browser/safe_browsing/srt_field_trial_win.cc b/chrome/browser/safe_browsing/srt_field_trial_win.cc
index 8548b29..aa37448 100644
--- a/chrome/browser/safe_browsing/srt_field_trial_win.cc
+++ b/chrome/browser/safe_browsing/srt_field_trial_win.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/safe_browsing/srt_field_trial_win.h"
 
 #include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
 #include "components/variations/variations_associated_data.h"
 
 namespace {
@@ -12,8 +13,7 @@
 // Field trial strings.
 const char kSRTCanaryGroupName[] = "SRTCanary";
 const char kSRTPromptTrialName[] = "SRTPromptFieldTrial";
-const char kSRTPromptOnGroup[] = "On";
-const char kSRTPromptDefaultGroup[] = "Default";
+const char kSRTPromptOffGroup[] = "Off";
 const char kSRTPromptSeedParamName[] = "Seed";
 
 // The download links of the Software Removal Tool.
@@ -30,7 +30,7 @@
 
 bool IsInSRTPromptFieldTrialGroups() {
   return base::FieldTrialList::FindFullName(kSRTPromptTrialName) !=
-         kSRTPromptDefaultGroup;
+         kSRTPromptOffGroup;
 }
 
 const char* GetSRTDownloadURL() {
@@ -45,4 +45,9 @@
                                             kSRTPromptSeedParamName);
 }
 
+void RecordSRTPromptHistogram(SRTPromptHistogramValue value) {
+  UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.PromptUsage", value,
+                            SRT_PROMPT_MAX);
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/srt_field_trial_win.h b/chrome/browser/safe_browsing/srt_field_trial_win.h
index c8b75768..d985d63 100644
--- a/chrome/browser/safe_browsing/srt_field_trial_win.h
+++ b/chrome/browser/safe_browsing/srt_field_trial_win.h
@@ -9,6 +9,18 @@
 
 namespace safe_browsing {
 
+// Enum values for the SRTPrompt histogram. Don't change order, always add
+// to the end, before SRT_PROMPT_MAX, of course.
+enum SRTPromptHistogramValue {
+  SRT_PROMPT_SHOWN = 0,
+  SRT_PROMPT_ACCEPTED = 1,
+  SRT_PROMPT_DENIED = 2,
+  SRT_PROMPT_FALLBACK = 3,
+  SRT_PROMPT_DOWNLOAD_UNAVAILABLE = 4,
+
+  SRT_PROMPT_MAX,
+};
+
 // Returns true if this Chrome is in a field trial group which shows the SRT
 // prompt.
 bool IsInSRTPromptFieldTrialGroups();
@@ -19,6 +31,9 @@
 // Returns the value of the incoming SRT seed.
 std::string GetIncomingSRTSeed();
 
+// Records a value for the SRT Prompt Histogram.
+void RecordSRTPromptHistogram(SRTPromptHistogramValue value);
+
 }  // namespace safe_browsing
 
 #endif  // CHROME_BROWSER_SAFE_BROWSING_SRT_FIELD_TRIAL_WIN_H_
diff --git a/chrome/browser/safe_browsing/srt_global_error_win.cc b/chrome/browser/safe_browsing/srt_global_error_win.cc
index 7ec6a1d..11bfe81 100644
--- a/chrome/browser/safe_browsing/srt_global_error_win.cc
+++ b/chrome/browser/safe_browsing/srt_global_error_win.cc
@@ -9,11 +9,11 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
-#include "base/metrics/histogram.h"
 #include "base/process/launch.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/safe_browsing/srt_field_trial_win.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/global_error/global_error_service.h"
@@ -40,22 +40,6 @@
 // A switch to add to the command line when executing the SRT.
 const char kChromePromptSwitch[] = "chrome-prompt";
 
-// Enum values for the SRTPrompt histogram. Don't change order, always add
-// to the end, before SRT_PROMPT_MAX, of course.
-enum SRTPromptHistogramValue {
-  SRT_PROMPT_SHOWN = 0,
-  SRT_PROMPT_ACCEPTED = 1,
-  SRT_PROMPT_DENIED = 2,
-  SRT_PROMPT_FALLBACK = 3,
-
-  SRT_PROMPT_MAX,
-};
-
-void RecordSRTPromptHistogram(SRTPromptHistogramValue value) {
-  UMA_HISTOGRAM_ENUMERATION(
-      "SoftwareReporter.PromptUsage", value, SRT_PROMPT_MAX);
-}
-
 void MaybeExecuteSRTFromBlockingPool(
     const base::FilePath& downloaded_path,
     const scoped_refptr<SingleThreadTaskRunner>& task_runner,
@@ -118,7 +102,7 @@
 }
 
 void SRTGlobalError::ShowBubbleView(Browser* browser) {
-  RecordSRTPromptHistogram(SRT_PROMPT_SHOWN);
+  safe_browsing::RecordSRTPromptHistogram(safe_browsing::SRT_PROMPT_SHOWN);
   GlobalErrorWithStandardBubble::ShowBubbleView(browser);
 }
 
@@ -150,13 +134,13 @@
 }
 
 void SRTGlobalError::BubbleViewAcceptButtonPressed(Browser* browser) {
-  RecordSRTPromptHistogram(SRT_PROMPT_ACCEPTED);
+  safe_browsing::RecordSRTPromptHistogram(safe_browsing::SRT_PROMPT_ACCEPTED);
   global_error_service_->RemoveGlobalError(this);
   MaybeExecuteSRT();
 }
 
 void SRTGlobalError::BubbleViewCancelButtonPressed(Browser* browser) {
-  RecordSRTPromptHistogram(SRT_PROMPT_DENIED);
+  safe_browsing::RecordSRTPromptHistogram(safe_browsing::SRT_PROMPT_DENIED);
   global_error_service_->RemoveGlobalError(this);
 
   BrowserThread::PostBlockingPoolTask(
@@ -186,7 +170,7 @@
 }
 
 void SRTGlobalError::FallbackToDownloadPage() {
-  RecordSRTPromptHistogram(SRT_PROMPT_FALLBACK);
+  safe_browsing::RecordSRTPromptHistogram(safe_browsing::SRT_PROMPT_FALLBACK);
 
   chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop();
   Browser* browser = chrome::FindLastActiveWithHostDesktopType(desktop_type);
diff --git a/chrome/browser/search/hotword_installer_browsertest.cc b/chrome/browser/search/hotword_installer_browsertest.cc
index 44d818c..3293bf2 100644
--- a/chrome/browser/search/hotword_installer_browsertest.cc
+++ b/chrome/browser/search/hotword_installer_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/webstore_startup_installer.h"
 #include "chrome/browser/profiles/profile.h"
@@ -67,8 +68,10 @@
   base::WeakPtrFactory<MockHotwordService> weak_factory_;
 };
 
-KeyedService* BuildMockHotwordService(content::BrowserContext* context) {
-  return new MockHotwordService(static_cast<Profile*>(context));
+scoped_ptr<KeyedService> BuildMockHotwordService(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(
+      new MockHotwordService(static_cast<Profile*>(context)));
 }
 
 }  // namespace
diff --git a/chrome/browser/search/hotword_service.cc b/chrome/browser/search/hotword_service.cc
index d222b150..5b08027 100644
--- a/chrome/browser/search/hotword_service.cc
+++ b/chrome/browser/search/hotword_service.cc
@@ -639,7 +639,11 @@
 }
 
 bool HotwordService::IsHotwordAllowed() {
+#if defined(ENABLE_HOTWORDING)
   return DoesHotwordSupportLanguage(profile_);
+#else
+  return false;
+#endif
 }
 
 bool HotwordService::IsOptedIntoAudioLogging() {
diff --git a/chrome/browser/search/hotword_service_unittest.cc b/chrome/browser/search/hotword_service_unittest.cc
index 588706c..9d53410 100644
--- a/chrome/browser/search/hotword_service_unittest.cc
+++ b/chrome/browser/search/hotword_service_unittest.cc
@@ -109,8 +109,10 @@
   std::string extension_id_;
 };
 
-KeyedService* BuildMockHotwordService(content::BrowserContext* context) {
-  return new MockHotwordService(static_cast<Profile*>(context));
+scoped_ptr<KeyedService> BuildMockHotwordService(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(
+      new MockHotwordService(static_cast<Profile*>(context)));
 }
 
 }  // namespace
@@ -157,6 +159,7 @@
                             extension_misc::kHotwordSharedModuleId));
 
 TEST_P(HotwordServiceTest, IsHotwordAllowedLocale) {
+#if defined(ENABLE_HOTWORDING)
   TestingProfile::Builder profile_builder;
   scoped_ptr<TestingProfile> profile = profile_builder.Build();
 
@@ -187,6 +190,7 @@
   Profile* otr_profile = profile->GetOffTheRecordProfile();
   SetApplicationLocale(otr_profile, "en");
   EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(otr_profile));
+#endif  // defined(ENABLE_HOTWORDING)
 }
 
 TEST_P(HotwordServiceTest, ShouldReinstallExtension) {
@@ -243,6 +247,7 @@
 }
 
 TEST_P(HotwordServiceTest, UninstallReinstallTriggeredCorrectly) {
+#if defined(ENABLE_HOTWORDING)
   InitializeEmptyExtensionService();
   service_->Init();
 
@@ -313,6 +318,7 @@
   EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile()));
   EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
   EXPECT_EQ(1, hotword_service->uninstall_count());  // no change
+#endif  // defined(ENABLE_HOTWORDING)
 }
 
 TEST_P(HotwordServiceTest, DisableAlwaysOnOnLanguageChange) {
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index 3fb513f..5d10b6f 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -94,7 +94,7 @@
   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableIconNtp))
     return true;
 
-  return StartsWithASCII(group_name, "Enabled", true);
+  return base::StartsWithASCII(group_name, "Enabled", true);
 }
 
 // Adds a localized string keyed by resource id to the dictionary.
diff --git a/chrome/browser/search/suggestions/image_fetcher_impl.cc b/chrome/browser/search/suggestions/image_fetcher_impl.cc
index 936beba..466c2af 100644
--- a/chrome/browser/search/suggestions/image_fetcher_impl.cc
+++ b/chrome/browser/search/suggestions/image_fetcher_impl.cc
@@ -42,10 +42,11 @@
     ImageRequest request(new chrome::BitmapFetcher(image_url, this));
     request.url = url;
     request.callbacks.push_back(callback);
-    request.fetcher->Start(
+    request.fetcher->Init(
         url_request_context_, std::string(),
         net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
         net::LOAD_NORMAL);
+    request.fetcher->Start();
     pending_net_requests_[image_url].swap(&request);
   } else {
     // Request in progress. Register as an interested callback.
diff --git a/chrome/browser/search/suggestions/suggestions_service_factory.cc b/chrome/browser/search/suggestions/suggestions_service_factory.cc
index a1e2982..77002ad2d 100644
--- a/chrome/browser/search/suggestions/suggestions_service_factory.cc
+++ b/chrome/browser/search/suggestions/suggestions_service_factory.cc
@@ -67,7 +67,9 @@
   scoped_ptr<ImageFetcherImpl> image_fetcher(
       new ImageFetcherImpl(the_profile->GetRequestContext()));
   scoped_ptr<ImageManager> thumbnail_manager(
-      new ImageManager(image_fetcher.Pass(), db.Pass(), database_dir));
+      new ImageManager(
+          image_fetcher.Pass(), db.Pass(), database_dir,
+          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
   return new SuggestionsService(
       the_profile->GetRequestContext(), suggestions_store.Pass(),
       thumbnail_manager.Pass(), blacklist_store.Pass());
diff --git a/chrome/browser/search_engines/template_url_service_factory.cc b/chrome/browser/search_engines/template_url_service_factory.cc
index c4229d3..4d6709a 100644
--- a/chrome/browser/search_engines/template_url_service_factory.cc
+++ b/chrome/browser/search_engines/template_url_service_factory.cc
@@ -35,7 +35,7 @@
 }
 
 // static
-KeyedService* TemplateURLServiceFactory::BuildInstanceFor(
+scoped_ptr<KeyedService> TemplateURLServiceFactory::BuildInstanceFor(
     content::BrowserContext* context) {
   base::Closure dsp_change_callback;
 #if defined(ENABLE_RLZ)
@@ -46,7 +46,7 @@
                  rlz_lib::SET_TO_GOOGLE);
 #endif
   Profile* profile = static_cast<Profile*>(context);
-  return new TemplateURLService(
+  return make_scoped_ptr(new TemplateURLService(
       profile->GetPrefs(),
       scoped_ptr<SearchTermsData>(new UIThreadSearchTermsData(profile)),
       WebDataServiceFactory::GetKeywordWebDataForProfile(
@@ -55,8 +55,7 @@
           HistoryServiceFactory::GetForProfile(
               profile, ServiceAccessType::EXPLICIT_ACCESS))),
       GoogleURLTrackerFactory::GetForProfile(profile),
-      g_browser_process->rappor_service(),
-      dsp_change_callback);
+      g_browser_process->rappor_service(), dsp_change_callback));
 }
 
 TemplateURLServiceFactory::TemplateURLServiceFactory()
@@ -72,7 +71,7 @@
 
 KeyedService* TemplateURLServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* profile) const {
-  return BuildInstanceFor(static_cast<Profile*>(profile));
+  return BuildInstanceFor(static_cast<Profile*>(profile)).release();
 }
 
 void TemplateURLServiceFactory::RegisterProfilePrefs(
diff --git a/chrome/browser/search_engines/template_url_service_factory.h b/chrome/browser/search_engines/template_url_service_factory.h
index 9939278da..db900b0f 100644
--- a/chrome/browser/search_engines/template_url_service_factory.h
+++ b/chrome/browser/search_engines/template_url_service_factory.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_SEARCH_ENGINES_TEMPLATE_URL_SERVICE_FACTORY_H_
 
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
@@ -19,7 +20,8 @@
 
   static TemplateURLServiceFactory* GetInstance();
 
-  static KeyedService* BuildInstanceFor(content::BrowserContext* profile);
+  static scoped_ptr<KeyedService> BuildInstanceFor(
+      content::BrowserContext* profile);
 
  private:
   friend struct DefaultSingletonTraits<TemplateURLServiceFactory>;
diff --git a/chrome/browser/services/gcm/fake_gcm_profile_service.cc b/chrome/browser/services/gcm/fake_gcm_profile_service.cc
index e1926a3..a1b5e3c 100644
--- a/chrome/browser/services/gcm/fake_gcm_profile_service.cc
+++ b/chrome/browser/services/gcm/fake_gcm_profile_service.cc
@@ -105,11 +105,12 @@
 }  // namespace
 
 // static
-KeyedService* FakeGCMProfileService::Build(content::BrowserContext* context) {
+scoped_ptr<KeyedService> FakeGCMProfileService::Build(
+    content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
-  FakeGCMProfileService* service = new FakeGCMProfileService(profile);
-  service->SetDriverForTesting(new CustomFakeGCMDriver(service));
-  return service;
+  scoped_ptr<FakeGCMProfileService> service(new FakeGCMProfileService(profile));
+  service->SetDriverForTesting(new CustomFakeGCMDriver(service.get()));
+  return service.Pass();
 }
 
 FakeGCMProfileService::FakeGCMProfileService(Profile* profile)
diff --git a/chrome/browser/services/gcm/fake_gcm_profile_service.h b/chrome/browser/services/gcm/fake_gcm_profile_service.h
index 58ba184..ce5907c 100644
--- a/chrome/browser/services/gcm/fake_gcm_profile_service.h
+++ b/chrome/browser/services/gcm/fake_gcm_profile_service.h
@@ -8,6 +8,7 @@
 #include <list>
 #include <vector>
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/services/gcm/gcm_profile_service.h"
 #include "components/gcm_driver/gcm_driver.h"
 
@@ -24,7 +25,7 @@
 
   // Helper function to be used with
   // KeyedService::SetTestingFactory().
-  static KeyedService* Build(content::BrowserContext* context);
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* context);
 
   explicit FakeGCMProfileService(Profile* profile);
   ~FakeGCMProfileService() override;
diff --git a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
index ea3ccda..8c3afb55 100644
--- a/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
+++ b/chrome/browser/services/gcm/gcm_profile_service_unittest.cc
@@ -35,14 +35,15 @@
 const char kTestAppID[] = "TestApp";
 const char kUserID[] = "user";
 
-KeyedService* BuildGCMProfileService(content::BrowserContext* context) {
-  return new GCMProfileService(
+scoped_ptr<KeyedService> BuildGCMProfileService(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(new GCMProfileService(
       Profile::FromBrowserContext(context),
       scoped_ptr<GCMClientFactory>(new FakeGCMClientFactory(
           content::BrowserThread::GetMessageLoopProxyForThread(
               content::BrowserThread::UI),
           content::BrowserThread::GetMessageLoopProxyForThread(
-              content::BrowserThread::IO))));
+              content::BrowserThread::IO)))));
 }
 
 }  // namespace
@@ -217,7 +218,7 @@
   GCMClient::OutgoingMessage message;
   message.id = "1";
   message.data["key1"] = "value1";
-  SendAndWaitForCompletion( message);
+  SendAndWaitForCompletion(message);
 
   EXPECT_EQ(message.id, send_message_id());
   EXPECT_EQ(GCMClient::SUCCESS, send_result());
diff --git a/chrome/browser/sessions/persistent_tab_restore_service_unittest.cc b/chrome/browser/sessions/persistent_tab_restore_service_unittest.cc
index fe4a05a10..cadb88b 100644
--- a/chrome/browser/sessions/persistent_tab_restore_service_unittest.cc
+++ b/chrome/browser/sessions/persistent_tab_restore_service_unittest.cc
@@ -146,9 +146,8 @@
   // way of AddWindowWithOneTabToSessionService. If |pinned| is true, the
   // tab is marked as pinned in the session service.
   void CreateSessionServiceWithOneWindow(bool pinned) {
-    // The profile takes ownership of this.
-    SessionService* session_service = new SessionService(profile());
-    SessionServiceFactory::SetForTestProfile(profile(), session_service);
+    scoped_ptr<SessionService> session_service(new SessionService(profile()));
+    SessionServiceFactory::SetForTestProfile(profile(), session_service.Pass());
 
     AddWindowWithOneTabToSessionService(pinned);
 
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc
index 0b8759a2..1e241d6 100644
--- a/chrome/browser/sessions/session_service.cc
+++ b/chrome/browser/sessions/session_service.cc
@@ -39,7 +39,6 @@
 #include "components/sessions/content/content_serialized_navigation_builder.h"
 #include "components/sessions/session_command.h"
 #include "components/sessions/session_types.h"
-#include "components/startup_metric_utils/startup_metric_utils.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_details.h"
@@ -701,9 +700,6 @@
   ScopedVector<sessions::SessionWindow> valid_windows;
   SessionID::id_type active_window_id = 0;
 
-  startup_metric_utils::ScopedSlowStartupUMA
-      scoped_timer("Startup.SlowStartupSessionServiceCreateTabsAndWindows");
-
   sessions::RestoreSessionFromCommands(
       commands, &valid_windows.get(), &active_window_id);
   RemoveUnusedRestoreWindows(&valid_windows.get());
diff --git a/chrome/browser/sessions/session_service_factory.h b/chrome/browser/sessions/session_service_factory.h
index 2c73d57..c0db39c 100644
--- a/chrome/browser/sessions/session_service_factory.h
+++ b/chrome/browser/sessions/session_service_factory.h
@@ -44,10 +44,11 @@
 #if defined(UNIT_TEST)
   // For test use: force setting of the session service for a given profile.
   // This will delete a previous session service for this profile if it exists.
-  static void SetForTestProfile(Profile* profile, SessionService* service) {
+  static void SetForTestProfile(Profile* profile,
+                                scoped_ptr<SessionService> service) {
     GetInstance()->BrowserContextShutdown(profile);
     GetInstance()->BrowserContextDestroyed(profile);
-    GetInstance()->Associate(profile, service);
+    GetInstance()->Associate(profile, service.Pass());
   }
 #endif
 
diff --git a/chrome/browser/signin/account_reconcilor_unittest.cc b/chrome/browser/signin/account_reconcilor_unittest.cc
index 5ccfb01a..2cee3f77 100644
--- a/chrome/browser/signin/account_reconcilor_unittest.cc
+++ b/chrome/browser/signin/account_reconcilor_unittest.cc
@@ -43,7 +43,7 @@
 
 class MockAccountReconcilor : public testing::StrictMock<AccountReconcilor> {
  public:
-  static KeyedService* Build(content::BrowserContext* context);
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* context);
 
   MockAccountReconcilor(ProfileOAuth2TokenService* token_service,
                         SigninManagerBase* signin_manager,
@@ -56,15 +56,16 @@
 };
 
 // static
-KeyedService* MockAccountReconcilor::Build(content::BrowserContext* context) {
+scoped_ptr<KeyedService> MockAccountReconcilor::Build(
+    content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
-  AccountReconcilor* reconcilor = new MockAccountReconcilor(
+  scoped_ptr<AccountReconcilor> reconcilor(new MockAccountReconcilor(
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
       SigninManagerFactory::GetForProfile(profile),
       ChromeSigninClientFactory::GetForProfile(profile),
-      GaiaCookieManagerServiceFactory::GetForProfile(profile));
+      GaiaCookieManagerServiceFactory::GetForProfile(profile)));
   reconcilor->Initialize(false /* start_reconcile_if_tokens_available */);
-  return reconcilor;
+  return reconcilor.Pass();
 }
 
 MockAccountReconcilor::MockAccountReconcilor(
@@ -316,7 +317,7 @@
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseOneAccountWithExpiry(
-      "user@gmail.com", true);
+      "user@gmail.com", "12345", true);
   EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
 
   AccountReconcilor* reconcilor =
@@ -333,7 +334,7 @@
   std::vector<gaia::ListedAccount> accounts;
   ASSERT_TRUE(cookie_manager_service()->ListAccounts(&accounts));
   ASSERT_EQ(1u, accounts.size());
-  ASSERT_EQ(account_id, accounts[0].email);
+  ASSERT_EQ(account_id, accounts[0].id);
 }
 
 TEST_F(AccountReconcilorTest, GetAccountsFromCookieFailure) {
@@ -367,7 +368,8 @@
       AccountReconcilorFactory::GetForProfile(profile());
   ASSERT_TRUE(reconcilor);
 
-  cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com");
+  cookie_manager_service()->SetListAccountsResponseOneAccount(
+      "user@gmail.com", "12345");
 
   reconcilor->StartReconcile();
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
@@ -487,7 +489,7 @@
   const std::string account_id =
       ConnectProfileToAccount("12345", "Dot.S@gmail.com");
   cookie_manager_service()->SetListAccountsResponseOneAccount(
-      "dot.s@gmail.com");
+      "dot.s@gmail.com", "12345");
   AccountReconcilor* reconcilor =
       AccountReconcilorFactory::GetForProfile(profile());
   ASSERT_TRUE(reconcilor);
@@ -508,7 +510,7 @@
   const std::string account_id2 =
       PickAccountIdForAccount("67890", "other@gmail.com");
   cookie_manager_service()->SetListAccountsResponseTwoAccounts(
-      "user@gmail.com", "other@gmail.com");
+      "user@gmail.com", "12345", "other@gmail.com", "67890");
   token_service()->UpdateCredentials(account_id2, "refresh_token");
 
   AccountReconcilor* reconcilor =
@@ -532,7 +534,7 @@
       ConnectProfileToAccount("12345", "user@gmail.com");
   token_service()->UpdateCredentials(account_id, "refresh_token");
   cookie_manager_service()->SetListAccountsResponseOneAccount(
-      "user@gmail.com");
+      "user@gmail.com", "12345");
 
   const std::string account_id2 =
       PickAccountIdForAccount("67890", "other@gmail.com");
@@ -564,7 +566,7 @@
       ConnectProfileToAccount("12345", "user@gmail.com");
   token_service()->UpdateCredentials(account_id, "refresh_token");
   cookie_manager_service()->SetListAccountsResponseTwoAccounts(
-      "user@gmail.com", "other@gmail.com");
+      "user@gmail.com", "12345", "other@gmail.com", "67890");
 
   EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
   EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
@@ -597,7 +599,7 @@
       PickAccountIdForAccount("34567", "third@gmail.com");
 
   cookie_manager_service()->SetListAccountsResponseOneAccount(
-      "user@gmail.com");
+      "user@gmail.com", "12345");
   token_service()->UpdateCredentials(account_id2, "refresh_token");
 
   EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
@@ -623,7 +625,7 @@
 
   // Do another pass after I've added a third account to the token service
   cookie_manager_service()->SetListAccountsResponseTwoAccounts(
-      "user@gmail.com", "other@gmail.com");
+      "user@gmail.com", "12345", "other@gmail.com", "67890");
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
 
   // This will cause the reconcilor to fire.
@@ -661,7 +663,7 @@
 
   token_service()->UpdateCredentials(account_id2, "refresh_token");
   cookie_manager_service()->SetListAccountsResponseTwoAccounts(
-      "other@gmail.com", "user@gmail.com");
+      "other@gmail.com", "12345", "user@gmail.com", "67890");
 
   EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
   EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
@@ -693,7 +695,7 @@
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseOneAccount(
-      "user@gmail.com");
+      "user@gmail.com", "12345");
 
   AccountReconcilor* reconcilor =
       AccountReconcilorFactory::GetForProfile(profile());
@@ -736,7 +738,7 @@
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseOneAccountWithExpiry(
-      "user@gmail.com", true);
+      "user@gmail.com", "12345", true);
 
   EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
 
diff --git a/chrome/browser/signin/cross_device_promo_unittest.cc b/chrome/browser/signin/cross_device_promo_unittest.cc
index 9f224022..1450884e 100644
--- a/chrome/browser/signin/cross_device_promo_unittest.cc
+++ b/chrome/browser/signin/cross_device_promo_unittest.cc
@@ -291,7 +291,7 @@
   // Setting a single cookie sets the time.
   base::Time before_setting_cookies = base::Time::Now();
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
-  cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
+  cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
   EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   base::RunLoop().RunUntilIdle();
 
@@ -307,7 +307,7 @@
 
   // A single cookie a second time doesn't change the time.
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
-  cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
+  cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
   EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   base::RunLoop().RunUntilIdle();
 
@@ -358,7 +358,7 @@
     base::HistogramTester test_single_account;
     std::vector<gaia::ListedAccount> accounts;
     cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
-    cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
+    cookie_manager_service()->SetListAccountsResponseOneAccount("a@b.com", "1");
     EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
     base::RunLoop().RunUntilIdle();
 
@@ -385,7 +385,7 @@
   InitPromoVariation();
   EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
-  cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
+  cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
   std::vector<gaia::ListedAccount> accounts;
   EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   base::RunLoop().RunUntilIdle();
@@ -455,7 +455,7 @@
 
   EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
-  cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
+  cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
   std::vector<gaia::ListedAccount> accounts;
   EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   base::RunLoop().RunUntilIdle();
@@ -477,7 +477,7 @@
   InitPromoVariation();
   EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
-  cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
+  cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
   std::vector<gaia::ListedAccount> accounts;
   EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   base::RunLoop().RunUntilIdle();
@@ -505,7 +505,7 @@
   InitPromoVariation();
   EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
-  cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
+  cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
   std::vector<gaia::ListedAccount> accounts;
   EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/signin/easy_unlock_app_manager_unittest.cc b/chrome/browser/signin/easy_unlock_app_manager_unittest.cc
index bab12ed..89bf24b 100644
--- a/chrome/browser/signin/easy_unlock_app_manager_unittest.cc
+++ b/chrome/browser/signin/easy_unlock_app_manager_unittest.cc
@@ -69,8 +69,9 @@
   DISALLOW_COPY_AND_ASSIGN(TestProcessManager);
 };
 
-KeyedService* CreateTestProcessManager(content::BrowserContext* context) {
-  return new TestProcessManager(context);
+scoped_ptr<KeyedService> CreateTestProcessManager(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(new TestProcessManager(context));
 }
 
 // Observes extension registry for unload and load events (in that order) of an
@@ -262,9 +263,11 @@
 };
 
 // TestEventRouter factory function
-KeyedService* TestEventRouterFactoryFunction(content::BrowserContext* context) {
-  return new TestEventRouter(static_cast<Profile*>(context),
-                             extensions::ExtensionPrefs::Get(context));
+scoped_ptr<KeyedService> TestEventRouterFactoryFunction(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(
+      new TestEventRouter(static_cast<Profile*>(context),
+                          extensions::ExtensionPrefs::Get(context)));
 }
 
 class EasyUnlockAppManagerTest : public testing::Test {
diff --git a/chrome/browser/signin/easy_unlock_service_unittest_chromeos.cc b/chrome/browser/signin/easy_unlock_service_unittest_chromeos.cc
index c5b3418..8c8ccaa 100644
--- a/chrome/browser/signin/easy_unlock_service_unittest_chromeos.cc
+++ b/chrome/browser/signin/easy_unlock_service_unittest_chromeos.cc
@@ -6,6 +6,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
@@ -169,21 +170,22 @@
 
 // EasyUnlockService factory function injected into testing profiles.
 // It creates an EasyUnlockService with test AppManager.
-KeyedService* CreateEasyUnlockServiceForTest(content::BrowserContext* context) {
+scoped_ptr<KeyedService> CreateEasyUnlockServiceForTest(
+    content::BrowserContext* context) {
   EXPECT_TRUE(app_manager_factory);
   if (!app_manager_factory)
-    return NULL;
+    return nullptr;
 
   scoped_ptr<EasyUnlockAppManager> app_manager =
       app_manager_factory->Create(context);
   EXPECT_TRUE(app_manager.get());
   if (!app_manager.get())
-    return NULL;
+    return nullptr;
 
-  EasyUnlockService* service =
-      new EasyUnlockServiceRegular(Profile::FromBrowserContext(context));
+  scoped_ptr<EasyUnlockServiceRegular> service(
+      new EasyUnlockServiceRegular(Profile::FromBrowserContext(context)));
   service->Initialize(app_manager.Pass());
-  return service;
+  return service.Pass();
 }
 
 class EasyUnlockServiceTest : public testing::Test {
diff --git a/chrome/browser/signin/fake_account_tracker_service.cc b/chrome/browser/signin/fake_account_tracker_service.cc
index 5fd0fcd..b9b38ab96 100644
--- a/chrome/browser/signin/fake_account_tracker_service.cc
+++ b/chrome/browser/signin/fake_account_tracker_service.cc
@@ -11,14 +11,14 @@
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 
 // static
-KeyedService* FakeAccountTrackerService::Build(
+scoped_ptr<KeyedService> FakeAccountTrackerService::Build(
     content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
   FakeAccountTrackerService* service = new FakeAccountTrackerService();
   service->Initialize(
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
       ChromeSigninClientFactory::GetForProfile(profile));
-  return service;
+  return scoped_ptr<KeyedService>(service);
 }
 
 FakeAccountTrackerService::FakeAccountTrackerService() {}
diff --git a/chrome/browser/signin/fake_account_tracker_service.h b/chrome/browser/signin/fake_account_tracker_service.h
index a30f9134..5008d512 100644
--- a/chrome/browser/signin/fake_account_tracker_service.h
+++ b/chrome/browser/signin/fake_account_tracker_service.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_SIGNIN_FAKE_ACCOUNT_TRACKER_SERVICE_H_
 #define CHROME_BROWSER_SIGNIN_FAKE_ACCOUNT_TRACKER_SERVICE_H_
 
+#include "base/memory/scoped_ptr.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 
 class KeyedService;
@@ -18,7 +19,7 @@
 // to prevent AccountTrackerService from sending network requests.
 class FakeAccountTrackerService : public AccountTrackerService {
  public:
-  static KeyedService* Build(content::BrowserContext* context);
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* context);
 
   void FakeUserInfoFetchSuccess(const std::string& email,
                                 const std::string& gaia,
diff --git a/chrome/browser/signin/fake_gaia_cookie_manager_service.cc b/chrome/browser/signin/fake_gaia_cookie_manager_service.cc
index 4c767d0..033a295 100644
--- a/chrome/browser/signin/fake_gaia_cookie_manager_service.cc
+++ b/chrome/browser/signin/fake_gaia_cookie_manager_service.cc
@@ -55,41 +55,42 @@
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseOneAccount(
-    const char* account) {
+    const char* email, const char* gaia_id) {
   DCHECK(url_fetcher_factory_);
   url_fetcher_factory_->SetFakeResponse(
       GaiaUrls::GetInstance()->ListAccountsURLWithSource(
           GaiaConstants::kChromeSource),
       base::StringPrintf(
-          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"22\"]]]",
-          account),
+          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"%s\"]]]",
+          email, gaia_id),
       net::HTTP_OK,
       net::URLRequestStatus::SUCCESS);
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseOneAccountWithExpiry(
-    const char* account, bool expired) {
+    const char* email, const char* gaia_id, bool expired) {
   DCHECK(url_fetcher_factory_);
   url_fetcher_factory_->SetFakeResponse(
       GaiaUrls::GetInstance()->ListAccountsURLWithSource(
           GaiaConstants::kChromeSource),
       base::StringPrintf(
-          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"22\"]]]",
-          account, expired ? 0 : 1),
+          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"%s\"]]]",
+          email, expired ? 0 : 1, gaia_id),
       net::HTTP_OK,
       net::URLRequestStatus::SUCCESS);
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseTwoAccounts(
-    const char* account1, const char* account2) {
+    const char* email1, const char* gaia_id1,
+    const char* email2, const char* gaia_id2) {
   DCHECK(url_fetcher_factory_);
   url_fetcher_factory_->SetFakeResponse(
       GaiaUrls::GetInstance()->ListAccountsURLWithSource(
           GaiaConstants::kChromeSource),
       base::StringPrintf(
-          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"22\"], "
-          "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"24\"]]]",
-          account1, account2),
+          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"%s\"], "
+          "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"%s\"]]]",
+          email1, gaia_id1, email2, gaia_id2),
       net::HTTP_OK,
       net::URLRequestStatus::SUCCESS);
 }
@@ -111,12 +112,11 @@
 }
 
 // static
-KeyedService* FakeGaiaCookieManagerService::Build(
+scoped_ptr<KeyedService> FakeGaiaCookieManagerService::Build(
     content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
-  FakeGaiaCookieManagerService* service = new FakeGaiaCookieManagerService(
+  return make_scoped_ptr(new FakeGaiaCookieManagerService(
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
       GaiaConstants::kChromeSource,
-      ChromeSigninClientFactory::GetForProfile(profile));
-  return service;
+      ChromeSigninClientFactory::GetForProfile(profile)));
 }
diff --git a/chrome/browser/signin/fake_gaia_cookie_manager_service.h b/chrome/browser/signin/fake_gaia_cookie_manager_service.h
index 5321482..662aca88 100644
--- a/chrome/browser/signin/fake_gaia_cookie_manager_service.h
+++ b/chrome/browser/signin/fake_gaia_cookie_manager_service.h
@@ -6,6 +6,7 @@
 
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 
 namespace content {
@@ -23,17 +24,19 @@
   void SetListAccountsResponseHttpNotFound();
   void SetListAccountsResponseWebLoginRequired();
   void SetListAccountsResponseNoAccounts();
-  void SetListAccountsResponseOneAccount(const char* account);
+  void SetListAccountsResponseOneAccount(
+      const char* email, const char* gaia_id);
   void SetListAccountsResponseOneAccountWithExpiry(
-      const char* account, bool expired);
-  void SetListAccountsResponseTwoAccounts(const char* account1,
-                                          const char* account2);
+      const char* account, const char* gaia_id, bool expired);
+  void SetListAccountsResponseTwoAccounts(
+    const char* email1, const char* gaia_id1,
+    const char* email2, const char* gaia_id2);
   void SetListAccountsResponseTwoAccountsWithExpiry(
       const char* account1, bool account1_expired,
       const char* account2, bool account2_expired);
 
   // Helper function to be used with KeyedService::SetTestingFactory().
-  static KeyedService* Build(content::BrowserContext* context);
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* context);
 
  private:
   // Provide a fake response for calls to /ListAccounts.
diff --git a/chrome/browser/signin/fake_profile_oauth2_token_service_builder.cc b/chrome/browser/signin/fake_profile_oauth2_token_service_builder.cc
index 90e9fe3..1888211 100644
--- a/chrome/browser/signin/fake_profile_oauth2_token_service_builder.cc
+++ b/chrome/browser/signin/fake_profile_oauth2_token_service_builder.cc
@@ -2,30 +2,33 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
+
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
-#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
 #include "chrome/browser/signin/signin_error_controller_factory.h"
 
 // TODO(blundell): Should these be namespaced?
-KeyedService* BuildFakeProfileOAuth2TokenService(
+scoped_ptr<KeyedService> BuildFakeProfileOAuth2TokenService(
     content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
-  FakeProfileOAuth2TokenService* service = new FakeProfileOAuth2TokenService();
+  scoped_ptr<FakeProfileOAuth2TokenService> service(
+      new FakeProfileOAuth2TokenService());
   service->Initialize(
       ChromeSigninClientFactory::GetInstance()->GetForProfile(profile),
       SigninErrorControllerFactory::GetInstance()->GetForProfile(profile));
-  return service;
+  return service.Pass();
 }
 
-KeyedService* BuildAutoIssuingFakeProfileOAuth2TokenService(
+scoped_ptr<KeyedService> BuildAutoIssuingFakeProfileOAuth2TokenService(
     content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
-  FakeProfileOAuth2TokenService* service = new FakeProfileOAuth2TokenService();
+  scoped_ptr<FakeProfileOAuth2TokenService> service(
+      new FakeProfileOAuth2TokenService());
   service->set_auto_post_fetch_response_on_message_loop(true);
   service->Initialize(
       ChromeSigninClientFactory::GetInstance()->GetForProfile(profile),
       SigninErrorControllerFactory::GetInstance()->GetForProfile(profile));
-  return service;
+  return service.Pass();
 }
diff --git a/chrome/browser/signin/fake_profile_oauth2_token_service_builder.h b/chrome/browser/signin/fake_profile_oauth2_token_service_builder.h
index 21672b66..d9cd4bd 100644
--- a/chrome/browser/signin/fake_profile_oauth2_token_service_builder.h
+++ b/chrome/browser/signin/fake_profile_oauth2_token_service_builder.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_SIGNIN_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_BUILDER_H_
 #define CHROME_BROWSER_SIGNIN_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_BUILDER_H_
 
+#include "base/memory/scoped_ptr.h"
+
 class KeyedService;
 
 namespace content {
@@ -14,14 +16,14 @@
 // Helper function to be used with
 // BrowserContextKeyedServiceFactory::SetTestingFactory() that returns a
 // FakeProfileOAuth2TokenService object.
-KeyedService* BuildFakeProfileOAuth2TokenService(
+scoped_ptr<KeyedService> BuildFakeProfileOAuth2TokenService(
     content::BrowserContext* context);
 
 // Helper function to be used with
 // BrowserContextKeyedServiceFactory::SetTestingFactory() that creates a
 // FakeProfileOAuth2TokenService object that posts fetch responses on the
 // current message loop.
-KeyedService* BuildAutoIssuingFakeProfileOAuth2TokenService(
+scoped_ptr<KeyedService> BuildAutoIssuingFakeProfileOAuth2TokenService(
     content::BrowserContext* context);
 
 #endif  // CHROME_BROWSER_SIGNIN_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_BUILDER_H_
diff --git a/chrome/browser/signin/fake_signin_manager.cc b/chrome/browser/signin/fake_signin_manager.cc
index 6cc2902a..f81b4b4 100644
--- a/chrome/browser/signin/fake_signin_manager.cc
+++ b/chrome/browser/signin/fake_signin_manager.cc
@@ -26,18 +26,19 @@
 }
 
 // static
-KeyedService* FakeSigninManagerBase::Build(content::BrowserContext* context) {
-  SigninManagerBase* manager;
+scoped_ptr<KeyedService> FakeSigninManagerBase::Build(
+    content::BrowserContext* context) {
+  scoped_ptr<SigninManagerBase> manager;
   Profile* profile = static_cast<Profile*>(context);
 #if defined(OS_CHROMEOS)
-  manager = new FakeSigninManagerBase(profile);
+  manager.reset(new FakeSigninManagerBase(profile));
 #else
-  manager = new FakeSigninManager(profile);
+  manager.reset(new FakeSigninManager(profile));
 #endif
   manager->Initialize(NULL);
   SigninManagerFactory::GetInstance()
-      ->NotifyObserversOfSigninManagerCreationForTesting(manager);
-  return manager;
+      ->NotifyObserversOfSigninManagerCreationForTesting(manager.get());
+  return manager.Pass();
 }
 
 #if !defined (OS_CHROMEOS)
diff --git a/chrome/browser/signin/fake_signin_manager.h b/chrome/browser/signin/fake_signin_manager.h
index 24e59c41..7128ae4 100644
--- a/chrome/browser/signin/fake_signin_manager.h
+++ b/chrome/browser/signin/fake_signin_manager.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_metrics.h"
 
@@ -32,7 +33,7 @@
   // the API of SigninManagerFactory::GetForProfile(), returns a
   // FakeSigninManagerBase* on ChromeOS, and a FakeSigninManager* on all other
   // platforms. The returned instance is initialized.
-  static KeyedService* Build(content::BrowserContext* context);
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* context);
 };
 
 #if !defined(OS_CHROMEOS)
diff --git a/chrome/browser/signin/signin_manager_unittest.cc b/chrome/browser/signin/signin_manager_unittest.cc
index 68a4c3b..bd5fb3e 100644
--- a/chrome/browser/signin/signin_manager_unittest.cc
+++ b/chrome/browser/signin/signin_manager_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
@@ -48,16 +49,15 @@
 
 namespace {
 
-KeyedService* SigninManagerBuild(content::BrowserContext* context) {
-  SigninManager* service = NULL;
+scoped_ptr<KeyedService> SigninManagerBuild(content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
-  service = new SigninManager(
+  scoped_ptr<SigninManager> service(new SigninManager(
       ChromeSigninClientFactory::GetInstance()->GetForProfile(profile),
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
       AccountTrackerServiceFactory::GetForProfile(profile),
-      GaiaCookieManagerServiceFactory::GetForProfile(profile));
+      GaiaCookieManagerServiceFactory::GetForProfile(profile)));
   service->Initialize(NULL);
-  return service;
+  return service.Pass();
 }
 
 class TestSigninManagerObserver : public SigninManagerBase::Observer {
@@ -444,3 +444,27 @@
   EXPECT_EQ("user@gmail.com", info.email);
   EXPECT_EQ("account_id", info.gaia);
 }
+
+TEST_F(SigninManagerTest, CanonicalizesPrefs) {
+  profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
+                                   "user.C@gmail.com");
+  CreateNakedSigninManager();
+  manager_->Initialize(g_browser_process->local_state());
+  EXPECT_EQ("user.C@gmail.com", manager_->GetAuthenticatedUsername());
+
+  // TODO(rogerta): until the migration to gaia id, the account id will remain
+  // the old username.
+  EXPECT_EQ("userc@gmail.com", manager_->GetAuthenticatedAccountId());
+  EXPECT_EQ("userc@gmail.com",
+            profile()->GetPrefs()->GetString(prefs::kGoogleServicesAccountId));
+  EXPECT_EQ("",
+            profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername));
+
+  // Make sure account tracker has a canonicalized username.
+  AccountTrackerService* service =
+      AccountTrackerServiceFactory::GetForProfile(profile());
+  AccountTrackerService::AccountInfo info = service->GetAccountInfo(
+      manager_->GetAuthenticatedAccountId());
+  EXPECT_EQ("user.C@gmail.com", info.email);
+  EXPECT_EQ("userc@gmail.com", info.account_id);
+}
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc
index cc6f009..e75bf10 100644
--- a/chrome/browser/signin/signin_ui_util.cc
+++ b/chrome/browser/signin/signin_ui_util.cc
@@ -58,7 +58,7 @@
   // No auth error - now try other services. Currently the list is just hard-
   // coded but in the future if we add more we can create some kind of
   // registration framework.
-  if (profile->IsSyncAccessible()) {
+  if (profile->IsSyncAllowed()) {
     SyncGlobalError* error = SyncGlobalErrorFactory::GetForProfile(profile);
     if (error && error->HasMenuItem())
       errors.push_back(error);
@@ -74,7 +74,7 @@
     return error->MenuItemLabel();
 
   // No errors, so just display the signed in user, if any.
-  ProfileSyncService* service = profile->IsSyncAccessible() ?
+  ProfileSyncService* service = profile->IsSyncAllowed() ?
       ProfileSyncServiceFactory::GetForProfile(profile) : NULL;
 
   // Even if the user is signed in, don't display the "signed in as..."
diff --git a/chrome/browser/signin/test_signin_client_builder.cc b/chrome/browser/signin/test_signin_client_builder.cc
index d846fa01..ef66af9 100644
--- a/chrome/browser/signin/test_signin_client_builder.cc
+++ b/chrome/browser/signin/test_signin_client_builder.cc
@@ -7,19 +7,12 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/signin/core/browser/test_signin_client.h"
 
-class KeyedService;
-
-namespace content {
-class BrowserContext;
-}
-
 namespace signin {
 
-KeyedService* BuildTestSigninClient(
+scoped_ptr<KeyedService> BuildTestSigninClient(
     content::BrowserContext* context) {
-  TestSigninClient* test_signin_client =
-      new TestSigninClient(static_cast<Profile*>(context)->GetPrefs());
-  return test_signin_client;
+  return make_scoped_ptr(
+      new TestSigninClient(static_cast<Profile*>(context)->GetPrefs()));
 }
 
 }  // namespace signin
diff --git a/chrome/browser/signin/test_signin_client_builder.h b/chrome/browser/signin/test_signin_client_builder.h
index 435231b..54bb6eb 100644
--- a/chrome/browser/signin/test_signin_client_builder.h
+++ b/chrome/browser/signin/test_signin_client_builder.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_SIGNIN_TEST_SIGNIN_CLIENT_BUILDER_H_
 #define CHROME_BROWSER_SIGNIN_TEST_SIGNIN_CLIENT_BUILDER_H_
 
+#include "base/memory/scoped_ptr.h"
+
 class KeyedService;
 
 namespace content {
@@ -15,7 +17,8 @@
 
 // Method to be used by the |ChromeSigninClientFactory| to create a test version
 // of the SigninClient
-KeyedService* BuildTestSigninClient(content::BrowserContext* context);
+scoped_ptr<KeyedService> BuildTestSigninClient(
+    content::BrowserContext* context);
 
 }  // namespace signin
 
diff --git a/chrome/browser/speech/extension_api/tts_extension_apitest.cc b/chrome/browser/speech/extension_api/tts_extension_apitest.cc
index 386175a..41780d0 100644
--- a/chrome/browser/speech/extension_api/tts_extension_apitest.cc
+++ b/chrome/browser/speech/extension_api/tts_extension_apitest.cc
@@ -359,6 +359,14 @@
   ASSERT_TRUE(RunExtensionTest("tts/pause_resume")) << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformPauseSpeakNoEnqueue) {
+  // While paused, one utterance is enqueued, and then a second utterance that
+  // cannot be enqueued cancels both.
+  InSequence s;
+  EXPECT_CALL(mock_platform_impl_, StopSpeaking()).WillOnce(Return(true));
+  ASSERT_TRUE(RunExtensionTest("tts/pause_speak_no_enqueue")) << message_;
+}
+
 //
 // TTS Engine tests.
 //
diff --git a/chrome/browser/speech/tts_controller_impl.cc b/chrome/browser/speech/tts_controller_impl.cc
index cad1bb3..07748fe 100644
--- a/chrome/browser/speech/tts_controller_impl.cc
+++ b/chrome/browser/speech/tts_controller_impl.cc
@@ -135,9 +135,9 @@
   // If we're paused and we get an utterance that can't be queued,
   // flush the queue but stay in the paused state.
   if (paused_ && !utterance->can_enqueue()) {
+    utterance_queue_.push(utterance);
     Stop();
     paused_ = true;
-    delete utterance;
     return;
   }
 
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
index 387636b9..dbd4da5a 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/strings/string_number_conversions.h"
@@ -53,8 +54,9 @@
 
 }  // namespace
 
-static KeyedService* BuildSpellcheckService(content::BrowserContext* profile) {
-  return new SpellcheckService(static_cast<Profile*>(profile));
+static scoped_ptr<KeyedService> BuildSpellcheckService(
+    content::BrowserContext* profile) {
+  return make_scoped_ptr(new SpellcheckService(static_cast<Profile*>(profile)));
 }
 
 class SpellcheckCustomDictionaryTest : public testing::Test {
diff --git a/chrome/browser/spellchecker/spellcheck_service_unittest.cc b/chrome/browser/spellchecker/spellcheck_service_unittest.cc
index 7cbc67b..f2fd9f0 100644
--- a/chrome/browser/spellchecker/spellcheck_service_unittest.cc
+++ b/chrome/browser/spellchecker/spellcheck_service_unittest.cc
@@ -6,14 +6,16 @@
 
 #include <algorithm>
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/spellchecker/feedback_sender.h"
 #include "chrome/browser/spellchecker/spellcheck_factory.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-static KeyedService* BuildSpellcheckService(content::BrowserContext* profile) {
-  return new SpellcheckService(static_cast<Profile*>(profile));
+static scoped_ptr<KeyedService> BuildSpellcheckService(
+    content::BrowserContext* profile) {
+  return make_scoped_ptr(new SpellcheckService(static_cast<Profile*>(profile)));
 }
 
 class SpellcheckServiceTest : public testing::Test {
diff --git a/chrome/browser/ssl/connection_security_helper.cc b/chrome/browser/ssl/connection_security_helper.cc
index 63455835..e55d1aca 100644
--- a/chrome/browser/ssl/connection_security_helper.cc
+++ b/chrome/browser/ssl/connection_security_helper.cc
@@ -128,3 +128,24 @@
       return NONE;
   }
 }
+
+content::SecurityStyle ConnectionSecurityHelper::GetSecurityStyleForWebContents(
+    const content::WebContents* web_contents) {
+  SecurityLevel security_level = GetSecurityLevelForWebContents(web_contents);
+
+  switch (security_level) {
+    case NONE:
+      return content::SECURITY_STYLE_UNAUTHENTICATED;
+    case EV_SECURE:
+    case SECURE:
+      return content::SECURITY_STYLE_AUTHENTICATED;
+    case SECURITY_WARNING:
+    case SECURITY_POLICY_WARNING:
+      return content::SECURITY_STYLE_WARNING;
+    case SECURITY_ERROR:
+      return content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
+  }
+
+  NOTREACHED();
+  return content::SECURITY_STYLE_UNKNOWN;
+}
diff --git a/chrome/browser/ssl/connection_security_helper.h b/chrome/browser/ssl/connection_security_helper.h
index 3a34b56..befba710 100644
--- a/chrome/browser/ssl/connection_security_helper.h
+++ b/chrome/browser/ssl/connection_security_helper.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_SSL_CONNECTION_SECURITY_HELPER_H_
 
 #include "base/macros.h"
+#include "content/public/common/security_style.h"
 
 namespace content {
 class WebContents;
@@ -52,6 +53,17 @@
   static SecurityLevel GetSecurityLevelForWebContents(
       const content::WebContents* web_contents);
 
+  // Returns the content::SecurityStyle for the given |web_contents|.
+  // Note: This is a lossy operation. Not all of the policies
+  // that can be expressed by a SecurityLevel (a //chrome concept) can
+  // be expressed by a content::SecurityStyle.
+  // In general, code in //chrome should prefer to use
+  // GetSecurityLevelForWebContents() to determine security policy, and
+  // only use this function when policy needs to be supplied back to
+  // layers in //content.
+  static content::SecurityStyle GetSecurityStyleForWebContents(
+      const content::WebContents* web_contents);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ConnectionSecurityHelper);
 };
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 223655a4..9ca088e 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -808,7 +808,7 @@
   // The title will be changed to 'PASS'.
   ui_test_utils::NavigateToURL(browser(), master_url);
   const base::string16 result = watcher.WaitAndGetTitle();
-  EXPECT_TRUE(LowerCaseEqualsASCII(result, "pass"));
+  EXPECT_TRUE(base::LowerCaseEqualsASCII(result, "pass"));
 
   // Close tabs which contains the test page.
   for (int i = 0; i < 16; ++i)
@@ -844,7 +844,7 @@
   // Test page run a WebSocket wss connection test. The result will be shown
   // as page title.
   const base::string16 result = watcher.WaitAndGetTitle();
-  EXPECT_TRUE(LowerCaseEqualsASCII(result, "pass"));
+  EXPECT_TRUE(base::LowerCaseEqualsASCII(result, "pass"));
 }
 
 #if defined(USE_NSS_CERTS)
@@ -931,7 +931,7 @@
   // Test page runs a WebSocket wss connection test. The result will be shown
   // as page title.
   const base::string16 result = watcher.WaitAndGetTitle();
-  EXPECT_TRUE(LowerCaseEqualsASCII(result, "pass"));
+  EXPECT_TRUE(base::LowerCaseEqualsASCII(result, "pass"));
 }
 #endif  // defined(USE_NSS_CERTS)
 
@@ -2083,7 +2083,7 @@
   // Test page run a WebSocket wss connection test. The result will be shown
   // as page title.
   const base::string16 result = watcher.WaitAndGetTitle();
-  EXPECT_TRUE(LowerCaseEqualsASCII(result, "pass"));
+  EXPECT_TRUE(base::LowerCaseEqualsASCII(result, "pass"));
 }
 
 // Verifies that the interstitial can proceed, even if JavaScript is disabled.
diff --git a/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker.cc b/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker.cc
index 04b2a8e..f7eb8ae8 100644
--- a/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker.cc
+++ b/chrome/browser/supervised_user/experimental/supervised_user_async_url_checker.cc
@@ -50,7 +50,7 @@
   // Strip leading "www." (if any).
   const std::string www("www.");
   const std::string host(url.host());
-  if (StartsWithASCII(host, www, true))
+  if (base::StartsWithASCII(host, www, true))
     replacements.SetHostStr(base::StringPiece(host).substr(www.size()));
   // Strip trailing slash (if any).
   const std::string path(url.path());
diff --git a/chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc b/chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
index ed4e0f4..d9cbc32 100644
--- a/chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
+++ b/chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.cc
@@ -42,7 +42,11 @@
 
 // kIssueTokenBodyFormatDeviceIdAddendum is appended to kIssueTokenBodyFormat
 // if device_id is provided.
-static const char kIssueTokenBodyFormatDeviceIdAddendum[] = "&device_id=%s";
+// TODO(pavely): lib_ver is passed to differentiate IssueToken requests from
+// different code locations. Remove once device_id mismatch is understood.
+// (crbug.com/481596)
+static const char kIssueTokenBodyFormatDeviceIdAddendum[] =
+    "&device_id=%s&lib_ver=supervised_user";
 
 static const char kAuthorizationHeaderFormat[] =
     "Authorization: Bearer %s";
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service.cc b/chrome/browser/supervised_user/supervised_user_settings_service.cc
index dc47d60..f18bc1e 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_settings_service.cc
@@ -44,7 +44,7 @@
 namespace {
 
 bool SettingShouldApplyToPrefs(const std::string& name) {
-  return !StartsWithASCII(name, kSupervisedUserInternalItemPrefix, false);
+  return !base::StartsWithASCII(name, kSupervisedUserInternalItemPrefix, false);
 }
 
 }  // namespace
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service_unittest.cc b/chrome/browser/supervised_user/supervised_user_settings_service_unittest.cc
index b13fa00..c2a99dc 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service_unittest.cc
+++ b/chrome/browser/supervised_user/supervised_user_settings_service_unittest.cc
@@ -99,9 +99,9 @@
     if (supervised_user_setting.name() == kAtomicItemName) {
       expected_value = atomic_setting_value_.get();
     } else {
-      EXPECT_TRUE(StartsWithASCII(supervised_user_setting.name(),
-                                  std::string(kSplitItemName) + ':',
-                                  true));
+      EXPECT_TRUE(base::StartsWithASCII(supervised_user_setting.name(),
+                                        std::string(kSplitItemName) + ':',
+                                        true));
       std::string key =
           supervised_user_setting.name().substr(strlen(kSplitItemName) + 1);
       EXPECT_TRUE(split_items_.GetWithoutPathExpansion(key, &expected_value));
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.cc b/chrome/browser/supervised_user/supervised_user_url_filter.cc
index d9b641c2..acfda8b 100644
--- a/chrome/browser/supervised_user/supervised_user_url_filter.cc
+++ b/chrome/browser/supervised_user/supervised_user_url_filter.cc
@@ -113,7 +113,7 @@
 }
 
 void FilterBuilder::AddHostnameHash(const std::string& hash, int site_id) {
-  contents_->hash_site_map.insert(std::make_pair(StringToUpperASCII(hash),
+  contents_->hash_site_map.insert(std::make_pair(base::StringToUpperASCII(hash),
                                                  site_id));
 }
 
@@ -250,7 +250,7 @@
     trimmed_host.erase(trimmed_host.length() - (registry_length + 1));
   }
 
-  if (StartsWithASCII(trimmed_pattern, "*.", true)) {
+  if (base::StartsWithASCII(trimmed_pattern, "*.", true)) {
     trimmed_pattern.erase(0, 2);
 
     // The remaining pattern should be non-empty, and it should not contain
diff --git a/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc b/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
index 972d169b..d218916 100644
--- a/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/autofill_data_type_controller_unittest.cc
@@ -6,6 +6,7 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -107,8 +108,8 @@
 
 class MockWebDataServiceWrapperSyncable : public MockWebDataServiceWrapper {
  public:
-  static KeyedService* Build(content::BrowserContext* profile) {
-    return new MockWebDataServiceWrapperSyncable();
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* profile) {
+    return make_scoped_ptr(new MockWebDataServiceWrapperSyncable());
   }
 
   MockWebDataServiceWrapperSyncable()
diff --git a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
index 340adc1..9f6c3b0 100644
--- a/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/bookmark_data_type_controller_unittest.cc
@@ -58,23 +58,25 @@
   ~HistoryMock() override {}
 };
 
-KeyedService* BuildChromeBookmarkClient(content::BrowserContext* context) {
-  return new ChromeBookmarkClient(static_cast<Profile*>(context));
+scoped_ptr<KeyedService> BuildChromeBookmarkClient(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(
+      new ChromeBookmarkClient(static_cast<Profile*>(context)));
 }
 
-KeyedService* BuildBookmarkModelWithoutLoading(
+scoped_ptr<KeyedService> BuildBookmarkModelWithoutLoading(
     content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
   ChromeBookmarkClient* bookmark_client =
       ChromeBookmarkClientFactory::GetForProfile(profile);
-  BookmarkModel* bookmark_model = new BookmarkModel(bookmark_client);
-  bookmark_client->Init(bookmark_model);
-  return bookmark_model;
+  scoped_ptr<BookmarkModel> bookmark_model(new BookmarkModel(bookmark_client));
+  bookmark_client->Init(bookmark_model.get());
+  return bookmark_model.Pass();
 }
 
-KeyedService* BuildBookmarkModel(content::BrowserContext* context) {
-  BookmarkModel* bookmark_model = static_cast<BookmarkModel*>(
-      BuildBookmarkModelWithoutLoading(context));
+scoped_ptr<KeyedService> BuildBookmarkModel(content::BrowserContext* context) {
+  scoped_ptr<BookmarkModel> bookmark_model(static_cast<BookmarkModel*>(
+      BuildBookmarkModelWithoutLoading(context).release()));
   Profile* profile = static_cast<Profile*>(context);
   bookmark_model->Load(profile->GetPrefs(),
                        profile->GetPrefs()->GetString(prefs::kAcceptLanguages),
@@ -82,11 +84,11 @@
                        profile->GetIOTaskRunner(),
                        content::BrowserThread::GetMessageLoopProxyForThread(
                            content::BrowserThread::UI));
-  return bookmark_model;
+  return bookmark_model.Pass();
 }
 
-KeyedService* BuildHistoryService(content::BrowserContext* profile) {
-  return new HistoryMock;
+scoped_ptr<KeyedService> BuildHistoryService(content::BrowserContext* profile) {
+  return scoped_ptr<KeyedService>(new HistoryMock);
 }
 
 }  // namespace
diff --git a/chrome/browser/sync/glue/sync_backend_host.h b/chrome/browser/sync/glue/sync_backend_host.h
index c9c486b..adf8e24 100644
--- a/chrome/browser/sync/glue/sync_backend_host.h
+++ b/chrome/browser/sync/glue/sync_backend_host.h
@@ -20,7 +20,6 @@
 #include "sync/internal_api/public/sync_context_proxy.h"
 #include "sync/internal_api/public/sync_manager.h"
 #include "sync/internal_api/public/sync_manager_factory.h"
-#include "sync/internal_api/public/util/report_unrecoverable_error_function.h"
 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
 #include "sync/internal_api/public/util/weak_handle.h"
 
@@ -58,8 +57,7 @@
   // Optionally deletes the "Sync Data" folder during init in order to make
   // sure we're starting fresh.
   //
-  // |report_unrecoverable_error_function| can be NULL.  Note:
-  // |unrecoverable_error_handler| may be invoked from any thread.
+  // Note: |unrecoverable_error_handler| may be invoked from any thread.
   virtual void Initialize(
       sync_driver::SyncFrontend* frontend,
       scoped_ptr<base::Thread> sync_thread,
@@ -69,8 +67,7 @@
       bool delete_sync_data_folder,
       scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
       scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
-      syncer::ReportUnrecoverableErrorFunction
-          report_unrecoverable_error_function,
+      const base::Closure& report_unrecoverable_error_function,
       syncer::NetworkResources* network_resources) = 0;
 
   // Called on the frontend's thread to update SyncCredentials.
diff --git a/chrome/browser/sync/glue/sync_backend_host_core.cc b/chrome/browser/sync/glue/sync_backend_host_core.cc
index ffce750..533f26f 100644
--- a/chrome/browser/sync/glue/sync_backend_host_core.cc
+++ b/chrome/browser/sync/glue/sync_backend_host_core.cc
@@ -56,7 +56,7 @@
     base::MessageLoop* sync_loop,
     SyncBackendRegistrar* registrar,
     const syncer::ModelSafeRoutingInfo& routing_info,
-    const std::vector<scoped_refptr<syncer::ModelSafeWorker> >& workers,
+    const std::vector<scoped_refptr<syncer::ModelSafeWorker>>& workers,
     const scoped_refptr<syncer::ExtensionsActivity>& extensions_activity,
     const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
     const GURL& service_url,
@@ -69,8 +69,7 @@
     const std::string& restored_keystore_key_for_bootstrapping,
     scoped_ptr<syncer::InternalComponentsFactory> internal_components_factory,
     scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
-    syncer::ReportUnrecoverableErrorFunction
-        report_unrecoverable_error_function)
+    const base::Closure& report_unrecoverable_error_function)
     : sync_loop(sync_loop),
       registrar(registrar),
       routing_info(routing_info),
diff --git a/chrome/browser/sync/glue/sync_backend_host_core.h b/chrome/browser/sync/glue/sync_backend_host_core.h
index 6bcb76750..4e876636 100644
--- a/chrome/browser/sync/glue/sync_backend_host_core.h
+++ b/chrome/browser/sync/glue/sync_backend_host_core.h
@@ -26,7 +26,7 @@
       base::MessageLoop* sync_loop,
       SyncBackendRegistrar* registrar,
       const syncer::ModelSafeRoutingInfo& routing_info,
-      const std::vector<scoped_refptr<syncer::ModelSafeWorker> >& workers,
+      const std::vector<scoped_refptr<syncer::ModelSafeWorker>>& workers,
       const scoped_refptr<syncer::ExtensionsActivity>& extensions_activity,
       const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
       const GURL& service_url,
@@ -39,8 +39,7 @@
       const std::string& restored_keystore_key_for_bootstrapping,
       scoped_ptr<syncer::InternalComponentsFactory> internal_components_factory,
       scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
-      syncer::ReportUnrecoverableErrorFunction
-          report_unrecoverable_error_function);
+      const base::Closure& report_unrecoverable_error_function);
   ~DoInitializeOptions();
 
   base::MessageLoop* sync_loop;
@@ -61,8 +60,7 @@
   std::string restored_keystore_key_for_bootstrapping;
   scoped_ptr<syncer::InternalComponentsFactory> internal_components_factory;
   scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler;
-  syncer::ReportUnrecoverableErrorFunction
-      report_unrecoverable_error_function;
+  base::Closure report_unrecoverable_error_function;
 };
 
 // Helper struct to handle currying params to
diff --git a/chrome/browser/sync/glue/sync_backend_host_impl.cc b/chrome/browser/sync/glue/sync_backend_host_impl.cc
index 3df2d2e0..04b77bf 100644
--- a/chrome/browser/sync/glue/sync_backend_host_impl.cc
+++ b/chrome/browser/sync/glue/sync_backend_host_impl.cc
@@ -104,8 +104,7 @@
     bool delete_sync_data_folder,
     scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
     scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
-    syncer::ReportUnrecoverableErrorFunction
-        report_unrecoverable_error_function,
+    const base::Closure& report_unrecoverable_error_function,
     syncer::NetworkResources* network_resources) {
   registrar_.reset(new browser_sync::SyncBackendRegistrar(name_,
                                             profile_,
diff --git a/chrome/browser/sync/glue/sync_backend_host_impl.h b/chrome/browser/sync/glue/sync_backend_host_impl.h
index 265b8a0b..57d99ec 100644
--- a/chrome/browser/sync/glue/sync_backend_host_impl.h
+++ b/chrome/browser/sync/glue/sync_backend_host_impl.h
@@ -24,7 +24,6 @@
 #include "sync/internal_api/public/sessions/sync_session_snapshot.h"
 #include "sync/internal_api/public/sessions/type_debug_info_observer.h"
 #include "sync/internal_api/public/sync_manager.h"
-#include "sync/internal_api/public/util/report_unrecoverable_error_function.h"
 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
 #include "sync/internal_api/public/util/weak_handle.h"
 #include "sync/protocol/encryption.pb.h"
@@ -88,8 +87,7 @@
       bool delete_sync_data_folder,
       scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
       scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
-      syncer::ReportUnrecoverableErrorFunction
-          report_unrecoverable_error_function,
+      const base::Closure& report_unrecoverable_error_function,
       syncer::NetworkResources* network_resources) override;
   void UpdateCredentials(const syncer::SyncCredentials& credentials) override;
   void StartSyncingWithServer() override;
diff --git a/chrome/browser/sync/glue/sync_backend_host_impl_unittest.cc b/chrome/browser/sync/glue/sync_backend_host_impl_unittest.cc
index 7301b1d..c8ef8d9 100644
--- a/chrome/browser/sync/glue/sync_backend_host_impl_unittest.cc
+++ b/chrome/browser/sync/glue/sync_backend_host_impl_unittest.cc
@@ -214,7 +214,7 @@
         true,
         fake_manager_factory_.Pass(),
         make_scoped_ptr(new syncer::TestUnrecoverableErrorHandler),
-        NULL,
+        base::Closure(),
         network_resources_.get());
     base::RunLoop run_loop;
     BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE,
diff --git a/chrome/browser/sync/glue/sync_backend_host_mock.cc b/chrome/browser/sync/glue/sync_backend_host_mock.cc
index 1c8244e..423a1cb 100644
--- a/chrome/browser/sync/glue/sync_backend_host_mock.cc
+++ b/chrome/browser/sync/glue/sync_backend_host_mock.cc
@@ -22,8 +22,7 @@
     bool delete_sync_data_folder,
     scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
     scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
-    syncer::ReportUnrecoverableErrorFunction
-        report_unrecoverable_error_function,
+    const base::Closure& report_unrecoverable_error_function,
     syncer::NetworkResources* network_resources) {
   frontend->OnBackendInitialized(
       syncer::WeakHandle<syncer::JsBackend>(),
diff --git a/chrome/browser/sync/glue/sync_backend_host_mock.h b/chrome/browser/sync/glue/sync_backend_host_mock.h
index 200407b..9ee2d33 100644
--- a/chrome/browser/sync/glue/sync_backend_host_mock.h
+++ b/chrome/browser/sync/glue/sync_backend_host_mock.h
@@ -34,8 +34,7 @@
       bool delete_sync_data_folder,
       scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
       scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
-      syncer::ReportUnrecoverableErrorFunction
-          report_unrecoverable_error_function,
+      const base::Closure& report_unrecoverable_error_function,
       syncer::NetworkResources* network_resources) override;
 
   void UpdateCredentials(const syncer::SyncCredentials& credentials) override;
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc
index 3175f55..75db227 100644
--- a/chrome/browser/sync/profile_sync_components_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc
@@ -45,7 +45,6 @@
 #include "chrome/common/pref_names.h"
 #include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
-#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
@@ -520,8 +519,7 @@
         return autofill::AutofillProfileSyncableService::FromWebDataService(
             web_data_service_.get())->AsWeakPtr();
       } else if (type == syncer::AUTOFILL_WALLET_METADATA) {
-        return autofill::AutofillWalletMetadataSyncableService::
-            FromWebDataService(web_data_service_.get())->AsWeakPtr();
+        return base::WeakPtr<syncer::SyncableService>();
       }
       return autofill::AutofillWalletSyncableService::FromWebDataService(
           web_data_service_.get())->AsWeakPtr();
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index db3c015..90004da 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -290,12 +290,11 @@
 }
 
 bool ProfileSyncService::IsSyncEnabledAndLoggedIn() {
-  // Exit if sync is disabled.
-  if (IsManaged() || sync_prefs_.IsStartSuppressed())
+  // Exit if sync is not allowed or not requested.
+  if (!IsSyncAllowed() || !IsSyncRequested())
     return false;
 
-  // Sync is logged in if there is a non-empty effective account id.
-  return !signin_->GetAccountIdToUse().empty();
+  return IsSignedIn();
 }
 
 bool ProfileSyncService::IsOAuthRefreshTokenAvailable() {
@@ -314,15 +313,15 @@
 
   sync_prefs_.AddSyncPrefObserver(this);
 
-  // For now, the only thing we can do through policy is to turn sync off.
-  if (IsManaged()) {
+  // If sync isn't allowed, the only thing to do is to turn it off.
+  if (!IsSyncAllowed()) {
     DisableForUser();
     return;
   }
 
   RegisterAuthNotifications();
 
-  if (!HasSyncSetupCompleted() || signin_->GetAccountIdToUse().empty()) {
+  if (!HasSyncSetupCompleted() || !IsSignedIn()) {
     // Clean up in case of previous crash / setup abort / signout.
     DisableForUser();
   }
@@ -348,8 +347,7 @@
   if (browser_sync::BackupRollbackController::IsBackupEnabled()) {
     // Backup is needed if user's not signed in or signed in but previous
     // backup didn't finish, i.e. backend didn't switch from backup to sync.
-    need_backup_ = signin_->GetAccountIdToUse().empty() ||
-        sync_prefs_.GetFirstSyncTime().is_null();
+    need_backup_ = !IsSignedIn() || sync_prefs_.GetFirstSyncTime().is_null();
 
     // Try to resume rollback if it didn't finish in last session.
     running_rollback = backup_rollback_controller_->StartRollback();
@@ -358,7 +356,7 @@
   }
 
 #if defined(ENABLE_PRE_SYNC_BACKUP)
-  if (!running_rollback && signin_->GetAccountIdToUse().empty()) {
+  if (!running_rollback && !IsSignedIn()) {
     CleanUpBackup();
   }
 #else
@@ -543,16 +541,12 @@
               MakeWeakHandle(weak_factory_.GetWeakPtr())));
 
   backend_->Initialize(
-      this,
-      sync_thread_.Pass(),
-      GetJsEventHandler(),
-      sync_service_url_,
-      credentials,
-      delete_stale_data,
+      this, sync_thread_.Pass(), GetJsEventHandler(), sync_service_url_,
+      credentials, delete_stale_data,
       scoped_ptr<syncer::SyncManagerFactory>(
           new syncer::SyncManagerFactory(GetManagerType())).Pass(),
       backend_unrecoverable_error_handler.Pass(),
-      &browser_sync::ChromeReportUnrecoverableError,
+      base::Bind(browser_sync::ChromeReportUnrecoverableError),
       network_resources_.get());
 }
 
@@ -1258,7 +1252,7 @@
 }
 
 void ProfileSyncService::StopSyncingPermanently() {
-  sync_prefs_.SetStartSuppressed(true);
+  sync_prefs_.SetSyncRequested(false);
   DisableForUser();
 }
 
@@ -1626,12 +1620,21 @@
   NotifyObservers();
 }
 
+bool ProfileSyncService::IsSyncAllowed() const {
+  return IsSyncAllowedByFlag() && !IsManaged();
+}
+
 bool ProfileSyncService::IsSyncActive() const {
   return backend_initialized_ && backend_mode_ == SYNC &&
          directory_data_type_manager_ &&
          directory_data_type_manager_->state() != DataTypeManager::STOPPED;
 }
 
+bool ProfileSyncService::IsSignedIn() const {
+  // Sync is logged in if there is a non-empty effective account id.
+  return !signin_->GetAccountIdToUse().empty();
+}
+
 bool ProfileSyncService::backend_initialized() const {
   return backend_initialized_;
 }
@@ -2217,7 +2220,7 @@
 void ProfileSyncService::GoogleSigninSucceeded(const std::string& account_id,
                                                const std::string& username,
                                                const std::string& password) {
-  if (!sync_prefs_.IsStartSuppressed() && !password.empty()) {
+  if (IsSyncRequested() && !password.empty()) {
     cached_passphrase_ = password;
     // Try to consume the passphrase we just cached. If the sync backend
     // is not running yet, the passphrase will remain cached until the
@@ -2429,16 +2432,16 @@
   return sync_prefs_.IsManaged() || sync_disabled_by_admin_;
 }
 
-void ProfileSyncService::StopAndSuppress() {
-  sync_prefs_.SetStartSuppressed(true);
+void ProfileSyncService::RequestStop() {
+  sync_prefs_.SetSyncRequested(false);
   if (HasSyncingBackend()) {
     backend_->UnregisterInvalidationIds();
   }
   ShutdownImpl(syncer::STOP_SYNC);
 }
 
-bool ProfileSyncService::IsStartSuppressed() const {
-  return sync_prefs_.IsStartSuppressed();
+bool ProfileSyncService::IsSyncRequested() const {
+  return sync_prefs_.IsSyncRequested();
 }
 
 SigninManagerBase* ProfileSyncService::signin() const {
@@ -2447,9 +2450,9 @@
   return signin_->GetOriginal();
 }
 
-void ProfileSyncService::UnsuppressAndStart() {
+void ProfileSyncService::RequestStart() {
   DCHECK(profile_);
-  sync_prefs_.SetStartSuppressed(false);
+  sync_prefs_.SetSyncRequested(true);
   DCHECK(!signin_.get() || signin_->GetOriginal()->IsAuthenticated());
   startup_controller_->TryStart();
 }
@@ -2562,7 +2565,7 @@
 }
 
 void ProfileSyncService::UpdateFirstSyncTimePref() {
-  if (signin_->GetAccountIdToUse().empty()) {
+  if (!IsSignedIn()) {
     // Clear if user's not signed in and rollback is done.
     if (backend_mode_ != ROLLBACK)
       sync_prefs_.ClearFirstSyncTime();
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index a6f24be..dbac6a5 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -275,11 +275,12 @@
 
   // sync_driver::SyncService implementation
   bool HasSyncSetupCompleted() const override;
+  bool IsSyncAllowed() const override;
   bool IsSyncActive() const override;
   bool IsSyncEnabledAndLoggedIn() override;
   void DisableForUser() override;
-  void StopAndSuppress() override;
-  void UnsuppressAndStart() override;
+  void RequestStop() override;
+  void RequestStart() override;
   syncer::ModelTypeSet GetActiveDataTypes() const override;
   syncer::ModelTypeSet GetPreferredDataTypes() const override;
   void OnUserChoseDatatypes(bool sync_everything,
@@ -474,9 +475,12 @@
   // Returns a human readable string describing backend initialization state.
   std::string GetBackendInitializationStateString() const;
 
-  // Returns true if startup is suppressed (i.e. user has stopped syncing via
-  // the google dashboard).
-  virtual bool IsStartSuppressed() const;
+  // Returns true if sync is requested to be running by the user.
+  // Note that this does not mean that sync WILL be running; e.g. if
+  // IsSyncAllowed() is false then sync won't start, and if the user
+  // doesn't confirm their settings (HasSyncSetupCompleted), sync will
+  // never become active. Use IsSyncActive to see if sync is running.
+  virtual bool IsSyncRequested() const;
 
   ProfileSyncComponentsFactory* factory() { return factory_.get(); }
 
@@ -491,7 +495,7 @@
   static void SyncEvent(SyncEventCodes code);
 
   // Returns whether sync is allowed to run based on command-line switches.
-  // Profile::IsSyncAccessible() is probably a better signal than this function.
+  // Profile::IsSyncAllowed() is probably a better signal than this function.
   // This function can be called from any thread, and the implementation doesn't
   // assume it's running on the UI thread.
   static bool IsSyncAllowedByFlag();
@@ -865,6 +869,9 @@
   // Various setup following backend initialization, mostly for syncing backend.
   void PostBackendInitialization();
 
+  // Whether sync has been authenticated with an account ID.
+  bool IsSignedIn() const;
+
   // True if a syncing backend exists.
   bool HasSyncingBackend() const;
 
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc
index 363fd41..ba06301 100644
--- a/chrome/browser/sync/profile_sync_service_android.cc
+++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -153,8 +153,8 @@
 void ProfileSyncServiceAndroid::EnableSync(JNIEnv* env, jobject) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Don't need to do anything if we're already enabled.
-  if (sync_prefs_->IsStartSuppressed())
-    sync_service_->UnsuppressAndStart();
+  if (!sync_service_->IsSyncRequested())
+    sync_service_->RequestStart();
   else
     DVLOG(2) << "Ignoring call to EnableSync() because sync is already enabled";
 }
@@ -162,8 +162,8 @@
 void ProfileSyncServiceAndroid::DisableSync(JNIEnv* env, jobject) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Don't need to do anything if we're already disabled.
-  if (!sync_prefs_->IsStartSuppressed()) {
-    sync_service_->StopAndSuppress();
+  if (sync_service_->IsSyncRequested()) {
+    sync_service_->RequestStop();
   } else {
     DVLOG(2)
         << "Ignoring call to DisableSync() because sync is already disabled";
@@ -182,9 +182,9 @@
     return;
   }
 
-  // Enable sync (if we don't have credentials yet, this will enable sync but
-  // will not start it up - sync will start once credentials arrive).
-  sync_service_->UnsuppressAndStart();
+  // Request that sync starts. If we don't have credentials yet, this will
+  // let sync start once credentials arrive.
+  sync_service_->RequestStart();
 }
 
 void ProfileSyncServiceAndroid::SignOutSync(JNIEnv* env, jobject) {
@@ -192,8 +192,8 @@
   DCHECK(profile_);
   sync_service_->DisableForUser();
 
-  // Need to clear suppress start flag manually
-  sync_prefs_->SetStartSuppressed(false);
+  // Need to reset sync requested flag manually
+  sync_prefs_->SetSyncRequested(true);
 }
 
 void ProfileSyncServiceAndroid::FlushDirectory(JNIEnv* env, jobject) {
@@ -442,10 +442,10 @@
   return sync_service_->HasSyncSetupCompleted();
 }
 
-jboolean ProfileSyncServiceAndroid::IsStartSuppressed(
+jboolean ProfileSyncServiceAndroid::IsSyncRequested(
     JNIEnv* env, jobject obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  return sync_prefs_->IsStartSuppressed();
+  return sync_service_->IsSyncRequested();
 }
 
 void ProfileSyncServiceAndroid::EnableEncryptEverything(
diff --git a/chrome/browser/sync/profile_sync_service_android.h b/chrome/browser/sync/profile_sync_service_android.h
index db7e679..d2984ac 100644
--- a/chrome/browser/sync/profile_sync_service_android.h
+++ b/chrome/browser/sync/profile_sync_service_android.h
@@ -174,8 +174,8 @@
   // Returns true if sync setup has been completed.
   jboolean HasSyncSetupCompleted(JNIEnv* env, jobject obj);
 
-  // Returns true if sync startup is currently suppressed.
-  jboolean IsStartSuppressed(JNIEnv* env, jobject obj);
+  // See ProfileSyncService::IsSyncRequested().
+  jboolean IsSyncRequested(JNIEnv* env, jobject obj);
 
   // Returns true if sync is configured to "sync everything".
   jboolean HasKeepEverythingSynced(JNIEnv* env, jobject obj);
diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
index 802bde3f..4ae6989f 100644
--- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
@@ -337,10 +337,10 @@
   DISALLOW_COPY_AND_ASSIGN(WebDataServiceFake);
 };
 
-KeyedService* BuildMockWebDataServiceWrapper(content::BrowserContext* profile) {
-  return new MockWebDataServiceWrapper(
-      new WebDataServiceFake(),
-      new TokenWebDataServiceFake());
+scoped_ptr<KeyedService> BuildMockWebDataServiceWrapper(
+    content::BrowserContext* profile) {
+  return make_scoped_ptr(new MockWebDataServiceWrapper(
+      new WebDataServiceFake(), new TokenWebDataServiceFake()));
 }
 
 ACTION_P(MakeAutocompleteSyncComponents, wds) {
@@ -425,8 +425,8 @@
   MOCK_METHOD0(LoadCreditCards, void());
   MOCK_METHOD0(Refresh, void());
 
-  static KeyedService* Build(content::BrowserContext* profile) {
-    return new MockPersonalDataManager();
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* profile) {
+    return make_scoped_ptr(new MockPersonalDataManager());
   }
 };
 
@@ -596,9 +596,7 @@
 
     sync_pb::EntitySpecifics specifics;
     AutocompleteSyncableService::WriteAutofillEntry(entry, &specifics);
-    sync_pb::AutofillSpecifics* autofill_specifics =
-        specifics.mutable_autofill();
-    node.SetAutofillSpecifics(*autofill_specifics);
+    node.SetEntitySpecifics(specifics);
     return true;
   }
 
@@ -618,9 +616,7 @@
 
     sync_pb::EntitySpecifics specifics;
     AutofillProfileSyncableService::WriteAutofillProfile(profile, &specifics);
-    sync_pb::AutofillProfileSpecifics* profile_specifics =
-        specifics.mutable_autofill_profile();
-    node.SetAutofillProfileSpecifics(*profile_specifics);
+    node.SetEntitySpecifics(specifics);
     return true;
   }
 
@@ -639,7 +635,7 @@
         return false;
 
       const sync_pb::AutofillSpecifics& autofill(
-          child_node.GetAutofillSpecifics());
+          child_node.GetEntitySpecifics().autofill());
       if (autofill.has_value()) {
         AutofillKey key(base::UTF8ToUTF16(autofill.name()),
                         base::UTF8ToUTF16(autofill.value()));
@@ -678,7 +674,7 @@
         return false;
 
       const sync_pb::AutofillProfileSpecifics& autofill(
-          child_node.GetAutofillProfileSpecifics());
+          child_node.GetEntitySpecifics().autofill_profile());
         AutofillProfile p;
         p.set_guid(autofill.guid());
         AutofillProfileSyncableService::OverwriteProfileWithServerData(
diff --git a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc b/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc
index d4db0f7e..b39cd76 100644
--- a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc
@@ -45,6 +45,8 @@
 #include "sync/internal_api/public/write_transaction.h"
 #include "sync/internal_api/syncapi_internal.h"
 #include "sync/syncable/mutable_entry.h"
+#include "sync/syncable/syncable_id.h"
+#include "sync/syncable/syncable_util.h"
 #include "sync/syncable/syncable_write_transaction.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -68,6 +70,22 @@
 
 namespace {
 
+void MakeServerUpdate(syncer::WriteTransaction* trans,
+                      syncer::WriteNode* node) {
+  syncer::syncable::ChangeEntryIDAndUpdateChildren(
+      trans->GetWrappedWriteTrans(), node->GetMutableEntryForTest(),
+      syncer::syncable::Id::CreateFromServerId(
+          base::Int64ToString(node->GetId())));
+  node->GetMutableEntryForTest()->PutBaseVersion(10);
+  node->GetMutableEntryForTest()->PutIsUnappliedUpdate(true);
+}
+
+void MakeServerUpdate(syncer::WriteTransaction* trans, int64 id) {
+  syncer::WriteNode node(trans);
+  EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(id));
+  MakeServerUpdate(trans, &node);
+}
+
 // FakeServerChange constructs a list of syncer::ChangeRecords while modifying
 // the sync model, and can pass the ChangeRecord list to a
 // syncer::SyncObserver (i.e., the ProfileSyncService) to test the client
@@ -855,13 +873,15 @@
   }
 
   // Associate the bookmark sync node with the native model one and make
-  // it deleted.
+  // it look like it was deleted by a server update.
   {
     syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
     syncer::WriteNode node(&trans);
     EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(bookmark_id));
 
     node.GetMutableEntryForTest()->PutLocalExternalId(bookmark->id());
+
+    MakeServerUpdate(&trans, &node);
     node.GetMutableEntryForTest()->PutServerIsDel(true);
     node.GetMutableEntryForTest()->PutIsDel(true);
   }
@@ -977,6 +997,7 @@
     EXPECT_EQ(BaseNode::INIT_OK,
               node.InitByIdLookup(sync_bookmark_id_to_delete));
 
+    MakeServerUpdate(&trans, &node);
     node.GetMutableEntryForTest()->PutServerIsDel(true);
     node.GetMutableEntryForTest()->PutIsDel(true);
   }
@@ -1490,6 +1511,10 @@
   {
     // Remove all folders/bookmarks except u3 added above.
     syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
+    MakeServerUpdate(&trans, f1);
+    MakeServerUpdate(&trans, u1);
+    MakeServerUpdate(&trans, f2);
+    MakeServerUpdate(&trans, u2);
     FakeServerChange dels(&trans);
     dels.Delete(u2);
     dels.Delete(f2);
diff --git a/chrome/browser/sync/profile_sync_service_mock.cc b/chrome/browser/sync/profile_sync_service_mock.cc
index 343c7934..bfa9b01 100644
--- a/chrome/browser/sync/profile_sync_service_mock.cc
+++ b/chrome/browser/sync/profile_sync_service_mock.cc
@@ -17,15 +17,10 @@
 #include "components/signin/core/browser/signin_manager.h"
 
 ProfileSyncServiceMock::ProfileSyncServiceMock(Profile* profile)
-    : ProfileSyncService(
+    : ProfileSyncServiceMock(
           scoped_ptr<ProfileSyncComponentsFactory>(
               new ProfileSyncComponentsFactoryMock()),
-          profile,
-          make_scoped_ptr(new SupervisedUserSigninManagerWrapper(
-              profile,
-              SigninManagerFactory::GetForProfile(profile))),
-          ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-          browser_sync::MANUAL_START) {
+          profile) {
 }
 
 ProfileSyncServiceMock::ProfileSyncServiceMock(
@@ -38,6 +33,7 @@
               SigninManagerFactory::GetForProfile(profile))),
           ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
           browser_sync::MANUAL_START) {
+    ON_CALL(*this, IsSyncRequested()).WillByDefault(testing::Return(true));
 }
 
 ProfileSyncServiceMock::~ProfileSyncServiceMock() {
@@ -52,7 +48,8 @@
 }
 
 // static
-KeyedService* ProfileSyncServiceMock::BuildMockProfileSyncService(
+scoped_ptr<KeyedService> ProfileSyncServiceMock::BuildMockProfileSyncService(
     content::BrowserContext* profile) {
-  return new ProfileSyncServiceMock(static_cast<Profile*>(profile));
+  return make_scoped_ptr(
+      new ProfileSyncServiceMock(static_cast<Profile*>(profile)));
 }
diff --git a/chrome/browser/sync/profile_sync_service_mock.h b/chrome/browser/sync/profile_sync_service_mock.h
index 0cc34d7..96c39ee 100644
--- a/chrome/browser/sync/profile_sync_service_mock.h
+++ b/chrome/browser/sync/profile_sync_service_mock.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/sync/profile_sync_service.h"
@@ -35,7 +36,7 @@
 
   // Helper routine to be used in conjunction with
   // BrowserContextKeyedServiceFactory::SetTestingFactory().
-  static KeyedService* BuildMockProfileSyncService(
+  static scoped_ptr<KeyedService> BuildMockProfileSyncService(
       content::BrowserContext* profile);
 
   MOCK_METHOD0(DisableForUser, void());
@@ -63,7 +64,7 @@
   MOCK_METHOD1(DisableDatatype, void(const syncer::SyncError&));
   MOCK_CONST_METHOD0(GetUserShare, syncer::UserShare*());
   MOCK_METHOD1(DeactivateDataType, void(syncer::ModelType));
-  MOCK_METHOD0(UnsuppressAndStart, void());
+  MOCK_METHOD0(RequestStart, void());
 
   MOCK_METHOD1(AddObserver, void(sync_driver::SyncServiceObserver*));
   MOCK_METHOD1(RemoveObserver, void(sync_driver::SyncServiceObserver*));
@@ -90,7 +91,7 @@
   MOCK_CONST_METHOD0(HasUnrecoverableError, bool());
   MOCK_CONST_METHOD0(IsSyncActive, bool());
   MOCK_CONST_METHOD0(backend_initialized, bool());
-  MOCK_CONST_METHOD0(IsStartSuppressed, bool());
+  MOCK_CONST_METHOD0(IsSyncRequested, bool());
   MOCK_CONST_METHOD0(waiting_for_auth, bool());
   MOCK_METHOD1(OnActionableError, void(const syncer::SyncProtocolError&));
   MOCK_METHOD1(SetSetupInProgress, void(bool));
diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
index 7926539..12c2f7e 100644
--- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
@@ -121,16 +121,16 @@
 
   void TearDown() override { sync_->RemoveObserver(&observer_); }
 
-  static KeyedService* BuildService(content::BrowserContext* browser_context) {
+  static scoped_ptr<KeyedService> BuildService(
+      content::BrowserContext* browser_context) {
     Profile* profile = static_cast<Profile*>(browser_context);
-    return new TestProfileSyncServiceNoBackup(
+    return make_scoped_ptr(new TestProfileSyncServiceNoBackup(
         scoped_ptr<ProfileSyncComponentsFactory>(
             new ProfileSyncComponentsFactoryMock()),
-        profile,
-        make_scoped_ptr(new SupervisedUserSigninManagerWrapper(
-            profile, SigninManagerFactory::GetForProfile(profile))),
+        profile, make_scoped_ptr(new SupervisedUserSigninManagerWrapper(
+                     profile, SigninManagerFactory::GetForProfile(profile))),
         ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-        browser_sync::MANUAL_START);
+        browser_sync::MANUAL_START));
   }
 
   void CreateSyncService() {
@@ -217,7 +217,8 @@
     sync_->AddObserver(&observer_);
   }
 
-  static KeyedService* BuildCrosService(content::BrowserContext* context) {
+  static scoped_ptr<KeyedService> BuildCrosService(
+      content::BrowserContext* context) {
     Profile* profile = static_cast<Profile*>(context);
     FakeSigninManagerForTesting* signin =
         static_cast<FakeSigninManagerForTesting*>(
@@ -226,14 +227,12 @@
     ProfileOAuth2TokenService* oauth2_token_service =
         ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
     EXPECT_TRUE(signin->IsAuthenticated());
-    return new TestProfileSyncServiceNoBackup(
+    return make_scoped_ptr(new TestProfileSyncServiceNoBackup(
         scoped_ptr<ProfileSyncComponentsFactory>(
             new ProfileSyncComponentsFactoryMock()),
-        profile,
-        make_scoped_ptr(new SupervisedUserSigninManagerWrapper(profile,
-                                                               signin)),
-        oauth2_token_service,
-        browser_sync::AUTO_START);
+        profile, make_scoped_ptr(
+                     new SupervisedUserSigninManagerWrapper(profile, signin)),
+        oauth2_token_service, browser_sync::AUTO_START));
   }
 };
 
diff --git a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
index 912e6f7..0334d137 100644
--- a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/callback.h"
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/thread_task_runner_handle.h"
@@ -157,15 +158,15 @@
   scoped_refptr<history::HistoryBackend> backend_;
 };
 
-KeyedService* BuildFakeProfileInvalidationProvider(
+scoped_ptr<KeyedService> BuildFakeProfileInvalidationProvider(
     content::BrowserContext* context) {
-  return new invalidation::ProfileInvalidationProvider(
+  return make_scoped_ptr(new invalidation::ProfileInvalidationProvider(
       scoped_ptr<invalidation::InvalidationService>(
-          new invalidation::FakeInvalidationService));
+          new invalidation::FakeInvalidationService)));
 }
 
-KeyedService* BuildHistoryService(content::BrowserContext* profile) {
-  return new HistoryServiceMock;
+scoped_ptr<KeyedService> BuildHistoryService(content::BrowserContext* profile) {
+  return scoped_ptr<KeyedService>(new HistoryServiceMock);
 }
 
 class TestTypedUrlModelAssociator : public TypedUrlModelAssociator {
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc
index d8cf8c2..d738304aa 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -112,8 +112,7 @@
       bool delete_sync_data_folder,
       scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
       scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
-      syncer::ReportUnrecoverableErrorFunction
-          report_unrecoverable_error_function,
+      const base::Closure& report_unrecoverable_error_function,
       syncer::NetworkResources* network_resources) override {}
 };
 
@@ -132,8 +131,7 @@
       bool delete_sync_data_folder,
       scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
       scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
-      syncer::ReportUnrecoverableErrorFunction
-          report_unrecoverable_error_function,
+      const base::Closure& report_unrecoverable_error_function,
       syncer::NetworkResources* network_resources) override {
     delete_dir_param_->push_back(delete_sync_data_folder);
     SyncBackendHostMock::Initialize(frontend, sync_thread.Pass(),
@@ -162,11 +160,11 @@
       delete_dir_param);
 }
 
-KeyedService* BuildFakeProfileInvalidationProvider(
+scoped_ptr<KeyedService> BuildFakeProfileInvalidationProvider(
     content::BrowserContext* context) {
-  return new invalidation::ProfileInvalidationProvider(
+  return make_scoped_ptr(new invalidation::ProfileInvalidationProvider(
       scoped_ptr<invalidation::InvalidationService>(
-          new invalidation::FakeInvalidationService));
+          new invalidation::FakeInvalidationService)));
 }
 
 // A test harness that uses a real ProfileSyncService and in most cases a
@@ -412,12 +410,12 @@
   ShutdownAndDeleteService();
 }
 
-// Test StopAndSuppress() before we've initialized the backend.
-TEST_F(ProfileSyncServiceTest, EarlyStopAndSuppress) {
+// Test RequestStop() before we've initialized the backend.
+TEST_F(ProfileSyncServiceTest, EarlyRequestStop) {
   CreateService(browser_sync::AUTO_START);
   IssueTestTokens();
 
-  service()->StopAndSuppress();
+  service()->RequestStop();
   EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
       sync_driver::prefs::kSyncSuppressStart));
 
@@ -428,13 +426,13 @@
   // Remove suppression.  This should be enough to allow init to happen.
   ExpectDataTypeManagerCreation(1);
   ExpectSyncBackendHostCreation(1);
-  service()->UnsuppressAndStart();
+  service()->RequestStart();
   EXPECT_TRUE(service()->IsSyncActive());
   EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
       sync_driver::prefs::kSyncSuppressStart));
 }
 
-// Test StopAndSuppress() after we've initialized the backend.
+// Test RequestStop() after we've initialized the backend.
 TEST_F(ProfileSyncServiceTest, DisableAndEnableSyncTemporarily) {
   CreateService(browser_sync::AUTO_START);
   IssueTestTokens();
@@ -448,7 +446,7 @@
 
   testing::Mock::VerifyAndClearExpectations(components_factory());
 
-  service()->StopAndSuppress();
+  service()->RequestStop();
   EXPECT_FALSE(service()->IsSyncActive());
   EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
       sync_driver::prefs::kSyncSuppressStart));
@@ -456,7 +454,7 @@
   ExpectDataTypeManagerCreation(1);
   ExpectSyncBackendHostCreation(1);
 
-  service()->UnsuppressAndStart();
+  service()->RequestStart();
   EXPECT_TRUE(service()->IsSyncActive());
   EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
       sync_driver::prefs::kSyncSuppressStart));
diff --git a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
index bc0ba59..c11c8d9 100644
--- a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
+++ b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
@@ -1010,8 +1010,8 @@
   for (int i = 1; i < 3; i++) {
     EXPECT_TRUE(output[i].IsValid());
     const SyncData data(output[i].sync_data());
-    EXPECT_TRUE(StartsWithASCII(syncer::SyncDataLocal(data).GetTag(),
-                                manager()->current_machine_tag(), true));
+    EXPECT_TRUE(base::StartsWithASCII(syncer::SyncDataLocal(data).GetTag(),
+                                      manager()->current_machine_tag(), true));
     const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
     EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
   }
@@ -1444,17 +1444,15 @@
   EXPECT_EQ(3U, out.size());  // Tab add, update, and header update.
 
   EXPECT_TRUE(
-      StartsWithASCII(syncer::SyncDataLocal(out[0].sync_data()).GetTag(),
-                      manager()->current_machine_tag(),
-                      true));
+      base::StartsWithASCII(syncer::SyncDataLocal(out[0].sync_data()).GetTag(),
+                            manager()->current_machine_tag(), true));
   EXPECT_EQ(manager()->current_machine_tag(),
             out[0].sync_data().GetSpecifics().session().session_tag());
   EXPECT_EQ(SyncChange::ACTION_ADD, out[0].change_type());
 
   EXPECT_TRUE(
-      StartsWithASCII(syncer::SyncDataLocal(out[1].sync_data()).GetTag(),
-                      manager()->current_machine_tag(),
-                      true));
+      base::StartsWithASCII(syncer::SyncDataLocal(out[1].sync_data()).GetTag(),
+                            manager()->current_machine_tag(), true));
   EXPECT_EQ(manager()->current_machine_tag(),
             out[1].sync_data().GetSpecifics().session().session_tag());
   EXPECT_TRUE(out[1].sync_data().GetSpecifics().session().has_tab());
@@ -1508,8 +1506,8 @@
     SCOPED_TRACE(i);
     EXPECT_TRUE(out[i].IsValid());
     const SyncData data(out[i].sync_data());
-    EXPECT_TRUE(StartsWithASCII(syncer::SyncDataLocal(data).GetTag(),
-                                manager()->current_machine_tag(), true));
+    EXPECT_TRUE(base::StartsWithASCII(syncer::SyncDataLocal(data).GetTag(),
+                                      manager()->current_machine_tag(), true));
     const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
     EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
     if (i % 6 == 0) {
@@ -1616,8 +1614,8 @@
   for (int i = 1; i < 5; i++) {
     EXPECT_TRUE(out[i].IsValid());
     const SyncData data(out[i].sync_data());
-    EXPECT_TRUE(StartsWithASCII(syncer::SyncDataLocal(data).GetTag(),
-                                manager()->current_machine_tag(), true));
+    EXPECT_TRUE(base::StartsWithASCII(syncer::SyncDataLocal(data).GetTag(),
+                                      manager()->current_machine_tag(), true));
     const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
     EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
     if (i % 2 == 1) {
diff --git a/chrome/browser/sync/startup_controller.cc b/chrome/browser/sync/startup_controller.cc
index d7f6ab0c..8f30c470c 100644
--- a/chrome/browser/sync/startup_controller.cc
+++ b/chrome/browser/sync/startup_controller.cc
@@ -118,7 +118,7 @@
   if (sync_prefs_->IsManaged())
     return false;
 
-  if (sync_prefs_->IsStartSuppressed())
+  if (!sync_prefs_->IsSyncRequested())
     return false;
 
   if (signin_->GetEffectiveUsername().empty())
diff --git a/chrome/browser/sync/startup_controller.h b/chrome/browser/sync/startup_controller.h
index cb611d1..54f04de 100644
--- a/chrome/browser/sync/startup_controller.h
+++ b/chrome/browser/sync/startup_controller.h
@@ -42,7 +42,7 @@
                     base::Closure start_backend);
   ~StartupController();
 
-  // Starts up sync if it is not suppressed and preconditions are met.
+  // Starts up sync if it is requested by the user and preconditions are met.
   // Returns true if these preconditions are met, although does not imply
   // the backend was started.
   bool TryStart();
diff --git a/chrome/browser/sync/startup_controller_unittest.cc b/chrome/browser/sync/startup_controller_unittest.cc
index 9c1d537..663b003 100644
--- a/chrome/browser/sync/startup_controller_unittest.cc
+++ b/chrome/browser/sync/startup_controller_unittest.cc
@@ -55,7 +55,7 @@
     profile_.reset(new TestingProfile());
     sync_prefs_.reset(new sync_driver::SyncPrefs(profile_->GetPrefs()));
     token_service_.reset(static_cast<FakeProfileOAuth2TokenService*>(
-        BuildFakeProfileOAuth2TokenService(profile_.get())));
+        BuildFakeProfileOAuth2TokenService(profile_.get()).release()));
     signin_.reset(new FakeSupervisedUserSigninManagerWrapper());
 
     ProfileSyncServiceStartBehavior behavior =
@@ -124,10 +124,11 @@
                                state == kStateStringStarted);
 }
 
-// Test that sync doesn't when suppressed even if all other conditons are met.
-TEST_F(StartupControllerTest, Suppressed) {
+// Test that sync doesn't start when not requested even if all other
+// conditons are met.
+TEST_F(StartupControllerTest, NotRequested) {
   sync_prefs()->SetSyncSetupCompleted();
-  sync_prefs()->SetStartSuppressed(true);
+  sync_prefs()->SetSyncRequested(false);
   signin()->set_account(kTestUser);
   token_service()->IssueRefreshTokenForUser(kTestUser, kTestToken);
   controller()->TryStart();
diff --git a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
index 6f213a5..51b20e38 100644
--- a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
+++ b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
@@ -82,9 +82,9 @@
   int focus_ui_call_count_;
 };
 
-KeyedService* BuildMockLoginUIService(
+scoped_ptr<KeyedService> BuildMockLoginUIService(
     content::BrowserContext* profile) {
-  return new FakeLoginUIService();
+  return make_scoped_ptr(new FakeLoginUIService());
 }
 
 class SyncErrorNotifierTest : public AshTestBase  {
diff --git a/chrome/browser/sync/sync_global_error_unittest.cc b/chrome/browser/sync/sync_global_error_unittest.cc
index a7193b3..585d4834 100644
--- a/chrome/browser/sync/sync_global_error_unittest.cc
+++ b/chrome/browser/sync/sync_global_error_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/sync/sync_global_error.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/sync/profile_sync_service_mock.h"
 #include "chrome/browser/sync/sync_error_controller.h"
@@ -47,8 +48,9 @@
   int focus_ui_call_count_;
 };
 
-KeyedService* BuildMockLoginUIService(content::BrowserContext* profile) {
-  return new FakeLoginUIService();
+scoped_ptr<KeyedService> BuildMockLoginUIService(
+    content::BrowserContext* profile) {
+  return make_scoped_ptr(new FakeLoginUIService());
 }
 
 // Same as BrowserWithTestWindowTest, but uses MockBrowser to test calls to
diff --git a/chrome/browser/sync/sync_startup_tracker.cc b/chrome/browser/sync/sync_startup_tracker.cc
index 9b06684..399a1c07fe 100644
--- a/chrome/browser/sync/sync_startup_tracker.cc
+++ b/chrome/browser/sync/sync_startup_tracker.cc
@@ -49,16 +49,15 @@
 // static
 SyncStartupTracker::SyncServiceState SyncStartupTracker::GetSyncServiceState(
     Profile* profile) {
-  // If sync is disabled, treat this as a startup error.
-  if (!profile->IsSyncAccessible())
+  // If sync is not allowed, treat this as a startup error.
+  if (!profile->IsSyncAllowed())
     return SYNC_STARTUP_ERROR;
 
   ProfileSyncService* service =
       ProfileSyncServiceFactory::GetForProfile(profile);
 
-  // If no service exists or sync is disabled, treat as a startup error.
-  if (!profile->IsSyncAccessible() || !service ||
-      !service->IsSyncEnabledAndLoggedIn()) {
+  // If no service exists or it can't be started, treat as a startup error.
+  if (!service || !service->IsSyncEnabledAndLoggedIn()) {
     return SYNC_STARTUP_ERROR;
   }
 
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index ec465ab2..f686a30 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -74,7 +74,7 @@
       // User is signed in, but sync is disabled.
       return l10n_util::GetStringFUTF16(IDS_SIGNED_IN_WITH_SYNC_DISABLED,
                                         user_name);
-    } else if (service->IsStartSuppressed()) {
+    } else if (!service->IsSyncRequested()) {
       // User is signed in, but sync has been stopped.
       return l10n_util::GetStringFUTF16(IDS_SIGNED_IN_WITH_SYNC_SUPPRESSED,
                                         user_name);
@@ -154,7 +154,7 @@
     return PRE_SYNCED;
 
   if (!service || service->IsManaged() || service->HasSyncSetupCompleted() ||
-      service->IsStartSuppressed()) {
+      !service->IsSyncRequested()) {
     // The order or priority is going to be: 1. Unrecoverable errors.
     // 2. Auth errors. 3. Protocol errors. 4. Passphrase errors.
 
@@ -220,7 +220,7 @@
 
       // Check to see if sync has been disabled via the dasboard and needs to be
       // set up once again.
-      if (service->IsStartSuppressed() &&
+      if (!service->IsSyncRequested() &&
           status.sync_protocol_error.error_type == syncer::NOT_MY_BIRTHDAY) {
         if (status_label) {
           status_label->assign(GetSyncedStateStatusLabel(service,
diff --git a/chrome/browser/sync/test/integration/extensions_helper.cc b/chrome/browser/sync/test/integration/extensions_helper.cc
index 9c233748..4448958 100644
--- a/chrome/browser/sync/test/integration/extensions_helper.cc
+++ b/chrome/browser/sync/test/integration/extensions_helper.cc
@@ -124,7 +124,7 @@
 }
 
 bool ExtensionNameToIndex(const std::string& name, int* index) {
-  if (!StartsWithASCII(name, extension_name_prefix, true) ||
+  if (!base::StartsWithASCII(name, extension_name_prefix, true) ||
       !base::StringToInt(name.substr(strlen(extension_name_prefix)), index)) {
     LOG(WARNING) << "Unable to convert extension name \"" << name
                  << "\" to index";
diff --git a/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc b/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
index 85cabd95..b3cb1b90 100644
--- a/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
@@ -63,7 +63,7 @@
   ProfileSyncService* sync_service = GetSyncService(0);
   base::FilePath directory_path = sync_service->GetDirectoryPathForTest();
   ASSERT_TRUE(base::DirectoryExists(directory_path));
-  sync_service->StopAndSuppress();
+  sync_service->RequestStop();
   sync_service->DisableForUser();
 
   // Wait for StartupController::StartUp()'s tasks to finish.
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 68d93bfc..77729564 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
@@ -142,34 +143,33 @@
   done->Signal();
 }
 
-KeyedService* BuildFakeServerProfileInvalidationProvider(
+scoped_ptr<KeyedService> BuildFakeServerProfileInvalidationProvider(
     content::BrowserContext* context) {
-  return new invalidation::ProfileInvalidationProvider(
+  return make_scoped_ptr(new invalidation::ProfileInvalidationProvider(
       scoped_ptr<invalidation::InvalidationService>(
-          new fake_server::FakeServerInvalidationService));
+          new fake_server::FakeServerInvalidationService)));
 }
 
-KeyedService* BuildP2PProfileInvalidationProvider(
+scoped_ptr<KeyedService> BuildP2PProfileInvalidationProvider(
     content::BrowserContext* context,
     syncer::P2PNotificationTarget notification_target) {
   Profile* profile = static_cast<Profile*>(context);
-  return new invalidation::ProfileInvalidationProvider(
+  return make_scoped_ptr(new invalidation::ProfileInvalidationProvider(
       scoped_ptr<invalidation::InvalidationService>(
           new invalidation::P2PInvalidationService(
               scoped_ptr<IdentityProvider>(new ProfileIdentityProvider(
                   SigninManagerFactory::GetForProfile(profile),
                   ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
                   LoginUIServiceFactory::GetForProfile(profile))),
-              profile->GetRequestContext(),
-              notification_target)));
+              profile->GetRequestContext(), notification_target))));
 }
 
-KeyedService* BuildSelfNotifyingP2PProfileInvalidationProvider(
+scoped_ptr<KeyedService> BuildSelfNotifyingP2PProfileInvalidationProvider(
     content::BrowserContext* context) {
   return BuildP2PProfileInvalidationProvider(context, syncer::NOTIFY_ALL);
 }
 
-KeyedService* BuildRealisticP2PProfileInvalidationProvider(
+scoped_ptr<KeyedService> BuildRealisticP2PProfileInvalidationProvider(
     content::BrowserContext* context) {
   return BuildP2PProfileInvalidationProvider(context, syncer::NOTIFY_OTHERS);
 }
diff --git a/chrome/browser/sync/test_profile_sync_service.cc b/chrome/browser/sync/test_profile_sync_service.cc
index 70e89dd..4ba4035 100644
--- a/chrome/browser/sync/test_profile_sync_service.cc
+++ b/chrome/browser/sync/test_profile_sync_service.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/sync/test_profile_sync_service.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -127,20 +128,17 @@
 }
 
 // static
-KeyedService* TestProfileSyncService::TestFactoryFunction(
+scoped_ptr<KeyedService> TestProfileSyncService::TestFactoryFunction(
     content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
   SigninManagerBase* signin =
       SigninManagerFactory::GetForProfile(profile);
   ProfileOAuth2TokenService* oauth2_token_service =
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
-  return new TestProfileSyncService(
+  return make_scoped_ptr(new TestProfileSyncService(
       scoped_ptr<ProfileSyncComponentsFactory>(
           new ProfileSyncComponentsFactoryMock()),
-      profile,
-      signin,
-      oauth2_token_service,
-      browser_sync::AUTO_START);
+      profile, signin, oauth2_token_service, browser_sync::AUTO_START));
 }
 
 // static
diff --git a/chrome/browser/sync/test_profile_sync_service.h b/chrome/browser/sync/test_profile_sync_service.h
index be4af67..890f699 100644
--- a/chrome/browser/sync/test_profile_sync_service.h
+++ b/chrome/browser/sync/test_profile_sync_service.h
@@ -97,7 +97,8 @@
   using ProfileSyncService::NotifyObservers;
 
  protected:
-  static KeyedService* TestFactoryFunction(content::BrowserContext* profile);
+  static scoped_ptr<KeyedService> TestFactoryFunction(
+      content::BrowserContext* profile);
 
   // Return NULL handle to use in backend initialization to avoid receiving
   // js messages on UI loop when it's being destroyed, which are not deleted
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_util.cc b/chrome/browser/sync_file_system/drive_backend/drive_backend_util.cc
index fe6b676..9984d8e2 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_backend_util.cc
+++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_util.cc
@@ -153,7 +153,7 @@
 
 bool RemovePrefix(const std::string& str, const std::string& prefix,
                   std::string* out) {
-  if (!StartsWithASCII(str, prefix, true)) {
+  if (!base::StartsWithASCII(str, prefix, true)) {
     if (out)
       *out = str;
     return false;
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.cc
index 8e44f75..b6564505 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.cc
@@ -522,7 +522,8 @@
   itr->Seek(kDemotedDirtyIDKeyPrefix);
   if (!itr->Valid())
     return false;
-  return StartsWithASCII(itr->key().ToString(), kDemotedDirtyIDKeyPrefix, true);
+  return base::StartsWithASCII(itr->key().ToString(), kDemotedDirtyIDKeyPrefix,
+                               true);
 }
 
 bool MetadataDatabaseIndexOnDisk::IsDemotedDirtyTracker(
@@ -570,7 +571,8 @@
   size_t count = 0;
   scoped_ptr<LevelDBWrapper::Iterator> itr(db_->NewIterator());
   for (itr->Seek(kFileMetadataKeyPrefix); itr->Valid(); itr->Next()) {
-    if (!StartsWithASCII(itr->key().ToString(), kFileMetadataKeyPrefix, true))
+    if (!base::StartsWithASCII(itr->key().ToString(), kFileMetadataKeyPrefix,
+                               true))
       break;
     ++count;
   }
@@ -582,7 +584,8 @@
   size_t count = 0;
   scoped_ptr<LevelDBWrapper::Iterator> itr(db_->NewIterator());
   for (itr->Seek(kFileTrackerKeyPrefix); itr->Valid(); itr->Next()) {
-    if (!StartsWithASCII(itr->key().ToString(), kFileTrackerKeyPrefix, true))
+    if (!base::StartsWithASCII(itr->key().ToString(), kFileTrackerKeyPrefix,
+                               true))
       break;
     ++count;
   }
@@ -1143,7 +1146,7 @@
 
   scoped_ptr<LevelDBWrapper::Iterator> itr(db_->NewIterator());
   for (itr->Seek(kDirtyIDKeyPrefix); itr->Valid(); itr->Next()) {
-    if (!StartsWithASCII(itr->key().ToString(), kDirtyIDKeyPrefix, true))
+    if (!base::StartsWithASCII(itr->key().ToString(), kDirtyIDKeyPrefix, true))
       break;
     ++num_dirty_trackers;
   }
@@ -1178,7 +1181,7 @@
   scoped_ptr<LevelDBWrapper::Iterator> itr(db_->NewIterator());
   for (itr->Seek(prefix); itr->Valid();) {
     const std::string key = itr->key().ToString();
-    if (!StartsWithASCII(key, prefix, true))
+    if (!base::StartsWithASCII(key, prefix, true))
       break;
     itr->Delete();
   }
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.cc b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.cc
index 95c094b2..deafbea3 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util.cc
@@ -46,22 +46,24 @@
     std::string key = itr->key().ToString();
 
     // Do nothing for valid entries in both versions.
-    if (StartsWithASCII(key, kServiceMetadataKey, true) ||
-        StartsWithASCII(key, kFileMetadataKeyPrefix, true) ||
-        StartsWithASCII(key, kFileTrackerKeyPrefix, true)) {
+    if (base::StartsWithASCII(key, kServiceMetadataKey, true) ||
+        base::StartsWithASCII(key, kFileMetadataKeyPrefix, true) ||
+        base::StartsWithASCII(key, kFileTrackerKeyPrefix, true)) {
       continue;
     }
 
     // Drop entries used in version 4 only.
-    if (StartsWithASCII(key, kAppRootIDByAppIDKeyPrefix, true) ||
-        StartsWithASCII(key, kActiveTrackerIDByFileIDKeyPrefix, true) ||
-        StartsWithASCII(key, kTrackerIDByFileIDKeyPrefix, true) ||
-        StartsWithASCII(key, kMultiTrackerByFileIDKeyPrefix, true) ||
-        StartsWithASCII(key, kActiveTrackerIDByParentAndTitleKeyPrefix, true) ||
-        StartsWithASCII(key, kTrackerIDByParentAndTitleKeyPrefix, true) ||
-        StartsWithASCII(key, kMultiBackingParentAndTitleKeyPrefix, true) ||
-        StartsWithASCII(key, kDirtyIDKeyPrefix, true) ||
-        StartsWithASCII(key, kDemotedDirtyIDKeyPrefix, true)) {
+    if (base::StartsWithASCII(key, kAppRootIDByAppIDKeyPrefix, true) ||
+        base::StartsWithASCII(key, kActiveTrackerIDByFileIDKeyPrefix, true) ||
+        base::StartsWithASCII(key, kTrackerIDByFileIDKeyPrefix, true) ||
+        base::StartsWithASCII(key, kMultiTrackerByFileIDKeyPrefix, true) ||
+        base::StartsWithASCII(key, kActiveTrackerIDByParentAndTitleKeyPrefix,
+                              true) ||
+        base::StartsWithASCII(key, kTrackerIDByParentAndTitleKeyPrefix, true) ||
+        base::StartsWithASCII(key, kMultiBackingParentAndTitleKeyPrefix,
+                              true) ||
+        base::StartsWithASCII(key, kDirtyIDKeyPrefix, true) ||
+        base::StartsWithASCII(key, kDemotedDirtyIDKeyPrefix, true)) {
       write_batch.Delete(key);
       continue;
     }
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
index 761a96f..2d9308c 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_db_migration_util_unittest.cc
@@ -40,7 +40,7 @@
 
   itr->Seek(key);
   EXPECT_TRUE(!itr->Valid() ||
-              !StartsWithASCII(itr->key().ToString(), key, true));
+              !base::StartsWithASCII(itr->key().ToString(), key, true));
 }
 
 }  // namespace
diff --git a/chrome/browser/task_management/web_contents_tags.h b/chrome/browser/task_management/web_contents_tags.h
index 087ebbdb..9adbfdd5 100644
--- a/chrome/browser/task_management/web_contents_tags.h
+++ b/chrome/browser/task_management/web_contents_tags.h
@@ -16,15 +16,19 @@
 namespace task_management {
 
 // Defines a factory class for creating the TaskManager-specific Tags for the
-// web_contents that are owned by various types of services.
+// WebContents that are owned by various types of services.
 //
-// Any service that creates WebContents instances (via WebContents::Create)
-// needs to make sure that they are tagged using this mechanism, otherwise the
-// associated render processes will not show up in the task manager.
+// Any service or feature that creates WebContents instances (via
+// WebContents::Create) needs to make sure that they are tagged using this
+// mechanism, otherwise the associated render processes will not show up in the
+// task manager.
 class WebContentsTags {
  public:
-  // Creates a BackgroundContentsTag, and attaches it to the specified
-  // WebContents. If an instance is already attached, it does nothing.
+  // Tag a BackgroundContents so that it shows up in the task manager. Calling
+  // this function creates a BackgroundContentsTag, and attaches it to
+  // |web_contents|. If an instance is already attached, this does nothing. The
+  // resulting tag does not have to be cleaned up by the caller, as it is owned
+  // by |web_contents|.
   static void CreateForBackgroundContents(
       content::WebContents* web_contents,
       BackgroundContents* background_contents);
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 6d833eb..51512e6 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -209,7 +209,8 @@
                                 const PersistingImagesTable* image_table,
                                 size_t image_table_size) {
   for (size_t i = 0; i < image_table_size; ++i) {
-    if (image_table[i].key && LowerCaseEqualsASCII(key, image_table[i].key)) {
+    if (image_table[i].key &&
+        base::LowerCaseEqualsASCII(key, image_table[i].key)) {
       return image_table[i].persistent_id;
     }
   }
@@ -344,7 +345,7 @@
                     StringToIntTable* table,
                     size_t table_length) {
   for (size_t i = 0; i < table_length; ++i) {
-    if (LowerCaseEqualsASCII(key, table[i].key)) {
+    if (base::LowerCaseEqualsASCII(key, table[i].key)) {
       return table[i].id;
     }
   }
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc
index 8e184c0f..f32530f 100644
--- a/chrome/browser/themes/theme_properties.cc
+++ b/chrome/browser/themes/theme_properties.cc
@@ -145,13 +145,13 @@
   int alignment_mask = 0;
   for (std::vector<std::string>::iterator component(split.begin());
        component != split.end(); ++component) {
-    if (LowerCaseEqualsASCII(*component, kAlignmentTop))
+    if (base::LowerCaseEqualsASCII(*component, kAlignmentTop))
       alignment_mask |= ALIGN_TOP;
-    else if (LowerCaseEqualsASCII(*component, kAlignmentBottom))
+    else if (base::LowerCaseEqualsASCII(*component, kAlignmentBottom))
       alignment_mask |= ALIGN_BOTTOM;
-    else if (LowerCaseEqualsASCII(*component, kAlignmentLeft))
+    else if (base::LowerCaseEqualsASCII(*component, kAlignmentLeft))
       alignment_mask |= ALIGN_LEFT;
-    else if (LowerCaseEqualsASCII(*component, kAlignmentRight))
+    else if (base::LowerCaseEqualsASCII(*component, kAlignmentRight))
       alignment_mask |= ALIGN_RIGHT;
   }
   return alignment_mask;
@@ -159,11 +159,11 @@
 
 // static
 int ThemeProperties::StringToTiling(const std::string& tiling) {
-  if (LowerCaseEqualsASCII(tiling, kTilingRepeatX))
+  if (base::LowerCaseEqualsASCII(tiling, kTilingRepeatX))
     return REPEAT_X;
-  if (LowerCaseEqualsASCII(tiling, kTilingRepeatY))
+  if (base::LowerCaseEqualsASCII(tiling, kTilingRepeatY))
     return REPEAT_Y;
-  if (LowerCaseEqualsASCII(tiling, kTilingRepeat))
+  if (base::LowerCaseEqualsASCII(tiling, kTilingRepeat))
     return REPEAT;
   // NO_REPEAT is the default choice.
   return NO_REPEAT;
diff --git a/chrome/browser/themes/theme_syncable_service_unittest.cc b/chrome/browser/themes/theme_syncable_service_unittest.cc
index ca607be..ff0fd7ed 100644
--- a/chrome/browser/themes/theme_syncable_service_unittest.cc
+++ b/chrome/browser/themes/theme_syncable_service_unittest.cc
@@ -113,8 +113,9 @@
   bool is_dirty_;
 };
 
-KeyedService* BuildMockThemeService(content::BrowserContext* profile) {
-  return new FakeThemeService;
+scoped_ptr<KeyedService> BuildMockThemeService(
+    content::BrowserContext* profile) {
+  return make_scoped_ptr(new FakeThemeService);
 }
 
 scoped_refptr<extensions::Extension> MakeThemeExtension(
diff --git a/chrome/browser/tracing/background_tracing_field_trial.cc b/chrome/browser/tracing/background_tracing_field_trial.cc
index 8d459ba0..4e827a9 100644
--- a/chrome/browser/tracing/background_tracing_field_trial.cc
+++ b/chrome/browser/tracing/background_tracing_field_trial.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/background_tracing_config.h"
 #include "content/public/browser/background_tracing_manager.h"
 #include "content/public/browser/browser_thread.h"
+#include "url/gurl.h"
 
 namespace tracing {
 
@@ -20,6 +21,7 @@
 
 const char kBackgroundTracingFieldTrial[] = "BackgroundTracing";
 const char kBackgroundTracingConfig[] = "config";
+const char kBackgroundTracingUploadUrl[] = "upload_url";
 
 void OnUploadProgress(int64, int64) {
   // We don't actually care about the progress, but TraceUploader::DoUpload
@@ -34,11 +36,13 @@
   done_callback.Run();
 }
 
-void UploadCallback(const scoped_refptr<base::RefCountedString>& file_contents,
+void UploadCallback(const std::string& upload_url,
+                    const scoped_refptr<base::RefCountedString>& file_contents,
                     base::Closure callback) {
   TraceCrashServiceUploader* uploader = new TraceCrashServiceUploader(
       g_browser_process->system_request_context());
 
+  uploader->SetUploadURL(upload_url);
   uploader->DoUpload(
       file_contents->data(), base::Bind(&OnUploadProgress),
       base::Bind(&OnUploadComplete, base::Owned(uploader), callback));
@@ -49,6 +53,12 @@
 void SetupBackgroundTracingFieldTrial() {
   std::string config_text = variations::GetVariationParamValue(
       kBackgroundTracingFieldTrial, kBackgroundTracingConfig);
+  std::string upload_url = variations::GetVariationParamValue(
+      kBackgroundTracingFieldTrial, kBackgroundTracingUploadUrl);
+
+  if (!GURL(upload_url).is_valid())
+    return;
+
   if (config_text.empty())
     return;
 
@@ -66,7 +76,7 @@
     return;
 
   content::BackgroundTracingManager::GetInstance()->SetActiveScenario(
-      config.Pass(), base::Bind(&UploadCallback),
+      config.Pass(), base::Bind(&UploadCallback, upload_url),
       content::BackgroundTracingManager::ANONYMIZE_DATA);
 }
 
diff --git a/chrome/browser/tracing/crash_service_uploader.cc b/chrome/browser/tracing/crash_service_uploader.cc
index c0983ea..9224a58 100644
--- a/chrome/browser/tracing/crash_service_uploader.cc
+++ b/chrome/browser/tracing/crash_service_uploader.cc
@@ -43,12 +43,27 @@
     net::URLRequestContextGetter* request_context)
     : request_context_(request_context) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+  std::string upload_url = kUploadURL;
+  if (command_line.HasSwitch(switches::kTraceUploadURL)) {
+    upload_url = command_line.GetSwitchValueASCII(switches::kTraceUploadURL);
+  }
+  SetUploadURL(upload_url);
 }
 
 TraceCrashServiceUploader::~TraceCrashServiceUploader() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
+void TraceCrashServiceUploader::SetUploadURL(const std::string& url) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  upload_url_ = url;
+
+  if (!GURL(upload_url_).is_valid())
+    upload_url_.clear();
+}
+
 void TraceCrashServiceUploader::OnURLFetchComplete(
     const net::URLFetcher* source) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -89,12 +104,13 @@
   content::BrowserThread::PostTask(
       content::BrowserThread::FILE, FROM_HERE,
       base::Bind(&TraceCrashServiceUploader::DoUploadOnFileThread,
-                 base::Unretained(this), file_contents, progress_callback,
-                 done_callback));
+                 base::Unretained(this), file_contents, upload_url_,
+                 progress_callback, done_callback));
 }
 
 void TraceCrashServiceUploader::DoUploadOnFileThread(
     const std::string& file_contents,
+    const std::string& upload_url,
     const UploadProgressCallback& progress_callback,
     const UploadDoneCallback& done_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
@@ -103,15 +119,6 @@
   progress_callback_ = progress_callback;
   done_callback_ = done_callback;
 
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  std::string upload_url = kUploadURL;
-  if (command_line.HasSwitch(switches::kTraceUploadURL)) {
-    upload_url = command_line.GetSwitchValueASCII(switches::kTraceUploadURL);
-  }
-  if (!GURL(upload_url).is_valid())
-    upload_url.clear();
-
   if (upload_url.empty()) {
     OnUploadError("Upload URL empty or invalid");
     return;
diff --git a/chrome/browser/tracing/crash_service_uploader.h b/chrome/browser/tracing/crash_service_uploader.h
index 23cf556..5211f43 100644
--- a/chrome/browser/tracing/crash_service_uploader.h
+++ b/chrome/browser/tracing/crash_service_uploader.h
@@ -38,6 +38,8 @@
       net::URLRequestContextGetter* request_context);
   ~TraceCrashServiceUploader() override;
 
+  void SetUploadURL(const std::string& url);
+
   // net::URLFetcherDelegate implementation.
   void OnURLFetchComplete(const net::URLFetcher* source) override;
   void OnURLFetchUploadProgress(const net::URLFetcher* source,
@@ -51,6 +53,7 @@
 
  private:
   void DoUploadOnFileThread(const std::string& file_contents,
+                            const std::string& upload_url,
                             const UploadProgressCallback& progress_callback,
                             const UploadDoneCallback& done_callback);
   // Sets up a multipart body to be uploaded. The body is produced according
@@ -78,6 +81,8 @@
 
   net::URLRequestContextGetter* request_context_;
 
+  std::string upload_url_;
+
   DISALLOW_COPY_AND_ASSIGN(TraceCrashServiceUploader);
 };
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 02e05b72..0353a12 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -198,7 +198,10 @@
     sources += rebase_path(gypi_values.chrome_browser_ui_views_sources,
                            ".",
                            "//chrome")
-    deps += [ "//components/constrained_window" ]
+    deps += [
+      "//components/constrained_window",
+      "//extensions/components/native_app_window",
+    ]
     if (!is_chromeos) {
       sources +=
           rebase_path(gypi_values.chrome_browser_ui_views_non_chromeos_sources,
@@ -210,7 +213,13 @@
           rebase_path(gypi_values.chrome_browser_ui_views_non_mac_sources,
                       ".",
                       "//chrome")
-      deps += [ "//extensions/components/native_app_window" ]
+      if (enable_extensions) {
+        sources += rebase_path(
+                gypi_values.chrome_browser_ui_views_extensions_non_mac_sources,
+                ".",
+                "//chrome")
+        deps += [ "//extensions/components/native_app_window" ]
+      }
       if (is_chromeos) {
         # TODO(GYP): crbug.com/481629. These files should probably not be
         # a part of ui_views_non_mac_sources at all.
@@ -311,6 +320,10 @@
           rebase_path(gypi_values.chrome_browser_ui_views_non_mac_sources,
                       ".",
                       "//chrome")
+      sources += rebase_path(
+              gypi_values.chrome_browser_ui_views_extensions_non_mac_sources,
+              ".",
+              "//chrome")
       deps += [ "//extensions/components/native_app_window" ]
     } else {
       sources += rebase_path(gypi_values.chrome_browser_ui_cocoa_sources,
diff --git a/chrome/browser/ui/android/infobars/confirm_infobar.cc b/chrome/browser/ui/android/infobars/confirm_infobar.cc
index 9fef5cf..43dcc78 100644
--- a/chrome/browser/ui/android/infobars/confirm_infobar.cc
+++ b/chrome/browser/ui/android/infobars/confirm_infobar.cc
@@ -4,13 +4,22 @@
 
 #include "chrome/browser/ui/android/infobars/confirm_infobar.h"
 
+#include <vector>
+
 #include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/logging.h"
 #include "chrome/browser/android/resource_mapper.h"
+#include "chrome/browser/content_settings/permission_infobar_delegate.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/media/media_stream_infobar_delegate.h"
+#include "components/content_settings/core/common/content_settings_types.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
+#include "content/public/browser/android/content_view_core.h"
+#include "content/public/browser/web_contents.h"
 #include "jni/ConfirmInfoBarDelegate_jni.h"
+#include "ui/android/window_android.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/image/image.h"
 
@@ -53,10 +62,37 @@
     java_bitmap = gfx::ConvertToJavaBitmap(delegate->GetIcon().ToSkBitmap());
   }
 
+  std::vector<int> content_settings;
+  if (delegate->AsPermissionInfobarDelegate()) {
+    content_settings.push_back(
+        delegate->AsPermissionInfobarDelegate()->content_setting());
+  } else if (delegate->AsMediaStreamInfoBarDelegate()) {
+    MediaStreamInfoBarDelegate* media_delegate =
+        delegate->AsMediaStreamInfoBarDelegate();
+    if (media_delegate->IsRequestingVideoAccess()) {
+      content_settings.push_back(
+          ContentSettingsType::CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
+    } else if (media_delegate->IsRequestingMicrophoneAccess()) {
+      content_settings.push_back(
+          ContentSettingsType::CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
+    }
+  }
+
+  content::WebContents* web_contents =
+      InfoBarService::WebContentsFromInfoBar(this);
+  DCHECK(web_contents);
+  content::ContentViewCore* cvc =
+      content::ContentViewCore::FromWebContents(web_contents);
+  DCHECK(cvc);
+  base::android::ScopedJavaLocalRef<jobject> jwindow_android =
+      cvc->GetWindowAndroid()->GetJavaObject();
+
   return Java_ConfirmInfoBarDelegate_showConfirmInfoBar(
-      env, java_confirm_delegate_.obj(), GetEnumeratedIconId(),
-      java_bitmap.obj(), message_text.obj(), link_text.obj(),
-      ok_button_text.obj(), cancel_button_text.obj());
+      env, java_confirm_delegate_.obj(),
+      jwindow_android.obj(), GetEnumeratedIconId(), java_bitmap.obj(),
+      message_text.obj(), link_text.obj(), ok_button_text.obj(),
+      cancel_button_text.obj(),
+      base::android::ToJavaIntArray(env, content_settings).obj());
 }
 
 void ConfirmInfoBar::OnLinkClicked(JNIEnv* env, jobject obj) {
diff --git a/chrome/browser/ui/app_list/app_list_prefs_factory.cc b/chrome/browser/ui/app_list/app_list_prefs_factory.cc
index 80d8801a..fcca1f0 100644
--- a/chrome/browser/ui/app_list/app_list_prefs_factory.cc
+++ b/chrome/browser/ui/app_list/app_list_prefs_factory.cc
@@ -27,8 +27,8 @@
 
 void AppListPrefsFactory::SetInstanceForTesting(
     content::BrowserContext* context,
-    AppListPrefs* prefs) {
-  Associate(context, prefs);
+    scoped_ptr<AppListPrefs> prefs) {
+  Associate(context, prefs.Pass());
 }
 
 AppListPrefsFactory::AppListPrefsFactory()
diff --git a/chrome/browser/ui/app_list/app_list_prefs_factory.h b/chrome/browser/ui/app_list/app_list_prefs_factory.h
index f6ebc856..febbff7b 100644
--- a/chrome/browser/ui/app_list/app_list_prefs_factory.h
+++ b/chrome/browser/ui/app_list/app_list_prefs_factory.h
@@ -20,7 +20,7 @@
   static AppListPrefsFactory* GetInstance();
 
   void SetInstanceForTesting(content::BrowserContext* context,
-                             AppListPrefs* prefs);
+                             scoped_ptr<AppListPrefs> prefs);
 
  private:
   friend struct DefaultSingletonTraits<AppListPrefsFactory>;
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc
index b3bc806..5a44a21f 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -142,7 +142,7 @@
 }
 
 bool IsDriveAppSyncId(const std::string& sync_id) {
-  return StartsWithASCII(sync_id, kDriveAppSyncIdPrefix, true);
+  return base::StartsWithASCII(sync_id, kDriveAppSyncIdPrefix, true);
 }
 
 std::string GetDriveAppSyncId(const std::string& drive_app_id) {
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
index 3ef9d923..06e73ced 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
@@ -35,7 +35,7 @@
 }
 
 // static
-KeyedService* AppListSyncableServiceFactory::BuildInstanceFor(
+scoped_ptr<KeyedService> AppListSyncableServiceFactory::BuildInstanceFor(
     content::BrowserContext* browser_context) {
   Profile* profile = static_cast<Profile*>(browser_context);
 #if defined(OS_CHROMEOS)
@@ -44,8 +44,8 @@
 #endif
   VLOG(1) << "BuildInstanceFor: " << profile->GetDebugName()
           << " (" << profile << ")";
-  return new AppListSyncableService(profile,
-                                    extensions::ExtensionSystem::Get(profile));
+  return make_scoped_ptr(new AppListSyncableService(
+      profile, extensions::ExtensionSystem::Get(profile)));
 }
 
 AppListSyncableServiceFactory::AppListSyncableServiceFactory()
@@ -70,7 +70,7 @@
 
 KeyedService* AppListSyncableServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* browser_context) const {
-  return BuildInstanceFor(static_cast<Profile*>(browser_context));
+  return BuildInstanceFor(static_cast<Profile*>(browser_context)).release();
 }
 
 void AppListSyncableServiceFactory::RegisterProfilePrefs(
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_factory.h b/chrome/browser/ui/app_list/app_list_syncable_service_factory.h
index 9caac4d..feaa743f 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_factory.h
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_factory.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_APP_LIST_APP_LIST_SYNCABLE_SERVICE_FACTORY_H_
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
@@ -24,7 +25,7 @@
 
   static AppListSyncableServiceFactory* GetInstance();
 
-  static KeyedService* BuildInstanceFor(
+  static scoped_ptr<KeyedService> BuildInstanceFor(
       content::BrowserContext* browser_context);
 
  private:
diff --git a/chrome/browser/ui/app_list/search/common/webservice_search_provider.cc b/chrome/browser/ui/app_list/search/common/webservice_search_provider.cc
index a7bcf57..32e64c1 100644
--- a/chrome/browser/ui/app_list/search/common/webservice_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/common/webservice_search_provider.cc
@@ -71,7 +71,7 @@
   // file, we shouldn't send it. Sending such things is a waste of time and a
   // disclosure of potentially private, local data. If the scheme is OK, we
   // still need to check other cases below.
-  if (LowerCaseEqualsASCII(query_as_url.scheme(), url::kFileScheme))
+  if (base::LowerCaseEqualsASCII(query_as_url.scheme(), url::kFileScheme))
     return true;
 
   // Don't send URLs with usernames, queries or refs. Some of these are
@@ -90,7 +90,7 @@
   // Don't send anything for https except the hostname. Hostnames are OK
   // because they are visible when the TCP connection is established, but the
   // specific path may reveal private information.
-  if (LowerCaseEqualsASCII(query_as_url.scheme(), url::kHttpsScheme) &&
+  if (base::LowerCaseEqualsASCII(query_as_url.scheme(), url::kHttpsScheme) &&
       !query_as_url.path().empty() && query_as_url.path() != "/") {
     return true;
   }
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc
index 232855bb6..9f4b4c1 100644
--- a/chrome/browser/ui/app_list/search/search_controller_factory.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -48,7 +48,7 @@
 // Returns whether the user is part of a group where the Suggestions provider is
 // enabled.
 bool IsSuggestionsSearchProviderEnabled() {
-  return StartsWithASCII(
+  return base::StartsWithASCII(
       base::FieldTrialList::FindFullName(kSuggestionsProviderFieldTrialName),
       kSuggestionsProviderFieldTrialEnabledPrefix, true);
 }
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc b/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
index 2c43cb3..72f9f06 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
@@ -40,13 +40,13 @@
 // Converts the item type string from the web store to an
 // extensions::Manifest::Type.
 extensions::Manifest::Type ParseItemType(const std::string& item_type_str) {
-  if (LowerCaseEqualsASCII(item_type_str, kPlatformAppType))
+  if (base::LowerCaseEqualsASCII(item_type_str, kPlatformAppType))
     return extensions::Manifest::TYPE_PLATFORM_APP;
 
-  if (LowerCaseEqualsASCII(item_type_str, kLegacyPackagedAppType))
+  if (base::LowerCaseEqualsASCII(item_type_str, kLegacyPackagedAppType))
     return extensions::Manifest::TYPE_LEGACY_PACKAGED_APP;
 
-  if (LowerCaseEqualsASCII(item_type_str, kHostedAppType))
+  if (base::LowerCaseEqualsASCII(item_type_str, kHostedAppType))
     return extensions::Manifest::TYPE_HOSTED_APP;
 
   return extensions::Manifest::TYPE_UNKNOWN;
diff --git a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
index 0b79244..e0c9c5c 100644
--- a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
+++ b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.cc
@@ -14,16 +14,15 @@
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_function_dispatcher.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/view_type_utils.h"
 #include "extensions/common/api/virtual_keyboard_private.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension_messages.h"
 #include "ipc/ipc_message_macros.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_controller_observer.h"
@@ -115,19 +114,13 @@
 }
 
 AshKeyboardControllerProxy::~AshKeyboardControllerProxy() {
-  DCHECK(!keyboard_controller_);
-}
-
-void AshKeyboardControllerProxy::OnRequest(
-    const ExtensionHostMsg_Request_Params& params) {
-  extension_function_dispatcher_->Dispatch(
-      params, web_contents()->GetRenderViewHost());
+  DCHECK(!keyboard_controller());
 }
 
 ui::InputMethod* AshKeyboardControllerProxy::GetInputMethod() {
-  aura::Window* root_window = ash::Shell::GetInstance()->GetPrimaryRootWindow();
+  aura::Window* root_window = ash::Shell::GetTargetRootWindow();
   DCHECK(root_window);
-  return root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
+  return root_window->GetHost()->GetInputMethod();
 }
 
 void AshKeyboardControllerProxy::RequestAudioInput(
@@ -149,47 +142,24 @@
 
 void AshKeyboardControllerProxy::SetupWebContents(
     content::WebContents* contents) {
-  extension_function_dispatcher_.reset(
-      new extensions::ExtensionFunctionDispatcher(browser_context(), this));
   extensions::SetViewType(contents, extensions::VIEW_TYPE_VIRTUAL_KEYBOARD);
   extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
       contents);
   Observe(contents);
 }
 
-extensions::WindowController*
-    AshKeyboardControllerProxy::GetExtensionWindowController() const {
-  // The keyboard doesn't have a window controller.
-  return NULL;
-}
-
 void AshKeyboardControllerProxy::SetController(
     keyboard::KeyboardController* controller) {
   // During KeyboardController destruction, controller can be set to null.
   if (!controller) {
-    DCHECK(keyboard_controller_);
-    keyboard_controller_->RemoveObserver(observer_.get());
-    keyboard_controller_ = nullptr;
+    DCHECK(keyboard_controller());
+    keyboard_controller()->RemoveObserver(observer_.get());
+    KeyboardControllerProxy::SetController(nullptr);
     return;
   }
-  keyboard_controller_ = controller;
+  KeyboardControllerProxy::SetController(controller);
   observer_.reset(new AshKeyboardControllerObserver(browser_context()));
-  keyboard_controller_->AddObserver(observer_.get());
-}
-
-content::WebContents*
-    AshKeyboardControllerProxy::GetAssociatedWebContents() const {
-  return web_contents();
-}
-
-bool AshKeyboardControllerProxy::OnMessageReceived(
-    const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(AshKeyboardControllerProxy, message)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
+  keyboard_controller()->AddObserver(observer_.get());
 }
 
 void AshKeyboardControllerProxy::RenderViewCreated(
diff --git a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h
index 64c042ce8..d78d9745 100644
--- a/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h
+++ b/chrome/browser/ui/ash/ash_keyboard_controller_proxy.h
@@ -8,7 +8,6 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "extensions/browser/extension_function_dispatcher.h"
 #include "ui/keyboard/keyboard_controller_proxy.h"
 
 namespace content {
@@ -34,15 +33,12 @@
 // access to the virtual keyboard window and setup Chrome extension functions.
 class AshKeyboardControllerProxy
     : public keyboard::KeyboardControllerProxy,
-      public content::WebContentsObserver,
-      public extensions::ExtensionFunctionDispatcher::Delegate {
+      public content::WebContentsObserver {
  public:
   explicit AshKeyboardControllerProxy(content::BrowserContext* context);
   ~AshKeyboardControllerProxy() override;
 
  private:
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
-
   // keyboard::KeyboardControllerProxy overrides
   ui::InputMethod* GetInputMethod() override;
   void RequestAudioInput(
@@ -62,18 +58,9 @@
   // that case.
   void SetUpdateInputType(ui::TextInputType type) override;
 
-  // extensions::ExtensionFunctionDispatcher::Delegate overrides
-  extensions::WindowController* GetExtensionWindowController() const override;
-  content::WebContents* GetAssociatedWebContents() const override;
-
   // content::WebContentsObserver overrides
-  bool OnMessageReceived(const IPC::Message& message) override;
   void RenderViewCreated(content::RenderViewHost* render_view_host) override;
 
-  keyboard::KeyboardController* keyboard_controller_;
-
-  scoped_ptr<extensions::ExtensionFunctionDispatcher>
-      extension_function_dispatcher_;
   scoped_ptr<keyboard::KeyboardControllerObserver> observer_;
 
   DISALLOW_COPY_AND_ASSIGN(AshKeyboardControllerProxy);
diff --git a/chrome/browser/ui/ash/cast_config_delegate_chromeos.cc b/chrome/browser/ui/ash/cast_config_delegate_chromeos.cc
index b2196e97..b538c60 100644
--- a/chrome/browser/ui/ash/cast_config_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/cast_config_delegate_chromeos.cc
@@ -127,25 +127,30 @@
 
 void CastConfigDelegateChromeos::GetReceiversAndActivities(
     const ReceiversAndActivitesCallback& callback) {
+  // The methods in backgroundSetup are renamed during minification, so we have
+  // to bind the exported global API methods to backgroundSetup using call().
   ExecuteJavaScriptWithCallback(
-      "backgroundSetup.getMirrorCapableReceiversAndActivities();",
+      "getMirrorCapableReceiversAndActivities.call(backgroundSetup);",
       base::Bind(&GetReceiversAndActivitiesCallback, callback));
 }
 
 void CastConfigDelegateChromeos::CastToReceiver(
     const std::string& receiver_id) {
-  ExecuteJavaScript("backgroundSetup.launchDesktopMirroring('" + receiver_id +
-                    "');");
+  // The methods in backgroundSetup are renamed during minification, so we have
+  // to bind the exported global API methods to backgroundSetup using call().
+  ExecuteJavaScript("launchDesktopMirroring.call(backgroundSetup, '" +
+                    receiver_id + "');");
 }
 
 void CastConfigDelegateChromeos::StopCasting() {
-  ExecuteJavaScript("backgroundSetup.stopMirroring('user-stop')");
+  // The methods in backgroundSetup are renamed during minification, so we have
+  // to bind the exported global API methods to backgroundSetup using call().
+  ExecuteJavaScript("stopMirroring.call(backgroundSetup, 'user-stop');");
 
   // TODO(jdufault): Remove this after the beta/release versions of the
   // cast extension have been updated so that they properly export the
   // stopMirroring function. For now, we try to invoke all of the other
   // names that the function goes by. See crbug.com/489929.
-  ExecuteJavaScript("backgroundSetup.stopCastMirroring('user-stop');");
   ExecuteJavaScript("backgroundSetup.Qu('user-stop');");
 }
 
diff --git a/chrome/browser/ui/ash/keyboard_controller_browsertest.cc b/chrome/browser/ui/ash/keyboard_controller_browsertest.cc
index 1144c91..e8a2e9a6 100644
--- a/chrome/browser/ui/ash/keyboard_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/keyboard_controller_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/shell.h"
 #include "base/command_line.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/web_contents.h"
@@ -20,8 +21,8 @@
 
 class VirtualKeyboardWebContentTest : public InProcessBrowserTest {
  public:
-  VirtualKeyboardWebContentTest() {};
-  ~VirtualKeyboardWebContentTest() override{};
+  VirtualKeyboardWebContentTest() {}
+  ~VirtualKeyboardWebContentTest() override {}
 
   void SetUp() override {
     ui::SetUpInputMethodFactoryForTesting();
@@ -39,12 +40,14 @@
   }
 
  protected:
-  void FocusEditableNodeAndShowKeyboard() {
+  void FocusEditableNodeAndShowKeyboard(const gfx::Rect& init_bounds) {
     client.reset(new ui::DummyTextInputClient(ui::TEXT_INPUT_TYPE_TEXT));
     ui::InputMethod* input_method = proxy()->GetInputMethod();
     input_method->SetFocusedTextInputClient(client.get());
     input_method->ShowImeIfNeeded();
-    ResizeKeyboardWindow();
+    // Mock window.resizeTo that is expected to be called after navigate to a
+    // new virtual keyboard.
+    proxy()->GetKeyboardWindow()->SetBounds(init_bounds);
   }
 
   void FocusNonEditableNode() {
@@ -53,10 +56,13 @@
     input_method->SetFocusedTextInputClient(client.get());
   }
 
-  void MockEnableIMEInDifferentExtension(const std::string& url) {
+  void MockEnableIMEInDifferentExtension(const std::string& url,
+                                         const gfx::Rect& init_bounds) {
     keyboard::SetOverrideContentUrl(GURL(url));
     keyboard::KeyboardController::GetInstance()->Reload();
-    ResizeKeyboardWindow();
+    // Mock window.resizeTo that is expected to be called after navigate to a
+    // new virtual keyboard.
+    proxy()->GetKeyboardWindow()->SetBounds(init_bounds);
   }
 
   bool IsKeyboardVisible() const {
@@ -64,17 +70,6 @@
   }
 
  private:
-  // Mock window.resizeTo that is expected to be called after navigate to a new
-  // virtual keyboard.
-  void ResizeKeyboardWindow() {
-    gfx::Rect bounds = proxy()->GetKeyboardWindow()->bounds();
-    proxy()->GetKeyboardWindow()->SetBounds(gfx::Rect(
-        bounds.x(),
-        bounds.bottom() - kKeyboardHeightForTest,
-        bounds.width(),
-        kKeyboardHeightForTest));
-  }
-
   scoped_ptr<ui::DummyTextInputClient> client;
 
   DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardWebContentTest);
@@ -84,16 +79,17 @@
 // its virtual keyboard should not become visible if previous one is not.
 IN_PROC_BROWSER_TEST_F(VirtualKeyboardWebContentTest,
                        EnableIMEInDifferentExtension) {
-  FocusEditableNodeAndShowKeyboard();
+  gfx::Rect test_bounds(0, 0, 0, kKeyboardHeightForTest);
+  FocusEditableNodeAndShowKeyboard(test_bounds);
   EXPECT_TRUE(IsKeyboardVisible());
   FocusNonEditableNode();
   EXPECT_FALSE(IsKeyboardVisible());
 
-  MockEnableIMEInDifferentExtension("chrome-extension://domain-1");
+  MockEnableIMEInDifferentExtension("chrome-extension://domain-1", test_bounds);
   // Keyboard should not become visible if previous keyboard is not.
   EXPECT_FALSE(IsKeyboardVisible());
 
-  FocusEditableNodeAndShowKeyboard();
+  FocusEditableNodeAndShowKeyboard(test_bounds);
   // Keyboard should become visible after focus on an editable node.
   EXPECT_TRUE(IsKeyboardVisible());
 
@@ -102,8 +98,35 @@
       keyboard::KeyboardController::HIDE_REASON_MANUAL);
   EXPECT_FALSE(IsKeyboardVisible());
 
-  MockEnableIMEInDifferentExtension("chrome-extension://domain-2");
+  MockEnableIMEInDifferentExtension("chrome-extension://domain-2", test_bounds);
   // Keyboard should not become visible if previous keyboard is not, even if it
   // is currently focused on an editable node.
   EXPECT_FALSE(IsKeyboardVisible());
 }
+
+// Test for crbug.com/489366. In FLOATING mode, switch to a new IME in a
+// different extension should exist FLOATIN mode and position the new IME in
+// FULL_WIDTH mode.
+IN_PROC_BROWSER_TEST_F(VirtualKeyboardWebContentTest,
+                       IMEInDifferentExtensionNotCentered) {
+  gfx::Rect test_bounds(0, 0, 0, kKeyboardHeightForTest);
+  FocusEditableNodeAndShowKeyboard(test_bounds);
+  keyboard::KeyboardController* controller =
+      keyboard::KeyboardController::GetInstance();
+  const gfx::Rect& screen_bounds = ash::Shell::GetPrimaryRootWindow()->bounds();
+  gfx::Rect keyboard_bounds = controller->GetContainerWindow()->bounds();
+  EXPECT_EQ(kKeyboardHeightForTest, keyboard_bounds.height());
+  EXPECT_EQ(screen_bounds.height(),
+            keyboard_bounds.height() + keyboard_bounds.y());
+  controller->SetKeyboardMode(keyboard::FLOATING);
+  // Move keyboard to a random place.
+  proxy()->GetKeyboardWindow()->SetBounds(gfx::Rect(50, 50, 50, 50));
+  EXPECT_EQ(gfx::Rect(50, 50, 50, 50),
+            controller->GetContainerWindow()->bounds());
+
+  MockEnableIMEInDifferentExtension("chrome-extension://domain-1", test_bounds);
+  keyboard_bounds = controller->GetContainerWindow()->bounds();
+  EXPECT_EQ(kKeyboardHeightForTest, keyboard_bounds.height());
+  EXPECT_EQ(screen_bounds.height(),
+            keyboard_bounds.height() + keyboard_bounds.y());
+}
diff --git a/chrome/browser/ui/ash/session_state_delegate_chromeos_unittest.cc b/chrome/browser/ui/ash/session_state_delegate_chromeos_unittest.cc
index 37da1a4b..8c3b0776 100644
--- a/chrome/browser/ui/ash/session_state_delegate_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/session_state_delegate_chromeos_unittest.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <vector>
 
+#include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
@@ -33,11 +34,11 @@
 // we've ensured the profile has been shut down.
 policy::PolicyCertVerifier* g_policy_cert_verifier_for_factory = NULL;
 
-KeyedService* CreateTestPolicyCertService(content::BrowserContext* context) {
+scoped_ptr<KeyedService> CreateTestPolicyCertService(
+    content::BrowserContext* context) {
   return policy::PolicyCertService::CreateForTesting(
-             kUser,
-             g_policy_cert_verifier_for_factory,
-             user_manager::UserManager::Get()).release();
+      kUser, g_policy_cert_verifier_for_factory,
+      user_manager::UserManager::Get());
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index ff627e8..a4111eca 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -3282,7 +3282,7 @@
   DCHECK_EQ(2U, country_code.size());
 
   if (section == SECTION_CC_BILLING)
-    return LowerCaseEqualsASCII(country_code, "us");
+    return base::LowerCaseEqualsASCII(country_code, "us");
 
   CountryComboboxModel* model = CountryComboboxModelForSection(section);
   const std::vector<AutofillCountry*>& countries = model->countries();
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
index b19fdee..6ac5712a 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
@@ -1398,15 +1398,15 @@
   EXPECT_EQ(ADDRESS_BILLING, form_structure()->field(1)->Type().group());
   // Inexact matching; single-line inputs get the address data concatenated but
   // separated by commas.
-  EXPECT_TRUE(StartsWith(form_structure()->field(0)->value,
-                         shipping_profile.GetRawInfo(ADDRESS_HOME_LINE1),
-                         true));
+  EXPECT_TRUE(base::StartsWith(form_structure()->field(0)->value,
+                               shipping_profile.GetRawInfo(ADDRESS_HOME_LINE1),
+                               true));
   EXPECT_TRUE(EndsWith(form_structure()->field(0)->value,
                        shipping_profile.GetRawInfo(ADDRESS_HOME_LINE2),
                        true));
-  EXPECT_TRUE(StartsWith(form_structure()->field(1)->value,
-                         billing_profile.GetRawInfo(ADDRESS_HOME_LINE1),
-                         true));
+  EXPECT_TRUE(base::StartsWith(form_structure()->field(1)->value,
+                               billing_profile.GetRawInfo(ADDRESS_HOME_LINE1),
+                               true));
   EXPECT_TRUE(EndsWith(form_structure()->field(1)->value,
                        billing_profile.GetRawInfo(ADDRESS_HOME_LINE2),
                        true));
diff --git a/chrome/browser/ui/blocked_content/blocked_window_params.cc b/chrome/browser/ui/blocked_content/blocked_window_params.cc
index cce4616..03e457f 100644
--- a/chrome/browser/ui/blocked_content/blocked_window_params.cc
+++ b/chrome/browser/ui/blocked_content/blocked_window_params.cc
@@ -19,7 +19,7 @@
     bool user_gesture,
     bool opener_suppressed,
     int render_process_id,
-    int opener_id)
+    int opener_render_frame_id)
     : target_url_(target_url),
       referrer_(referrer),
       disposition_(disposition),
@@ -27,7 +27,7 @@
       user_gesture_(user_gesture),
       opener_suppressed_(opener_suppressed),
       render_process_id_(render_process_id),
-      opener_id_(opener_id) {
+      opener_render_frame_id_(opener_render_frame_id) {
 }
 
 chrome::NavigateParams BlockedWindowParams::CreateNavigateParams(
diff --git a/chrome/browser/ui/blocked_content/blocked_window_params.h b/chrome/browser/ui/blocked_content/blocked_window_params.h
index ad3f8a31d..afed194c 100644
--- a/chrome/browser/ui/blocked_content/blocked_window_params.h
+++ b/chrome/browser/ui/blocked_content/blocked_window_params.h
@@ -18,13 +18,13 @@
 class BlockedWindowParams {
  public:
   BlockedWindowParams(const GURL& target_url,
-                     const content::Referrer& referrer,
-                     WindowOpenDisposition disposition,
-                     const blink::WebWindowFeatures& features,
-                     bool user_gesture,
-                     bool opener_suppressed,
-                     int render_process_id,
-                     int opener_id);
+                      const content::Referrer& referrer,
+                      WindowOpenDisposition disposition,
+                      const blink::WebWindowFeatures& features,
+                      bool user_gesture,
+                      bool opener_suppressed,
+                      int render_process_id,
+                      int opener_render_frame_id);
 
   chrome::NavigateParams CreateNavigateParams(
       content::WebContents* web_contents) const;
@@ -33,8 +33,8 @@
     return features_;
   }
 
-  int opener_id() const {
-    return opener_id_;
+  int opener_render_frame_id() const {
+    return opener_render_frame_id_;
   }
 
   int render_process_id() const {
@@ -53,7 +53,7 @@
   bool user_gesture_;
   bool opener_suppressed_;
   int render_process_id_;
-  int opener_id_;
+  int opener_render_frame_id_;
 };
 
 #endif  // CHROME_BROWSER_UI_BLOCKED_CONTENT_BLOCKED_WINDOW_PARAMS_H_
diff --git a/chrome/browser/ui/bookmarks/bookmark_unittest.cc b/chrome/browser/ui/bookmarks/bookmark_unittest.cc
index 27f14c7..db20131 100644
--- a/chrome/browser/ui/bookmarks/bookmark_unittest.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/url_constants.h"
@@ -57,12 +58,12 @@
   }
 
  private:
-  static KeyedService* CreateTemplateURLService(
+  static scoped_ptr<KeyedService> CreateTemplateURLService(
       content::BrowserContext* profile) {
-    return new TemplateURLService(
+    return make_scoped_ptr(new TemplateURLService(
         static_cast<Profile*>(profile)->GetPrefs(),
         make_scoped_ptr(new SearchTermsData), NULL,
-        scoped_ptr<TemplateURLServiceClient>(), NULL, NULL, base::Closure());
+        scoped_ptr<TemplateURLServiceClient>(), NULL, NULL, base::Closure()));
   }
 
   DISALLOW_COPY_AND_ASSIGN(BookmarkInstantExtendedTest);
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 1cc78f2..f9be85aa 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1301,6 +1301,10 @@
   return true;
 }
 
+content::SecurityStyle Browser::GetSecurityStyle(WebContents* web_contents) {
+  return ConnectionSecurityHelper::GetSecurityStyleForWebContents(web_contents);
+}
+
 bool Browser::IsMouseLocked() const {
   return exclusive_access_manager_->mouse_lock_controller()->IsMouseLocked();
 }
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index c4a3a62c..6b5e907 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -462,6 +462,8 @@
   bool CanDragEnter(content::WebContents* source,
                     const content::DropData& data,
                     blink::WebDragOperationsMask operations_allowed) override;
+  content::SecurityStyle GetSecurityStyle(
+      content::WebContents* web_contents) override;
 
   bool is_type_tabbed() const { return type_ == TYPE_TABBED; }
   bool is_type_popup() const { return type_ == TYPE_POPUP; }
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 451c41f..da40c21 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -316,6 +316,51 @@
   DISALLOW_COPY_AND_ASSIGN(RenderViewSizeObserver);
 };
 
+void ProceedThroughInterstitial(content::WebContents* web_contents) {
+  InterstitialPage* interstitial_page = web_contents->GetInterstitialPage();
+  ASSERT_TRUE(interstitial_page);
+
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<NavigationController>(&web_contents->GetController()));
+  interstitial_page->Proceed();
+  observer.Wait();
+}
+
+bool GetFilePathWithHostAndPortReplacement(
+    const std::string& original_file_path,
+    const net::HostPortPair& host_port_pair,
+    std::string* replacement_path) {
+  std::vector<net::SpawnedTestServer::StringPair> replacement_text;
+  replacement_text.push_back(
+      make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()));
+  return net::SpawnedTestServer::GetFilePathWithReplacements(
+      original_file_path, replacement_text, replacement_path);
+}
+
+// A WebContentsObserver useful for testing the SecurityStyleChanged()
+// method: it keeps track of the latest security style that was fired.
+class SecurityStyleTestObserver : public WebContentsObserver {
+ public:
+  explicit SecurityStyleTestObserver(content::WebContents* web_contents)
+      : content::WebContentsObserver(web_contents),
+        latest_security_style_(content::SECURITY_STYLE_UNKNOWN) {}
+  ~SecurityStyleTestObserver() override {}
+
+  void SecurityStyleChanged(content::SecurityStyle security_style) override {
+    latest_security_style_ = security_style;
+  }
+
+  content::SecurityStyle latest_security_style() const {
+    return latest_security_style_;
+  }
+
+ private:
+  content::SecurityStyle latest_security_style_;
+
+  DISALLOW_COPY_AND_ASSIGN(SecurityStyleTestObserver);
+};
+
 }  // namespace
 
 class BrowserTest : public ExtensionBrowserTest {
@@ -2768,3 +2813,56 @@
   EXPECT_TRUE(chrome::CanDuplicateTabAt(browser(), 0));
   EXPECT_TRUE(chrome::CanDuplicateTabAt(browser(), 1));
 }
+
+// Tests that the WebContentsObserver::SecurityStyleChanged event fires
+// with the current style on HTTP, broken HTTPS, and valid HTTPS pages.
+IN_PROC_BROWSER_TEST_F(BrowserTest, SecurityStyleChangedObserver) {
+  net::SpawnedTestServer https_test_server(net::SpawnedTestServer::TYPE_HTTPS,
+                                           net::SpawnedTestServer::kLocalhost,
+                                           base::FilePath(kDocRoot));
+  net::SpawnedTestServer https_test_server_expired(
+      net::SpawnedTestServer::TYPE_HTTPS,
+      net::SpawnedTestServer::SSLOptions(
+          net::SpawnedTestServer::SSLOptions::CERT_EXPIRED),
+      base::FilePath(kDocRoot));
+
+  ASSERT_TRUE(https_test_server.Start());
+  ASSERT_TRUE(https_test_server_expired.Start());
+  ASSERT_TRUE(test_server()->Start());
+
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  SecurityStyleTestObserver observer(web_contents);
+
+  // Visit an HTTP url.
+  GURL http_url(test_server()->GetURL(std::string()));
+  ui_test_utils::NavigateToURL(browser(), http_url);
+  EXPECT_EQ(content::SECURITY_STYLE_UNAUTHENTICATED,
+            observer.latest_security_style());
+
+  // Visit a valid HTTPS url.
+  GURL valid_https_url(https_test_server.GetURL(std::string()));
+  ui_test_utils::NavigateToURL(browser(), valid_https_url);
+  EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATED,
+            observer.latest_security_style());
+
+  // Visit an (otherwise valid) HTTPS page that displays mixed content.
+  std::string replacement_path;
+  ASSERT_TRUE(GetFilePathWithHostAndPortReplacement(
+      "files/ssl/page_displays_insecure_content.html",
+      test_server()->host_port_pair(), &replacement_path));
+
+  GURL mixed_content_url(https_test_server.GetURL(replacement_path));
+  ui_test_utils::NavigateToURL(browser(), mixed_content_url);
+  EXPECT_EQ(content::SECURITY_STYLE_WARNING, observer.latest_security_style());
+
+  // Visit a broken HTTPS url. Other conditions cannot be tested after
+  // this one because once the interstitial is clicked through, all URLs
+  // for this host will remain in a broken state.
+  GURL expired_url(https_test_server_expired.GetURL(std::string()));
+  ui_test_utils::NavigateToURL(browser(), expired_url);
+
+  ProceedThroughInterstitial(web_contents);
+  EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATION_BROKEN,
+            observer.latest_security_style());
+}
diff --git a/chrome/browser/ui/browser_close_browsertest.cc b/chrome/browser/ui/browser_close_browsertest.cc
deleted file mode 100644
index e9183c69..0000000
--- a/chrome/browser/ui/browser_close_browsertest.cc
+++ /dev/null
@@ -1,569 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "base/prefs/pref_service.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/download/download_service.h"
-#include "chrome/browser/download/download_service_factory.h"
-#include "chrome/browser/download/download_test_file_activity_observer.h"
-#include "chrome/browser/net/url_request_mock_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_iterator.h"
-#include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "content/public/browser/download_item.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/download_test_observer.h"
-#include "net/test/url_request/url_request_slow_download_job.h"
-#include "ui/base/page_transition_types.h"
-
-using content::BrowserContext;
-using content::BrowserThread;
-using content::DownloadItem;
-using content::DownloadManager;
-
-class BrowserCloseTest : public InProcessBrowserTest {
- public:
-  // Structure defining test cases for DownloadsCloseCheck.
-  struct DownloadsCloseCheckCase {
-    std::string DebugString() const;
-
-    // Input
-    struct {
-      struct {
-        int windows;
-        int downloads;
-      } regular;
-      struct {
-        int windows;
-        int downloads;
-      } incognito;
-    } profile_a;
-
-    struct {
-      struct {
-        int windows;
-        int downloads;
-      } regular;
-      struct {
-        int windows;
-        int downloads;
-      } incognito;
-    } profile_b;
-
-    // We always probe a window in profile A.
-    enum { REGULAR = 0, INCOGNITO = 1 } window_to_probe;
-
-    // Output
-    Browser::DownloadClosePreventionType type;
-
-    // Unchecked if type == DOWNLOAD_CLOSE_OK.
-    int num_blocking;
-  };
-
- protected:
-  void SetUpOnMainThread() override {
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
-  }
-
-  // Create a second profile to work within multi-profile.
-  Profile* CreateSecondProfile() {
-    base::FilePath user_data_dir;
-    PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-
-    if (!second_profile_data_dir_.CreateUniqueTempDirUnderPath(user_data_dir))
-      return NULL;
-
-    Profile* second_profile =
-        g_browser_process->profile_manager()->GetProfile(
-            second_profile_data_dir_.path());
-    if (!second_profile)
-      return NULL;
-
-    bool result = second_profile_downloads_dir_.CreateUniqueTempDir();
-    if (!result)
-      return NULL;
-    second_profile->GetPrefs()->SetFilePath(
-        prefs::kDownloadDefaultDirectory,
-        second_profile_downloads_dir_.path());
-
-    return second_profile;
-  }
-
-  // Create |num_downloads| number of downloads that are stalled
-  // (will quickly get to a place where the server won't
-  // provide any more data) so that we can test closing the
-  // browser with active downloads.
-  void CreateStalledDownloads(Browser* browser, int num_downloads) {
-    GURL url(net::URLRequestSlowDownloadJob::kKnownSizeUrl);
-
-    if (num_downloads == 0)
-      return;
-
-    // Setup an observer waiting for the given number of downloads
-    // to get to IN_PROGRESS.
-    DownloadManager* download_manager =
-        BrowserContext::GetDownloadManager(browser->profile());
-    scoped_ptr<content::DownloadTestObserver> observer(
-        new content::DownloadTestObserverInProgress(download_manager,
-                                                    num_downloads));
-
-    // Set of that number of downloads.
-    size_t count_downloads = num_downloads;
-    while (num_downloads--)
-      ui_test_utils::NavigateToURLWithDisposition(
-          browser, url, NEW_BACKGROUND_TAB,
-          ui_test_utils::BROWSER_TEST_NONE);
-
-    // Wait for them.
-    observer->WaitForFinished();
-    EXPECT_EQ(count_downloads,
-              observer->NumDownloadsSeenInState(DownloadItem::IN_PROGRESS));
-  }
-
-  // All all downloads created in CreateStalledDownloads() to
-  // complete, and block in this routine until they do complete.
-  void CompleteAllDownloads(Browser* browser) {
-    GURL finish_url(net::URLRequestSlowDownloadJob::kFinishDownloadUrl);
-    ui_test_utils::NavigateToURL(browser, finish_url);
-
-    // Go through and, for every single profile, wait until there are
-    // no active downloads on that download manager.
-    std::vector<Profile*> profiles(
-        g_browser_process->profile_manager()->GetLoadedProfiles());
-    for (std::vector<Profile*>::const_iterator pit = profiles.begin();
-         pit != profiles.end(); ++pit) {
-      DownloadService* download_service =
-          DownloadServiceFactory::GetForBrowserContext(*pit);
-      if (download_service->HasCreatedDownloadManager()) {
-        DownloadManager *mgr = BrowserContext::GetDownloadManager(*pit);
-        scoped_refptr<content::DownloadTestFlushObserver> observer(
-            new content::DownloadTestFlushObserver(mgr));
-        observer->WaitForFlush();
-      }
-      if ((*pit)->HasOffTheRecordProfile()) {
-        DownloadService* incognito_download_service =
-          DownloadServiceFactory::GetForBrowserContext(
-              (*pit)->GetOffTheRecordProfile());
-        if (incognito_download_service->HasCreatedDownloadManager()) {
-          DownloadManager *mgr = BrowserContext::GetDownloadManager(
-              (*pit)->GetOffTheRecordProfile());
-          scoped_refptr<content::DownloadTestFlushObserver> observer(
-              new content::DownloadTestFlushObserver(mgr));
-          observer->WaitForFlush();
-        }
-      }
-    }
-  }
-
-  // Create a Browser (with associated window) on the specified profile.
-  Browser* CreateBrowserOnProfile(Profile* profile,
-                                  chrome::HostDesktopType host_desktop_type) {
-    Browser* new_browser =
-        new Browser(Browser::CreateParams(profile, host_desktop_type));
-    chrome::AddSelectedTabWithURL(new_browser,
-                                  GURL(url::kAboutBlankURL),
-                                  ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
-    content::WaitForLoadStop(
-        new_browser->tab_strip_model()->GetActiveWebContents());
-    new_browser->window()->Show();
-    return new_browser;
-  }
-
-  // Adjust the number of browsers and associated windows up or down
-  // to |num_windows|.  This routine assumes that there is only a single
-  // browser associated with the profile on entry.  |*base_browser| contains
-  // this browser, and the profile is derived from that browser.  On output,
-  // if |*base_browser| was destroyed (because |num_windows == 0|), NULL
-  // is assigned to that memory location.
-  bool AdjustBrowsersOnProfile(Browser** base_browser, int num_windows) {
-    int num_downloads_blocking;
-    if (num_windows == 0) {
-      if (Browser::DOWNLOAD_CLOSE_OK !=
-          (*base_browser)->OkToCloseWithInProgressDownloads(
-              &num_downloads_blocking))
-        return false;
-      (*base_browser)->window()->Close();
-      *base_browser = 0;
-      return true;
-    }
-
-    // num_windows > 0
-    Profile* profile((*base_browser)->profile());
-    chrome::HostDesktopType host_desktop_type =
-        (*base_browser)->host_desktop_type();
-    for (int w = 1; w < num_windows; ++w) {
-      CreateBrowserOnProfile(profile, host_desktop_type);
-    }
-    return true;
-  }
-
-  int TotalUnclosedBrowsers() {
-    int count = 0;
-    for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-      if (!it->IsAttemptingToCloseBrowser())
-        count++;
-    }
-    return count;
-  }
-
-  // Note that this is invalid to call if TotalUnclosedBrowsers() == 0.
-  Browser* FirstUnclosedBrowser() {
-    for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-      if (!it->IsAttemptingToCloseBrowser())
-        return *it;
-    }
-    return NULL;
-  }
-
-  bool SetupForDownloadCloseCheck() {
-    first_profile_ = browser()->profile();
-
-    bool result = first_profile_downloads_dir_.CreateUniqueTempDir();
-    EXPECT_TRUE(result);
-    if (!result) return false;
-    first_profile_->GetPrefs()->SetFilePath(
-        prefs::kDownloadDefaultDirectory,
-        first_profile_downloads_dir_.path());
-
-    second_profile_ = CreateSecondProfile();
-    EXPECT_TRUE(second_profile_);
-    if (!second_profile_) return false;
-
-    DownloadTestFileActivityObserver(first_profile_) .EnableFileChooser(false);
-    DownloadTestFileActivityObserver(second_profile_).EnableFileChooser(false);
-    return true;
-  }
-
-  // Test a specific DownloadsCloseCheckCase.  Returns false if
-  // an assertion has failed and the test should be aborted.
-  bool ExecuteDownloadCloseCheckCase(size_t i) {
-    const DownloadsCloseCheckCase& check_case(download_close_check_cases[i]);
-    SCOPED_TRACE(testing::Message() << "Case" << i
-                                    << ": " << check_case.DebugString());
-
-    // Test invariant: so that we don't actually try and close the browser,
-    // we always enter the function with a single browser window open on the
-    // main profile.  That means we need to exit the function the same way.
-    // So we setup everything except for the |first_profile_| regular, and then
-    // flip the bit on the main window.
-    // Note that this means that browser() is unreliable in the context
-    // of this function or its callers; we'll be killing that main window
-    // and recreating it fairly frequently.
-    int unclosed_browsers = TotalUnclosedBrowsers();
-    EXPECT_EQ(1, unclosed_browsers);
-    if (1 != unclosed_browsers)
-      return false;
-
-    Browser* entry_browser = FirstUnclosedBrowser();
-    EXPECT_EQ(first_profile_, entry_browser->profile());
-    if (first_profile_ != entry_browser->profile())
-      return false;
-    int total_download_count =
-        DownloadService::NonMaliciousDownloadCountAllProfiles();
-    EXPECT_EQ(0, total_download_count);
-    if (0 != total_download_count)
-      return false;
-    Profile* first_profile_incognito = first_profile_->GetOffTheRecordProfile();
-    Profile* second_profile_incognito =
-        second_profile_->GetOffTheRecordProfile();
-    DownloadTestFileActivityObserver(first_profile_incognito)
-        .EnableFileChooser(false);
-    DownloadTestFileActivityObserver(second_profile_incognito)
-        .EnableFileChooser(false);
-
-    // For simplicty of coding, we create a window on each profile so that
-    // we can easily create downloads, then we destroy or create windows
-    // as necessary.
-    chrome::HostDesktopType host_desktop_type =
-        entry_browser->host_desktop_type();
-    Browser* browser_a_regular(CreateBrowserOnProfile(first_profile_,
-                                                      host_desktop_type));
-    Browser* browser_a_incognito(
-        CreateBrowserOnProfile(first_profile_incognito, host_desktop_type));
-    Browser* browser_b_regular(CreateBrowserOnProfile(second_profile_,
-                                                      host_desktop_type));
-    Browser* browser_b_incognito(
-        CreateBrowserOnProfile(second_profile_incognito, host_desktop_type));
-
-    // Kill our entry browser.
-    entry_browser->window()->Close();
-    entry_browser = NULL;
-
-    // Create all downloads needed.
-    CreateStalledDownloads(
-        browser_a_regular, check_case.profile_a.regular.downloads);
-    CreateStalledDownloads(
-        browser_a_incognito, check_case.profile_a.incognito.downloads);
-    CreateStalledDownloads(
-        browser_b_regular, check_case.profile_b.regular.downloads);
-    CreateStalledDownloads(
-        browser_b_incognito, check_case.profile_b.incognito.downloads);
-
-    // Adjust the windows
-    Browser** browsers[] = {
-      &browser_a_regular, &browser_a_incognito,
-      &browser_b_regular, &browser_b_incognito
-    };
-    int window_counts[] = {
-      check_case.profile_a.regular.windows,
-      check_case.profile_a.incognito.windows,
-      check_case.profile_b.regular.windows,
-      check_case.profile_b.incognito.windows,
-    };
-    for (size_t j = 0; j < arraysize(browsers); ++j) {
-      bool result = AdjustBrowsersOnProfile(browsers[j], window_counts[j]);
-      EXPECT_TRUE(result);
-      if (!result)
-        return false;
-    }
-    content::RunAllPendingInMessageLoop();
-
-    // All that work, for this one little test.
-    EXPECT_TRUE((check_case.window_to_probe ==
-                 DownloadsCloseCheckCase::REGULAR) ||
-                (check_case.window_to_probe ==
-                 DownloadsCloseCheckCase::INCOGNITO));
-    if (!((check_case.window_to_probe ==
-           DownloadsCloseCheckCase::REGULAR) ||
-          (check_case.window_to_probe ==
-           DownloadsCloseCheckCase::INCOGNITO)))
-      return false;
-
-    int num_downloads_blocking;
-    Browser* browser_to_probe =
-        (check_case.window_to_probe == DownloadsCloseCheckCase::REGULAR ?
-         browser_a_regular :
-         browser_a_incognito);
-    Browser::DownloadClosePreventionType type =
-        browser_to_probe->OkToCloseWithInProgressDownloads(
-            &num_downloads_blocking);
-    EXPECT_EQ(check_case.type, type);
-    if (type != Browser::DOWNLOAD_CLOSE_OK)
-      EXPECT_EQ(check_case.num_blocking, num_downloads_blocking);
-
-    // Release all the downloads.
-    CompleteAllDownloads(browser_to_probe);
-
-    // Create a new main window and kill everything else.
-    entry_browser = CreateBrowserOnProfile(first_profile_, host_desktop_type);
-    for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-      if ((*it) != entry_browser) {
-        if (!it->window()) {
-          ADD_FAILURE();
-          return false;
-        }
-        it->window()->Close();
-      }
-    }
-    content::RunAllPendingInMessageLoop();
-
-    return true;
-  }
-
-  static const DownloadsCloseCheckCase download_close_check_cases[];
-
-  // DownloadCloseCheck variables.
-  Profile* first_profile_;
-  Profile* second_profile_;
-
-  base::ScopedTempDir first_profile_downloads_dir_;
-  base::ScopedTempDir second_profile_data_dir_;
-  base::ScopedTempDir second_profile_downloads_dir_;
-};
-
-const BrowserCloseTest::DownloadsCloseCheckCase
-BrowserCloseTest::download_close_check_cases[] = {
-  // Top level nesting is {profile_a, profile_b}
-  // Second level nesting is {regular, incognito
-  // Third level (inner) nesting is {windows, downloads}
-
-  // Last window (incognito) triggers browser close warning.
-  {{{0, 0}, {1, 1}}, {{0, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
-   Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN, 1},
-
-  // Last incognito window triggers incognito close warning.
-  {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
-   Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE, 1},
-
-  // Last incognito window with no downloads triggers no warning.
-  {{{0, 0}, {1, 0}}, {{0, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
-   Browser::DOWNLOAD_CLOSE_OK},
-
-  // Last incognito window with window+download on another incognito profile
-  // triggers no warning.
-  {{{0, 0}, {1, 0}}, {{0, 0}, {1, 1}},
-   BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
-   Browser::DOWNLOAD_CLOSE_OK},
-
-  // Non-last incognito window triggers no warning.
-  {{{0, 0}, {2, 1}}, {{0, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
-   Browser::DOWNLOAD_CLOSE_OK},
-
-  // Non-last regular window triggers no warning.
-  {{{2, 1}, {0, 0}}, {{0, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
-   Browser::DOWNLOAD_CLOSE_OK},
-
-  // Last regular window triggers browser close.
-  {{{1, 1}, {0, 0}}, {{0, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
-   Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN, 1},
-
-  // Last regular window triggers browser close for download on different
-  // profile.
-  {{{1, 0}, {0, 0}}, {{0, 1}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
-   Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN, 1},
-
-  // Last regular window triggers no warning if incognito
-  // active (http://crbug.com/61257).
-  {{{1, 0}, {1, 1}}, {{0, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
-   Browser::DOWNLOAD_CLOSE_OK},
-
-  // Last regular window triggers no warning if other profile window active.
-  {{{1, 1}, {0, 0}}, {{1, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
-   Browser::DOWNLOAD_CLOSE_OK},
-
-  // Last regular window triggers no warning if other incognito window
-  // active.
-  {{{1, 0}, {0, 0}}, {{0, 0}, {1, 1}},
-   BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
-   Browser::DOWNLOAD_CLOSE_OK},
-
-  // Last regular window triggers no warning if incognito active.
-  {{{1, 1}, {1, 0}}, {{0, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
-   Browser::DOWNLOAD_CLOSE_OK},
-
-  // Test plural for regular.
-  {{{1, 2}, {0, 0}}, {{0, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::REGULAR,
-   Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN, 2},
-
-  // Test plural for incognito.
-  {{{1, 0}, {1, 2}}, {{0, 0}, {0, 0}},
-   BrowserCloseTest::DownloadsCloseCheckCase::INCOGNITO,
-   Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE, 2},
-};
-
-std::string BrowserCloseTest::DownloadsCloseCheckCase::DebugString() const {
-  std::string result;
-  result += "{";
-  if (profile_a.regular.windows || profile_a.regular.downloads)
-    result += base::StringPrintf("Regular profile A: (%d w, %d d), ",
-                                 profile_a.regular.windows,
-                                 profile_a.regular.downloads);
-  if (profile_a.incognito.windows || profile_a.incognito.downloads)
-    result += base::StringPrintf("Incognito profile A: (%d w, %d d), ",
-                                 profile_a.incognito.windows,
-                                 profile_a.incognito.downloads);
-  if (profile_b.regular.windows || profile_b.regular.downloads)
-    result += base::StringPrintf("Regular profile B: (%d w, %d d), ",
-                                 profile_b.regular.windows,
-                                 profile_b.regular.downloads);
-  if (profile_b.incognito.windows || profile_b.incognito.downloads)
-    result += base::StringPrintf("Incognito profile B: (%d w, %d d), ",
-                                 profile_b.incognito.windows,
-                                 profile_b.incognito.downloads);
-  result += (window_to_probe == REGULAR ? "Probe regular" :
-             window_to_probe == INCOGNITO ? "Probe incognito" :
-             "Probe unknown");
-  result += "} -> ";
-  if (type == Browser::DOWNLOAD_CLOSE_OK) {
-    result += "No warning";
-  } else {
-    result += base::StringPrintf(
-        "%s (%d downloads) warning",
-        (type == Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN ? "Browser shutdown" :
-         type == Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE ?
-         "Incognito close" : "Unknown"),
-        num_blocking);
-  }
-  return result;
-}
-
-// The following test is split into six chunks to reduce the chance
-// of hitting the 25s timeout.
-
-// This test is timing out very often under AddressSanitizer.
-// http://crbug.com/111914 and http://crbug.com/103371.
-// Crashing on Linux. http://crbug.com/100566
-// Timing out on XP debug. http://crbug.com/111914
-// Timing out, http://crbug.com/159449 .
-
-#define MAYBE_DownloadsCloseCheck_0 DISABLED_DownloadsCloseCheck_0
-#define MAYBE_DownloadsCloseCheck_1 DISABLED_DownloadsCloseCheck_1
-#define MAYBE_DownloadsCloseCheck_2 DISABLED_DownloadsCloseCheck_2
-#define MAYBE_DownloadsCloseCheck_3 DISABLED_DownloadsCloseCheck_3
-#define MAYBE_DownloadsCloseCheck_4 DISABLED_DownloadsCloseCheck_4
-#define MAYBE_DownloadsCloseCheck_5 DISABLED_DownloadsCloseCheck_5
-
-IN_PROC_BROWSER_TEST_F(BrowserCloseTest, MAYBE_DownloadsCloseCheck_0) {
-  ASSERT_TRUE(SetupForDownloadCloseCheck());
-  for (size_t i = 0; i < arraysize(download_close_check_cases) / 6; ++i) {
-    ExecuteDownloadCloseCheckCase(i);
-  }
-}
-
-IN_PROC_BROWSER_TEST_F(BrowserCloseTest, MAYBE_DownloadsCloseCheck_1) {
-  ASSERT_TRUE(SetupForDownloadCloseCheck());
-  for (size_t i = arraysize(download_close_check_cases) / 6;
-       i < 2 * arraysize(download_close_check_cases) / 6; ++i) {
-    ExecuteDownloadCloseCheckCase(i);
-  }
-}
-
-IN_PROC_BROWSER_TEST_F(BrowserCloseTest, MAYBE_DownloadsCloseCheck_2) {
-  ASSERT_TRUE(SetupForDownloadCloseCheck());
-  for (size_t i = 2 * arraysize(download_close_check_cases) / 6;
-       i < 3 * arraysize(download_close_check_cases) / 6; ++i) {
-    ExecuteDownloadCloseCheckCase(i);
-  }
-}
-
-IN_PROC_BROWSER_TEST_F(BrowserCloseTest, MAYBE_DownloadsCloseCheck_3) {
-  ASSERT_TRUE(SetupForDownloadCloseCheck());
-  for (size_t i = 3 * arraysize(download_close_check_cases) / 6;
-       i < 4 * arraysize(download_close_check_cases) / 6; ++i) {
-    ExecuteDownloadCloseCheckCase(i);
-  }
-}
-
-IN_PROC_BROWSER_TEST_F(BrowserCloseTest, MAYBE_DownloadsCloseCheck_4) {
-  ASSERT_TRUE(SetupForDownloadCloseCheck());
-  for (size_t i = 4 * arraysize(download_close_check_cases) / 6;
-       i < 5 * arraysize(download_close_check_cases) / 6; ++i) {
-    ExecuteDownloadCloseCheckCase(i);
-  }
-}
-
-IN_PROC_BROWSER_TEST_F(BrowserCloseTest, MAYBE_DownloadsCloseCheck_5) {
-  ASSERT_TRUE(SetupForDownloadCloseCheck());
-  for (size_t i = 5 * arraysize(download_close_check_cases) / 6;
-       i < 6 * arraysize(download_close_check_cases) / 6; ++i) {
-    ExecuteDownloadCloseCheckCase(i);
-  }
-}
diff --git a/chrome/browser/ui/browser_close_unittest.cc b/chrome/browser/ui/browser_close_unittest.cc
new file mode 100644
index 0000000..5121265
--- /dev/null
+++ b/chrome/browser/ui/browser_close_unittest.cc
@@ -0,0 +1,347 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/download/chrome_download_manager_delegate.h"
+#include "chrome/browser/download/download_service.h"
+#include "chrome/browser/download/download_service_factory.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/test/base/test_browser_window.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class MockDownloadService : public DownloadService {
+ public:
+  MockDownloadService() : download_count_(0) {}
+  ~MockDownloadService() override {}
+
+  // All methods that aren't expected to be called in the execution of
+  // this unit test are marked to result in test failure.  Using a simple
+  // mock for this class should be re-evaluated if any of these
+  // methods are being called; it may mean that a more fully featured
+  // DownloadService implementation is needed.
+
+  void SetDownloadCount(int download_count) {
+    download_count_ = download_count;
+  }
+
+  // DownloadService
+  ChromeDownloadManagerDelegate* GetDownloadManagerDelegate() override {
+    ADD_FAILURE();
+    return nullptr;
+  }
+
+  DownloadHistory* GetDownloadHistory() override {
+    ADD_FAILURE();
+    return nullptr;
+  }
+
+#if defined(ENABLE_EXTENSIONS)
+  extensions::ExtensionDownloadsEventRouter* GetExtensionEventRouter()
+      override {
+    ADD_FAILURE();
+    return nullptr;
+  }
+#endif
+  bool HasCreatedDownloadManager() override { return true; }
+
+  int NonMaliciousDownloadCount() const override { return download_count_; }
+
+  void CancelDownloads() override {}
+
+  void SetDownloadManagerDelegateForTesting(
+      scoped_ptr<ChromeDownloadManagerDelegate> delegate) override {
+    ADD_FAILURE();
+  }
+
+  bool IsShelfEnabled() override {
+    return true;
+  }
+
+  // KeyedService
+  void Shutdown() override {}
+
+ private:
+  int download_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockDownloadService);
+};
+
+static scoped_ptr<KeyedService> CreateMockDownloadService(
+    content::BrowserContext* browser_context) {
+  return scoped_ptr<KeyedService>(new MockDownloadService());
+}
+
+class BrowserCloseTest : public testing::Test {
+ public:
+  BrowserCloseTest()
+      : profile_manager_(TestingBrowserProcess::GetGlobal()), name_index_(0) {}
+
+  ~BrowserCloseTest() override {}
+
+  void SetUp() override { ASSERT_TRUE(profile_manager_.SetUp()); }
+
+  void TearDown() override {
+    for (auto& browser_window_pair : browser_windows_) {
+      while (!browser_window_pair.second.empty()) {
+        TestBrowserWindow* window = browser_window_pair.second.back();
+        browser_window_pair.second.pop_back();
+        delete window;
+      }
+    }
+    for (auto& browser_pair : browsers_) {
+      while (!browser_pair.second.empty()) {
+        Browser* browser = browser_pair.second.back();
+        browser_pair.second.pop_back();
+        delete browser;
+      }
+    }
+  }
+
+  // Create a profile with the specified number of windows and downloads
+  // associated with it.
+  Profile* CreateProfile(int windows, int downloads) {
+    std::string name(base::StringPrintf("Profile_%d", ++name_index_));
+    TestingProfile* profile = profile_manager_.CreateTestingProfile(name);
+
+    ConfigureCreatedProfile(profile, windows, downloads);
+
+    return profile;
+  }
+
+  Profile* CreateIncognitoProfile(Profile* profile,
+                                  int windows,
+                                  int downloads) {
+    Profile* otr_profile = profile->GetOffTheRecordProfile();
+
+    ConfigureCreatedProfile(otr_profile, windows, downloads);
+
+    return otr_profile;
+  }
+
+  Browser* GetProfileBrowser(Profile* profile, int index) {
+    CHECK(browsers_.end() != browsers_.find(profile));
+    CHECK_GT(browsers_[profile].size(), static_cast<size_t>(index));
+
+    return browsers_[profile][index];
+  }
+
+ private:
+  void ConfigureCreatedProfile(Profile* profile,
+                               int num_windows,
+                               int num_downloads) {
+    DownloadServiceFactory::GetInstance()->SetTestingFactory(
+        profile, &CreateMockDownloadService);
+    DownloadService* download_service(
+        DownloadServiceFactory::GetForBrowserContext(profile));
+    MockDownloadService* mock_download_service(
+        static_cast<MockDownloadService*>(download_service));
+    mock_download_service->SetDownloadCount(num_downloads);
+
+    CHECK(browser_windows_.end() == browser_windows_.find(profile));
+    CHECK(browsers_.end() == browsers_.find(profile));
+
+    std::vector<TestBrowserWindow*> windows;
+    std::vector<Browser*> browsers;
+    for (int i = 0; i < num_windows; ++i) {
+      TestBrowserWindow* window = new TestBrowserWindow();
+      Browser::CreateParams params(profile, chrome::HOST_DESKTOP_TYPE_FIRST);
+      params.type = Browser::TYPE_TABBED;
+      params.window = window;
+      Browser* browser = new Browser(params);
+
+      windows.push_back(window);
+      browsers.push_back(browser);
+    }
+
+    browser_windows_[profile] = windows;
+    browsers_[profile] = browsers;
+  }
+
+  // Note that the vector elements are all owned by this class and must be
+  // cleaned up.
+  std::map<Profile*, std::vector<TestBrowserWindow*>> browser_windows_;
+  std::map<Profile*, std::vector<Browser*>> browsers_;
+
+  content::TestBrowserThreadBundle thread_bundle_;
+  TestingProfileManager profile_manager_;
+  int name_index_;
+};
+
+// Last window close (incognito window) will trigger warning.
+TEST_F(BrowserCloseTest, LastWindowIncognito) {
+  Profile* profile = CreateProfile(0, 0);
+  Profile* incognito_profile = CreateIncognitoProfile(profile, 1, 1);
+  Browser* browser = GetProfileBrowser(incognito_profile, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+  EXPECT_EQ(num_downloads_blocking, 1);
+}
+
+// Last incognito window close triggers incognito warning.
+TEST_F(BrowserCloseTest, LastIncognito) {
+  Profile* profile = CreateProfile(1, 0);
+  Profile* incognito_profile = CreateIncognitoProfile(profile, 1, 1);
+  Browser* browser(GetProfileBrowser(incognito_profile, 0));
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+  EXPECT_EQ(num_downloads_blocking, 1);
+}
+
+// Last incognito window close with no downloads => no warning.
+TEST_F(BrowserCloseTest, LastIncognitoNoDownloads) {
+  Profile* profile = CreateProfile(0, 0);
+  Profile* incognito_profile = CreateIncognitoProfile(profile, 1, 0);
+  Browser* browser = GetProfileBrowser(incognito_profile, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_OK,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+}
+
+// Last incognito window with window+download on another incognito profile
+// => no warning.
+TEST_F(BrowserCloseTest, NoIncognitoCrossChat) {
+  Profile* profile1 = CreateProfile(0, 0);
+  Profile* incognito_profile1 = CreateIncognitoProfile(profile1, 1, 0);
+  Profile* profile2 = CreateProfile(0, 0);
+  CreateIncognitoProfile(profile2, 1, 1);
+
+  Browser* browser = GetProfileBrowser(incognito_profile1, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_OK,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+}
+
+// Non-last incognito window => no warning.
+TEST_F(BrowserCloseTest, NonLastIncognito) {
+  Profile* profile = CreateProfile(0, 0);
+  Profile* incognito_profile = CreateIncognitoProfile(profile, 2, 1);
+  Browser* browser = GetProfileBrowser(incognito_profile, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_OK,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+}
+
+// Non-last regular window => no warning.
+TEST_F(BrowserCloseTest, NonLastRegular) {
+  Profile* profile = CreateProfile(2, 1);
+  Browser* browser = GetProfileBrowser(profile, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_OK,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+}
+
+// Last regular window triggers browser close warning.
+TEST_F(BrowserCloseTest, LastRegular) {
+  Profile* profile = CreateProfile(1, 1);
+  Browser* browser = GetProfileBrowser(profile, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+  EXPECT_EQ(num_downloads_blocking, 1);
+}
+
+// Last regular window triggers browser close warning if download is on a
+// different profile.
+TEST_F(BrowserCloseTest, LastRegularDifferentProfile) {
+  Profile* profile1 = CreateProfile(1, 0);
+  CreateProfile(0, 1);
+
+  Browser* browser = GetProfileBrowser(profile1, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+  EXPECT_EQ(num_downloads_blocking, 1);
+}
+
+// Last regular + incognito window + download => no warning.
+TEST_F(BrowserCloseTest, LastRegularPlusIncognito) {
+  Profile* profile = CreateProfile(1, 0);
+  CreateIncognitoProfile(profile, 1, 1);
+
+  Browser* browser = GetProfileBrowser(profile, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_OK,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+}
+
+// Last regular window + window on other profile => no warning.
+TEST_F(BrowserCloseTest, LastRegularPlusOtherProfile) {
+  Profile* profile = CreateProfile(1, 1);
+  CreateProfile(1, 0);
+
+  Browser* browser = GetProfileBrowser(profile, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_OK,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+}
+
+// Last regular window + window on other incognito profile => no warning.
+TEST_F(BrowserCloseTest, LastRegularPlusOtherIncognito) {
+  Profile* profile1 = CreateProfile(1, 0);
+  Profile* profile2 = CreateProfile(0, 0);
+  CreateIncognitoProfile(profile2, 1, 1);
+
+  Browser* browser = GetProfileBrowser(profile1, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_OK,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+}
+
+// Last regular + download + incognito window => no warning.
+TEST_F(BrowserCloseTest, LastRegularPlusIncognito2) {
+  Profile* profile = CreateProfile(1, 1);
+  CreateIncognitoProfile(profile, 1, 0);
+
+  Browser* browser = GetProfileBrowser(profile, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_OK,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+}
+
+// Multiple downloads are recognized.
+TEST_F(BrowserCloseTest, Plural) {
+  Profile* profile = CreateProfile(1, 2);
+
+  Browser* browser = GetProfileBrowser(profile, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+  EXPECT_EQ(2, num_downloads_blocking);
+}
+
+// Multiple downloads are recognized for incognito.
+TEST_F(BrowserCloseTest, PluralIncognito) {
+  Profile* profile = CreateProfile(1, 0);
+  Profile* incognito_profile = CreateIncognitoProfile(profile, 1, 2);
+
+  Browser* browser = GetProfileBrowser(incognito_profile, 0);
+
+  int num_downloads_blocking = 0;
+  EXPECT_EQ(Browser::DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE,
+            browser->OkToCloseWithInProgressDownloads(&num_downloads_blocking));
+  EXPECT_EQ(2, num_downloads_blocking);
+}
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc
index 7ab288b..196b0d9 100644
--- a/chrome/browser/ui/browser_navigator_browsertest.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -1291,10 +1291,9 @@
     observer.Wait();
   }
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  EXPECT_TRUE(StartsWithASCII(
+  EXPECT_TRUE(base::StartsWithASCII(
       browser()->tab_strip_model()->GetActiveWebContents()->GetURL().spec(),
-      chrome::kChromeUIBookmarksURL,
-      true));
+      chrome::kChromeUIBookmarksURL, true));
 }
 
 IN_PROC_BROWSER_TEST_F(BrowserNavigatorTest,
diff --git a/chrome/browser/ui/cocoa/DEPS b/chrome/browser/ui/cocoa/DEPS
index 2fedb51b..c536acc 100644
--- a/chrome/browser/ui/cocoa/DEPS
+++ b/chrome/browser/ui/cocoa/DEPS
@@ -2,4 +2,18 @@
   "+third_party/apple_sample_code",  # Apple code ImageAndTextCell.
   "+third_party/molokocacao",  # For NSBezierPath additions.
   "+third_party/ocmock",  # For unit tests.
+  # Tooklit-views dependencies shouldn't be introduced here except for special
+  # cases below.
+  "-ui/views",
 ]
+
+specific_include_rules = {
+  # Allow access to toolkit-views for specific bridging classes to integrate
+  # with a Cocoa browser window. These need to have "_views" somewhere in the
+  # file name. Mac-specific toolkit-views code that doesn't need to interact
+  # with a Cocoa browser should go under chrome/browser/ui/views.
+  ".*(_views).*\.(cc|h|mm)$": [
+    "+chrome/browser/ui/views",
+    "+ui/views",
+  ],
+}
diff --git a/chrome/browser/ui/cocoa/OWNERS b/chrome/browser/ui/cocoa/OWNERS
index 2f7e46b..59c98e4e 100644
--- a/chrome/browser/ui/cocoa/OWNERS
+++ b/chrome/browser/ui/cocoa/OWNERS
@@ -7,4 +7,5 @@
 rohitrao@chromium.org
 rsesek@chromium.org
 shess@chromium.org
+tapted@chromium.org
 thakis@chromium.org
diff --git a/chrome/browser/ui/cocoa/apps/chrome_app_window_client_cocoa.mm b/chrome/browser/ui/cocoa/apps/chrome_app_window_client_cocoa.mm
deleted file mode 100644
index 5a86433..0000000
--- a/chrome/browser/ui/cocoa/apps/chrome_app_window_client_cocoa.mm
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/apps/chrome_app_window_client.h"
-
-#import "chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h"
-
-// static
-extensions::NativeAppWindow* ChromeAppWindowClient::CreateNativeAppWindowImpl(
-    extensions::AppWindow* app_window,
-    const extensions::AppWindow::CreateParams& params) {
-  return new NativeAppWindowCocoa(app_window, params);
-}
diff --git a/chrome/browser/ui/cocoa/apps/chrome_app_window_client_views_cocoa.mm b/chrome/browser/ui/cocoa/apps/chrome_app_window_client_views_cocoa.mm
new file mode 100644
index 0000000..5185df5
--- /dev/null
+++ b/chrome/browser/ui/cocoa/apps/chrome_app_window_client_views_cocoa.mm
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/apps/chrome_app_window_client.h"
+
+#include "base/command_line.h"
+#import "chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h"
+#include "chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h"
+#include "chrome/common/chrome_switches.h"
+
+namespace {
+
+bool UseMacViewsNativeAppWindows() {
+  const base::CommandLine* command_line =
+      base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableMacViewsNativeAppWindows))
+    return true;
+  if (command_line->HasSwitch(switches::kDisableMacViewsNativeAppWindows))
+    return false;
+  return false;  // Current default.
+}
+
+}  // namespace
+
+// static
+extensions::NativeAppWindow* ChromeAppWindowClient::CreateNativeAppWindowImpl(
+    extensions::AppWindow* app_window,
+    const extensions::AppWindow::CreateParams& params) {
+  if (UseMacViewsNativeAppWindows()) {
+    ChromeNativeAppWindowViewsMac* window = new ChromeNativeAppWindowViewsMac;
+    window->Init(app_window, params);
+    return window;
+  }
+
+  return new NativeAppWindowCocoa(app_window, params);
+}
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
index 080cfce..a8130c75 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
@@ -763,10 +763,7 @@
 }
 
 void NativeAppWindowCocoa::WindowDidEnterFullscreen() {
-  if (!is_fullscreen_) {
-    is_fullscreen_ = true;
-    app_window_->OSFullscreen();
-  }
+  is_fullscreen_ = true;
   app_window_->OnNativeWindowChanged();
 }
 
@@ -775,7 +772,6 @@
   if (!shows_fullscreen_controls_)
     gfx::SetNSWindowCanFullscreen(window(), false);
 
-  app_window_->Restore();
   app_window_->OnNativeWindowChanged();
 }
 
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
index 6c0d454..7ca858a 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file tests whichever implementation of NativeAppWindow is used.
-// I.e. it could be NativeAppWindowCocoa or ChromeNativeAppWindowViewsMac.
 #include "extensions/browser/app_window/native_app_window.h"
 
 #import <Cocoa/Cocoa.h>
@@ -20,12 +18,14 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #import "chrome/browser/ui/test/scoped_fake_nswindow_main_status.h"
+#include "chrome/common/chrome_switches.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/common/constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #import "ui/base/test/nswindow_fullscreen_notification_waiter.h"
+#import "ui/gfx/mac/nswindow_frame_controls.h"
 
 using extensions::AppWindow;
 using extensions::PlatformAppBrowserTest;
@@ -36,10 +36,21 @@
 
 namespace {
 
-class NativeAppWindowCocoaBrowserTest : public PlatformAppBrowserTest {
+// The param selects whether to use ChromeNativeAppWindowViewsMac, otherwise it
+// will use NativeAppWindowCocoa.
+class NativeAppWindowCocoaBrowserTest
+    : public testing::WithParamInterface<bool>,
+      public PlatformAppBrowserTest {
  protected:
   NativeAppWindowCocoaBrowserTest() {}
 
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    PlatformAppBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(
+        GetParam() ? switches::kEnableMacViewsNativeAppWindows
+                   : switches::kDisableMacViewsNativeAppWindows);
+  }
+
   void SetUpAppWithWindows(int num_windows) {
     app_ = InstallExtension(
         test_data_dir_.AppendASCII("platform_apps").AppendASCII("minimal"), 1);
@@ -65,7 +76,7 @@
 }  // namespace
 
 // Test interaction of Hide/Show() with Hide/ShowWithApp().
-IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, HideShowWithApp) {
+IN_PROC_BROWSER_TEST_P(NativeAppWindowCocoaBrowserTest, HideShowWithApp) {
   SetUpAppWithWindows(2);
   extensions::AppWindowRegistry::AppWindowList windows =
       extensions::AppWindowRegistry::Get(profile())->app_windows();
@@ -160,7 +171,7 @@
 }  // namespace
 
 // Test Hide/Show and Hide/ShowWithApp() behavior when shims are enabled.
-IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest,
+IN_PROC_BROWSER_TEST_P(NativeAppWindowCocoaBrowserTest,
                        HideShowWithAppWithShim) {
   test::AppShimHostManagerTestApi test_api(
       g_browser_process->platform_part()->app_shim_host_manager());
@@ -240,12 +251,12 @@
 
 // Test that NativeAppWindow and AppWindow fullscreen state is updated when
 // the window is fullscreened natively.
-IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, Fullscreen) {
+IN_PROC_BROWSER_TEST_P(NativeAppWindowCocoaBrowserTest, Fullscreen) {
   if (!base::mac::IsOSLionOrLater())
     return;
 
-  SetUpAppWithWindows(1);
-  AppWindow* app_window = GetFirstAppWindow();
+  extensions::AppWindow* app_window =
+      CreateTestAppWindow("{\"alwaysOnTop\": true }");
   extensions::NativeAppWindow* window = app_window->GetBaseWindow();
   NSWindow* ns_window = app_window->GetNativeWindow();
   base::scoped_nsobject<ScopedNotificationWatcher> watcher;
@@ -254,6 +265,7 @@
             app_window->fullscreen_types_for_test());
   EXPECT_FALSE(window->IsFullscreen());
   EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask);
+  EXPECT_TRUE(gfx::IsNSWindowAlwaysOnTop(ns_window));
 
   watcher.reset([[ScopedNotificationWatcher alloc]
       initWithNotification:NSWindowDidEnterFullScreenNotification
@@ -264,6 +276,7 @@
               AppWindow::FULLSCREEN_TYPE_OS);
   EXPECT_TRUE(window->IsFullscreen());
   EXPECT_TRUE([ns_window styleMask] & NSFullScreenWindowMask);
+  EXPECT_FALSE(gfx::IsNSWindowAlwaysOnTop(ns_window));
 
   watcher.reset([[ScopedNotificationWatcher alloc]
       initWithNotification:NSWindowDidExitFullScreenNotification
@@ -275,6 +288,7 @@
             app_window->fullscreen_types_for_test());
   EXPECT_FALSE(window->IsFullscreen());
   EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask);
+  EXPECT_TRUE(gfx::IsNSWindowAlwaysOnTop(ns_window));
 
   watcher.reset([[ScopedNotificationWatcher alloc]
       initWithNotification:NSWindowDidEnterFullScreenNotification
@@ -286,6 +300,7 @@
               AppWindow::FULLSCREEN_TYPE_WINDOW_API);
   EXPECT_TRUE(window->IsFullscreen());
   EXPECT_TRUE([ns_window styleMask] & NSFullScreenWindowMask);
+  EXPECT_FALSE(gfx::IsNSWindowAlwaysOnTop(ns_window));
 
   watcher.reset([[ScopedNotificationWatcher alloc]
       initWithNotification:NSWindowDidExitFullScreenNotification
@@ -296,11 +311,12 @@
             app_window->fullscreen_types_for_test());
   EXPECT_FALSE(window->IsFullscreen());
   EXPECT_FALSE([ns_window styleMask] & NSFullScreenWindowMask);
+  EXPECT_TRUE(gfx::IsNSWindowAlwaysOnTop(ns_window));
 }
 
 // Test that, in frameless windows, the web contents has the same size as the
 // window.
-IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, Frameless) {
+IN_PROC_BROWSER_TEST_P(NativeAppWindowCocoaBrowserTest, Frameless) {
   AppWindow* app_window = CreateTestAppWindow("{\"frame\": \"none\"}");
   NSWindow* ns_window = app_window->GetNativeWindow();
   NSView* web_contents = app_window->web_contents()->GetNativeView();
@@ -398,16 +414,16 @@
 
 }  // namespace
 
-IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, Controls) {
+IN_PROC_BROWSER_TEST_P(NativeAppWindowCocoaBrowserTest, Controls) {
   TestControls(CreateTestAppWindow("{}"));
 }
 
-IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, ControlsFrameless) {
+IN_PROC_BROWSER_TEST_P(NativeAppWindowCocoaBrowserTest, ControlsFrameless) {
   TestControls(CreateTestAppWindow("{\"frame\": \"none\"}"));
 }
 
 // Test that the colored frames have the correct color when active and inactive.
-IN_PROC_BROWSER_TEST_F(NativeAppWindowCocoaBrowserTest, FrameColor) {
+IN_PROC_BROWSER_TEST_P(NativeAppWindowCocoaBrowserTest, FrameColor) {
   // The hex values indicate an RGB color. When we get the NSColor later, the
   // components are CGFloats in the range [0, 1].
   extensions::AppWindow* app_window = CreateTestAppWindow(
@@ -437,3 +453,7 @@
   EXPECT_EQ(0, [color greenComponent]);
   EXPECT_EQ(0, [color blueComponent]);
 }
+
+INSTANTIATE_TEST_CASE_P(NativeAppWindowCocoaBrowserTestInstance,
+                        NativeAppWindowCocoaBrowserTest,
+                        ::testing::Bool());
diff --git a/chrome/browser/ui/cocoa/autofill/down_arrow_popup_menu_cell.mm b/chrome/browser/ui/cocoa/autofill/down_arrow_popup_menu_cell.mm
index 0c8b46b2a..43de6e9 100644
--- a/chrome/browser/ui/cocoa/autofill/down_arrow_popup_menu_cell.mm
+++ b/chrome/browser/ui/cocoa/autofill/down_arrow_popup_menu_cell.mm
@@ -41,10 +41,7 @@
   if ([title length])
     [self drawTitle:title withFrame:titleRect inView:controlView];
 
-  // Only draw custom focus ring if the 10.7 focus ring APIs are not available.
-  // TODO(groby): Remove once we build against the 10.7 SDK.
-  if (![self respondsToSelector:@selector(drawFocusRingMaskWithFrame:inView:)])
-    [super drawFocusRingWithFrame:cellFrame inView:controlView];
+  [self drawFocusRingWithFrame:cellFrame inView:controlView];
 }
 
 @end
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller.h b/chrome/browser/ui/cocoa/base_bubble_controller.h
index 1db46fe1..8bff225 100644
--- a/chrome/browser/ui/cocoa/base_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/base_bubble_controller.h
@@ -47,7 +47,7 @@
   BOOL shouldCloseOnResignKey_;
 }
 
-@property(nonatomic, readonly) NSWindow* parentWindow;
+@property(nonatomic, assign) NSWindow* parentWindow;
 // The point in base screen coordinates at which the bubble should open and the
 // arrow tip points.
 @property(nonatomic, assign) NSPoint anchorPoint;
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller.mm b/chrome/browser/ui/cocoa/base_bubble_controller.mm
index 1751625..2fb7f9a 100644
--- a/chrome/browser/ui/cocoa/base_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/base_bubble_controller.mm
@@ -32,7 +32,6 @@
 
 @implementation BaseBubbleController
 
-@synthesize parentWindow = parentWindow_;
 @synthesize anchorPoint = anchor_;
 @synthesize bubble = bubble_;
 @synthesize shouldOpenAsKeyWindow = shouldOpenAsKeyWindow_;
@@ -44,11 +43,10 @@
   nibPath = [base::mac::FrameworkBundle() pathForResource:nibPath
                                                    ofType:@"nib"];
   if ((self = [super initWithWindowNibPath:nibPath owner:self])) {
-    parentWindow_ = parentWindow;
+    [self setParentWindow:parentWindow];
     anchor_ = anchoredAt;
     shouldOpenAsKeyWindow_ = YES;
     shouldCloseOnResignKey_ = YES;
-    [self registerForNotifications];
   }
   return self;
 }
@@ -72,7 +70,7 @@
           anchoredAt:(NSPoint)anchoredAt {
   DCHECK(theWindow);
   if ((self = [super initWithWindow:theWindow])) {
-    parentWindow_ = parentWindow;
+    [self setParentWindow:parentWindow];
     shouldOpenAsKeyWindow_ = YES;
     shouldCloseOnResignKey_ = YES;
 
@@ -84,7 +82,6 @@
     [theWindow setContentView:contentView.get()];
     bubble_ = contentView.get();
 
-    [self registerForNotifications];
     [self awakeFromNib];
     [self setAnchorPoint:anchoredAt];
   }
@@ -115,6 +112,10 @@
 }
 
 - (void)registerForNotifications {
+  // No window to register notifications for.
+  if (!parentWindow_)
+    return;
+
   NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
   // Watch to see if the parent window closes, and if so, close this one.
   [center addObserver:self
@@ -134,6 +135,45 @@
                object:parentWindow_];
 }
 
+- (void)unregisterFromNotifications {
+  // No window to unregister notifications.
+  if (!parentWindow_)
+    return;
+
+  NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+  [center removeObserver:self
+                    name:NSWindowWillCloseNotification
+                  object:parentWindow_];
+  [center removeObserver:self
+                    name:NSWindowWillEnterFullScreenNotification
+                  object:parentWindow_];
+  [center removeObserver:self
+                    name:NSWindowDidResizeNotification
+                  object:parentWindow_];
+}
+
+- (NSWindow*)parentWindow {
+  return parentWindow_;
+}
+
+- (void)setParentWindow:(NSWindow*)parentWindow {
+  if (parentWindow_ == parentWindow) {
+    return;
+  }
+
+  [self unregisterFromNotifications];
+
+  if (parentWindow_ && [[self window] isVisible]) {
+    [parentWindow_ removeChildWindow:[self window]];
+    parentWindow_ = parentWindow;
+    [parentWindow_ addChildWindow:[self window] ordered:NSWindowAbove];
+  } else {
+    parentWindow_ = parentWindow;
+  }
+
+  [self registerForNotifications];
+}
+
 - (void)setAnchorPoint:(NSPoint)anchor {
   anchor_ = anchor;
   [self updateOriginFromAnchor];
@@ -179,12 +219,12 @@
 }
 
 - (void)parentWindowWillClose:(NSNotification*)notification {
-  parentWindow_ = nil;
+  [self setParentWindow:nil];
   [self close];
 }
 
 - (void)parentWindowWillBecomeFullScreen:(NSNotification*)notification {
-  parentWindow_ = nil;
+  [self setParentWindow:nil];
   [self close];
 }
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 06b489a..8d5ebeef 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -942,6 +942,34 @@
   NSView* chromeContentView = [self chromeContentView];
   BOOL autoresizesSubviews = [chromeContentView autoresizesSubviews];
   [chromeContentView setAutoresizesSubviews:NO];
+
+  // On Yosemite the toolbar can flicker when hiding or showing the bookmarks
+  // bar. Here, |chromeContentView| is set to not autoresize its subviews during
+  // the window resize. Because |chromeContentView| is not flipped, if the
+  // window is getting shorter, the toolbar will move up within the window.
+  // Soon after, a call to layoutSubviews corrects its position. Passing NO to
+  // setFrame:display: should keep the toolbarView's intermediate position
+  // hidden, as should the prior call to NSDisableScreenUpdates(). For some
+  // reason, neither prevents the toolbarView's intermediate position from
+  // becoming visible. Its subsequent appearance in its correct location causes
+  // the flicker. It may be that the Appkit assumes that updating the window
+  // immediately is not a big deal given that everything in it is layer-backed.
+  // Indeed, turning off layer backing for all ancestors of the toolbarView
+  // causes the flicker to go away.
+  //
+  // By shifting the toolbarView enough so that it's in its correct location
+  // immediately after the call to setFrame:display:, the toolbar will be in
+  // the right spot when the Appkit prematurely flushes the window contents to
+  // the screen. http://crbug.com/444080 .
+  if ([self hasToolbar]) {
+    NSView* toolbarView = [toolbarController_ view];
+    NSRect currentWindowFrame = [window frame];
+    NSRect toolbarViewFrame = [toolbarView frame];
+    toolbarViewFrame.origin.y += windowFrame.size.height -
+        currentWindowFrame.size.height;
+    [toolbarView setFrame:toolbarViewFrame];
+  }
+
   [window setFrame:windowFrame display:NO];
   [chromeContentView setAutoresizesSubviews:autoresizesSubviews];
   return YES;
@@ -2068,6 +2096,11 @@
                                                  command.accelerator());
 }
 
+// For testing purposes.
+- (PermissionBubbleCocoa*)permissionBubbleCocoa {
+  return permissionBubbleCocoa_.get();
+}
+
 @end  // @implementation BrowserWindowController
 
 @implementation BrowserWindowController(Fullscreen)
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index 42403d3..2dcfa79 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -228,6 +228,11 @@
   [self applyLayout:layout];
 
   [toolbarController_ setDividerOpacity:[self toolbarDividerOpacity]];
+
+  // Will update the location of the permission bubble when showing/hiding the
+  // top level toolbar in fullscreen.
+  if (permissionBubbleCocoa_)
+    permissionBubbleCocoa_->UpdateAnchorPoint();
 }
 
 - (void)applyTabStripLayout:(const chrome::TabStripLayout&)layout {
@@ -388,7 +393,8 @@
   if (statusBubble_)
     statusBubble_->SwitchParentWindow(destWindow);
 
-  permissionBubbleCocoa_->SwitchParentWindow(destWindow);
+  if (permissionBubbleCocoa_)
+    permissionBubbleCocoa_->SetParentWindow(destWindow);
 
   // Move the title over.
   [destWindow setTitle:[sourceWindow title]];
diff --git a/chrome/browser/ui/cocoa/hover_close_button.mm b/chrome/browser/ui/cocoa/hover_close_button.mm
index c2fed30..fbcb2ec 100644
--- a/chrome/browser/ui/cocoa/hover_close_button.mm
+++ b/chrome/browser/ui/cocoa/hover_close_button.mm
@@ -93,14 +93,6 @@
 
   switch(self.hoverState) {
     case kHoverStateMouseOver:
-      [image drawInRect:destRect
-               fromRect:imageRect
-              operation:NSCompositeSourceOver
-               fraction:1.0
-         respectFlipped:YES
-                  hints:nil];
-      break;
-
     case kHoverStateMouseDown:
       [image drawInRect:destRect
                fromRect:imageRect
@@ -137,6 +129,17 @@
   }
 }
 
+- (NSRect)focusRingMaskBounds {
+  // This override won't be needed once we link with 10.8+ SDK.
+  return [self bounds];
+}
+
+- (void)drawFocusRingMask {
+  // Match the hover image's shape.
+  NSRect circleRect = NSInsetRect([self bounds], 2, 2);
+  [[NSBezierPath bezierPathWithOvalInRect:circleRect] fill];
+}
+
 - (void)setFadeOutValue:(CGFloat)value {
   [self setNeedsDisplay];
 }
diff --git a/chrome/browser/ui/cocoa/image_button_cell.h b/chrome/browser/ui/cocoa/image_button_cell.h
index e539284c..7d93d43 100644
--- a/chrome/browser/ui/cocoa/image_button_cell.h
+++ b/chrome/browser/ui/cocoa/image_button_cell.h
@@ -75,6 +75,9 @@
 // Draws the cell's image within |cellFrame|.
 - (void)drawImageWithFrame:(NSRect)cellFrame inView:(NSView*)controlView;
 
+// Draws |image| centered within |dstRect|.
++ (void)drawImage:(NSImage*)image inRect:(NSRect)dstRect alpha:(CGFloat)alpha;
+
 // If |controlView| is a first responder then draws a blue focus ring.
 - (void)drawFocusRingWithFrame:(NSRect)cellFrame inView:(NSView*)controlView;
 
diff --git a/chrome/browser/ui/cocoa/image_button_cell.mm b/chrome/browser/ui/cocoa/image_button_cell.mm
index ac155151..1b43e70 100644
--- a/chrome/browser/ui/cocoa/image_button_cell.mm
+++ b/chrome/browser/ui/cocoa/image_button_cell.mm
@@ -5,6 +5,7 @@
 #import "chrome/browser/ui/cocoa/image_button_cell.h"
 
 #include "base/logging.h"
+#include "base/mac/mac_util.h"
 #import "chrome/browser/themes/theme_service.h"
 #import "chrome/browser/ui/cocoa/rect_path_utils.h"
 #import "chrome/browser/ui/cocoa/themed_window.h"
@@ -83,12 +84,16 @@
     }
   }
 
+  [ImageButtonCell drawImage:image inRect:cellFrame alpha:alpha];
+}
+
++ (void)drawImage:(NSImage*)image inRect:(NSRect)dstRect alpha:(CGFloat)alpha {
   NSRect imageRect;
   imageRect.size = [image size];
-  imageRect.origin.x = cellFrame.origin.x +
-    roundf((NSWidth(cellFrame) - NSWidth(imageRect)) / 2.0);
-  imageRect.origin.y = cellFrame.origin.y +
-    roundf((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0);
+  imageRect.origin.x =
+      dstRect.origin.x + roundf((NSWidth(dstRect) - NSWidth(imageRect)) / 2.0);
+  imageRect.origin.y = dstRect.origin.y +
+                       roundf((NSHeight(dstRect) - NSHeight(imageRect)) / 2.0);
 
   [image drawInRect:imageRect
            fromRect:NSZeroRect
@@ -100,10 +105,7 @@
 
 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
   [self drawImageWithFrame:cellFrame inView:controlView];
-  // Only draw custom focus ring if the 10.7 focus ring APIs are not available.
-  // TODO(groby): Remove once we build against the 10.7 SDK.
-  if (![self respondsToSelector:@selector(drawFocusRingMaskWithFrame:inView:)])
-    [self drawFocusRingWithFrame:cellFrame inView:controlView];
+  [self drawFocusRingWithFrame:cellFrame inView:controlView];
 }
 
 - (void)setImageID:(NSInteger)imageID
@@ -137,6 +139,12 @@
 }
 
 - (void)drawFocusRingWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+  // Draw custom focus ring only if AppKit won't draw one automatically.
+  // The new focus ring APIs became available with 10.7, but did not get
+  // applied to buttons (only editable text fields) until 10.8.
+  if (base::mac::IsOSMountainLionOrLater())
+    return;
+
   if (![self showsFirstResponder])
     return;
   gfx::ScopedNSGraphicsContextSaveGState scoped_state;
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
index 38b5a4e..5265755 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
@@ -722,11 +722,11 @@
 
 // Takes a destination URL, a suggested file name, & an extension (eg .webloc).
 // Returns the complete file name with extension you should use.
-// The name returned will not contain /, : or ?, will not be longer than
-// kMaxNameLength + length of extension, and will not be a file name that
-// already exists in that directory. If necessary it will try appending a space
-// and a number to the name (but before the extension) trying numbers up to and
-// including kMaxIndex.
+// The name returned will not contain /, : or ?, will not start with a dot,
+// will not be longer than kMaxNameLength + length of extension, and will not
+// be a file name that already exists in that directory. If necessary it will
+// try appending a space and a number to the name (but before the extension)
+// trying numbers up to and including kMaxIndex.
 // If the function gives up it returns nil.
 static NSString* UnusedLegalNameForNewDropFile(NSURL* saveLocation,
                                                NSString *fileName,
@@ -741,6 +741,11 @@
                                                          withString:@"-"];
   filteredName = [filteredName stringByReplacingOccurrencesOfString:@"?"
                                                          withString:@"-"];
+  filteredName =
+      [filteredName stringByReplacingOccurrencesOfString:@"."
+                                              withString:@"-"
+                                                 options:0
+                                                   range:NSMakeRange(0,1)];
 
   if ([filteredName length] > kMaxNameLength)
     filteredName = [filteredName substringToIndex:kMaxNameLength];
diff --git a/chrome/browser/ui/cocoa/new_tab_button.mm b/chrome/browser/ui/cocoa/new_tab_button.mm
index 176c80c0..02fd53d 100644
--- a/chrome/browser/ui/cocoa/new_tab_button.mm
+++ b/chrome/browser/ui/cocoa/new_tab_button.mm
@@ -56,6 +56,19 @@
   return nil;
 }
 
+- (NSRect)focusRingMaskBounds {
+  // This override won't be needed once we link with 10.8+ SDK.
+  return [self bounds];
+}
+
+- (void)drawFocusRingMask {
+  // Match the button's shape.
+  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+  NSImage* image =
+      bundle.GetNativeImageNamed(IDR_NEWTAB_BUTTON_MASK).ToNSImage();
+  [ImageButtonCell drawImage:image inRect:[self bounds] alpha:1.0];
+}
+
 // ThemedWindowDrawing implementation.
 
 - (void)windowDidChangeTheme {
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
index 7e60da9..d72200b9 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
@@ -17,9 +17,6 @@
 // provides some default initialization.
 @interface OmniboxPopupCell : NSButtonCell {
  @private
-  // The popup view parent of this cell.
-  OmniboxPopupViewMac* parent_;
-
   // The match which will be rendered for this row in omnibox dropdown.
   AutocompleteMatch match_;
 
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
index 67d7c22..9cef5fa 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
@@ -281,7 +281,7 @@
 
 @implementation OmniboxPopupCell
 
-- (id)init {
+- (instancetype)init {
   self = [super init];
   if (self) {
     [self setImagePosition:NSImageLeft];
@@ -315,9 +315,9 @@
     DCHECK(!match_.answer->second_line().text_fields().empty());
     for (const SuggestionAnswer::TextField& textField :
          match_.answer->second_line().text_fields()) {
-      NSAttributedString* as =
+      NSAttributedString* attributedString =
           CreateAnswerString(textField.text(), textField.type());
-      [answerString appendAttributedString:as];
+      [answerString appendAttributedString:attributedString];
     }
     const base::char16 space(' ');
     const SuggestionAnswer::TextField* textField =
@@ -450,7 +450,6 @@
                withContentsMaxWidth:(int*)contentsMaxWidth {
   CGFloat offset = 0.0f;
   CGFloat remainingWidth = GetContentAreaWidth(cellFrame);
-  bool isRTL = base::i18n::IsRTL();
   bool isContentsRTL = (base::i18n::RIGHT_TO_LEFT ==
       base::i18n::GetFirstStrongCharacterDirection(match_.contents));
   // Prefix may not have any characters with strong directionality, and may take
@@ -464,7 +463,7 @@
   CGFloat prefixWidth = [prefix_ size].width;
 
   CGFloat prefixOffset = 0.0f;
-  if (isRTL != isContentsRTL) {
+  if (base::i18n::IsRTL() != isContentsRTL) {
     // The contents is rendered between the contents offset extending towards
     // the start edge, while prefix is rendered in opposite direction. Ideally
     // the prefix should be rendered at |contentsOffset_|. If that is not
@@ -495,7 +494,7 @@
   return offset;
 }
 
-- (CGFloat)drawMatchPart:(NSAttributedString*)as
+- (CGFloat)drawMatchPart:(NSAttributedString*)attributedString
                withFrame:(NSRect)cellFrame
                 atOffset:(CGFloat)offset
             withMaxWidth:(int)maxWidth
@@ -506,7 +505,7 @@
   renderRect.size.width =
       std::min(NSWidth(renderRect), static_cast<CGFloat>(maxWidth));
   if (renderRect.size.width != 0) {
-    [self drawTitle:as
+    [self drawTitle:attributedString
           withFrame:FlipIfRTL(renderRect, cellFrame)
              inView:controlView];
   }
@@ -527,19 +526,19 @@
       match.GetAdditionalInfo(kACMatchPropertyContentsStartIndex),
       &contentsStartIndex);
   // Ignore invalid state.
-  if (!StartsWith(match.fill_into_edit, inputText, true)
-      || !EndsWith(match.fill_into_edit, match.contents, true)
-      || ((size_t)contentsStartIndex >= inputText.length())) {
+  if (!base::StartsWith(match.fill_into_edit, inputText, true) ||
+      !EndsWith(match.fill_into_edit, match.contents, true) ||
+      ((size_t)contentsStartIndex >= inputText.length())) {
     return 0;
   }
-  bool isRTL = base::i18n::IsRTL();
   bool isContentsRTL = (base::i18n::RIGHT_TO_LEFT ==
       base::i18n::GetFirstStrongCharacterDirection(match.contents));
 
   // Color does not matter.
-  NSAttributedString* as = CreateAttributedString(inputText, DimTextColor());
-  base::scoped_nsobject<NSTextStorage> textStorage([[NSTextStorage alloc]
-      initWithAttributedString:as]);
+  NSAttributedString* attributedString =
+      CreateAttributedString(inputText, DimTextColor());
+  base::scoped_nsobject<NSTextStorage> textStorage(
+      [[NSTextStorage alloc] initWithAttributedString:attributedString]);
   base::scoped_nsobject<NSLayoutManager> layoutManager(
       [[NSLayoutManager alloc] init]);
   base::scoped_nsobject<NSTextContainer> textContainer(
@@ -555,7 +554,7 @@
   // left edge of the string, irrespective of the directionality of UI or text.
   CGFloat glyphOffset = [layoutManager locationForGlyphAtIndex:glyphIndex].x;
 
-  CGFloat inputWidth = [as size].width;
+  CGFloat inputWidth = [attributedString size].width;
 
   // The offset obtained above may need to be corrected because the left-most
   // glyph may not have 0 offset. So we find the offset of left-most glyph, and
@@ -569,7 +568,7 @@
   // we are looking for.
   CGFloat glyphWidth = inputWidth;
 
-  for (NSUInteger i = 0; i < [as length]; i++) {
+  for (NSUInteger i = 0; i < [attributedString length]; i++) {
     if (i == charIndex) continue;
     glyphIndex = [layoutManager glyphIndexForCharacterAtIndex:i];
     CGFloat offset = [layoutManager locationForGlyphAtIndex:glyphIndex].x;
@@ -582,7 +581,7 @@
     glyphWidth = inputWidth - glyphOffset;
   if (isContentsRTL)
     glyphOffset += glyphWidth;
-  return isRTL ? (inputWidth - glyphOffset) : glyphOffset;
+  return base::i18n::IsRTL() ? (inputWidth - glyphOffset) : glyphOffset;
 }
 
 @end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h
index 3bfd3c2c..0f6d41e47 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h
@@ -33,9 +33,9 @@
 }
 
 // Create a zero-size matrix.
-- (id)initWithObserver:(OmniboxPopupMatrixObserver*)observer;
+- (instancetype)initWithObserver:(OmniboxPopupMatrixObserver*)observer;
 
-// Sets the delegate.
+// Sets the observer.
 - (void)setObserver:(OmniboxPopupMatrixObserver*)observer;
 
 // Return the currently highlighted row.  Returns -1 if no row is highlighted.
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
index 3548b9f..072547e 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
@@ -23,7 +23,7 @@
 
 @implementation OmniboxPopupMatrix
 
-- (id)initWithObserver:(OmniboxPopupMatrixObserver*)observer {
+- (instancetype)initWithObserver:(OmniboxPopupMatrixObserver*)observer {
   if ((self = [super initWithFrame:NSZeroRect])) {
     observer_ = observer;
     [self setCellClass:[OmniboxPopupCell class]];
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
index 5114a92..29ec953a 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
@@ -66,7 +66,7 @@
   void PositionPopup(const CGFloat matrixHeight);
 
   // Returns the NSImage that should be used as an icon for the given match.
-  NSImage* ImageForMatch(const AutocompleteMatch& match);
+  NSImage* ImageForMatch(const AutocompleteMatch& match) const;
 
   // Opens the URL at the given row.
   void OpenURLForRow(size_t row, WindowOpenDisposition disposition);
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
index df0fde6..fdbbdb2 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
@@ -75,8 +75,7 @@
 void OmniboxPopupViewMac::UpdatePopupAppearance() {
   DCHECK([NSThread isMainThread]);
   const AutocompleteResult& result = GetResult();
-  const size_t start_match = result.ShouldHideTopMatch() ? 1 : 0;
-  const size_t rows = result.size() - start_match;
+  const size_t rows = result.size();
   if (rows == 0) {
     [[popup_ parentWindow] removeChildWindow:popup_];
     [popup_ orderOut:nil];
@@ -107,7 +106,7 @@
   CGFloat contents_offset = -1.0f;
   for (size_t ii = 0; ii < rows; ++ii) {
     OmniboxPopupCell* cell = [matrix_ cellAtRow:ii column:0];
-    const AutocompleteMatch& match = GetResult().match_at(ii + start_match);
+    const AutocompleteMatch& match = GetResult().match_at(ii);
     [cell setImage:ImageForMatch(match)];
     [cell setMatch:match];
     // Only set the image on the one cell with match.answer.
@@ -161,19 +160,12 @@
 // This is only called by model in SetSelectedLine() after updating
 // everything.  Popup should already be visible.
 void OmniboxPopupViewMac::PaintUpdatesNow() {
-  size_t start_match = model_->result().ShouldHideTopMatch() ? 1 : 0;
-  if (start_match > model_->selected_line()) {
-    [matrix_ deselectAllCells];
-  } else {
-    [matrix_ selectCellAtRow:model_->selected_line() - start_match column:0];
-  }
-
+  [matrix_ selectCellAtRow:model_->selected_line() column:0];
 }
 
 void OmniboxPopupViewMac::OnMatrixRowSelected(OmniboxPopupMatrix* matrix,
                                               size_t row) {
-  size_t start_match = model_->result().ShouldHideTopMatch() ? 1 : 0;
-  model_->SetSelectedLine(row + start_match, false, false);
+  model_->SetSelectedLine(row, false, false);
 }
 
 void OmniboxPopupViewMac::OnMatrixRowClicked(OmniboxPopupMatrix* matrix,
@@ -324,7 +316,8 @@
     [[field_ window] addChildWindow:popup_ ordered:NSWindowAbove];
 }
 
-NSImage* OmniboxPopupViewMac::ImageForMatch(const AutocompleteMatch& match) {
+NSImage* OmniboxPopupViewMac::ImageForMatch(
+    const AutocompleteMatch& match) const {
   gfx::Image image = model_->GetIconIfExtensionMatch(match);
   if (!image.IsEmpty())
     return image.AsNSImage();
@@ -336,8 +329,6 @@
 
 void OmniboxPopupViewMac::OpenURLForRow(size_t row,
                                         WindowOpenDisposition disposition) {
-  size_t start_match = model_->result().ShouldHideTopMatch() ? 1 : 0;
-  row += start_match;
   DCHECK_LT(row, GetResult().size());
   omnibox_view_->OpenMatch(GetResult().match_at(row), disposition, GURL(),
                            base::string16(), row);
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
index 6ecc9368..120724768 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
@@ -157,13 +157,13 @@
   // though here we cannot really do the in-place operation they do.
   void EmphasizeURLComponents() override;
 
-  // Apply our font and paragraph style to |as|.
-  void ApplyTextStyle(NSMutableAttributedString* as);
+  // Apply our font and paragraph style to |attributedString|.
+  void ApplyTextStyle(NSMutableAttributedString* attributedString);
 
   // Calculates text attributes according to |display_text| and applies them
-  // to the given |as| object.
+  // to the given |attributedString| object.
   void ApplyTextAttributes(const base::string16& display_text,
-                           NSMutableAttributedString* as);
+                           NSMutableAttributedString* attributedString);
 
   // Return the number of UTF-16 units in the current buffer, excluding the
   // suggested text.
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
index aa59925..732f7f7 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
@@ -427,11 +427,11 @@
   }
 
   NSString* ss = base::SysUTF16ToNSString(display_text);
-  NSMutableAttributedString* as =
+  NSMutableAttributedString* attributedString =
       [[[NSMutableAttributedString alloc] initWithString:ss] autorelease];
 
-  ApplyTextAttributes(display_text, as);
-  [field_ setAttributedStringValue:as];
+  ApplyTextAttributes(display_text, attributedString);
+  [field_ setAttributedStringValue:attributedString];
 
   // TODO(shess): This may be an appropriate place to call:
   //   model()->OnChanged();
@@ -482,9 +482,11 @@
   }
 }
 
-void OmniboxViewMac::ApplyTextStyle(NSMutableAttributedString* as) {
-  [as addAttribute:NSFontAttributeName value:GetFieldFont(gfx::Font::NORMAL)
-             range:NSMakeRange(0, [as length])];
+void OmniboxViewMac::ApplyTextStyle(
+    NSMutableAttributedString* attributedString) {
+  [attributedString addAttribute:NSFontAttributeName
+                           value:GetFieldFont(gfx::Font::NORMAL)
+                           range:NSMakeRange(0, [attributedString length])];
 
   // Make a paragraph style locking in the standard line height as the maximum,
   // otherwise the baseline may shift "downwards".
@@ -494,21 +496,24 @@
   [paragraph_style setMaximumLineHeight:line_height];
   [paragraph_style setMinimumLineHeight:line_height];
   [paragraph_style setLineBreakMode:NSLineBreakByTruncatingTail];
-  [as addAttribute:NSParagraphStyleAttributeName value:paragraph_style
-             range:NSMakeRange(0, [as length])];
+  [attributedString addAttribute:NSParagraphStyleAttributeName
+                           value:paragraph_style
+                           range:NSMakeRange(0, [attributedString length])];
 }
 
-void OmniboxViewMac::ApplyTextAttributes(const base::string16& display_text,
-                                         NSMutableAttributedString* as) {
-  NSUInteger as_length = [as length];
+void OmniboxViewMac::ApplyTextAttributes(
+    const base::string16& display_text,
+    NSMutableAttributedString* attributedString) {
+  NSUInteger as_length = [attributedString length];
   NSRange as_entire_string = NSMakeRange(0, as_length);
 
-  ApplyTextStyle(as);
+  ApplyTextStyle(attributedString);
 
   // A kinda hacky way to add breaking at periods. This is what Safari does.
   // This works for IDNs too, despite the "en_US".
-  [as addAttribute:@"NSLanguage" value:@"en_US_POSIX"
-             range:as_entire_string];
+  [attributedString addAttribute:@"NSLanguage"
+                           value:@"en_US_POSIX"
+                           range:as_entire_string];
 
   url::Component scheme, host;
   AutocompleteInput::ParseForEmphasizeComponents(
@@ -518,12 +523,14 @@
       base::UTF8ToUTF16(extensions::kExtensionScheme);
   if (model()->CurrentTextIsURL() &&
       (host.is_nonempty() || grey_out_url)) {
-    [as addAttribute:NSForegroundColorAttributeName value:BaseTextColor()
-               range:as_entire_string];
+    [attributedString addAttribute:NSForegroundColorAttributeName
+                             value:BaseTextColor()
+                             range:as_entire_string];
 
     if (!grey_out_url) {
-      [as addAttribute:NSForegroundColorAttributeName value:HostTextColor()
-               range:ComponentToNSRange(host)];
+      [attributedString addAttribute:NSForegroundColorAttributeName
+                               value:HostTextColor()
+                               range:ComponentToNSRange(host)];
     }
   }
 
@@ -544,7 +551,7 @@
     } else if (security_level == ConnectionSecurityHelper::SECURITY_ERROR) {
       color = SecurityErrorSchemeColor();
       // Add a strikethrough through the scheme.
-      [as addAttribute:NSStrikethroughStyleAttributeName
+      [attributedString addAttribute:NSStrikethroughStyleAttributeName
                  value:[NSNumber numberWithInt:NSUnderlineStyleSingle]
                  range:ComponentToNSRange(scheme)];
     } else if (security_level == ConnectionSecurityHelper::SECURITY_WARNING) {
@@ -553,8 +560,9 @@
       NOTREACHED();
       color = BaseTextColor();
     }
-    [as addAttribute:NSForegroundColorAttributeName value:color
-               range:ComponentToNSRange(scheme)];
+    [attributedString addAttribute:NSForegroundColorAttributeName
+                             value:color
+                             range:ComponentToNSRange(scheme)];
   }
 }
 
diff --git a/chrome/browser/ui/cocoa/passwords/manage_password_item_view_controller.mm b/chrome/browser/ui/cocoa/passwords/manage_password_item_view_controller.mm
index c6792cfa..590034d 100644
--- a/chrome/browser/ui/cocoa/passwords/manage_password_item_view_controller.mm
+++ b/chrome/browser/ui/cocoa/passwords/manage_password_item_view_controller.mm
@@ -19,7 +19,6 @@
 #include "ui/gfx/image/image.h"
 #include "ui/native_theme/common_theme.h"
 #include "ui/resources/grit/ui_resources.h"
-#include "ui/views/layout/layout_constants.h"
 
 using namespace password_manager::mac::ui;
 
@@ -28,6 +27,10 @@
 const CGFloat kBorderWidth = 1;
 const SkColor kHoverColor = SkColorSetARGBInline(0xFF, 0xEB, 0xEB, 0xEB);
 
+// Constants shared with toolkit-views layout_constants.h.
+const CGFloat kItemLabelSpacing = 10;
+const CGFloat kRelatedControlVerticalSpacing = 8;
+
 NSColor* HoverColor() {
   return gfx::SkColorToCalibratedNSColor(kHoverColor);
 }
@@ -63,9 +66,9 @@
   const CGFloat width =
       kFramePadding +
       FirstFieldWidth() +
-      views::kItemLabelSpacing +
+      kItemLabelSpacing +
       SecondFieldWidth() +
-      views::kItemLabelSpacing +
+      kItemLabelSpacing +
       chrome_style::GetCloseButtonSize() +
       kFramePadding;
   return width;
@@ -131,7 +134,7 @@
 
     const CGFloat width = ItemWidth();
     CGFloat curX = kFramePadding;
-    CGFloat curY = views::kRelatedControlVerticalSpacing;
+    CGFloat curY = kRelatedControlVerticalSpacing;
 
     // Add the explanation text.
     NSTextField* label =
@@ -146,7 +149,7 @@
 
     // Move to the top-right of the delete button.
     curX = NSMaxX([undoButton_ frame]) + kFramePadding;
-    curY = NSMaxY([undoButton_ frame]) + views::kRelatedControlVerticalSpacing;
+    curY = NSMaxY([undoButton_ frame]) + kRelatedControlVerticalSpacing;
 
     // Update the frame.
     DCHECK_EQ(width, curX);
@@ -184,7 +187,7 @@
 
     const CGFloat width = ItemWidth();
     CGFloat curX = kFramePadding;
-    CGFloat curY = views::kRelatedControlVerticalSpacing;
+    CGFloat curY = kRelatedControlVerticalSpacing;
 
     // Add the username.
     usernameField_.reset([UsernameLabel(GetDisplayUsername(form)) retain]);
@@ -192,7 +195,7 @@
     [self addSubview:usernameField_];
 
     // Move to the right of the username and add the password.
-    curX = NSMaxX([usernameField_ frame]) + views::kItemLabelSpacing;
+    curX = NSMaxX([usernameField_ frame]) + kItemLabelSpacing;
     passwordField_.reset([PasswordLabel(form.password_value) retain]);
     [passwordField_ setFrameOrigin:NSMakePoint(curX, curY)];
     [self addSubview:passwordField_];
@@ -204,8 +207,7 @@
 
     // Move to the top-right of the delete button.
     curX = NSMaxX([deleteButton_ frame]) + kFramePadding;
-    curY =
-        NSMaxY([deleteButton_ frame]) + views::kRelatedControlVerticalSpacing;
+    curY = NSMaxY([deleteButton_ frame]) + kRelatedControlVerticalSpacing;
 
     // Update the frame.
     DCHECK_EQ(width, curX);
@@ -232,7 +234,7 @@
 - (id)initWithForm:(const autofill::PasswordForm&)form {
   if ((self = [super initWithFrame:NSZeroRect])) {
     CGFloat curX = kFramePadding;
-    CGFloat curY = views::kRelatedControlVerticalSpacing;
+    CGFloat curY = kRelatedControlVerticalSpacing;
 
     // Add the username.
     usernameField_.reset([UsernameLabel(GetDisplayUsername(form)) retain]);
@@ -240,14 +242,13 @@
     [self addSubview:usernameField_];
 
     // Move to the right of the username and add the password.
-    curX = NSMaxX([usernameField_ frame]) + views::kItemLabelSpacing;
+    curX = NSMaxX([usernameField_ frame]) + kItemLabelSpacing;
     passwordField_.reset([PasswordLabel(form.password_value) retain]);
     [passwordField_ setFrameOrigin:NSMakePoint(curX, curY)];
     [self addSubview:passwordField_];
 
     // Move to the top-right of the password.
-    curY =
-        NSMaxY([passwordField_ frame]) + views::kRelatedControlVerticalSpacing;
+    curY = NSMaxY([passwordField_ frame]) + kRelatedControlVerticalSpacing;
 
     // Update the frame.
     [self setFrameSize:NSMakeSize(ItemWidth(), curY)];
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
index ba88a32f..50dae68d 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_button_controller.mm
@@ -114,6 +114,18 @@
   ui::DrawNinePartImage(frame, imageIds, NSCompositeSourceOver, 1.0, true);
 }
 
+- (NSRect)focusRingMaskBoundsForFrame:(NSRect)cellFrame inView:(NSView*)view {
+  // This override won't be needed once we link with 10.8+ SDK.
+  return cellFrame;
+}
+
+- (void)drawFocusRingMaskWithFrame:(NSRect)frame inView:(NSView*)view {
+  // Match the bezel's shape.
+  [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 2, 2)
+                                   xRadius:2
+                                   yRadius:2] fill];
+}
+
 - (void)setIsThemedWindow:(BOOL)isThemedWindow {
   isThemedWindow_ = isThemedWindow;
 }
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.mm b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.mm
index b2688dfb..ff148e00 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.mm
@@ -31,7 +31,7 @@
 // Minimum margins on all sides.
 static const CGFloat kTabMargin = 13;
 // Maximum margin on top.
-static const CGFloat kMaxTopMargin = 100;
+static const CGFloat kMaxTopMargin = 130;
 
 @interface SadTabTextView : NSTextField
 
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
index 7e971cdf..320e008 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
@@ -48,4 +48,16 @@
   return handleMiddleClick_ && [theEvent buttonNumber] == 2;
 }
 
+- (NSRect)focusRingMaskBounds {
+  // This override won't be needed once we link with 10.8+ SDK.
+  return [self bounds];
+}
+
+- (void)drawFocusRingMask {
+  // Match the hover image's bezel.
+  [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect([self bounds], 2, 2)
+                                   xRadius:2
+                                   yRadius:2] fill];
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h b/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h
index 7a1c35a..490aa00 100644
--- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h
+++ b/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.h
@@ -38,11 +38,15 @@
   // should point.
   NSPoint GetAnchorPoint();
 
+  // Repositions the bubble. This should be called if the anchor has moved
+  // within the window.
+  void UpdateAnchorPoint();
+
   // Returns the NSWindow containing the bubble.
   NSWindow* window();
 
-  // Change the parent window to be used the next time the bubble is shown.
-  void SwitchParentWindow(NSWindow* parent);
+  // Change the parent window.
+  void SetParentWindow(NSWindow* parent);
 
   info_bubble::BubbleArrowLocation GetArrowLocation();
 
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.mm b/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.mm
index ee2f13c..8c771975 100644
--- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.mm
+++ b/chrome/browser/ui/cocoa/website_settings/permission_bubble_cocoa.mm
@@ -86,8 +86,14 @@
   return [bubbleController_ window];
 }
 
-void PermissionBubbleCocoa::SwitchParentWindow(NSWindow* parent) {
+void PermissionBubbleCocoa::UpdateAnchorPoint() {
+  [bubbleController_ setAnchorPoint:GetAnchorPoint()];
+}
+
+void PermissionBubbleCocoa::SetParentWindow(NSWindow* parent) {
   parent_window_ = parent;
+  [bubbleController_ setParentWindow:parent_window_];
+  UpdateAnchorPoint();
 }
 
 bool PermissionBubbleCocoa::HasLocationBar() {
diff --git a/chrome/browser/ui/login/login_prompt.cc b/chrome/browser/ui/login/login_prompt.cc
index 95717d5..1c955a1 100644
--- a/chrome/browser/ui/login/login_prompt.cc
+++ b/chrome/browser/ui/login/login_prompt.cc
@@ -432,9 +432,9 @@
     LoginHandler* handler,
     std::vector<PasswordForm>* password_manager_input) {
   PasswordForm dialog_form;
-  if (LowerCaseEqualsASCII(auth_info->scheme, "basic")) {
+  if (base::LowerCaseEqualsASCII(auth_info->scheme, "basic")) {
     dialog_form.scheme = PasswordForm::SCHEME_BASIC;
-  } else if (LowerCaseEqualsASCII(auth_info->scheme, "digest")) {
+  } else if (base::LowerCaseEqualsASCII(auth_info->scheme, "digest")) {
     dialog_form.scheme = PasswordForm::SCHEME_DIGEST;
   } else {
     dialog_form.scheme = PasswordForm::SCHEME_OTHER;
diff --git a/chrome/browser/ui/omnibox/omnibox_controller.cc b/chrome/browser/ui/omnibox/omnibox_controller.cc
index db2aaa10..9876ae36 100644
--- a/chrome/browser/ui/omnibox/omnibox_controller.cc
+++ b/chrome/browser/ui/omnibox/omnibox_controller.cc
@@ -39,12 +39,10 @@
 //
 // If the kAllowPrefetchNonDefaultMatch field trial is enabled we return the
 // prefetch suggestion even if it is not the default match. Otherwise we only
-// care about matches that are the default or the very first entry in the
-// dropdown (which can happen for non-default matches only if we're hiding a top
-// verbatim match) or the second entry in the dropdown (which can happen for
-// non-default matches when a top verbatim match is shown); for other matches,
-// we think the likelihood of the user selecting them is low enough that
-// prefetching isn't worth doing.
+// care about matches that are the default or the second entry in the dropdown
+// (which can happen for non-default matches when a top verbatim match is
+// shown); for other matches, we think the likelihood of the user selecting
+// them is low enough that prefetching isn't worth doing.
 const AutocompleteMatch* GetMatchToPrefetch(const AutocompleteResult& result) {
   if (chrome::ShouldAllowPrefetchNonDefaultMatch()) {
     const AutocompleteResult::const_iterator prefetch_match = std::find_if(
@@ -53,17 +51,14 @@
   }
 
   // If the default match should be prefetched, do that.
-  const AutocompleteResult::const_iterator default_match(
-      result.default_match());
+  const auto default_match = result.default_match();
   if ((default_match != result.end()) &&
       SearchProvider::ShouldPrefetch(*default_match))
     return &(*default_match);
 
   // Otherwise, if the top match is a verbatim match and the very next match
   // is prefetchable, fetch that.
-  if ((result.ShouldHideTopMatch() ||
-       result.TopMatchIsStandaloneVerbatimMatch()) &&
-      (result.size() > 1) &&
+  if (result.TopMatchIsStandaloneVerbatimMatch() && (result.size() > 1) &&
       SearchProvider::ShouldPrefetch(result.match_at(1)))
     return &result.match_at(1);
 
diff --git a/chrome/browser/ui/omnibox/omnibox_view.cc b/chrome/browser/ui/omnibox/omnibox_view.cc
index 833cdfa..177bb7ec 100644
--- a/chrome/browser/ui/omnibox/omnibox_view.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view.cc
@@ -28,7 +28,7 @@
   const base::string16 kJsPrefix(
       base::ASCIIToUTF16(url::kJavaScriptScheme) + base::ASCIIToUTF16(":"));
   base::string16 out(text);
-  while (StartsWith(out, kJsPrefix, false)) {
+  while (base::StartsWith(out, kJsPrefix, false)) {
     base::TrimWhitespace(out.substr(kJsPrefix.length()), base::TRIM_LEADING,
                          &out);
   }
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index 2083426..ef63966 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -49,6 +49,11 @@
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/gfx/geometry/point.h"
 
+// For fine-grained suppression on flaky tests.
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 using base::ASCIIToUTF16;
 using base::UTF16ToUTF8;
 using base::Time;
@@ -448,6 +453,11 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(OmniboxViewTest, MAYBE_PopupAccelerators) {
+#if defined(OS_WIN)
+  // Flaky on XP bot. http://crbug.com/499155
+  if (base::win::GetVersion() <= base::win::VERSION_XP)
+    return;
+#endif
   // Create a popup.
   Browser* popup = CreateBrowserForPopup(browser()->profile());
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(popup));
diff --git a/chrome/browser/ui/panels/panel_host.cc b/chrome/browser/ui/panels/panel_host.cc
index 8c70a68..a334dbd1 100644
--- a/chrome/browser/ui/panels/panel_host.cc
+++ b/chrome/browser/ui/panels/panel_host.cc
@@ -40,7 +40,6 @@
 PanelHost::PanelHost(Panel* panel, Profile* profile)
     : panel_(panel),
       profile_(profile),
-      extension_function_dispatcher_(profile, this),
       weak_factory_(this) {
 }
 
@@ -71,6 +70,8 @@
   PrefsTabHelper::CreateForWebContents(web_contents_.get());
   extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
       web_contents_.get());
+  extensions::ExtensionWebContentsObserver::GetForWebContents(
+      web_contents_.get())->dispatcher()->set_delegate(this);
 
   web_contents_->GetController().LoadURL(
       url, content::Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
@@ -225,23 +226,6 @@
   panel_->Close();
 }
 
-bool PanelHost::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(PanelHost, message)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void PanelHost::OnRequest(const ExtensionHostMsg_Request_Params& params) {
-  if (!web_contents_.get())
-    return;
-
-  extension_function_dispatcher_.Dispatch(params,
-                                          web_contents_->GetRenderViewHost());
-}
-
 extensions::WindowController* PanelHost::GetExtensionWindowController() const {
   return panel_->extension_window_controller();
 }
diff --git a/chrome/browser/ui/panels/panel_host.h b/chrome/browser/ui/panels/panel_host.h
index 91634b8..fda5653f 100644
--- a/chrome/browser/ui/panels/panel_host.h
+++ b/chrome/browser/ui/panels/panel_host.h
@@ -77,7 +77,6 @@
   void RenderViewCreated(content::RenderViewHost* render_view_host) override;
   void RenderProcessGone(base::TerminationStatus status) override;
   void WebContentsDestroyed() override;
-  bool OnMessageReceived(const IPC::Message& message) override;
 
   // extensions::ExtensionFunctionDispatcher::Delegate overrides.
   extensions::WindowController* GetExtensionWindowController() const override;
@@ -93,12 +92,8 @@
   // Helper to close panel via the message loop.
   void ClosePanel();
 
-  // Message handlers.
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
-
   Panel* panel_;  // Weak, owns us.
   Profile* profile_;
-  extensions::ExtensionFunctionDispatcher extension_function_dispatcher_;
 
   scoped_ptr<content::WebContents> web_contents_;
 
diff --git a/chrome/browser/ui/passwords/account_avatar_fetcher.cc b/chrome/browser/ui/passwords/account_avatar_fetcher.cc
index 2db5037..3889e11a 100644
--- a/chrome/browser/ui/passwords/account_avatar_fetcher.cc
+++ b/chrome/browser/ui/passwords/account_avatar_fetcher.cc
@@ -19,10 +19,11 @@
 
 void AccountAvatarFetcher::Start(
     net::URLRequestContextGetter* request_context) {
-  fetcher_.Start(request_context, std::string(),
-                 net::URLRequest::NEVER_CLEAR_REFERRER,
-                 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
-                     net::LOAD_MAYBE_USER_GESTURE);
+  fetcher_.Init(request_context, std::string(),
+                net::URLRequest::NEVER_CLEAR_REFERRER,
+                net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
+                    net::LOAD_MAYBE_USER_GESTURE);
+  fetcher_.Start();
 }
 
 void AccountAvatarFetcher::OnFetchComplete(const GURL& /*url*/,
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.cc b/chrome/browser/ui/prefs/prefs_tab_helper.cc
index 670e36a..19c396d2 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.cc
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.cc
@@ -137,7 +137,7 @@
     PrefChangeRegistrar* registrar,
     const char* map_name,
     const PrefChangeRegistrar::NamedChangeCallback& obs) {
-  DCHECK(StartsWithASCII(map_name, "webkit.webprefs.", true));
+  DCHECK(base::StartsWithASCII(map_name, "webkit.webprefs.", true));
 
   for (size_t i = 0; i < prefs::kWebKitScriptsForFontFamilyMapsLength; ++i) {
     const char* script = prefs::kWebKitScriptsForFontFamilyMaps[i];
@@ -149,7 +149,7 @@
 // On Windows with antialising we want to use an alternate fixed font like
 // Consolas, which looks much better than Courier New.
 bool ShouldUseAlternateDefaultFixedFont(const std::string& script) {
-  if (!StartsWithASCII(script, "courier", false))
+  if (!base::StartsWithASCII(script, "courier", false))
     return false;
   UINT smooth_type = 0;
   SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smooth_type, 0);
diff --git a/chrome/browser/ui/search/instant_extended_manual_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_manual_interactive_uitest.cc
index 7707c58..e25c471b 100644
--- a/chrome/browser/ui/search/instant_extended_manual_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_manual_interactive_uitest.cc
@@ -58,8 +58,8 @@
   void SetUpOnMainThread() override {
     const testing::TestInfo* const test_info =
         testing::UnitTest::GetInstance()->current_test_info();
-    ASSERT_TRUE(StartsWithASCII(test_info->name(), "MANUAL_", true) ||
-                StartsWithASCII(test_info->name(), "DISABLED_", true));
+    ASSERT_TRUE(base::StartsWithASCII(test_info->name(), "MANUAL_", true) ||
+                base::StartsWithASCII(test_info->name(), "DISABLED_", true));
     // Make IsOffline() return false so we don't try to use the local NTP.
     disable_network_change_notifier_.reset(
         new net::NetworkChangeNotifier::DisableForTest());
diff --git a/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc b/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc
index d3d9c4d..1bb6a04 100644
--- a/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc
+++ b/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc
@@ -51,9 +51,9 @@
 TEST_F(SessionCrashedInfoBarDelegateUnitTest, DetachingTabWithCrashedInfoBar) {
   SessionServiceFactory::SetForTestProfile(
       browser()->profile(),
-      static_cast<SessionService*>(
+      make_scoped_ptr(static_cast<SessionService*>(
           SessionServiceFactory::GetInstance()->BuildServiceInstanceFor(
-              browser()->profile())));
+              browser()->profile()))));
 
   // Create a browser which we can close during the test.
   Browser::CreateParams params(browser()->profile(),
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc b/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc
index 6d7734b2..0f24ae2 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/signin_promo.h"
@@ -48,8 +49,9 @@
 
   // Helper routine to be used in conjunction with
   // BrowserContextKeyedServiceFactory::SetTestingFactory().
-  static KeyedService* Build(content::BrowserContext* profile) {
-    return new OneClickTestProfileSyncService(static_cast<Profile*>(profile));
+  static scoped_ptr<KeyedService> Build(content::BrowserContext* profile) {
+    return make_scoped_ptr(
+        new OneClickTestProfileSyncService(static_cast<Profile*>(profile)));
   }
 
   bool FirstSetupInProgress() const override {
@@ -103,8 +105,8 @@
 };
 
 // A trivial factory to build a null service.
-KeyedService* BuildNullService(content::BrowserContext* context) {
-  return NULL;
+scoped_ptr<KeyedService> BuildNullService(content::BrowserContext* context) {
+  return nullptr;
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index 10f04cb..a87c44c 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -141,10 +141,10 @@
   if (profile_sync_service)
     profile_sync_service->SetSetupInProgress(true);
 
-  // Make sure the syncing is not suppressed, otherwise the SigninManager
+  // Make sure the syncing is requested, otherwise the SigninManager
   // will not be able to complete sucessfully.
   sync_driver::SyncPrefs sync_prefs(profile_->GetPrefs());
-  sync_prefs.SetStartSuppressed(false);
+  sync_prefs.SetSyncRequested(true);
 }
 
 void OneClickSigninSyncStarter::ConfirmSignin(const std::string& oauth_token) {
@@ -569,7 +569,7 @@
 
 ProfileSyncService* OneClickSigninSyncStarter::GetProfileSyncService() {
   ProfileSyncService* service = NULL;
-  if (profile_->IsSyncAccessible())
+  if (profile_->IsSyncAllowed())
     service = ProfileSyncServiceFactory::GetForProfile(profile_);
   return service;
 }
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc
index a2720e7..f5c74b95 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc
@@ -94,8 +94,10 @@
   int succeeded_count_;
 
  private:
-  static KeyedService* BuildSigninManager(content::BrowserContext* profile) {
-    return new FakeSigninManager(static_cast<Profile*>(profile));
+  static scoped_ptr<KeyedService> BuildSigninManager(
+      content::BrowserContext* profile) {
+    return make_scoped_ptr(
+        new FakeSigninManager(static_cast<Profile*>(profile)));
   }
 
   DISALLOW_COPY_AND_ASSIGN(OneClickSigninSyncStarterTest);
diff --git a/chrome/browser/ui/sync/sync_promo_ui.cc b/chrome/browser/ui/sync/sync_promo_ui.cc
index 9b5c491..3aba10ffa 100644
--- a/chrome/browser/ui/sync/sync_promo_ui.cc
+++ b/chrome/browser/ui/sync/sync_promo_ui.cc
@@ -13,8 +13,8 @@
     return false;
   }
 
-  // Don't show if sync is disabled by policy.
-  if (!profile->IsSyncAccessible())
+  // Don't show if sync is not allowed to start.
+  if (!profile->IsSyncAllowed())
     return false;
 
   return true;
diff --git a/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc b/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc
index 29057b7..f5bdf11 100644
--- a/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc
+++ b/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc
@@ -5,6 +5,7 @@
 #include <string>
 #include <vector>
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/tabs/pinned_tab_codec.h"
@@ -18,8 +19,9 @@
 
 namespace {
 
-KeyedService* BuildPinnedTabService(content::BrowserContext* profile) {
-  return new PinnedTabService(static_cast<Profile*>(profile));
+scoped_ptr<KeyedService> BuildPinnedTabService(
+    content::BrowserContext* profile) {
+  return make_scoped_ptr(new PinnedTabService(static_cast<Profile*>(profile)));
 }
 
 PinnedTabService* BuildForProfile(Profile* profile) {
diff --git a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
index 4824b5a2..01b3dd3 100644
--- a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
+++ b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
@@ -335,7 +335,14 @@
   EXPECT_FALSE(browser_actions_bar()->OverflowedActionButtonWantsToRun());
 }
 
-IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, BrowserActionPopupTest) {
+// Flaky on Mac ASan 64 bot. See http://crbug.com/498665.
+#if defined(OS_MACOSX) && defined(ADDRESS_SANITIZER)
+#define MAYBE_BrowserActionPopupTest DISABLED_BrowserActionPopupTest
+#else
+#define MAYBE_BrowserActionPopupTest BrowserActionPopupTest
+#endif
+IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest,
+                       MAYBE_BrowserActionPopupTest) {
   // Load up two extensions that have browser action popups.
   base::FilePath data_dir =
       test_data_dir_.AppendASCII("api_test").AppendASCII("browser_action");
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
index b37f5fc..422d36e 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/sessions/persistent_tab_restore_service.h"
@@ -140,11 +141,10 @@
     content::RunAllBlockingPoolTasksUntilIdle();
   }
 
-  static KeyedService* GetTabRestoreService(
+  static scoped_ptr<KeyedService> GetTabRestoreService(
       content::BrowserContext* browser_context) {
-    // Ownership is tranfered to the profile.
-    return new PersistentTabRestoreService(
-        Profile::FromBrowserContext(browser_context), NULL);
+    return make_scoped_ptr(new PersistentTabRestoreService(
+        Profile::FromBrowserContext(browser_context), NULL));
   }
 
   browser_sync::OpenTabsUIDelegate* GetOpenTabsDelegate() {
@@ -258,7 +258,8 @@
   // Create a SessionService for the profile (profile owns the service) and add
   // a window with a tab to this session.
   SessionService* session_service = new SessionService(profile());
-  SessionServiceFactory::SetForTestProfile(profile(), session_service);
+  SessionServiceFactory::SetForTestProfile(profile(),
+                                           make_scoped_ptr(session_service));
   SessionID tab_id;
   SessionID window_id;
   session_service->SetWindowType(window_id,
diff --git a/chrome/browser/ui/views/apps/app_window_easy_resize_window_targeter.cc b/chrome/browser/ui/views/apps/app_window_easy_resize_window_targeter.cc
index 98be8215..891511e 100644
--- a/chrome/browser/ui/views/apps/app_window_easy_resize_window_targeter.cc
+++ b/chrome/browser/ui/views/apps/app_window_easy_resize_window_targeter.cc
@@ -19,9 +19,8 @@
 }
 
 bool AppWindowEasyResizeWindowTargeter::EventLocationInsideBounds(
-    ui::EventTarget* target,
+    aura::Window* window,
     const ui::LocatedEvent& event) const {
-  aura::Window* window = static_cast<aura::Window*>(target);
   // EasyResizeWindowTargeter intercepts events landing at the edges of the
   // window. Since maximized and fullscreen windows can't be resized anyway,
   // skip EasyResizeWindowTargeter so that the web contents receive all mouse
diff --git a/chrome/browser/ui/views/apps/app_window_easy_resize_window_targeter.h b/chrome/browser/ui/views/apps/app_window_easy_resize_window_targeter.h
index 69b08d6..90aa8c4 100644
--- a/chrome/browser/ui/views/apps/app_window_easy_resize_window_targeter.h
+++ b/chrome/browser/ui/views/apps/app_window_easy_resize_window_targeter.h
@@ -23,8 +23,8 @@
   ~AppWindowEasyResizeWindowTargeter() override;
 
  protected:
-  // ui::EventTargeter:
-  bool EventLocationInsideBounds(ui::EventTarget* target,
+  // aura::WindowTargeter:
+  bool EventLocationInsideBounds(aura::Window* window,
                                  const ui::LocatedEvent& event) const override;
 
  private:
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
index 830d049..4f1635a 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
@@ -93,8 +93,7 @@
 }  // namespace
 
 ChromeNativeAppWindowViews::ChromeNativeAppWindowViews()
-    : is_fullscreen_(false),
-      has_frame_color_(false),
+    : has_frame_color_(false),
       active_frame_color_(SK_ColorBLACK),
       inactive_frame_color_(SK_ColorBLACK) {
 }
@@ -332,16 +331,12 @@
   // Fullscreen not supported by panels.
   if (app_window()->window_type_is_panel())
     return;
-  is_fullscreen_ = (fullscreen_types != AppWindow::FULLSCREEN_TYPE_NONE);
-  widget()->SetFullscreen(is_fullscreen_);
 
-  // TODO(jeremya) we need to call RenderViewHost::ExitFullscreen() if we
-  // ever drop the window out of fullscreen in response to something that
-  // wasn't the app calling webkitCancelFullScreen().
+  widget()->SetFullscreen(fullscreen_types != AppWindow::FULLSCREEN_TYPE_NONE);
 }
 
 bool ChromeNativeAppWindowViews::IsFullscreenOrPending() const {
-  return is_fullscreen_;
+  return widget()->IsFullscreen();
 }
 
 void ChromeNativeAppWindowViews::UpdateShape(scoped_ptr<SkRegion> region) {
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views.h
index a21b9659..5de83b1 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.h
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.h
@@ -75,9 +75,6 @@
       const extensions::AppWindow::CreateParams& create_params) override;
 
  private:
-  // True if the window is fullscreen or fullscreen is pending.
-  bool is_fullscreen_;
-
   // Custom shape of the window. If this is not set then the window has a
   // default shape, usually rectangular.
   scoped_ptr<SkRegion> shape_;
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h
index fda6c54..5d930c873 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h
@@ -29,6 +29,8 @@
   void FlashFrame(bool flash) override;
 
   // NativeAppWindow implementation.
+  void UpdateDraggableRegions(
+      const std::vector<extensions::DraggableRegion>& regions) override;
   // These are used to simulate Mac-style hide/show. Since windows can be hidden
   // and shown using the app.window API, this sets is_hidden_with_app_ to
   // differentiate the reason a window was hidden.
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.mm b/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.mm
index d99a1c91..61e9657b 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.mm
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.mm
@@ -4,9 +4,16 @@
 
 #import "chrome/browser/ui/views/apps/chrome_native_app_window_views_mac.h"
 
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/scoped_nsobject.h"
 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
-#include "chrome/browser/ui/views/apps/app_window_native_widget_mac.h"
-#include "chrome/browser/ui/views/apps/native_app_window_frame_view_mac.h"
+#import "chrome/browser/ui/views/apps/app_window_native_widget_mac.h"
+#import "chrome/browser/ui/views/apps/native_app_window_frame_view_mac.h"
+
+@interface NSView (WebContentsView)
+- (void)setMouseDownCanMoveWindow:(BOOL)can_move;
+@end
 
 ChromeNativeAppWindowViewsMac::ChromeNativeAppWindowViewsMac()
     : is_hidden_with_app_(false) {
@@ -28,12 +35,12 @@
 
 views::NonClientFrameView*
 ChromeNativeAppWindowViewsMac::CreateStandardDesktopAppFrame() {
-  return new NativeAppWindowFrameViewMac(widget());
+  return new NativeAppWindowFrameViewMac(widget(), this);
 }
 
 views::NonClientFrameView*
 ChromeNativeAppWindowViewsMac::CreateNonStandardAppFrame() {
-  return new NativeAppWindowFrameViewMac(widget());
+  return new NativeAppWindowFrameViewMac(widget(), this);
 }
 
 void ChromeNativeAppWindowViewsMac::Show() {
@@ -59,6 +66,14 @@
                           : apps::APP_SHIM_ATTENTION_CANCEL);
 }
 
+void ChromeNativeAppWindowViewsMac::UpdateDraggableRegions(
+    const std::vector<extensions::DraggableRegion>& regions) {
+  ChromeNativeAppWindowViews::UpdateDraggableRegions(regions);
+
+  NSView* web_contents_view = app_window()->web_contents()->GetNativeView();
+  [web_contents_view setMouseDownCanMoveWindow:YES];
+}
+
 void ChromeNativeAppWindowViewsMac::ShowWithApp() {
   is_hidden_with_app_ = false;
   if (!app_window()->is_hidden())
diff --git a/chrome/browser/ui/views/apps/native_app_window_frame_view_mac.h b/chrome/browser/ui/views/apps/native_app_window_frame_view_mac.h
index 0509f5c..ee96b27 100644
--- a/chrome/browser/ui/views/apps/native_app_window_frame_view_mac.h
+++ b/chrome/browser/ui/views/apps/native_app_window_frame_view_mac.h
@@ -7,20 +7,30 @@
 
 #include "ui/views/window/native_frame_view.h"
 
+namespace extensions {
+class NativeAppWindow;
+}
+
 class Widget;
 
 // Provides metrics consistent with a native frame on Mac. The actual frame is
 // drawn by NSWindow.
 class NativeAppWindowFrameViewMac : public views::NativeFrameView {
  public:
-  explicit NativeAppWindowFrameViewMac(views::Widget* frame);
+  NativeAppWindowFrameViewMac(views::Widget* frame,
+                              extensions::NativeAppWindow* window);
   ~NativeAppWindowFrameViewMac() override;
 
   // NonClientFrameView:
   gfx::Rect GetWindowBoundsForClientBounds(
       const gfx::Rect& client_bounds) const override;
+  int NonClientHitTest(const gfx::Point& point) override;
 
  private:
+  // Weak. Owned by extensions::AppWindow (which manages our Widget via its
+  // WebContents).
+  extensions::NativeAppWindow* native_app_window_;
+
   DISALLOW_COPY_AND_ASSIGN(NativeAppWindowFrameViewMac);
 };
 
diff --git a/chrome/browser/ui/views/apps/native_app_window_frame_view_mac.mm b/chrome/browser/ui/views/apps/native_app_window_frame_view_mac.mm
index 444a6df..e20efc5 100644
--- a/chrome/browser/ui/views/apps/native_app_window_frame_view_mac.mm
+++ b/chrome/browser/ui/views/apps/native_app_window_frame_view_mac.mm
@@ -6,11 +6,15 @@
 
 #import <Cocoa/Cocoa.h>
 
+#include "extensions/browser/app_window/native_app_window.h"
+#include "ui/base/hit_test.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
 #include "ui/views/widget/widget.h"
 
-NativeAppWindowFrameViewMac::NativeAppWindowFrameViewMac(views::Widget* frame)
-    : views::NativeFrameView(frame) {
+NativeAppWindowFrameViewMac::NativeAppWindowFrameViewMac(
+    views::Widget* frame,
+    extensions::NativeAppWindow* window)
+    : views::NativeFrameView(frame), native_app_window_(window) {
 }
 
 NativeAppWindowFrameViewMac::~NativeAppWindowFrameViewMac() {
@@ -27,3 +31,19 @@
     window_bounds.set_size(gfx::Size(1, 1));
   return window_bounds;
 }
+
+int NativeAppWindowFrameViewMac::NonClientHitTest(const gfx::Point& point) {
+  if (!bounds().Contains(point))
+    return HTNOWHERE;
+
+  if (GetWidget()->IsFullscreen())
+    return HTCLIENT;
+
+  // Check for possible draggable region in the client area for the frameless
+  // window.
+  SkRegion* draggable_region = native_app_window_->GetDraggableRegion();
+  if (draggable_region && draggable_region->contains(point.x(), point.y()))
+    return HTCAPTION;
+
+  return HTCLIENT;
+}
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc
index f84b7ab1..2ab778e 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -124,12 +125,12 @@
   scoped_ptr<BookmarkBarView> bookmark_bar_view_;
 
  private:
-  static KeyedService* CreateTemplateURLService(
+  static scoped_ptr<KeyedService> CreateTemplateURLService(
       content::BrowserContext* profile) {
-    return new TemplateURLService(
+    return make_scoped_ptr(new TemplateURLService(
         static_cast<Profile*>(profile)->GetPrefs(),
         make_scoped_ptr(new SearchTermsData), NULL,
-        scoped_ptr<TemplateURLServiceClient>(), NULL, NULL, base::Closure());
+        scoped_ptr<TemplateURLServiceClient>(), NULL, NULL, base::Closure()));
   }
 
   scoped_ptr<ScopedTestingLocalState> local_state_;
diff --git a/chrome/browser/ui/views/certificate_selector.cc b/chrome/browser/ui/views/certificate_selector.cc
index ab901d0c..efc479f7 100644
--- a/chrome/browser/ui/views/certificate_selector.cc
+++ b/chrome/browser/ui/views/certificate_selector.cc
@@ -18,7 +18,6 @@
 #include "ui/base/models/table_model.h"
 #include "ui/base/models/table_model_observer.h"
 #include "ui/views/controls/button/label_button.h"
-#include "ui/views/controls/label.h"
 #include "ui/views/controls/table/table_view.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/layout/layout_constants.h"
@@ -27,6 +26,9 @@
 
 namespace chrome {
 
+const int CertificateSelector::kTableViewWidth = 400;
+const int CertificateSelector::kTableViewHeight = 100;
+
 class CertificateSelector::CertificateTableModel : public ui::TableModel {
  public:
   explicit CertificateTableModel(const net::CertificateList& certificates);
@@ -93,26 +95,17 @@
   table_->Select(0);
 }
 
-void CertificateSelector::InitWithText(const base::string16& text) {
+void CertificateSelector::InitWithText(scoped_ptr<views::View> text_label) {
   views::GridLayout* const layout = views::GridLayout::CreatePanel(this);
   SetLayoutManager(layout);
 
-  // The dimensions of the certificate selector table view, in pixels.
-  const int kTableViewWidth = 400;
-  const int kTableViewHeight = 100;
-
   const int kColumnSetId = 0;
   views::ColumnSet* const column_set = layout->AddColumnSet(kColumnSetId);
   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                         views::GridLayout::USE_PREF, 0, 0);
 
   layout->StartRow(0, kColumnSetId);
-  scoped_ptr<views::Label> label(new views::Label(text));
-  label->SetMultiLine(true);
-  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  label->SetAllowCharacterBreak(true);
-  label->SizeToFit(kTableViewWidth);
-  layout->AddView(label.release());
+  layout->AddView(text_label.release());
 
   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 
diff --git a/chrome/browser/ui/views/certificate_selector.h b/chrome/browser/ui/views/certificate_selector.h
index e4f52cf..0f4d246d5 100644
--- a/chrome/browser/ui/views/certificate_selector.h
+++ b/chrome/browser/ui/views/certificate_selector.h
@@ -20,6 +20,7 @@
 namespace views {
 class LabelButton;
 class TableView;
+class View;
 }
 
 namespace chrome {
@@ -65,10 +66,14 @@
   void OnDoubleClick() override;
 
  protected:
+  // The dimensions of the certificate selector table view, in pixels.
+  static const int kTableViewWidth;
+  static const int kTableViewHeight;
+
   // Initializes the dialog. |text| is shown above the list of certificates
   // and is supposed to explain to the user what the implication of the
   // certificate selection is.
-  void InitWithText(const base::string16& text);
+  void InitWithText(scoped_ptr<views::View> text_label);
 
  private:
   const net::CertificateList certificates_;
diff --git a/chrome/browser/ui/views/certificate_selector_browsertest.cc b/chrome/browser/ui/views/certificate_selector_browsertest.cc
index 5e5ff0f..4ccea64 100644
--- a/chrome/browser/ui/views/certificate_selector_browsertest.cc
+++ b/chrome/browser/ui/views/certificate_selector_browsertest.cc
@@ -15,6 +15,7 @@
 #include "net/cert/x509_certificate.h"
 #include "net/test/cert_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/label.h"
 
 namespace {
 
@@ -24,7 +25,10 @@
                           content::WebContents* web_contents)
       : CertificateSelector(certificates, web_contents) {}
 
-  void Init() { InitWithText(base::ASCIIToUTF16("some arbitrary text")); }
+  void Init() {
+    InitWithText(make_scoped_ptr(
+        new views::Label(base::ASCIIToUTF16("some arbitrary text"))));
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestCertificateSelector);
diff --git a/chrome/browser/ui/views/certificate_viewer_win.cc b/chrome/browser/ui/views/certificate_viewer_win.cc
index 2ae3675..b3c6dcb 100644
--- a/chrome/browser/ui/views/certificate_viewer_win.cc
+++ b/chrome/browser/ui/views/certificate_viewer_win.cc
@@ -43,10 +43,16 @@
   // while the the certificate dialog is open.
   base::MessageLoop::ScopedNestableTaskAllower allow(
       base::MessageLoop::current());
+
+  // Tell the message loop to only handle certain types of messages while the
+  // dialog is open to avoid bad things happening. See https://crbug.com/344012
+  // for details.
+  base::MessageLoop::current()->set_os_modal_loop(true);
   // This next call blocks but keeps processing windows messages, making it
   // modal to the browser window.
   ::CryptUIDlgViewCertificate(&view_info, &properties_changed);
 
+  base::MessageLoop::current()->set_os_modal_loop(false);
   CertFreeCertificateContext(cert_list);
 }
 
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
index f65a152..f10252d 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
@@ -22,8 +22,8 @@
 void ChromeBrowserMainExtraPartsViews::ToolkitInitialized() {
   // The delegate needs to be set before any UI is created so that windows
   // display the correct icon.
-  if (!views::ViewsDelegate::views_delegate)
-    views::ViewsDelegate::views_delegate = new ChromeViewsDelegate;
+  if (!views::ViewsDelegate::GetInstance())
+    views_delegate_.reset(new ChromeViewsDelegate);
 
   SetConstrainedWindowViewsClient(CreateChromeConstrainedWindowViewsClient());
 
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h
index 598a14c..bd9afcc 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h
@@ -9,6 +9,10 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
 
+namespace views {
+class ViewsDelegate;
+}
+
 #if defined(USE_AURA)
 namespace wm {
 class WMState;
@@ -24,6 +28,8 @@
   void ToolkitInitialized() override;
 
  private:
+  scoped_ptr<views::ViewsDelegate> views_delegate_;
+
 #if defined(USE_AURA)
   scoped_ptr<wm::WMState> wm_state_;
 #endif
diff --git a/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc b/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc
index 967c1f8..904fec60 100644
--- a/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc
+++ b/chrome/browser/ui/views/find_bar_host_interactive_uitest.cc
@@ -24,7 +24,6 @@
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/view.h"
-#include "ui/views/views_delegate.h"
 
 using base::ASCIIToUTF16;
 using content::WebContents;
diff --git a/chrome/browser/ui/views/frame/browser_frame_mac.mm b/chrome/browser/ui/views/frame/browser_frame_mac.mm
index a6be243d..2d9aa266 100644
--- a/chrome/browser/ui/views/frame/browser_frame_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_frame_mac.mm
@@ -47,7 +47,8 @@
 gfx::NativeWindow BrowserFrameMac::CreateNSWindow(
     const views::Widget::InitParams& params) {
   NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
-                          NSMiniaturizableWindowMask | NSResizableWindowMask;
+                          NSMiniaturizableWindowMask | NSResizableWindowMask |
+                          NSTexturedBackgroundWindowMask;
   return [[[NativeWidgetMacFramelessNSWindow alloc]
       initWithContentRect:ui::kWindowSizeDeterminedLater
                 styleMask:style_mask
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
index 5eaf26d..e7de1ed 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
@@ -69,7 +69,15 @@
 }
 
 int BrowserNonClientFrameViewMac::NonClientHitTest(const gfx::Point& point) {
-  return frame()->client_view()->NonClientHitTest(point);
+  int component = frame()->client_view()->NonClientHitTest(point);
+
+  // BrowserView::NonClientHitTest will return HTNOWHERE for points that hit
+  // the native title bar. On Mac, we need to explicitly return HTCAPTION for
+  // those points.
+  if (component == HTNOWHERE && bounds().Contains(point))
+    return HTCAPTION;
+
+  return component;
 }
 
 void BrowserNonClientFrameViewMac::GetWindowMask(const gfx::Size& size,
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index e155e51..60b3046 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -582,10 +582,10 @@
 
   // Do not show caption buttons if the window manager is forcefully providing a
   // title bar (e.g., in Ubuntu Unity, if the window is maximized).
-  if (!views::ViewsDelegate::views_delegate)
+  if (!views::ViewsDelegate::GetInstance())
     return true;
-  return !views::ViewsDelegate::views_delegate->WindowManagerProvidesTitleBar(
-              IsMaximized());
+  return !views::ViewsDelegate::GetInstance()->WindowManagerProvidesTitleBar(
+      IsMaximized());
 }
 
 void OpaqueBrowserFrameView::PaintRestoredFrameBorder(gfx::Canvas* canvas) {
diff --git a/chrome/browser/ui/views/frame/test_with_browser_view.cc b/chrome/browser/ui/views/frame/test_with_browser_view.cc
index 843c172..5a284b11 100644
--- a/chrome/browser/ui/views/frame/test_with_browser_view.cc
+++ b/chrome/browser/ui/views/frame/test_with_browser_view.cc
@@ -31,10 +31,10 @@
 
 namespace {
 
-// Caller owns the returned service.
-KeyedService* CreateTemplateURLService(content::BrowserContext* context) {
+scoped_ptr<KeyedService> CreateTemplateURLService(
+    content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
-  return new TemplateURLService(
+  return make_scoped_ptr(new TemplateURLService(
       profile->GetPrefs(),
       scoped_ptr<SearchTermsData>(new UIThreadSearchTermsData(profile)),
       WebDataServiceFactory::GetKeywordWebDataForProfile(
@@ -42,16 +42,17 @@
       scoped_ptr<TemplateURLServiceClient>(new ChromeTemplateURLServiceClient(
           HistoryServiceFactory::GetForProfile(
               profile, ServiceAccessType::EXPLICIT_ACCESS))),
-      nullptr, nullptr, base::Closure());
+      nullptr, nullptr, base::Closure()));
 }
 
-KeyedService* CreateAutocompleteClassifier(content::BrowserContext* context) {
+scoped_ptr<KeyedService> CreateAutocompleteClassifier(
+    content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
-  return new AutocompleteClassifier(
+  return make_scoped_ptr(new AutocompleteClassifier(
       make_scoped_ptr(new AutocompleteController(
           profile, TemplateURLServiceFactory::GetForProfile(profile), nullptr,
           AutocompleteClassifier::kDefaultOmniboxProviders)),
-      scoped_ptr<AutocompleteSchemeClassifier>(new TestSchemeClassifier()));
+      scoped_ptr<AutocompleteSchemeClassifier>(new TestSchemeClassifier())));
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/views/keyboard_access_browsertest.cc b/chrome/browser/ui/views/keyboard_access_browsertest.cc
index 76636d5..5bf8784 100644
--- a/chrome/browser/ui/views/keyboard_access_browsertest.cc
+++ b/chrome/browser/ui/views/keyboard_access_browsertest.cc
@@ -256,7 +256,7 @@
     GetClassName(reinterpret_cast<HWND>(w_param),
                  class_name,
                  arraysize(class_name));
-    if (LowerCaseEqualsASCII(class_name, "#32768")) {
+    if (base::LowerCaseEqualsASCII(class_name, "#32768")) {
       // Select the New Tab option and then send the enter key to execute it.
       ::PostMessage(reinterpret_cast<HWND>(w_param), WM_CHAR, 'T', 0);
       ::PostMessage(reinterpret_cast<HWND>(w_param), WM_KEYDOWN, VK_RETURN, 0);
diff --git a/chrome/browser/ui/views/menu_test_base.cc b/chrome/browser/ui/views/menu_test_base.cc
index 4ec701c..5874c75 100644
--- a/chrome/browser/ui/views/menu_test_base.cc
+++ b/chrome/browser/ui/views/menu_test_base.cc
@@ -10,6 +10,7 @@
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/menu/menu_item_view.h"
 #include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/widget/widget.h"
 
 MenuTestBase::MenuTestBase()
     : ViewEventTestBase(),
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 4428faa..fc8cba7 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -149,9 +149,7 @@
 }
 
 void OmniboxPopupContentsView::UpdatePopupAppearance() {
-  const size_t hidden_matches = model_->result().ShouldHideTopMatch() ? 1 : 0;
-  if (model_->result().size() <= hidden_matches ||
-      omnibox_view_->IsImeShowingPopup()) {
+  if (model_->result().empty() || omnibox_view_->IsImeShowingPopup()) {
     // No matches or the IME is showing a popup window which may overlap
     // the omnibox popup window.  Close any existing popup.
     if (popup_ != NULL) {
@@ -175,7 +173,7 @@
     OmniboxResultView* view = result_view_at(i);
     const AutocompleteMatch& match = GetMatchAtIndex(i);
     view->SetMatch(match);
-    view->SetVisible(i >= hidden_matches);
+    view->SetVisible(true);
     if (match.answer && !model_->answer_bitmap().isNull()) {
       view->SetAnswerImage(
           gfx::ImageSkia::CreateFrom1xBitmap(model_->answer_bitmap()));
@@ -379,8 +377,7 @@
 int OmniboxPopupContentsView::CalculatePopupHeight() {
   DCHECK_GE(static_cast<size_t>(child_count()), model_->result().size());
   int popup_height = 0;
-  for (size_t i = model_->result().ShouldHideTopMatch() ? 1 : 0;
-       i < model_->result().size(); ++i)
+  for (size_t i = 0; i < model_->result().size(); ++i)
     popup_height += child_at(i)->GetPreferredSize().height();
 
   // Add enough space on the top and bottom so it looks like there is the same
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 56b09d13..48ce4fcd 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -50,7 +50,6 @@
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/ime/input_method.h"
 #include "ui/views/layout/fill_layout.h"
-#include "ui/views/views_delegate.h"
 #include "ui/views/widget/widget.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/ui/views/passwords/manage_password_items_view.cc b/chrome/browser/ui/views/passwords/manage_password_items_view.cc
index 54dd1d3..b7e38177 100644
--- a/chrome/browser/ui/views/passwords/manage_password_items_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_password_items_view.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/passwords/manage_password_items_view.h"
 
+#include <numeric>
+
 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
 #include "chrome/grit/generated_resources.h"
 #include "grit/components_strings.h"
@@ -36,7 +38,7 @@
   column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
   column_set->AddColumn(views::GridLayout::FILL,
                         views::GridLayout::FILL,
-                        2,
+                        1,
                         views::GridLayout::USE_PREF,
                         0,
                         0);
@@ -63,24 +65,59 @@
   column_set->AddPaddingColumn(0, views::kItemLabelSpacing);
 }
 
-views::Label* GenerateUsernameLabel(const autofill::PasswordForm& form) {
-  views::Label* label = new views::Label(
+scoped_ptr<views::Label> GenerateUsernameLabel(
+    const autofill::PasswordForm& form) {
+  scoped_ptr<views::Label> label(new views::Label(
       form.username_value.empty()
           ? l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_EMPTY_LOGIN)
-          : form.username_value);
+          : form.username_value));
   label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
       ui::ResourceBundle::SmallFont));
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  return label;
+  return label.Pass();
 }
 
-views::Label* GeneratePasswordLabel(const autofill::PasswordForm& form) {
-  views::Label* label = new views::Label(form.password_value);
+scoped_ptr<views::Label> GeneratePasswordLabel(
+    const autofill::PasswordForm& form) {
+  scoped_ptr<views::Label> label(new views::Label(form.password_value));
   label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
       ui::ResourceBundle::SmallFont));
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   label->SetObscured(true);
-  return label;
+  return label.Pass();
+}
+
+scoped_ptr<views::ImageButton> GenerateDeleteButton(
+    views::ButtonListener* listener) {
+  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
+  scoped_ptr<views::ImageButton> button(new views::ImageButton(listener));
+  button->SetImage(views::ImageButton::STATE_NORMAL,
+                   rb->GetImageNamed(IDR_CLOSE_2).ToImageSkia());
+  button->SetImage(views::ImageButton::STATE_HOVERED,
+                   rb->GetImageNamed(IDR_CLOSE_2_H).ToImageSkia());
+  button->SetImage(views::ImageButton::STATE_PRESSED,
+                   rb->GetImageNamed(IDR_CLOSE_2_P).ToImageSkia());
+  return button.Pass();
+}
+
+scoped_ptr<views::Label> GenerateDeletedPasswordLabel() {
+  scoped_ptr<views::Label> text(new views::Label(
+      l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED)));
+  text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  text->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
+      ui::ResourceBundle::SmallFont));
+  return text.Pass();
+}
+
+scoped_ptr<views::Link> GenerateUndoLink(views::LinkListener* listener) {
+  scoped_ptr<views::Link> undo_link(new views::Link(
+      l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO)));
+  undo_link->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
+  undo_link->set_listener(listener);
+  undo_link->SetUnderline(false);
+  undo_link->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
+      ui::ResourceBundle::SmallFont));
+  return undo_link.Pass();
 }
 
 }  // namespace
@@ -91,11 +128,18 @@
                                                  public views::LinkListener {
  public:
   PasswordFormRow(ManagePasswordItemsView* host,
-                  const autofill::PasswordForm* password_form);
+                  const autofill::PasswordForm* password_form,
+                  int fixed_height);
   ~PasswordFormRow() override = default;
 
   void AddRow(views::GridLayout* layout);
 
+  // Returns the fixed height for a row excluding padding. 0 means no fixed
+  // height required.
+  // In MANAGE_STATE a row may represent a credential or a deleted credential.
+  // To avoid repositioning all the rows should have a fixed height.
+  static int GetFixedHeight(password_manager::ui::State state);
+
  private:
   void AddCredentialsRow(views::GridLayout* layout);
   void AddUndoRow(views::GridLayout* layout);
@@ -109,17 +153,24 @@
 
   ManagePasswordItemsView* host_;
   const autofill::PasswordForm* password_form_;
+  // The UI elements pointers are weak and owned by their parent.
   views::Link* undo_link_;
   views::ImageButton* delete_button_;
+  const int fixed_height_;
   bool deleted_;
+
+  DISALLOW_COPY_AND_ASSIGN(PasswordFormRow);
 };
 
 ManagePasswordItemsView::PasswordFormRow::PasswordFormRow(
-    ManagePasswordItemsView* host, const autofill::PasswordForm* password_form)
+    ManagePasswordItemsView* host,
+    const autofill::PasswordForm* password_form,
+    int fixed_height)
     : host_(host),
       password_form_(password_form),
       undo_link_(nullptr),
       delete_button_(nullptr),
+      fixed_height_(fixed_height),
       deleted_(false) {}
 
 void ManagePasswordItemsView::PasswordFormRow::AddRow(
@@ -131,6 +182,20 @@
   }
 }
 
+int ManagePasswordItemsView::PasswordFormRow::GetFixedHeight(
+    password_manager::ui::State state) {
+  if (state != password_manager::ui::MANAGE_STATE)
+    return 0;
+  scoped_ptr<views::ImageButton> delete_button(GenerateDeleteButton(nullptr));
+  scoped_ptr<views::Link> link(GenerateUndoLink(nullptr));
+  scoped_ptr<views::Label> label(GenerateDeletedPasswordLabel());
+  views::View* row_views[] = {delete_button.get(), link.get(), label.get()};
+  return std::accumulate(row_views, row_views + arraysize(row_views), 0,
+                         [](int max_height, const views::View* view) {
+    return std::max(max_height, view->GetPreferredSize().height());
+  });
+}
+
 void ManagePasswordItemsView::PasswordFormRow::AddCredentialsRow(
     views::GridLayout* layout) {
   ResetControls();
@@ -141,41 +206,35 @@
   BuildColumnSetIfNeeded(layout, column_set_id);
   layout->StartRowWithPadding(0, column_set_id, 0,
                               views::kRelatedControlVerticalSpacing);
-  layout->AddView(GenerateUsernameLabel(*password_form_));
-  layout->AddView(GeneratePasswordLabel(*password_form_));
+  layout->AddView(GenerateUsernameLabel(*password_form_).release(), 1, 1,
+                  views::GridLayout::FILL, views::GridLayout::FILL,
+                  0, fixed_height_);
+  layout->AddView(GeneratePasswordLabel(*password_form_).release(), 1, 1,
+                  views::GridLayout::FILL, views::GridLayout::FILL,
+                  0, fixed_height_);
   if (column_set_id == THREE_COLUMN_SET) {
-    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
-    delete_button_ = new views::ImageButton(this);
-    delete_button_->SetImage(views::ImageButton::STATE_NORMAL,
-                             rb->GetImageNamed(IDR_CLOSE_2).ToImageSkia());
-    delete_button_->SetImage(views::ImageButton::STATE_HOVERED,
-                             rb->GetImageNamed(IDR_CLOSE_2_H).ToImageSkia());
-    delete_button_->SetImage(views::ImageButton::STATE_PRESSED,
-                             rb->GetImageNamed(IDR_CLOSE_2_P).ToImageSkia());
-    layout->AddView(delete_button_);
+    delete_button_ = GenerateDeleteButton(this).release();
+    layout->AddView(delete_button_, 1, 1,
+                    views::GridLayout::TRAILING, views::GridLayout::FILL,
+                    0, fixed_height_);
   }
 }
 
 void ManagePasswordItemsView::PasswordFormRow::AddUndoRow(
     views::GridLayout* layout) {
   ResetControls();
-  views::Label* text =
-      new views::Label(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_DELETED));
-  text->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  text->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
-      ui::ResourceBundle::SmallFont));
-  undo_link_ =
-      new views::Link(l10n_util::GetStringUTF16(IDS_MANAGE_PASSWORDS_UNDO));
-  undo_link_->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
-  undo_link_->set_listener(this);
-  undo_link_->SetUnderline(false);
-  undo_link_->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
-      ui::ResourceBundle::SmallFont));
+  scoped_ptr<views::Label> text = GenerateDeletedPasswordLabel();
+  scoped_ptr<views::Link> undo_link = GenerateUndoLink(this);
+  undo_link_ = undo_link.get();
   BuildColumnSetIfNeeded(layout, TWO_COLUMN_SET);
   layout->StartRowWithPadding(0, TWO_COLUMN_SET, 0,
                               views::kRelatedControlVerticalSpacing);
-  layout->AddView(text);
-  layout->AddView(undo_link_);
+  layout->AddView(text.release(), 1, 1,
+                  views::GridLayout::FILL, views::GridLayout::FILL,
+                  0, fixed_height_);
+  layout->AddView(undo_link.release(), 1, 1,
+                  views::GridLayout::FILL, views::GridLayout::FILL,
+                  0, fixed_height_);
 }
 
 void ManagePasswordItemsView::PasswordFormRow::ButtonPressed(
@@ -202,9 +261,10 @@
     ManagePasswordsBubbleModel* manage_passwords_bubble_model,
     const std::vector<const autofill::PasswordForm*>& password_forms)
     : model_(manage_passwords_bubble_model) {
+  int fixed_height = PasswordFormRow::GetFixedHeight(model_->state());
   for (const autofill::PasswordForm* password_form : password_forms) {
     password_forms_rows_.push_back(
-        ManagePasswordItemsView::PasswordFormRow(this, password_form));
+        new PasswordFormRow(this, password_form, fixed_height));
   }
   AddRows();
 }
@@ -214,8 +274,8 @@
 void ManagePasswordItemsView::AddRows() {
   views::GridLayout* layout = new views::GridLayout(this);
   SetLayoutManager(layout);
-  for (auto& row : password_forms_rows_) {
-    row.AddRow(layout);
+  for (auto* row : password_forms_rows_) {
+    row->AddRow(layout);
   }
   GetLayoutManager()->Layout(this);
 }
diff --git a/chrome/browser/ui/views/passwords/manage_password_items_view.h b/chrome/browser/ui/views/passwords/manage_password_items_view.h
index 379b7874..6200e71 100644
--- a/chrome/browser/ui/views/passwords/manage_password_items_view.h
+++ b/chrome/browser/ui/views/passwords/manage_password_items_view.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/memory/scoped_vector.h"
 #include "components/autofill/core/common/password_form.h"
 #include "ui/views/view.h"
 
@@ -36,7 +37,7 @@
   // Changes the views according to the state of |password_forms_rows_|.
   void Refresh();
 
-  std::vector<PasswordFormRow> password_forms_rows_;
+  ScopedVector<PasswordFormRow> password_forms_rows_;
   ManagePasswordsBubbleModel* model_;
 
   DISALLOW_COPY_AND_ASSIGN(ManagePasswordItemsView);
diff --git a/chrome/browser/ui/views/platform_keys_certificate_selector_chromeos.cc b/chrome/browser/ui/views/platform_keys_certificate_selector_chromeos.cc
index b5203ca..e1f5c14 100644
--- a/chrome/browser/ui/views/platform_keys_certificate_selector_chromeos.cc
+++ b/chrome/browser/ui/views/platform_keys_certificate_selector_chromeos.cc
@@ -9,6 +9,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/font.h"
+#include "ui/views/controls/styled_label.h"
 
 namespace chromeos {
 
@@ -26,10 +28,19 @@
 }
 
 void PlatformKeysCertificateSelector::Init() {
-  const base::string16 text =
-      l10n_util::GetStringFUTF16(IDS_PLATFORM_KEYS_SELECT_CERT_DIALOG_TEXT,
-                                 base::ASCIIToUTF16(extension_name_));
-  CertificateSelector::InitWithText(text);
+  const base::string16 name = base::ASCIIToUTF16(extension_name_);
+
+  size_t offset;
+  const base::string16 text = l10n_util::GetStringFUTF16(
+      IDS_PLATFORM_KEYS_SELECT_CERT_DIALOG_TEXT, name, &offset);
+
+  scoped_ptr<views::StyledLabel> label(
+      new views::StyledLabel(text, nullptr /* no listener */));
+
+  views::StyledLabel::RangeStyleInfo bold_style;
+  bold_style.font_style = gfx::Font::BOLD;
+  label->AddStyleRange(gfx::Range(offset, offset + name.size()), bold_style);
+  CertificateSelector::InitWithText(label.Pass());
 }
 
 bool PlatformKeysCertificateSelector::Cancel() {
diff --git a/chrome/browser/ui/views/sad_tab_view.cc b/chrome/browser/ui/views/sad_tab_view.cc
index d8e6c69..54170f9 100644
--- a/chrome/browser/ui/views/sad_tab_view.cc
+++ b/chrome/browser/ui/views/sad_tab_view.cc
@@ -33,6 +33,10 @@
 #include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/memory/oom_memory_details.h"
+#endif
+
 using content::OpenURLParams;
 using content::WebContents;
 
@@ -98,17 +102,23 @@
           "Tabs.SadTab.CrashCreated", crashed, 1, 1000, 50);
       break;
     }
-    case chrome::SAD_TAB_KIND_KILLED:
+    case chrome::SAD_TAB_KIND_KILLED: {
       RecordKillCreated();
+      LOG(WARNING) << "Tab Killed: "
+                   <<  web_contents->GetURL().GetOrigin().spec();
       break;
+    }
 #if defined(OS_CHROMEOS)
-    case chrome::SAD_TAB_KIND_KILLED_BY_OOM:
+    case chrome::SAD_TAB_KIND_KILLED_BY_OOM: {
       RecordKillCreated();
       RecordKillCreatedOOM();
+      const std::string spec = web_contents->GetURL().GetOrigin().spec();
+      chromeos::OomMemoryDetails::Log(
+          "Tab OOM-Killed Memory details: " + spec + ", ",
+          base::Closure());
       break;
+    }
 #endif
-    default:
-      NOTREACHED();
   }
 
   // Set the background color.
diff --git a/chrome/browser/ui/views/ssl_client_certificate_selector.cc b/chrome/browser/ui/views/ssl_client_certificate_selector.cc
index 2396ffc..c76ab8e6 100644
--- a/chrome/browser/ui/views/ssl_client_certificate_selector.cc
+++ b/chrome/browser/ui/views/ssl_client_certificate_selector.cc
@@ -15,6 +15,7 @@
 #include "net/cert/x509_certificate.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/views/controls/label.h"
 #include "ui/views/widget/widget.h"
 
 #if defined(USE_NSS_CERTS)
@@ -36,9 +37,15 @@
 
 void SSLClientCertificateSelector::Init() {
   StartObserving();
-  InitWithText(l10n_util::GetStringFUTF16(
-      IDS_CLIENT_CERT_DIALOG_TEXT,
-      base::ASCIIToUTF16(cert_request_info()->host_and_port.ToString())));
+  scoped_ptr<views::Label> text_label(
+      new views::Label(l10n_util::GetStringFUTF16(
+          IDS_CLIENT_CERT_DIALOG_TEXT,
+          base::ASCIIToUTF16(cert_request_info()->host_and_port.ToString()))));
+  text_label->SetMultiLine(true);
+  text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  text_label->SetAllowCharacterBreak(true);
+  text_label->SizeToFit(kTableViewWidth);
+  InitWithText(text_label.Pass());
 }
 
 void SSLClientCertificateSelector::OnCertSelectedByNotification() {
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 2790730d..1911f4c 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -579,7 +579,7 @@
   ~MaskedWindowTargeter() override {}
 
   // aura::WindowTargeter:
-  bool EventLocationInsideBounds(ui::EventTarget* target,
+  bool EventLocationInsideBounds(aura::Window* target,
                                  const ui::LocatedEvent& event) const override {
     aura::Window* window = static_cast<aura::Window*>(target);
     gfx::Point local_point = event.location();
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index bdfe4f8..e8101ec9 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -277,18 +277,23 @@
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_SHARED_MEM_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_CPU_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_NET_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_PROCESS_ID_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
@@ -296,27 +301,34 @@
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_GDI_HANDLES_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_USER_HANDLES_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
 #endif
   columns_.push_back(ui::TableColumn(
       IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN,
       ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(
       IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN,
       ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   columns_.push_back(ui::TableColumn(
       IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN,
       ui::TableColumn::RIGHT, -1, 0));
@@ -325,11 +337,13 @@
       ui::TableColumn(IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN,
                       ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
   // TODO(port) http://crbug.com/120488 for non-Linux.
 #if defined(OS_LINUX)
   columns_.push_back(ui::TableColumn(IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN,
                                      ui::TableColumn::RIGHT, -1, 0));
   columns_.back().sortable = true;
+  columns_.back().initial_sort_is_ascending = false;
 #endif
 
   tab_table_ = new views::TableView(
diff --git a/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc b/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc
index cf35c04..abaf4c8 100644
--- a/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/mobile_setup_ui.cc
@@ -108,7 +108,7 @@
   value->SetString("activation_type", activation_type);
   value->SetString("carrier", name);
   value->SetString("payment_url", payment_url);
-  if (LowerCaseEqualsASCII(post_method, "post") && !post_data.empty())
+  if (base::LowerCaseEqualsASCII(post_method, "post") && !post_data.empty())
     value->SetString("post_data", post_data);
 
   // Use the cached DeviceState properties.
@@ -464,7 +464,7 @@
     return;
 
   MobileActivator::GetInstance()->OnSetTransactionStatus(
-      LowerCaseEqualsASCII(status, kJsApiResultOK));
+      base::LowerCaseEqualsASCII(status, kJsApiResultOK));
 }
 
 void MobileSetupHandler::HandlePaymentPortalLoad(const base::ListValue* args) {
@@ -481,7 +481,7 @@
     return;
 
   MobileActivator::GetInstance()->OnPortalLoaded(
-      LowerCaseEqualsASCII(result, kJsApiResultOK));
+      base::LowerCaseEqualsASCII(result, kJsApiResultOK));
 }
 
 void MobileSetupHandler::HandleGetDeviceInfo(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/devtools_ui.cc b/chrome/browser/ui/webui/devtools_ui.cc
index 4360cf1..e80b772 100644
--- a/chrome/browser/ui/webui/devtools_ui.cc
+++ b/chrome/browser/ui/webui/devtools_ui.cc
@@ -143,7 +143,7 @@
   // Serve request from local bundle.
   std::string bundled_path_prefix(chrome::kChromeUIDevToolsBundledPath);
   bundled_path_prefix += "/";
-  if (StartsWithASCII(path, bundled_path_prefix, false)) {
+  if (base::StartsWithASCII(path, bundled_path_prefix, false)) {
     StartBundledDataRequest(path.substr(bundled_path_prefix.length()),
                             render_process_id, render_frame_id, callback);
     return;
@@ -152,7 +152,7 @@
   // Serve request from remote location.
   std::string remote_path_prefix(chrome::kChromeUIDevToolsRemotePath);
   remote_path_prefix += "/";
-  if (StartsWithASCII(path, remote_path_prefix, false)) {
+  if (base::StartsWithASCII(path, remote_path_prefix, false)) {
     StartRemoteDataRequest(path.substr(remote_path_prefix.length()),
                            render_process_id, render_frame_id, callback);
     return;
diff --git a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
index b1d3d56..cd688e653 100644
--- a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
+++ b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
@@ -75,8 +75,8 @@
 
   if (webstore_url.scheme() != webstore_base_url.scheme() ||
       webstore_url.host() != webstore_base_url.host() ||
-      !StartsWithASCII(
-          webstore_url.path(), webstore_base_url.path(), true)) {
+      !base::StartsWithASCII(webstore_url.path(), webstore_base_url.path(),
+                             true)) {
     return false;
   }
 
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
index aef43a8b0..97c5b6b 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
@@ -24,7 +24,6 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "extensions/browser/api/management/management_api.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/test_extension_registry_observer.h"
@@ -87,7 +86,8 @@
 }
 
 void ExtensionSettingsUIBrowserTest::SetAutoConfirmUninstall() {
-  extensions::ManagementUninstallFunctionBase::SetAutoConfirmForTest(true);
+  uninstall_auto_confirm_.reset(new extensions::ScopedTestDialogAutoConfirm(
+      extensions::ScopedTestDialogAutoConfirm::ACCEPT));
 }
 
 void ExtensionSettingsUIBrowserTest::EnableErrorConsole() {
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
index 9730dff..6a43a773 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
@@ -8,6 +8,7 @@
 #include "chrome/browser/extensions/extension_test_notification_observer.h"
 #include "chrome/common/extensions/features/feature_channel.h"
 #include "chrome/test/base/web_ui_browser_test.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/test_management_policy.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/feature_switch.h"
@@ -64,6 +65,8 @@
   // Used to enable the error console.
   scoped_ptr<extensions::FeatureSwitch::ScopedOverride> error_console_override_;
 
+  scoped_ptr<extensions::ScopedTestDialogAutoConfirm> uninstall_auto_confirm_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionSettingsUIBrowserTest);
 };
 
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
index f71f025..23833b1 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -182,9 +182,9 @@
     int render_frame_id,
     const content::URLDataSource::GotDataCallback& callback) {
   scoped_ptr<content::InterstitialPageDelegate> interstitial_delegate;
-  if (StartsWithASCII(path, "ssl", true)) {
+  if (base::StartsWithASCII(path, "ssl", true)) {
     interstitial_delegate.reset(CreateSSLBlockingPage(web_contents_));
-  } else if (StartsWithASCII(path, "safebrowsing", true)) {
+  } else if (base::StartsWithASCII(path, "safebrowsing", true)) {
     interstitial_delegate.reset(CreateSafeBrowsingBlockingPage(web_contents_));
   }
 
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
index 049c95a..2adb5338 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
@@ -272,9 +272,6 @@
 const char kURLRegisterComplete[] =
     "http://1.2.3.4:8888/privet/register?action=complete&user=user%40host.com";
 
-const char kURLGaiaToken[] =
-    "https://accounts.google.com/o/oauth2/token";
-
 const char kSampleGaiaId[] = "12345";
 const char kSampleUser[] = "user@host.com";
 
@@ -398,13 +395,13 @@
         net::URLRequestStatus::SUCCESS);
 
     fake_fetcher_factory().SetFakeResponse(
-        GURL(kURLGaiaToken),
+        GaiaUrls::GetInstance()->oauth2_token_url(),
         kResponseGaiaToken,
         net::HTTP_OK,
         net::URLRequestStatus::SUCCESS);
 
     EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
-        kURLGaiaToken))
+        GaiaUrls::GetInstance()->oauth2_token_url().spec()))
         .Times(AnyNumber());
 
     fake_fetcher_factory().SetFakeResponse(
diff --git a/chrome/browser/ui/webui/media_router/media_router_dialog_controller.cc b/chrome/browser/ui/webui/media_router/media_router_dialog_controller.cc
index 546eaee3..392ebfc8 100644
--- a/chrome/browser/ui/webui/media_router/media_router_dialog_controller.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_dialog_controller.cc
@@ -123,8 +123,8 @@
  private:
   void WebContentsDestroyed() override {
     // The dialog is already closed. No need to call Close() again.
-    // NOTE: |this| is deleted after RemoveObservers() returns.
-    dialog_controller_->RemoveObservers();
+    // NOTE: |this| is deleted after Reset() returns.
+    dialog_controller_->Reset();
   }
 
   void NavigationEntryCommitted(const LoadCommittedDetails& load_details)
@@ -188,14 +188,35 @@
   // Get the media router dialog for |initiator|, or create a new dialog
   // if not found.
   WebContents* media_router_dialog = GetMediaRouterDialog();
-  if (!media_router_dialog)
-    return CreateMediaRouterDialog();
+  if (!media_router_dialog) {
+    CreateMediaRouterDialog();
+    return GetMediaRouterDialog();
+  }
 
   // Show the initiator holding the existing media router dialog.
   initiator_->GetDelegate()->ActivateContents(initiator_);
   return media_router_dialog;
 }
 
+WebContents* MediaRouterDialogController::ShowMediaRouterDialogForPresentation(
+    scoped_ptr<CreateSessionRequest> request) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Get the media router dialog for |initiator|, or create a new dialog
+  // if not found.
+  WebContents* media_router_dialog = GetMediaRouterDialog();
+  if (!media_router_dialog) {
+    CreateMediaRouterDialog();
+    media_router_dialog = GetMediaRouterDialog();
+    presentation_request_ = request.Pass();
+    return media_router_dialog;
+  }
+
+  // Show the initiator holding the existing media router dialog.
+  initiator_->GetDelegate()->ActivateContents(initiator_);
+  return nullptr;
+}
+
 WebContents* MediaRouterDialogController::GetMediaRouterDialog() const {
   DCHECK(thread_checker_.CalledOnValidThread());
   return dialog_observer_.get() ? dialog_observer_->web_contents() : nullptr;
@@ -206,7 +227,7 @@
   DCHECK(initiator_observer_.get());
   WebContents* media_router_dialog = GetMediaRouterDialog();
   CHECK(media_router_dialog);
-  RemoveObservers();
+  Reset();
 
   content::WebUI* web_ui = media_router_dialog->GetWebUI();
   if (web_ui) {
@@ -217,7 +238,7 @@
   }
 }
 
-WebContents* MediaRouterDialogController::CreateMediaRouterDialog() {
+void MediaRouterDialogController::CreateMediaRouterDialog() {
   DCHECK(!initiator_observer_.get());
   DCHECK(!dialog_observer_.get());
 
@@ -256,15 +277,15 @@
       initiator_, this));
   dialog_observer_.reset(new DialogWebContentsObserver(
       media_router_dialog, this));
-  return media_router_dialog;
 }
 
-void MediaRouterDialogController::RemoveObservers() {
+void MediaRouterDialogController::Reset() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(initiator_observer_.get());
   DCHECK(dialog_observer_.get());
   initiator_observer_.reset();
   dialog_observer_.reset();
+  presentation_request_.reset();
 }
 
 void MediaRouterDialogController::OnDialogNavigated(
@@ -284,7 +305,42 @@
 
   media_router_dialog_pending_ = false;
 
-  // TODO(imcheng): Initialize dialog.
+  PopulateDialog(media_router_dialog);
+}
+
+void MediaRouterDialogController::PopulateDialog(
+    content::WebContents* media_router_dialog) {
+  DCHECK(media_router_dialog);
+  DCHECK(initiator_observer_);
+  if (!initiator_observer_) {
+    Reset();
+    return;
+  }
+  content::WebContents* initiator = initiator_observer_->web_contents();
+  DCHECK(initiator);
+  if (!initiator || !media_router_dialog->GetWebUI()) {
+    Reset();
+    return;
+  }
+
+  MediaRouterUI* media_router_ui = static_cast<MediaRouterUI*>(
+      media_router_dialog->GetWebUI()->GetController());
+  DCHECK(media_router_ui);
+  if (!media_router_ui) {
+    Reset();
+    return;
+  }
+
+  if (!presentation_request_.get()) {
+    PresentationServiceDelegateImpl::CreateForWebContents(initiator);
+    PresentationServiceDelegateImpl* delegate =
+        PresentationServiceDelegateImpl::FromWebContents(initiator);
+    CHECK(delegate);
+    media_router_ui->InitWithDefaultMediaSource(delegate);
+  } else {
+    media_router_ui->InitWithPresentationSessionRequest(
+        initiator, presentation_request_.Pass());
+  }
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/ui/webui/media_router/media_router_dialog_controller.h b/chrome/browser/ui/webui/media_router/media_router_dialog_controller.h
index 5cdf88b..f357d00 100644
--- a/chrome/browser/ui/webui/media_router/media_router_dialog_controller.h
+++ b/chrome/browser/ui/webui/media_router/media_router_dialog_controller.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_DIALOG_CONTROLLER_H_
 
 #include "base/macros.h"
+#include "chrome/browser/media/router/create_session_request.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
@@ -33,6 +34,14 @@
   // Returns WebContents for the media router dialog.
   content::WebContents* ShowMediaRouterDialog();
 
+  // Creates a Media Router modal dialog using the initiator and parameters
+  // specified in |request|. If the dialog already exists, brings the dialog
+  // to the front, but does not change the dialog with |request|.
+  // Returns WebContents for the media router dialog if a dialog was created.
+  // Otherwise returns nullptr and |request| is deleted.
+  content::WebContents* ShowMediaRouterDialogForPresentation(
+      scoped_ptr<CreateSessionRequest> request);
+
   // Returns the media router dialog WebContents.
   // Returns nullptr if there is no dialog.
   content::WebContents* GetMediaRouterDialog() const;
@@ -51,15 +60,16 @@
   explicit MediaRouterDialogController(content::WebContents* web_contents);
 
   // Creates a new media router dialog modal to |initiator_|.
-  // Returns the WebContents of the newly created dialog.
-  content::WebContents* CreateMediaRouterDialog();
+  void CreateMediaRouterDialog();
 
-  // Removes WebContentsObservers for the initiator and dialog WebContents.
-  void RemoveObservers();
+  // Resets this dialog controller to an empty state.
+  void Reset();
 
   // Invoked when the dialog WebContents has navigated.
   void OnDialogNavigated(const content::LoadCommittedDetails& details);
 
+  void PopulateDialog(content::WebContents* media_router_dialog);
+
   scoped_ptr<InitiatorWebContentsObserver> initiator_observer_;
   scoped_ptr<DialogWebContentsObserver> dialog_observer_;
 
@@ -69,6 +79,11 @@
   // created.
   bool media_router_dialog_pending_;
 
+  // Data for dialogs created under a Presentation API context.
+  // Passed from the caller of ShowMediaRouterDialogForPresentation(), and
+  // passed to the MediaRouterUI when it is initialized.
+  scoped_ptr<CreateSessionRequest> presentation_request_;
+
   base::ThreadChecker thread_checker_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaRouterDialogController);
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc
index 9c96f70a..9e6d529d 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -6,11 +6,22 @@
 
 #include <string>
 
+#include "base/strings/string_util.h"
+#include "chrome/browser/media/router/create_session_request.h"
+#include "chrome/browser/media/router/issue.h"
 #include "chrome/browser/media/router/issues_observer.h"
+#include "chrome/browser/media/router/media_route.h"
 #include "chrome/browser/media/router/media_router.h"
 #include "chrome/browser/media/router/media_router_mojo_impl.h"
 #include "chrome/browser/media/router/media_router_mojo_impl_factory.h"
+#include "chrome/browser/media/router/media_routes_observer.h"
+#include "chrome/browser/media/router/media_sink.h"
+#include "chrome/browser/media/router/media_sinks_observer.h"
+#include "chrome/browser/media/router/media_source.h"
+#include "chrome/browser/media/router/media_source_helper.h"
+#include "chrome/browser/media/router/presentation_service_delegate_impl.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/ui/webui/media_router/media_router_localized_strings_provider.h"
 #include "chrome/browser/ui/webui/media_router/media_router_resources_provider.h"
 #include "chrome/browser/ui/webui/media_router/media_router_webui_message_handler.h"
@@ -22,6 +33,17 @@
 
 namespace media_router {
 
+namespace {
+
+std::string GetHostFromURL(const GURL& gurl) {
+  std::string host = gurl.host();
+  if (base::StartsWithASCII(host, "www.", false))
+    host = host.substr(4);
+  return host;
+}
+
+}  // namespace
+
 // This class calls to refresh the UI when the highest priority issue is
 // updated.
 class MediaRouterUI::UIIssuesObserver : public IssuesObserver {
@@ -63,20 +85,14 @@
       handler_(new MediaRouterWebUIMessageHandler()),
       ui_initialized_(false),
       has_pending_route_request_(false),
+      requesting_route_for_default_source_(false),
+      initiator_(nullptr),
       router_(nullptr),
       weak_factory_(this) {
   // Create a WebUIDataSource containing the chrome://media-router page's
   // content.
   scoped_ptr<content::WebUIDataSource> html_source(
       content::WebUIDataSource::Create(chrome::kChromeUIMediaRouterHost));
-  AddLocalizedStrings(html_source.get());
-  AddMediaRouterUIResources(html_source.get());
-  // Ownership of |html_source| is transferred to the BrowserContext.
-  content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
-                                html_source.release());
-
-  // Ownership of |handler_| is transferred to |web_ui|.
-  web_ui->AddMessageHandler(handler_);
 
   content::WebContents* wc = web_ui->GetWebContents();
   DCHECK(wc);
@@ -85,17 +101,115 @@
       wc->GetBrowserContext());
   DCHECK(router_);
 
-  // Register for Issue and MediaRoute updates.
-  issues_observer_.reset(new UIIssuesObserver(this));
-  routes_observer_.reset(new UIMediaRoutesObserver(router_, this));
+  AddLocalizedStrings(html_source.get());
+  AddMediaRouterUIResources(html_source.get());
+  // Ownership of |html_source| is transferred to the BrowserContext.
+  content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
+                                html_source.release());
+
+  // Ownership of |handler_| is transferred to |web_ui|.
+  web_ui->AddMessageHandler(handler_);
 }
 
 MediaRouterUI::~MediaRouterUI() {
   if (query_result_manager_.get())
     query_result_manager_->RemoveObserver(this);
+  if (presentation_service_delegate_.get())
+    presentation_service_delegate_->RemoveDefaultMediaSourceObserver(this);
+}
+
+void MediaRouterUI::InitWithDefaultMediaSource(
+    PresentationServiceDelegateImpl* delegate) {
+  DCHECK(delegate);
+  DCHECK(!presentation_service_delegate_);
+  DCHECK(!query_result_manager_.get());
+
+  presentation_service_delegate_ = delegate->GetWeakPtr();
+  presentation_service_delegate_->AddDefaultMediaSourceObserver(this);
+  InitCommon(presentation_service_delegate_->web_contents(),
+             presentation_service_delegate_->default_source(),
+             presentation_service_delegate_->default_frame_url());
+}
+
+void MediaRouterUI::InitWithPresentationSessionRequest(
+    const content::WebContents* initiator,
+    scoped_ptr<CreateSessionRequest> request) {
+  DCHECK(request.get());
+  DCHECK(!presentation_session_request_.get());
+  DCHECK(!query_result_manager_.get());
+
+  presentation_session_request_ = request.Pass();
+  InitCommon(initiator, presentation_session_request_->GetMediaSource(),
+             presentation_session_request_->frame_url());
+}
+
+void MediaRouterUI::InitCommon(const content::WebContents* initiator,
+                               const MediaSource& default_source,
+                               const GURL& default_frame_url) {
+  DCHECK(initiator);
+
+  // Register for Issue and MediaRoute updates.
+  issues_observer_.reset(new UIIssuesObserver(this));
+  routes_observer_.reset(new UIMediaRoutesObserver(router_, this));
+
+  query_result_manager_.reset(new QueryResultManager(router_));
+  query_result_manager_->AddObserver(this);
+
+  // These modes are always available.
+  // Use the same MediaSource for all mirroring modes for now.
+  // TODO(imcheng): Figure out MediaSources for the different modes.
+  initiator_ = initiator;
+  MediaSource mirroring_source(
+      MediaSourceForTab(SessionTabHelper::IdForTab(initiator)));
+  query_result_manager_->StartSinksQuery(
+      MediaCastMode::DESKTOP_OR_WINDOW_MIRROR, MediaSourceForDesktop());
+  query_result_manager_->StartSinksQuery(
+      MediaCastMode::SOUND_OPTIMIZED_TAB_MIRROR, mirroring_source);
+  query_result_manager_->StartSinksQuery(MediaCastMode::TAB_MIRROR,
+                                         mirroring_source);
+
+  OnDefaultMediaSourceChanged(default_source, default_frame_url);
+}
+
+void MediaRouterUI::OnDefaultMediaSourceChanged(const MediaSource& source,
+                                                const GURL& frame_url) {
+  if (source.Empty()) {
+    query_result_manager_->StopSinksQuery(MediaCastMode::DEFAULT);
+  } else {
+    query_result_manager_->StartSinksQuery(MediaCastMode::DEFAULT, source);
+  }
+  UpdateSourceHostAndCastModes(frame_url);
+}
+
+void MediaRouterUI::HandleRouteResponseForPresentation(
+    const MediaRoute* route,
+    const std::string& error) {
+  if (!route) {
+    presentation_session_request_->MaybeInvokeErrorCallback(
+        content::PresentationError(content::PRESENTATION_ERROR_UNKNOWN, error));
+  } else {
+    // TODO(imcheng): Presentation ID should come from the response
+    // as the IDs might not be the same.
+    presentation_session_request_->MaybeInvokeSuccessCallback();
+  }
+}
+
+void MediaRouterUI::UpdateSourceHostAndCastModes(const GURL& frame_url) {
+  DCHECK(query_result_manager_);
+  frame_url_ = frame_url;
+  query_result_manager_->GetSupportedCastModes(&cast_modes_);
+  if (ui_initialized_)
+    handler_->UpdateCastModes(cast_modes_, GetHostFromURL(frame_url_));
 }
 
 void MediaRouterUI::Close() {
+  if (presentation_session_request_.get()) {
+    presentation_session_request_->MaybeInvokeErrorCallback(
+        content::PresentationError(
+            content::PRESENTATION_ERROR_SESSION_REQUEST_CANCELLED,
+            "Dialog closed."));
+  }
+
   ConstrainedWebDialogDelegate* delegate = GetConstrainedDelegate();
   if (delegate) {
     delegate->GetWebDialogDelegate()->OnDialogClosed(std::string());
@@ -131,8 +245,8 @@
   if (cast_modes_.empty())
     return std::string();
 
-  // TODO(imcheng): Pass in source_host_ once DEFAULT mode is upstreamed.
-  return MediaCastModeToTitle(GetPreferredCastMode(cast_modes_), std::string());
+  return MediaCastModeToTitle(GetPreferredCastMode(cast_modes_),
+                              GetHostFromURL(frame_url_));
 }
 
 void MediaRouterUI::OnResultsUpdated(
@@ -162,7 +276,20 @@
   else
     handler_->AddRoute(*route);
 
+  if (requesting_route_for_default_source_) {
+    if (presentation_session_request_.get()) {
+      HandleRouteResponseForPresentation(route.get(), error);
+    } else {
+      // Dialog initiated via browser action. Let
+      // PresentationServiceDelegateImpl perform the match against the default
+      // presentation URL.
+      if (route && presentation_service_delegate_.get())
+        presentation_service_delegate_->OnRouteCreated(*route);
+    }
+  }
+
   has_pending_route_request_ = false;
+  requesting_route_for_default_source_ = false;
 }
 
 bool MediaRouterUI::DoCreateRoute(const MediaSink::Id& sink_id,
@@ -182,6 +309,7 @@
   }
 
   has_pending_route_request_ = true;
+  requesting_route_for_default_source_ = cast_mode == MediaCastMode::DEFAULT;
   router_->CreateRoute(source.id(), sink_id,
                        base::Bind(&MediaRouterUI::OnRouteResponseReceived,
                                   weak_factory_.GetWeakPtr()));
@@ -189,4 +317,3 @@
 }
 
 }  // namespace media_router
-
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.h b/chrome/browser/ui/webui/media_router/media_router_ui.h
index 33768de..be21125 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.h
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.h
@@ -5,30 +5,68 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_UI_H_
 #define CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_UI_H_
 
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/media/router/issue.h"
+#include "chrome/browser/media/router/media_source.h"
+#include "chrome/browser/media/router/presentation_service_delegate_impl.h"
 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
 #include "chrome/browser/ui/webui/media_router/media_cast_mode.h"
 #include "chrome/browser/ui/webui/media_router/media_sink_with_cast_modes.h"
 #include "chrome/browser/ui/webui/media_router/query_result_manager.h"
 #include "content/public/browser/web_ui_data_source.h"
 
+namespace content {
+class WebContents;
+}  // namespace content
+
 namespace media_router {
 
 class IssuesObserver;
+class MediaRoute;
+class MediaRouter;
 class MediaRouterWebUIMessageHandler;
 class MediaRoutesObserver;
+class MediaSink;
+class MediaSinksObserver;
+class CreateSessionRequest;
 
 // Implements the chrome://media-router user interface.
-class MediaRouterUI : public ConstrainedWebDialogUI,
-                      public QueryResultManager::Observer {
+class MediaRouterUI
+    : public ConstrainedWebDialogUI,
+      public QueryResultManager::Observer,
+      public PresentationServiceDelegateImpl::DefaultMediaSourceObserver {
  public:
   // |web_ui| owns this object and is used to initialize the base class.
   explicit MediaRouterUI(content::WebUI* web_ui);
   ~MediaRouterUI() override;
 
+  // Initializes internal state (e.g. starts listening for MediaSinks) for
+  // targeting the default MediaSource (if any) of the tab. The contents of the
+  // UI will change as the default MediaSource changes. If there is a default
+  // MediaSource, then DEFAULT MediaCastMode will be added to |cast_modes_|.
+  // |source_manager|: PresentationServiceDelegateImpl of the initiator tab.
+  // Must not be null.
+  // Can only be called once.
+  // TODO(imcheng): Replace use of impl with an intermediate abstract
+  // interface.
+  void InitWithDefaultMediaSource(PresentationServiceDelegateImpl* delegate);
+
+  // Initializes internal state targeting the presentation specified in
+  // |request|. Also sets up mirroring sources based on |initiator|.
+  // This is different from |InitWithDefaultMediaSource| in that it does not
+  // listen for default media source changes, as the UI is fixed to the source
+  // in |request|.
+  void InitWithPresentationSessionRequest(
+      const content::WebContents* initiator,
+      scoped_ptr<CreateSessionRequest> request);
+
   // Closes the media router UI.
   void Close();
 
@@ -61,10 +99,13 @@
   std::string GetInitialHeaderText() const;
 
   bool has_pending_route_request() const { return has_pending_route_request_; }
+  const GURL& frame_url() const { return frame_url_; }
   const std::vector<MediaSinkWithCastModes>& sinks() const { return sinks_; }
   const std::vector<MediaRoute>& routes() const { return routes_; }
   const std::set<MediaCastMode>& cast_modes() const { return cast_modes_; }
 
+  const content::WebContents* initiator() const { return initiator_; }
+
  private:
   class UIIssuesObserver;
   class UIMediaRoutesObserver;
@@ -88,6 +129,26 @@
 
   bool DoCreateRoute(const MediaSink::Id& sink_id, MediaCastMode cast_mode);
 
+  // Sets the source host name to be displayed in the UI.
+  // Gets cast modes from |query_result_manager_| and forwards it to UI.
+  // One of the Init* functions must have been called before.
+  void UpdateSourceHostAndCastModes(const GURL& frame_url);
+
+  // Initializes the dialog with mirroring sources derived from |initiator|,
+  // and optional |default_source| and |default_frame_url| if any.
+  void InitCommon(const content::WebContents* initiator,
+                  const MediaSource& default_source,
+                  const GURL& default_frame_url);
+
+  // Invoke presentation callbacks based on |route| and |error| if the dialog
+  // was created for Presentation API.
+  void HandleRouteResponseForPresentation(const MediaRoute* route,
+                                          const std::string& error);
+
+  // PresentationServiceDelegateImpl::DefaultMediaSourceObserver
+  void OnDefaultMediaSourceChanged(const MediaSource& source,
+                                   const GURL& frame_url) override;
+
   // Owned by the |web_ui| passed in the ctor, and guaranteed to be deleted
   // only after it has deleted |this|.
   MediaRouterWebUIMessageHandler* handler_;
@@ -103,12 +164,29 @@
   // Set to |true| if there is a pending route request for this UI.
   bool has_pending_route_request_;
 
+  bool requesting_route_for_default_source_;
+
   std::vector<MediaSinkWithCastModes> sinks_;
   std::vector<MediaRoute> routes_;
   CastModeSet cast_modes_;
+  GURL frame_url_;
 
   scoped_ptr<QueryResultManager> query_result_manager_;
 
+  // Only set if the UI is created as a result of Presentation API.
+  scoped_ptr<CreateSessionRequest> presentation_session_request_;
+
+  // It's possible for PresentationServiceDelegateImpl to be destroyed before
+  // this class.
+  // (e.g. if a tab with the UI open is closed, then the tab WebContents will
+  // be destroyed first momentarily before the UI WebContents).
+  // Holding a WeakPtr to PresentationServiceDelegateImpl is the cleanest way to
+  // handle this.
+  // TODO(imcheng): hold a weak ptr to an abstract type instead.
+  base::WeakPtr<PresentationServiceDelegateImpl> presentation_service_delegate_;
+
+  const content::WebContents* initiator_;
+
   // Cached pointer to the MediaRouter for this instance's BrowserContext.
   MediaRouter* router_;
 
diff --git a/chrome/browser/ui/webui/ntp/favicon_webui_handler.cc b/chrome/browser/ui/webui/ntp/favicon_webui_handler.cc
index 8f1c392..dcb600d 100644
--- a/chrome/browser/ui/webui/ntp/favicon_webui_handler.cc
+++ b/chrome/browser/ui/webui/ntp/favicon_webui_handler.cc
@@ -84,7 +84,7 @@
   std::string path;
   CHECK(args->GetString(0, &path));
   std::string prefix = "chrome://favicon/size/";
-  DCHECK(StartsWithASCII(path, prefix, false)) << "path is " << path;
+  DCHECK(base::StartsWithASCII(path, prefix, false)) << "path is " << path;
   size_t slash = path.find("/", prefix.length());
   path = path.substr(slash + 1);
 
diff --git a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc
index dba6e45..3d7e62f 100644
--- a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc
@@ -124,11 +124,14 @@
   UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTileFallbacks",
                           number_of_external_tile_fallbacks_);
   number_of_external_tile_fallbacks_ = 0;
-  UMA_HISTOGRAM_CUSTOM_TIMES("NewTabPage.LoadTime",
-                             load_time_,
-                             base::TimeDelta::FromMilliseconds(1),
-                             base::TimeDelta::FromSeconds(60), 100);
-  load_time_ = base::TimeDelta::FromMilliseconds(0);
+  // LoadTime only gets update once per page, so we don't have it on reloads.
+  if (load_time_ > base::TimeDelta::FromMilliseconds(0)) {
+    UMA_HISTOGRAM_CUSTOM_TIMES("NewTabPage.LoadTime",
+                               load_time_,
+                               base::TimeDelta::FromMilliseconds(1),
+                               base::TimeDelta::FromSeconds(60), 100);
+    load_time_ = base::TimeDelta::FromMilliseconds(0);
+  }
   has_emitted_ = true;
 }
 
diff --git a/chrome/browser/ui/webui/options/certificate_manager_handler.cc b/chrome/browser/ui/webui/options/certificate_manager_handler.cc
index 12b76ef..cf03f83 100644
--- a/chrome/browser/ui/webui/options/certificate_manager_handler.cc
+++ b/chrome/browser/ui/webui/options/certificate_manager_handler.cc
@@ -13,7 +13,7 @@
 #include "base/i18n/string_compare.h"
 #include "base/id_map.h"
 #include "base/memory/scoped_vector.h"
-#include "base/safe_strerror_posix.h"
+#include "base/posix/safe_strerror.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -692,7 +692,8 @@
     ShowError(
         l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
         l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_WRITE_ERROR_FORMAT,
-                                  UTF8ToUTF16(safe_strerror(*write_errno))));
+                                  UTF8ToUTF16(
+                                      base::safe_strerror(*write_errno))));
   }
 }
 
@@ -749,7 +750,8 @@
     ShowError(
         l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
         l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
-                                  UTF8ToUTF16(safe_strerror(*read_errno))));
+                                  UTF8ToUTF16(
+                                      base::safe_strerror(*read_errno))));
     return;
   }
 
@@ -857,7 +859,8 @@
     ShowError(
         l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
         l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
-                                  UTF8ToUTF16(safe_strerror(*read_errno))));
+                                  UTF8ToUTF16(
+                                      base::safe_strerror(*read_errno))));
     return;
   }
 
@@ -916,7 +919,8 @@
     ShowError(
         l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
         l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
-                                  UTF8ToUTF16(safe_strerror(*read_errno))));
+                                  UTF8ToUTF16(
+                                      base::safe_strerror(*read_errno))));
     return;
   }
 
diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
index 036770a..6b8a0bf 100644
--- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
@@ -15,6 +15,7 @@
 #include "base/bind_helpers.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/enrollment_dialog_view.h"
 #include "chrome/browser/chromeos/mobile_config.h"
 #include "chrome/browser/chromeos/options/network_config_view.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -303,10 +304,14 @@
 
 void InternetOptionsHandler::ConfigureNetwork(const base::ListValue* args) {
   std::string guid;
-  if (args->GetSize() != 1 || !args->GetString(0, &guid)) {
+  if (args->GetSize() < 1 || !args->GetString(0, &guid)) {
     NOTREACHED();
     return;
   }
+  bool force_show = false;
+  if (args->GetSize() >= 2)
+    args->GetBoolean(1, &force_show);
+
   const std::string service_path = ServicePathFromGuid(guid);
   if (service_path.empty())
     return;
@@ -325,6 +330,12 @@
     return;
   }
 
+  // If a network is not connectable, show the enrollment dialog if available.
+  if (!force_show && !network->connectable() &&
+      enrollment::CreateDialog(service_path, GetNativeWindow())) {
+    return;
+  }
+
   NetworkConfigView::Show(service_path, GetNativeWindow());
 }
 
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler.cc b/chrome/browser/ui/webui/options/sync_setup_handler.cc
index 48e10b0..5599612 100644
--- a/chrome/browser/ui/webui/options/sync_setup_handler.cc
+++ b/chrome/browser/ui/webui/options/sync_setup_handler.cc
@@ -470,7 +470,7 @@
 
 ProfileSyncService* SyncSetupHandler::GetSyncService() const {
   Profile* profile = GetProfile();
-  return profile->IsSyncAccessible() ?
+  return profile->IsSyncAllowed() ?
       ProfileSyncServiceFactory::GetForProfile(GetProfile()) : NULL;
 }
 
@@ -803,7 +803,7 @@
   ProfileSyncService* service = GetSyncService();
   DCHECK(service);
   if (!service->backend_initialized()) {
-    service->UnsuppressAndStart();
+    service->RequestStart();
 
     // See if it's even possible to bring up the sync backend - if not
     // (unrecoverable error?), don't bother displaying a spinner that will be
diff --git a/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
index 61faba5..2b4af17 100644
--- a/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
@@ -441,8 +441,9 @@
   DISALLOW_COPY_AND_ASSIGN(FakePrinterProviderAPI);
 };
 
-KeyedService* BuildTestingPrinterProviderAPI(content::BrowserContext* context) {
-  return new FakePrinterProviderAPI();
+scoped_ptr<KeyedService> BuildTestingPrinterProviderAPI(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(new FakePrinterProviderAPI());
 }
 
 class FakeDeviceClient : public device::DeviceClient {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 6d6ffae..43df837 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -210,6 +210,16 @@
                              IDS_PRINT_PREVIEW_PAGE_LABEL_SINGULAR);
   source->AddLocalizedString("printPreviewPageLabelPlural",
                              IDS_PRINT_PREVIEW_PAGE_LABEL_PLURAL);
+  source->AddLocalizedString("selectButton",
+                             IDS_PRINT_PREVIEW_BUTTON_SELECT);
+  source->AddLocalizedString("goBackButton",
+                             IDS_PRINT_PREVIEW_BUTTON_GO_BACK);
+  source->AddLocalizedString(
+      "resolveExtensionUSBPermissionMessage",
+      IDS_PRINT_PREVIEW_RESOLVE_EXTENSION_USB_PERMISSION_MESSAGE);
+  source->AddLocalizedString(
+      "resolveExtensionUSBErrorMessage",
+      IDS_PRINT_PREVIEW_RESOLVE_EXTENSION_USB_ERROR_MESSAGE);
   const base::string16 shortcut_text(base::UTF8ToUTF16(kBasicPrintShortcut));
 #if !defined(OS_CHROMEOS)
   source->AddString(
diff --git a/chrome/browser/ui/webui/settings/appearance_handler.cc b/chrome/browser/ui/webui/settings/appearance_handler.cc
new file mode 100644
index 0000000..01ead427
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/appearance_handler.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/settings/appearance_handler.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/themes/theme_service_factory.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/web_ui.h"
+
+namespace settings {
+
+AppearanceHandler::AppearanceHandler(content::WebUI* webui)
+    : profile_(Profile::FromWebUI(webui)) {
+  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+                 content::Source<ThemeService>(
+                     ThemeServiceFactory::GetForProfile(profile_)));
+}
+
+AppearanceHandler::~AppearanceHandler() {
+  registrar_.RemoveAll();
+}
+
+void AppearanceHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "resetTheme",
+      base::Bind(&AppearanceHandler::ResetTheme, base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "getResetThemeEnabled",
+      base::Bind(&AppearanceHandler::GetResetThemeEnabled,
+                 base::Unretained(this)));
+}
+
+void AppearanceHandler::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  switch (type) {
+    case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: {
+      base::StringValue event("reset-theme-enabled-changed");
+      base::FundamentalValue enabled(QueryResetThemeEnabledState());
+      web_ui()->CallJavascriptFunction(
+          "cr.webUIListenerCallback", event, enabled);
+      break;
+    }
+    default:
+      NOTREACHED();
+  }
+}
+
+void AppearanceHandler::ResetTheme(const base::ListValue* /* args */) {
+  Profile* profile = Profile::FromWebUI(web_ui());
+  ThemeServiceFactory::GetForProfile(profile)->UseDefaultTheme();
+}
+
+base::FundamentalValue AppearanceHandler::QueryResetThemeEnabledState() {
+  ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_);
+  bool is_system_theme = false;
+
+  // TODO(jhawkins): Handle native/system theme button.
+
+  bool is_classic_theme = !is_system_theme &&
+                          theme_service->UsingDefaultTheme();
+  return base::FundamentalValue(!is_classic_theme);
+}
+
+void AppearanceHandler::GetResetThemeEnabled(const base::ListValue* args) {
+  CHECK_EQ(2U, args->GetSize());
+
+  std::string callbackFn;
+  CHECK(args->GetString(0, &callbackFn));
+  const base::Value* callbackId;
+  CHECK(args->Get(1, &callbackId));
+
+  base::FundamentalValue enabled(QueryResetThemeEnabledState());
+  web_ui()->CallJavascriptFunction(callbackFn, *callbackId, enabled);
+}
+
+}  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/appearance_handler.h b/chrome/browser/ui/webui/settings/appearance_handler.h
new file mode 100644
index 0000000..56161bd
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/appearance_handler.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_APPEARANCE_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SETTINGS_APPEARANCE_HANDLER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+namespace base {
+class ListValue;
+}
+
+namespace content {
+class WebUI;
+}
+
+class Profile;
+
+namespace settings {
+
+// Chrome "Appearance" settings page UI handler.
+class AppearanceHandler : public SettingsPageUIHandler,
+                          public content::NotificationObserver {
+ public:
+  explicit AppearanceHandler(content::WebUI* webui);
+  ~AppearanceHandler() override;
+
+  // SettingsPageUIHandler implementation.
+  void RegisterMessages() override;
+
+ private:
+  // content::NotificationObserver implementation.
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
+  // Queries the enabled state of the reset-theme control.
+  base::FundamentalValue QueryResetThemeEnabledState();
+
+  // Resets the UI theme of the browser to the default theme.
+  void ResetTheme(const base::ListValue*);
+
+  // Sends the enabled state of the reset-theme control to the JS.
+  void GetResetThemeEnabled(const base::ListValue* args);
+
+  Profile* profile_;  // Weak pointer.
+
+  // Used to register for relevant notifications.
+  content::NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppearanceHandler);
+};
+
+}  // namespace settings
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_APPEARANCE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index e9b373e..81b2e07 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -4,10 +4,14 @@
 
 #include "chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.h"
 
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
+#include "chrome/grit/google_chrome_strings.h"
 #include "chrome/grit/locale_settings.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace {
 
@@ -113,6 +117,42 @@
 }
 #endif
 
+void AddPrivacyStrings(content::WebUIDataSource* html_source) {
+  html_source->AddLocalizedString("privacyPageTitle",
+                                  IDS_SETTINGS_PRIVACY_PAGE_TITLE);
+  html_source->AddString("improveBrowsingExperience",
+                         l10n_util::GetStringFUTF16(
+                             IDS_SETTINGS_IMPROVE_BROWSING_EXPERIENCE,
+                             base::ASCIIToUTF16(chrome::kPrivacyLearnMoreURL)));
+  html_source->AddLocalizedString("linkDoctorPref",
+                                  IDS_SETTINGS_LINKDOCTOR_PREF);
+  html_source->AddLocalizedString("searchSuggestPref",
+                                  IDS_SETTINGS_SUGGEST_PREF);
+  html_source->AddLocalizedString(
+      "networkPredictionEnabled",
+      IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESCRIPTION);
+  html_source->AddLocalizedString("safeBrowsingEnableProtection",
+                                  IDS_SETTINGS_SAFEBROWSING_ENABLEPROTECTION);
+  html_source->AddLocalizedString(
+      "safeBrowsingEnableExtendedReporting",
+      IDS_SETTINGS_SAFEBROWSING_ENABLE_EXTENDED_REPORTING);
+  html_source->AddLocalizedString("spellingPref",
+                                  IDS_SETTINGS_SPELLING_PREF);
+  html_source->AddLocalizedString("enableLogging",
+                                  IDS_SETTINGS_ENABLE_LOGGING);
+  html_source->AddLocalizedString("doNotTrack",
+                                  IDS_SETTINGS_ENABLE_DO_NOT_TRACK);
+  html_source->AddLocalizedString(
+      "enableContentProtectionAttestation",
+      IDS_SETTINGS_ENABLE_CONTENT_PROTECTION_ATTESTATION);
+  html_source->AddLocalizedString("wakeOnWifi",
+                                  IDS_SETTINGS_WAKE_ON_WIFI_DESCRIPTION);
+  html_source->AddLocalizedString("siteSettingsLabel",
+                                  IDS_SETTINGS_SITE_SETTINGS);
+  html_source->AddLocalizedString("clearBrowsingDataLabel",
+                                  IDS_SETTINGS_CLEAR_DATA);
+}
+
 void AddSearchStrings(content::WebUIDataSource* html_source) {
   html_source->AddLocalizedString("searchPageTitle",
                                   IDS_SETTINGS_SEARCH_PAGE_TITLE);
@@ -228,6 +268,7 @@
 #if defined(OS_CHROMEOS)
   AddInternetStrings(html_source);
 #endif
+  AddPrivacyStrings(html_source);
   AddSearchStrings(html_source);
   AddSearchEnginesStrings(html_source);
   AddSyncStrings(html_source);
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index 0d7d578e..ced1ef5 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/settings/appearance_handler.h"
 #include "chrome/browser/ui/webui/settings/downloads_handler.h"
 #include "chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.h"
 #include "chrome/common/url_constants.h"
@@ -28,8 +29,8 @@
 
 MdSettingsUI::MdSettingsUI(content::WebUI* web_ui)
     : content::WebUIController(web_ui) {
-  DownloadsHandler* downloads_handler = new DownloadsHandler();
-  AddSettingsPageUIHandler(downloads_handler);
+  AddSettingsPageUIHandler(new AppearanceHandler(web_ui));
+  AddSettingsPageUIHandler(new DownloadsHandler());
 
   content::WebUIDataSource* html_source =
       content::WebUIDataSource::Create(chrome::kChromeUIMdSettingsHost);
diff --git a/chrome/browser/web_applications/web_app_mac.mm b/chrome/browser/web_applications/web_app_mac.mm
index 12fd2df1..f5c8e8d1 100644
--- a/chrome/browser/web_applications/web_app_mac.mm
+++ b/chrome/browser/web_applications/web_app_mac.mm
@@ -212,11 +212,10 @@
   base::FilePath user_data_dir;
   PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
   DCHECK(!user_data_dir.empty());
-  return StartsWithASCII(
+  return base::StartsWithASCII(
       base::SysNSStringToUTF8(
           [plist valueForKey:app_mode::kCrAppModeUserDataDirKey]),
-      user_data_dir.value(),
-      true /* case_sensitive */);
+      user_data_dir.value(), true /* case_sensitive */);
 }
 
 void LaunchShimOnFileThread(scoped_ptr<web_app::ShortcutInfo> shortcut_info,
@@ -454,7 +453,7 @@
 
 bool IsShimForProfile(const base::FilePath& base_name,
                       const std::string& profile_base_name) {
-  if (!StartsWithASCII(base_name.value(), profile_base_name, true))
+  if (!base::StartsWithASCII(base_name.value(), profile_base_name, true))
     return false;
 
   if (base_name.Extension() != ".app")
diff --git a/chrome/chrome.isolate b/chrome/chrome.isolate
index 6ba6903..43bc6056 100644
--- a/chrome/chrome.isolate
+++ b/chrome/chrome.isolate
@@ -6,7 +6,6 @@
     ['OS=="linux"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
         ],
       },
@@ -71,7 +70,6 @@
           '<(PRODUCT_DIR)/<(mac_product_name) Helper.app/',
           '<(PRODUCT_DIR)/<(mac_product_name).app/',
           '<(PRODUCT_DIR)/exif.so',
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
         ],
       },
     }],
@@ -82,7 +80,6 @@
           '<(PRODUCT_DIR)/<(mac_product_name) Helper.app.dSYM/',
           '<(PRODUCT_DIR)/<(mac_product_name).app.dSYM/',
           '<(PRODUCT_DIR)/exif.so.dSYM/',
-          '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
         ],
       },
     }],
@@ -93,7 +90,6 @@
           '<(PRODUCT_DIR)/chrome_200_percent.pak',
           '<(PRODUCT_DIR)/chrome.dll',
           '<(PRODUCT_DIR)/chrome_elf.dll',
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/libexif.dll',
           '<(PRODUCT_DIR)/osmesa.dll',
         ],
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 97645e85..fb92804 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -76,8 +76,6 @@
       'browser/android/compositor/scene_layer/static_tab_scene_layer.h',
       'browser/android/compositor/tab_content_manager.cc',
       'browser/android/compositor/tab_content_manager.h',
-      'browser/android/content_view_util.cc',
-      'browser/android/content_view_util.h',
       'browser/android/cookies/cookies_fetcher.cc',
       'browser/android/cookies/cookies_fetcher.h',
       'browser/android/dev_tools_discovery_provider_android.cc',
@@ -220,6 +218,8 @@
       'browser/android/warmup_manager.h',
       'browser/android/webapps/single_tab_mode_tab_helper.cc',
       'browser/android/webapps/single_tab_mode_tab_helper.h',
+      'browser/android/web_contents_factory.cc',
+      'browser/android/web_contents_factory.h',
       'browser/app_controller_mac.h',
       'browser/app_controller_mac.mm',
       'browser/app_icon_win.cc',
@@ -411,6 +411,8 @@
       'browser/download/download_service.h',
       'browser/download/download_service_factory.cc',
       'browser/download/download_service_factory.h',
+      'browser/download/download_service_impl.cc',
+      'browser/download/download_service_impl.h',
       'browser/download/download_started_animation.h',
       'browser/download/download_stats.cc',
       'browser/download/download_stats.h',
@@ -556,6 +558,7 @@
       'browser/media/desktop_media_picker.h',
       'browser/media/desktop_streams_registry.cc',
       'browser/media/desktop_streams_registry.h',
+      'browser/media/media_access_handler.h',
       'browser/media/media_capture_devices_dispatcher.cc',
       'browser/media/media_capture_devices_dispatcher.h',
       'browser/media/media_device_id_salt.cc',
@@ -578,6 +581,8 @@
       'browser/media/midi_permission_infobar_delegate.h',
       'browser/media/native_desktop_media_list.cc',
       'browser/media/native_desktop_media_list.h',
+      'browser/media/permission_bubble_media_access_handler.cc',
+      'browser/media/permission_bubble_media_access_handler.h',
       # TODO(brettw) should this go with the webrtc sources?
       'browser/media/webrtc_log_list.cc',
       'browser/media/webrtc_log_list.h',
@@ -604,8 +609,6 @@
       'browser/platform_util_internal.h',
       'browser/platform_util_mac.mm',
       'browser/platform_util_win.cc',
-      'browser/precache/most_visited_urls_provider.cc',
-      'browser/precache/most_visited_urls_provider.h',
       'browser/pref_service_flags_storage.cc',
       'browser/pref_service_flags_storage.h',
       'browser/prefetch/prefetch.cc',
@@ -1284,8 +1287,6 @@
       'browser/autocomplete/in_memory_url_index.h',
       'browser/autocomplete/in_memory_url_index_factory.cc',
       'browser/autocomplete/in_memory_url_index_factory.h',
-      'browser/autocomplete/in_memory_url_index_types.cc',
-      'browser/autocomplete/in_memory_url_index_types.h',
       'browser/autocomplete/scored_history_match.cc',
       'browser/autocomplete/scored_history_match.h',
       'browser/autocomplete/shortcuts_backend.cc',
@@ -1326,6 +1327,8 @@
       'browser/bookmarks/chrome_bookmark_client_factory.h',
       'browser/bookmarks/enhanced_bookmarks_features.cc',
       'browser/bookmarks/enhanced_bookmarks_features.h',
+      'browser/bookmarks/startup_task_runner_service_factory.cc',
+      'browser/bookmarks/startup_task_runner_service_factory.h',
       'browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.cc',
       'browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.h',
       'browser/enhanced_bookmarks/enhanced_bookmark_model_factory.cc',
@@ -1433,8 +1436,6 @@
       'browser/guest_view/app_view/chrome_app_view_guest_delegate.h',
       'browser/guest_view/extension_options/chrome_extension_options_guest_delegate.cc',
       'browser/guest_view/extension_options/chrome_extension_options_guest_delegate.h',
-      'browser/guest_view/extension_view/chrome_extension_view_guest_delegate.cc',
-      'browser/guest_view/extension_view/chrome_extension_view_guest_delegate.h',
       'browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.cc',
       'browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.h',
       'browser/guest_view/web_view/chrome_web_view_guest_delegate.cc',
@@ -1445,6 +1446,12 @@
       'browser/guest_view/web_view/context_menu_content_type_web_view.h',
       'browser/media/cast_transport_host_filter.cc',
       'browser/media/cast_transport_host_filter.h',
+      'browser/media/desktop_capture_access_handler.cc',
+      'browser/media/desktop_capture_access_handler.h',
+      'browser/media/extension_media_access_handler.cc',
+      'browser/media/extension_media_access_handler.h',
+      'browser/media/tab_capture_access_handler.cc',
+      'browser/media/tab_capture_access_handler.h',
       'browser/metrics/extensions_metrics_provider.cc',
       'browser/metrics/extensions_metrics_provider.h',
       'browser/renderer_context_menu/context_menu_content_type_app_mode.cc',
@@ -1612,8 +1619,6 @@
       'browser/favicon/chrome_fallback_icon_client_factory.h',
       'browser/favicon/chrome_favicon_client.cc',
       'browser/favicon/chrome_favicon_client.h',
-      'browser/favicon/chrome_favicon_client_factory.cc',
-      'browser/favicon/chrome_favicon_client_factory.h',
       'browser/favicon/fallback_icon_service_factory.cc',
       'browser/favicon/fallback_icon_service_factory.h',
       'browser/favicon/favicon_helper.cc',
@@ -1695,7 +1700,6 @@
       'android/java/src/org/chromium/chrome/browser/ChromeBrowserProvider.java',
       'android/java/src/org/chromium/chrome/browser/ChromeHttpAuthHandler.java',
       'android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java',
-      'android/java/src/org/chromium/chrome/browser/ContentViewUtil.java',
       'android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java',
       'android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java',
       'android/java/src/org/chromium/chrome/browser/compositor/scene_layer/SceneLayer.java',
@@ -1768,6 +1772,7 @@
       'android/java/src/org/chromium/chrome/browser/UrlUtilities.java',
       'android/java/src/org/chromium/chrome/browser/WarmupManager.java',
       'android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java',
+      'android/java/src/org/chromium/chrome/browser/WebContentsFactory.java',
       'android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java',
       'android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java',
       'android/java/src/org/chromium/chrome/browser/infobar/AccountChooserInfoBar.java',
@@ -2391,10 +2396,6 @@
       'browser/profiles/profile_shortcut_manager_win.h',
       'browser/profiles/profiles_state.cc',
       'browser/profiles/profiles_state.h',
-      'browser/profiles/startup_task_runner_service.cc',
-      'browser/profiles/startup_task_runner_service.h',
-      'browser/profiles/startup_task_runner_service_factory.cc',
-      'browser/profiles/startup_task_runner_service_factory.h',
       'browser/profiles/storage_partition_descriptor.h',
     ],
     'chrome_browser_rlz_sources': [
@@ -2434,11 +2435,11 @@
     'chrome_browser_safe_browsing_mobile_extended_sources': [
       'browser/renderer_host/safe_browsing_resource_throttle.cc',
       'browser/renderer_host/safe_browsing_resource_throttle.h',
-      'browser/safe_browsing/android_safe_browsing_api_handler.cc',
-      'browser/safe_browsing/android_safe_browsing_api_handler.h',
       'browser/safe_browsing/database_manager.h',
       'browser/safe_browsing/remote_database_manager.cc',
       'browser/safe_browsing/remote_database_manager.h',
+      'browser/safe_browsing/safe_browsing_api_handler.cc',
+      'browser/safe_browsing/safe_browsing_api_handler.h',
     ],
     # "Safe Browsing Full" files in addition to the "basic" ones to use for
     # full safe browsing. This has some in common with "mobile_extended."
@@ -3580,6 +3581,9 @@
         ['enable_session_service==1', {
           'sources': [ '<@(chrome_browser_session_service_sources)' ],
         }],
+        ['enable_hotwording==1', {
+          'defines': [ 'ENABLE_HOTWORDING' ],
+        }],
         ['OS!="android" and OS!="ios" and chromeos==0', {
           'sources': [ '<@(chrome_browser_desktop_sources)' ],
         }],
@@ -3590,6 +3594,7 @@
           'dependencies': [
             '../components/components.gyp:feedback_component',
             '../device/core/core.gyp:device_core',
+            '../device/devices_app/devices_app.gyp:devices_app_lib',
             '../device/usb/usb.gyp:device_usb',
             '../net/net.gyp:net_browser_services',
           ]
@@ -3624,6 +3629,9 @@
           'conditions': [
             ['use_seccomp_bpf==1', {
               'defines': ['USE_SECCOMP_BPF'],
+              'dependencies': [
+                '../sandbox/sandbox.gyp:seccomp_bpf',
+              ],
             }],
           ],
         }],
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index f62851a..4d3b94e3 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -708,6 +708,8 @@
         'browser/chromeos/login/wizard_controller.h',
         'browser/chromeos/memory/low_memory_observer.cc',
         'browser/chromeos/memory/low_memory_observer.h',
+        'browser/chromeos/memory/oom_memory_details.cc',
+        'browser/chromeos/memory/oom_memory_details.h',
         'browser/chromeos/memory/oom_priority_manager.cc',
         'browser/chromeos/memory/oom_priority_manager.h',
         'browser/chromeos/memory/system_memory_stats_recorder.cc',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 51613b6..9b71ff1 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -134,6 +134,8 @@
       'browser/extensions/api/autofill_private/autofill_util.cc',
       'browser/extensions/api/autofill_private/autofill_util.h',
       'browser/extensions/api/automation_internal/automation_action_adapter.h',
+      'browser/extensions/api/automation_internal/automation_event_router.cc',
+      'browser/extensions/api/automation_internal/automation_event_router.h',
       'browser/extensions/api/automation_internal/automation_internal_api.cc',
       'browser/extensions/api/automation_internal/automation_internal_api.h',
       'browser/extensions/api/automation_internal/automation_util.cc',
@@ -213,6 +215,8 @@
       'browser/extensions/api/declarative_content/content_condition.h',
       'browser/extensions/api/declarative_content/content_constants.cc',
       'browser/extensions/api/declarative_content/content_constants.h',
+      'browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.cc',
+      'browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h',
       'browser/extensions/api/desktop_capture/desktop_capture_api.cc',
       'browser/extensions/api/desktop_capture/desktop_capture_api.h',
       'browser/extensions/api/desktop_capture/desktop_capture_base.cc',
@@ -546,6 +550,8 @@
       'browser/extensions/chrome_component_extension_resource_manager.h',
       'browser/extensions/chrome_content_browser_client_extensions_part.cc',
       'browser/extensions/chrome_content_browser_client_extensions_part.h',
+      'browser/extensions/chrome_content_verifier_delegate.cc',
+      'browser/extensions/chrome_content_verifier_delegate.h',
       'browser/extensions/chrome_extension_function.cc',
       'browser/extensions/chrome_extension_function.h',
       'browser/extensions/chrome_extension_function_details.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 58ee9ce..4ee0a9b4 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -760,7 +760,7 @@
       'browser/ui/cocoa/applescript/tab_applescript.mm',
       'browser/ui/cocoa/applescript/window_applescript.h',
       'browser/ui/cocoa/applescript/window_applescript.mm',
-      'browser/ui/cocoa/apps/chrome_app_window_client_cocoa.mm',
+      'browser/ui/cocoa/apps/chrome_app_window_client_views_cocoa.mm',
       'browser/ui/cocoa/apps/native_app_window_cocoa.h',
       'browser/ui/cocoa/apps/native_app_window_cocoa.mm',
       'browser/ui/cocoa/autofill/autofill_account_chooser.h',
@@ -1439,7 +1439,6 @@
       'browser/ui/cocoa/notifications/message_center_tray_bridge.h',
       'browser/ui/cocoa/notifications/message_center_tray_bridge.mm',
       'browser/ui/cocoa/panels/display_settings_provider_cocoa.mm',
-      'browser/ui/cocoa/panels/display_settings_provider_cocoa.mm',
       'browser/ui/cocoa/profiles/profile_menu_controller.h',
       'browser/ui/cocoa/profiles/profile_menu_controller.mm',
       'browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.h',
@@ -1912,6 +1911,8 @@
       'browser/ui/webui/quota_internals/quota_internals_types.h',
       'browser/ui/webui/quota_internals/quota_internals_ui.cc',
       'browser/ui/webui/quota_internals/quota_internals_ui.h',
+      'browser/ui/webui/settings/appearance_handler.cc',
+      'browser/ui/webui/settings/appearance_handler.h',
       'browser/ui/webui/settings/downloads_handler.cc',
       'browser/ui/webui/settings/downloads_handler.h',
       'browser/ui/webui/settings/md_settings_localized_strings_provider.cc',
@@ -1969,18 +1970,28 @@
       'browser/ui/views/apps/app_info_dialog/app_info_permissions_panel.h',
       'browser/ui/views/apps/app_info_dialog/app_info_summary_panel.cc',
       'browser/ui/views/apps/app_info_dialog/app_info_summary_panel.h',
+      'browser/ui/views/apps/app_window_native_widget_mac.h',
+      'browser/ui/views/apps/app_window_native_widget_mac.mm',
       'browser/ui/views/apps/chrome_native_app_window_views.cc',
       'browser/ui/views/apps/chrome_native_app_window_views.h',
+      'browser/ui/views/apps/chrome_native_app_window_views_mac.h',
+      'browser/ui/views/apps/chrome_native_app_window_views_mac.mm',
       'browser/ui/views/apps/desktop_keyboard_capture.cc',
       'browser/ui/views/apps/desktop_keyboard_capture.h',
       'browser/ui/views/apps/keyboard_hook_handler.cc',
       'browser/ui/views/apps/keyboard_hook_handler.h',
+      'browser/ui/views/apps/native_app_window_frame_view_mac.h',
+      'browser/ui/views/apps/native_app_window_frame_view_mac.mm',
       'browser/ui/views/chrome_browser_main_extra_parts_views.cc',
       'browser/ui/views/chrome_browser_main_extra_parts_views.h',
       'browser/ui/views/chrome_constrained_window_views_client.cc',
       'browser/ui/views/chrome_constrained_window_views_client.h',
       'browser/ui/views/chrome_views_delegate.cc',
       'browser/ui/views/chrome_views_delegate.h',
+      'browser/ui/views/extensions/extension_keybinding_registry_views.cc',
+      'browser/ui/views/extensions/extension_keybinding_registry_views.h',
+      'browser/ui/views/frame/native_widget_mac_frameless_nswindow.h',
+      'browser/ui/views/frame/native_widget_mac_frameless_nswindow.mm',
     ],
     # Views files for everywhere but ChromeOS.
     'chrome_browser_ui_views_non_chromeos_sources': [
@@ -2107,39 +2118,6 @@
       'browser/ui/views/exclusive_access_bubble_views.cc',
       'browser/ui/views/exclusive_access_bubble_views.h',
       'browser/ui/views/exclusive_access_bubble_views_context.h',
-      'browser/ui/views/extensions/bookmark_app_bubble_view.cc',
-      'browser/ui/views/extensions/bookmark_app_bubble_view.h',
-      'browser/ui/views/extensions/browser_action_drag_data.cc',
-      'browser/ui/views/extensions/browser_action_drag_data.h',
-      'browser/ui/views/extensions/bundle_installed_bubble.cc',
-      'browser/ui/views/extensions/device_permissions_dialog_view.cc',
-      'browser/ui/views/extensions/device_permissions_dialog_view.h',
-      'browser/ui/views/extensions/extension_action_platform_delegate_views.cc',
-      'browser/ui/views/extensions/extension_action_platform_delegate_views.h',
-      'browser/ui/views/extensions/extension_dialog.cc',
-      'browser/ui/views/extensions/extension_dialog.h',
-      'browser/ui/views/extensions/extension_dialog_observer.cc',
-      'browser/ui/views/extensions/extension_dialog_observer.h',
-      'browser/ui/views/extensions/extension_install_dialog_view.cc',
-      'browser/ui/views/extensions/extension_installed_bubble_view.cc',
-      'browser/ui/views/extensions/extension_installed_bubble_view.h',
-      'browser/ui/views/extensions/extension_keybinding_registry_views.cc',
-      'browser/ui/views/extensions/extension_keybinding_registry_views.h',
-      'browser/ui/views/extensions/extension_message_bubble_view.cc',
-      'browser/ui/views/extensions/extension_message_bubble_view.h',
-      'browser/ui/views/extensions/extension_popup.cc',
-      'browser/ui/views/extensions/extension_popup.h',
-      'browser/ui/views/extensions/extension_popup_aura.cc',
-      'browser/ui/views/extensions/extension_popup_aura.h',
-      'browser/ui/views/extensions/extension_toolbar_icon_surfacing_bubble_views.cc',
-      'browser/ui/views/extensions/extension_toolbar_icon_surfacing_bubble_views.h',
-      'browser/ui/views/extensions/extension_uninstall_dialog_view.cc',
-      'browser/ui/views/extensions/extension_view_views.cc',
-      'browser/ui/views/extensions/extension_view_views.h',
-      'browser/ui/views/extensions/media_galleries_dialog_views.cc',
-      'browser/ui/views/extensions/media_galleries_dialog_views.h',
-      'browser/ui/views/extensions/media_gallery_checkbox_view.cc',
-      'browser/ui/views/extensions/media_gallery_checkbox_view.h',
       'browser/ui/views/find_bar_host.cc',
       'browser/ui/views/find_bar_host.h',
       'browser/ui/views/find_bar_view.cc',
@@ -2189,8 +2167,6 @@
       'browser/ui/views/frame/native_browser_frame_factory.h',
       'browser/ui/views/frame/native_browser_frame_factory_chromeos.cc',
       'browser/ui/views/frame/native_browser_frame_factory_mac.cc',
-      'browser/ui/views/frame/native_widget_mac_frameless_nswindow.h',
-      'browser/ui/views/frame/native_widget_mac_frameless_nswindow.mm',
       'browser/ui/views/frame/opaque_browser_frame_view.cc',
       'browser/ui/views/frame/opaque_browser_frame_view.h',
       'browser/ui/views/frame/opaque_browser_frame_view_layout.cc',
@@ -2414,17 +2390,44 @@
       'browser/ui/views/website_settings/website_settings_popup_view.cc',
       'browser/ui/views/website_settings/website_settings_popup_view.h',
     ],
+    'chrome_browser_ui_views_extensions_non_mac_sources': [
+      'browser/ui/views/extensions/bookmark_app_bubble_view.cc',
+      'browser/ui/views/extensions/bookmark_app_bubble_view.h',
+      'browser/ui/views/extensions/browser_action_drag_data.cc',
+      'browser/ui/views/extensions/browser_action_drag_data.h',
+      'browser/ui/views/extensions/bundle_installed_bubble.cc',
+      'browser/ui/views/extensions/device_permissions_dialog_view.cc',
+      'browser/ui/views/extensions/device_permissions_dialog_view.h',
+      'browser/ui/views/extensions/extension_action_platform_delegate_views.cc',
+      'browser/ui/views/extensions/extension_action_platform_delegate_views.h',
+      'browser/ui/views/extensions/extension_dialog.cc',
+      'browser/ui/views/extensions/extension_dialog.h',
+      'browser/ui/views/extensions/extension_dialog_observer.cc',
+      'browser/ui/views/extensions/extension_dialog_observer.h',
+      'browser/ui/views/extensions/extension_install_dialog_view.cc',
+      'browser/ui/views/extensions/extension_installed_bubble_view.cc',
+      'browser/ui/views/extensions/extension_installed_bubble_view.h',
+      'browser/ui/views/extensions/extension_message_bubble_view.cc',
+      'browser/ui/views/extensions/extension_message_bubble_view.h',
+      'browser/ui/views/extensions/extension_popup.cc',
+      'browser/ui/views/extensions/extension_popup.h',
+      'browser/ui/views/extensions/extension_popup_aura.cc',
+      'browser/ui/views/extensions/extension_popup_aura.h',
+      'browser/ui/views/extensions/extension_toolbar_icon_surfacing_bubble_views.cc',
+      'browser/ui/views/extensions/extension_toolbar_icon_surfacing_bubble_views.h',
+      'browser/ui/views/extensions/extension_uninstall_dialog_view.cc',
+      'browser/ui/views/extensions/extension_view_views.cc',
+      'browser/ui/views/extensions/extension_view_views.h',
+      'browser/ui/views/extensions/media_galleries_dialog_views.cc',
+      'browser/ui/views/extensions/media_galleries_dialog_views.h',
+      'browser/ui/views/extensions/media_gallery_checkbox_view.cc',
+      'browser/ui/views/extensions/media_gallery_checkbox_view.h',
+    ],
     # MacViews sources that we still want to keep behind a compile-time flag.
     # TODO(jackhou): Move items to chrome_browser_ui_views_sources when they
     # migrate from mac_views_browser to a chrome://flag.
     'chrome_browser_ui_views_mac_experimental_sources': [
-      'browser/ui/views/apps/app_window_native_widget_mac.h',
-      'browser/ui/views/apps/app_window_native_widget_mac.mm',
       'browser/ui/views/apps/chrome_app_window_client_views_mac.mm',
-      'browser/ui/views/apps/chrome_native_app_window_views_mac.h',
-      'browser/ui/views/apps/chrome_native_app_window_views_mac.mm',
-      'browser/ui/views/apps/native_app_window_frame_view_mac.h',
-      'browser/ui/views/apps/native_app_window_frame_view_mac.mm',
     ],
     # Windows-only. Assume ash/aura/views.
     'chrome_browser_ui_win_sources': [
@@ -2902,6 +2905,7 @@
           'sources': [ '<@(chrome_browser_ui_views_sources)' ],
           'dependencies': [
             '<(DEPTH)/components/components.gyp:constrained_window',
+            '<(DEPTH)/extensions/components/extensions_components.gyp:native_app_window',
           ],
           'conditions': [
             ['chromeos == 0 and (OS!="mac" or mac_views_browser==1)', {
@@ -2912,8 +2916,13 @@
             }],
             ['OS!="mac"', {
               'sources': [ '<@(chrome_browser_ui_views_non_mac_sources)' ],
-              'dependencies': [
-                '<(DEPTH)/extensions/components/extensions_components.gyp:native_app_window',
+              'conditions': [
+                ['enable_extensions==1', {
+                  'sources': [ '<@(chrome_browser_ui_views_extensions_non_mac_sources)' ],
+                  'dependencies': [
+                    '<(DEPTH)/extensions/components/extensions_components.gyp:native_app_window',
+                  ],
+                }],
               ],
             }],
           ],
@@ -2986,9 +2995,7 @@
               'sources': [
                 '<@(chrome_browser_ui_views_mac_experimental_sources)',
                 '<@(chrome_browser_ui_views_non_mac_sources)',
-              ],
-              'dependencies': [
-                '<(DEPTH)/extensions/components/extensions_components.gyp:native_app_window',
+                '<@(chrome_browser_ui_views_extensions_non_mac_sources)',
               ],
             }, {
               'sources': [ '<@(chrome_browser_ui_cocoa_sources)' ],
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 5a4cdc9..36eb00e2 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -223,6 +223,8 @@
       'common/safe_browsing/download_protection_util.h',
       'common/safe_browsing/ipc_protobuf_message_macros.h',
       'common/safe_browsing/ipc_protobuf_message_null_macros.h',
+      'common/safe_browsing/mach_o_image_reader_mac.cc',
+      'common/safe_browsing/mach_o_image_reader_mac.h',
       'common/safe_browsing/pe_image_reader_win.cc',
       'common/safe_browsing/pe_image_reader_win.h',
       'common/safe_browsing/protobuf_message_log_macros.h',
diff --git a/chrome/chrome_dll_bundle.gypi b/chrome/chrome_dll_bundle.gypi
index a938500..e9fc1030 100644
--- a/chrome/chrome_dll_bundle.gypi
+++ b/chrome/chrome_dll_bundle.gypi
@@ -136,7 +136,6 @@
       'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Libraries',
       'files': [
         '<(PRODUCT_DIR)/exif.so',
-        '<(PRODUCT_DIR)/ffmpegsumo.so',
       ],
     },
     {
diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi
index cc1a332..99ccd5c3 100644
--- a/chrome/chrome_installer.gypi
+++ b/chrome/chrome_installer.gypi
@@ -438,7 +438,6 @@
           # files? (e.g. all locales, resources, etc.)
           '<(PRODUCT_DIR)/chrome',
           '<(PRODUCT_DIR)/chrome_sandbox',
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/xdg-mime',
           '<(PRODUCT_DIR)/xdg-settings',
           '<(PRODUCT_DIR)/locales/en-US.pak',
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 2945b6a6..73b86fe 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -36,8 +36,8 @@
       'renderer/net_benchmarking_extension.h',
       'renderer/page_load_histograms.cc',
       'renderer/page_load_histograms.h',
-      'renderer/plugins/chrome_plugin_placeholder.cc',
-      'renderer/plugins/chrome_plugin_placeholder.h',
+      'renderer/plugins/non_loadable_plugin_placeholder.cc',
+      'renderer/plugins/non_loadable_plugin_placeholder.h',
       'renderer/plugins/plugin_uma.cc',
       'renderer/plugins/plugin_uma.h',
       'renderer/plugins/shadow_dom_plugin_placeholder.cc',
@@ -182,6 +182,8 @@
       'renderer/pepper/pepper_shared_memory_message_filter.h',
       'renderer/pepper/pepper_uma_host.cc',
       'renderer/pepper/pepper_uma_host.h',
+      'renderer/plugins/chrome_plugin_placeholder.cc',
+      'renderer/plugins/chrome_plugin_placeholder.h',
       'renderer/plugins/plugin_preroller.cc',
       'renderer/plugins/plugin_preroller.h',
     ],
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index f04c45a8..f4456ed 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -65,7 +65,6 @@
       'browser/apps/speech_recognition_browsertest.cc',
       'browser/apps/window_controls_browsertest.cc',
       'browser/autocomplete/autocomplete_browsertest.cc',
-      'browser/autocomplete/in_memory_url_index_types_unittest.cc',
       'browser/autofill/autofill_browsertest.cc',
       'browser/autofill/autofill_server_browsertest.cc',
       'browser/autofill/content_autofill_driver_browsertest.cc',
@@ -447,7 +446,6 @@
       'browser/ui/blocked_content/popup_blocker_browsertest.cc',
       'browser/ui/bookmarks/bookmark_browsertest.cc',
       'browser/ui/browser_browsertest.cc',
-      'browser/ui/browser_close_browsertest.cc',
       'browser/ui/browser_command_controller_browsertest.cc',
       'browser/ui/browser_navigator_browsertest.cc',
       'browser/ui/browser_navigator_browsertest.h',
@@ -1064,8 +1062,8 @@
       'browser/ui/views/frame/browser_view_interactive_uitest.cc',
       'browser/ui/views/keyboard_access_browsertest.cc',
       'browser/ui/views/location_bar/location_icon_view_interactive_uitest.cc',
-      'browser/ui/views/location_bar/star_view_browsertest.cc',
       'browser/ui/views/location_bar/page_action_image_view_interactive_uitest.cc',
+      'browser/ui/views/location_bar/star_view_browsertest.cc',
       'browser/ui/views/omnibox/omnibox_view_views_browsertest.cc',
       'browser/ui/views/passwords/manage_passwords_bubble_view_browsertest.cc',
       'browser/ui/views/passwords/manage_passwords_icon_view_browsertest.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 04d9765f..5306add6f 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -656,6 +656,7 @@
       'browser/extensions/api/declarative_content/chrome_content_rules_registry_unittest.cc',
       'browser/extensions/api/declarative_content/content_action_unittest.cc',
       'browser/extensions/api/declarative_content/content_condition_unittest.cc',
+      'browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc',
       'browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc',
       'browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc',
       'browser/extensions/api/developer_private/developer_private_api_unittest.cc',
@@ -1035,6 +1036,7 @@
       'common/safe_browsing/binary_feature_extractor_win_unittest.cc',
       'common/safe_browsing/ipc_protobuf_message_test_messages.h',
       'common/safe_browsing/ipc_protobuf_message_unittest.cc',
+      'common/safe_browsing/mach_o_image_reader_mac_unittest.cc',
       'common/safe_browsing/pe_image_reader_win_unittest.cc',
       'renderer/safe_browsing/features_unittest.cc',
       'renderer/safe_browsing/murmurhash3_util_unittest.cc',
@@ -1509,6 +1511,7 @@
       'browser/ui/autofill/test_generated_credit_card_bubble_view.h',
       'browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc',
       'browser/ui/bookmarks/bookmark_unittest.cc',
+      'browser/ui/browser_close_unittest.cc',
       'browser/ui/browser_command_controller_unittest.cc',
       'browser/ui/browser_instant_controller_unittest.cc',
       'browser/ui/browser_iterator_unittest.cc',
diff --git a/chrome/chrome_utility.gypi b/chrome/chrome_utility.gypi
index 6b1db2ff..76cdbc8 100644
--- a/chrome/chrome_utility.gypi
+++ b/chrome/chrome_utility.gypi
@@ -154,12 +154,6 @@
             'utility/importer/nss_decryptor_system_nss.h',
           ],
         }],
-        ['OS=="android" and use_seccomp_bpf==1', {
-          'dependencies': [
-            '../sandbox/sandbox.gyp:seccomp_bpf',
-          ],
-          'defines': ['USE_SECCOMP_BPF'],
-        }],
         ['enable_extensions==1', {
           'dependencies': [
             '../extensions/extensions.gyp:extensions_utility',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 23b5dc22..9c05eb2 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1221,6 +1221,10 @@
 // Disables app shim creation for hosted apps on Mac.
 const char kDisableHostedAppShimCreation[] = "disable-hosted-app-shim-creation";
 
+// Disables use of toolkit-views based native app windows.
+const char kDisableMacViewsNativeAppWindows[] =
+    "disable-mac-views-native-app-windows";
+
 // Forcibly disables Lion-style on newer OSes, to allow developers to test the
 // older, SnowLeopard-style fullscreen.
 const char kDisableSystemFullscreenForTesting[] =
@@ -1230,6 +1234,10 @@
 // chrome://apps and chrome://extensions and is already enabled on non-mac.
 const char kEnableAppInfoDialogMac[] = "enable-app-info-dialog-mac";
 
+// Enables use of toolkit-views based native app windows.
+const char kEnableMacViewsNativeAppWindows[] =
+    "enable-mac-views-native-app-windows";
+
 // Enables Translate experimental new UX which replaces the infobar.
 const char kEnableTranslateNewUX[]         = "enable-translate-new-ux";
 
@@ -1304,11 +1312,6 @@
 const char kDebugPrint[] = "debug-print";
 #endif
 
-#ifndef NDEBUG
-// Enables overriding the path of file manager extension.
-const char kFileManagerExtensionPath[]      = "filemgr-ext-path";
-#endif
-
 bool AboutInSettingsEnabled() {
   return SettingsWindowEnabled() &&
          !base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index caa803c..d368232c 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -351,8 +351,10 @@
 extern const char kHostedAppQuitNotification[];
 extern const char kDisableAppInfoDialogMac[];
 extern const char kDisableHostedAppShimCreation[];
+extern const char kDisableMacViewsNativeAppWindows[];
 extern const char kDisableSystemFullscreenForTesting[];
 extern const char kEnableAppInfoDialogMac[];
+extern const char kEnableMacViewsNativeAppWindows[];
 extern const char kEnableTranslateNewUX[];
 extern const char kMetricsClientID[];
 extern const char kRelauncherProcess[];
@@ -389,10 +391,6 @@
 extern const char kEnablePluginPowerSaver[];
 #endif
 
-#ifndef NDEBUG
-extern const char kFileManagerExtensionPath[];
-#endif
-
 bool AboutInSettingsEnabled();
 bool MdSettingsEnabled();
 bool MediaRouterEnabled();
diff --git a/chrome/common/chrome_utility_messages.h b/chrome/common/chrome_utility_messages.h
index aa519cb..f67c63d 100644
--- a/chrome/common/chrome_utility_messages.h
+++ b/chrome/common/chrome_utility_messages.h
@@ -204,13 +204,6 @@
                      ChromeUtilityMsg_GetSaveFileName_Params /* params */)
 #endif  // defined(OS_WIN)
 
-#if defined(OS_ANDROID)
-// Instructs the utility process to detect support for seccomp-bpf,
-// and the result is reported through
-// ChromeUtilityHostMsg_DetectSeccompSupport_Result.
-IPC_MESSAGE_CONTROL0(ChromeUtilityMsg_DetectSeccompSupport)
-#endif
-
 //------------------------------------------------------------------------------
 // Utility process host messages:
 // These are messages from the utility process to the browser.
@@ -263,10 +256,3 @@
 IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_BuildDirectWriteFontCache,
                      base::FilePath /* cache file path */)
 #endif  // defined(OS_WIN)
-
-#if defined(OS_ANDROID)
-// Reply to ChromeUtilityMsg_DetectSeccompSupport to report the level
-// of kernel support for seccomp-bpf.
-IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_DetectSeccompSupport_ResultPrctl,
-                     bool /* seccomp prctl supported */)
-#endif
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index d9be107..c44f1bf 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -339,11 +339,11 @@
 
 #if defined(OS_WIN)
   // Just about everything has this, don't bother.
-  if (StartsWithASCII(flag, "/prefetch:", true))
+  if (base::StartsWithASCII(flag, "/prefetch:", true))
     return true;
 #endif
 
-  if (!StartsWithASCII(flag, "--", true))
+  if (!base::StartsWithASCII(flag, "--", true))
     return false;
   size_t end = flag.find("=");
   size_t len = (end == std::string::npos) ? flag.length() - 2 : end - 2;
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 3f688b77..69fbc7d 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -158,7 +158,12 @@
       "FA01E0B81978950F2BC5A50512FD769725F57510",  // Beta
       "B11A93E7E5B541F8010245EBDE2C74647D6C14B9",  // Canary
       "F155646B5D1CA545F7E1E4E20D573DFDD44C2540",  // Google Cast Beta
-      "16CA7A47AAE4BE49B1E75A6B960C3875E945B264"   // Google Cast Stable
+      "16CA7A47AAE4BE49B1E75A6B960C3875E945B264",  // Google Cast Stable
+      // The extensions below here only use openPopup on a user action,
+      // so are safe, and can be removed when the whitelist on that
+      // capability is lifted. See crbug.com/436489 for context.
+      "A4577D8C2AF4CF26F40CBCA83FFA4251D6F6C8F8",  // http://crbug.com/497301
+      "A8208CCC87F8261AFAEB6B85D5E8D47372DDEA6B"   // http://crbug.com/497301
     ],
     "contexts": ["blessed_extension"]
   }],
diff --git a/chrome/common/extensions/api/automation_internal.idl b/chrome/common/extensions/api/automation_internal.idl
index ce22523..b290c63 100644
--- a/chrome/common/extensions/api/automation_internal.idl
+++ b/chrome/common/extensions/api/automation_internal.idl
@@ -89,6 +89,12 @@
     DOMString selector;
   };
 
+  // Arguments for the enableTab function.
+  dictionary EnableTabParams {
+    long routingID;
+    long? tabID;
+  };
+
   // Returns the accessibility tree id of the web contents who's accessibility
   // was enabled using enableTab().
   callback EnableTabCallback = void(long tree_id);
@@ -103,13 +109,15 @@
     // Enable automation of the tab with the given id, or the active tab if no
     // tab id is given, and retrieves accessibility tree id for use in
     // future updates.
-    static void enableTab(optional long tabId, EnableTabCallback callback);
+    static void enableTab(EnableTabParams args,
+                          EnableTabCallback callback);
 
     // Enable automation of the frame with the given tree id.
     static void enableFrame(long tree_id);
 
     // Enables desktop automation.
-    static void enableDesktop(EnableDesktopCallback callback);
+    static void enableDesktop(long routingID,
+                              EnableDesktopCallback callback);
 
     // Performs an action on an automation node.
     static void performAction(PerformActionRequiredParams args,
diff --git a/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc b/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc
index ac957e4..c2a4e7b 100644
--- a/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc
+++ b/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc
@@ -200,9 +200,8 @@
         return NULL;
       }
       base::StringToLowerASCII(&filter);
-      if (!StartsWithASCII(filter,
-                           std::string(url::kFileSystemScheme) + ':',
-                           true)) {
+      if (!base::StartsWithASCII(
+              filter, std::string(url::kFileSystemScheme) + ':', true)) {
         *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
             errors::kInvalidURLPatternError, filter);
         return NULL;
diff --git a/chrome/common/extensions/api/networking_private/networking_private_crypto_unittest.cc b/chrome/common/extensions/api/networking_private/networking_private_crypto_unittest.cc
index 15bd935..f2fea82 100644
--- a/chrome/common/extensions/api/networking_private/networking_private_crypto_unittest.cc
+++ b/chrome/common/extensions/api/networking_private/networking_private_crypto_unittest.cc
@@ -6,8 +6,15 @@
 #include "base/base64.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
+#include "extensions/common/cast/cast_cert_validator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+
+namespace cast_crypto = ::extensions::core_api::cast_crypto;
+
+}  // namespace
+
 // Tests of networking_private_crypto support for Networking Private API.
 class NetworkingPrivateCryptoTest : public testing::Test {
  protected:
@@ -26,6 +33,28 @@
 
 // Test that networking_private_crypto::VerifyCredentials behaves as expected.
 TEST_F(NetworkingPrivateCryptoTest, VerifyCredentials) {
+  std::string keys =
+      "CrMCCiBSnZzWf+XraY5w3SbX2PEmWfHm5SNIv2pc9xbhP0EOcxKOAjCCAQoCggEBALwigL2A"
+      "9johADuudl41fz3DZFxVlIY0LwWHKM33aYwXs1CnuIL638dDLdZ+q6BvtxNygKRHFcEgmVDN"
+      "7BRiCVukmM3SQbY2Tv/oLjIwSoGoQqNsmzNuyrL1U2bgJ1OGGoUepzk/SneO+1RmZvtYVMBe"
+      "Ocf1UAYL4IrUzuFqVR+LFwDmaaMn5gglaTwSnY0FLNYuojHetFJQ1iBJ3nGg+a0gQBLx3SXr"
+      "1ea4NvTWj3/KQ9zXEFvmP1GKhbPz//YDLcsjT5ytGOeTBYysUpr3TOmZer5ufk0K48YcqZP6"
+      "OqWRXRy9ZuvMYNyGdMrP+JIcmH1X+mFHnquAt+RIgCqSxRsCAwEAAQqzAgogmNZt6BxWR4RN"
+      "lkNNN8SNws5/CHJQGee26JJ/VtaBqhgSjgIwggEKAoIBAQC8IoC9gPY6IQA7rnZeNX89w2Rc"
+      "VZSGNC8FhyjN92mMF7NQp7iC+t/HQy3Wfqugb7cTcoCkRxXBIJlQzewUYglbpJjN0kG2Nk7/"
+      "6C4yMEqBqEKjbJszbsqy9VNm4CdThhqFHqc5P0p3jvtUZmb7WFTAXjnH9VAGC+CK1M7halUf"
+      "ixcA5mmjJ+YIJWk8Ep2NBSzWLqIx3rRSUNYgSd5xoPmtIEAS8d0l69XmuDb01o9/ykPc1xBb"
+      "5j9RioWz8//2Ay3LI0+crRjnkwWMrFKa90zpmXq+bn5NCuPGHKmT+jqlkV0cvWbrzGDchnTK"
+      "z/iSHJh9V/phR56rgLfkSIAqksUbAgMBAAE=";
+  std::string signature =
+      "eHMoa7dP2ByNtDnxM/Q6yV3ZyUyihBFgOthq937yuiu2uwW2X/i8h1YrJFaWrA0iTTfSLAa6"
+      "PBAN1hhnwXlWYy8MvViJ9eJqf5FfCCkOjdRN0QIFPpmIJm/EcIv91bNMWnOGANgSW1Hons+s"
+      "C0/kROPbPABPLLwfgGizBDSZNapxgj8G+iDvi1JRRvvNdmjUs2AUIPNrSp3Knt3FyZ5F2Smk"
+      "Khpo7XVTWgSuWOzUJu6zNHn2krm64Ymd2HxRDyKTm1DBzy1MoXv4/8mbLYdj+KAvhqKJfRcr"
+      "GkUXVK++wCHERwxcvfk7e6lN6adcCVYP9pZPMhE/UyAJY6/uE1X0cw==";
+  EXPECT_TRUE(
+      cast_crypto::SetTrustedCertificateAuthoritiesForTest(keys, signature));
+
   static const char kCertData[] =
       "-----BEGIN CERTIFICATE-----"
       "MIIDhzCCAm8CBFE2SCMwDQYJKoZIhvcNAQEFBQAwfTELMAkGA1UEBhMCVVMxEzARBgNVBAgM"
diff --git a/chrome/common/extensions/chrome_extension_messages.h b/chrome/common/extensions/chrome_extension_messages.h
index cbc5f206..da46506 100644
--- a/chrome/common/extensions/chrome_extension_messages.h
+++ b/chrome/common/extensions/chrome_extension_messages.h
@@ -12,10 +12,14 @@
 
 #include "base/strings/string16.h"
 #include "base/values.h"
+#include "chrome/common/extensions/api/automation_internal.h"
 #include "chrome/common/extensions/api/webstore/webstore_api_constants.h"
 #include "chrome/common/extensions/webstore_install_result.h"
 #include "extensions/common/stack_frame.h"
 #include "ipc/ipc_message_macros.h"
+#include "ui/accessibility/ax_enums.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree_update.h"
 #include "url/gurl.h"
 
 #define IPC_MESSAGE_START ChromeExtensionMsgStart
@@ -50,6 +54,28 @@
                     std::string /* error */,
                     extensions::webstore_install::Result /* result */)
 
+IPC_STRUCT_BEGIN(ExtensionMsg_AccessibilityEventParams)
+  // ID of the accessibility tree that this event applies to.
+  IPC_STRUCT_MEMBER(int, tree_id)
+
+  // The global offset of all coordinates in this accessibility tree.
+  IPC_STRUCT_MEMBER(gfx::Vector2d, location_offset)
+
+  // The tree update.
+  IPC_STRUCT_MEMBER(ui::AXTreeUpdate, update)
+
+  // Type of event.
+  IPC_STRUCT_MEMBER(ui::AXEvent, event_type)
+
+  // ID of the node that the event applies to.
+  IPC_STRUCT_MEMBER(int, id)
+IPC_STRUCT_END()
+
+// Forward an accessibility message to an extension process where an
+// extension is using the automation API to listen for accessibility events.
+IPC_MESSAGE_ROUTED1(ExtensionMsg_AccessibilityEvent,
+                    ExtensionMsg_AccessibilityEventParams)
+
 // Messages sent from the renderer to the browser.
 
 
diff --git a/chrome/common/extensions/chrome_extensions_client.cc b/chrome/common/extensions/chrome_extensions_client.cc
index 7d886088..1b07deb5 100644
--- a/chrome/common/extensions/chrome_extensions_client.cc
+++ b/chrome/common/extensions/chrome_extensions_client.cc
@@ -367,8 +367,10 @@
   // ExtensionUpdater ensures that we notice a change. This is the full URL
   // of a blacklist:
   // http://www.gstatic.com/chrome/extensions/blacklist/l_0_0_0_7.txt
-  return StartsWithASCII(url.spec(), kExtensionBlocklistUrlPrefix, true) ||
-         StartsWithASCII(url.spec(), kExtensionBlocklistHttpsUrlPrefix, true);
+  return base::StartsWithASCII(url.spec(), kExtensionBlocklistUrlPrefix,
+                               true) ||
+         base::StartsWithASCII(url.spec(), kExtensionBlocklistHttpsUrlPrefix,
+                               true);
 }
 
 std::set<base::FilePath> ChromeExtensionsClient::GetBrowserImagePaths(
diff --git a/chrome/common/extensions/docs/templates/public/owners.html b/chrome/common/extensions/docs/templates/public/owners.html
index c3d23c3..579d7cda 100644
--- a/chrome/common/extensions/docs/templates/public/owners.html
+++ b/chrome/common/extensions/docs/templates/public/owners.html
@@ -1,56 +1,28 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <title>Extensions/Apps API Owners</title>
-    <style>
-      .warning {
-        color: #f90101;
-      }
-      html, body {
-        width: 1400px;
-      }
-      table {
-        border-collapse: collapse;
-      }
-      table, th, td {
-        border: 1px solid #eee;
-        padding: 2px 6px;
-      }
-      tr:target {
-        font-weight: bold;
-        background-color: #dcdcdc;
-      }
-      #notes {
-        white-space: pre-line;
-      }
-    </style>
-  </head>
-  <body>
-    <h1><center>Extensions/Apps API Owners</center></h1>
-    <table>
-      <tr>
-        <th>API</th>
-        <th>Owners</th>
-        <th>Notes</th>
-      </tr>
-      {{#entry:owners.apis}}
-      <tr id={{entry.id}}>
-        <td>{{entry.apiName}}</td>
-        <td>
-          {{?entry.owners}}
-            {{#owner:entry.owners}}
-            <a href="https://codereview.chromium.org/user/{{owner.email}}">
-              {{owner.username}}</a>{{^owner.last}}, {{/owner.last}}
-            {{/entry.owners}}
-          {{:}}
-            <a href="#core"><span class="warning">No owners.</span></a>
-          {{/entry.owners}}
-        </td>
-        <td id="notes">
-          {{entry.notes}}
-        </td>
-      </tr>
-      {{/owners.apis}}
-    </table>
-  </body>
-</html>
+{{+content:partials.site}}
+<h1>Extensions & Apps API Owners</h1>
+<table>
+  <tr>
+    <th>API</th>
+    <th>Owners</th>
+    <th>Notes</th>
+  </tr>
+  {{#entry:owners.apis}}
+  <tr id={{entry.id}}>
+    <td>{{entry.apiName}}</td>
+    <td>
+      {{?entry.owners}}
+        {{#owner:entry.owners}}
+        <a href="https://codereview.chromium.org/user/{{owner.email}}">
+          {{owner.username}}</a>{{^owner.last}}, {{/owner.last}}
+        {{/entry.owners}}
+      {{:}}
+        N/A.
+      {{/entry.owners}}
+    </td>
+    <td id="notes">
+      {{entry.notes}}
+    </td>
+  </tr>
+  {{/owners.apis}}
+</table>
+{{/partials.site}}
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
index 67683db8..cb86156 100644
--- a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
@@ -103,7 +103,7 @@
 // A www. prefix is not informative and thus not worth the limited real estate
 // in the permissions UI.
 std::string RemoveWwwPrefix(const std::string& url) {
-  if (StartsWithASCII(url, kWwwPrefix, false))
+  if (base::StartsWithASCII(url, kWwwPrefix, false))
     return url.substr(strlen(kWwwPrefix));
   return url;
 }
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_homepage_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_homepage_unittest.cc
index 5a1afab..5ba9582 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_homepage_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_homepage_unittest.cc
@@ -39,10 +39,9 @@
   // The Google Gallery URL ends with the id, which depends on the path, which
   // can be different in testing, so we just check the part before id.
   extension = LoadAndExpectSuccess("homepage_google_hosted.json");
-  EXPECT_TRUE(StartsWithASCII(
+  EXPECT_TRUE(base::StartsWithASCII(
       extensions::ManifestURL::GetHomepageURL(extension.get()).spec(),
-      "https://chrome.google.com/webstore/detail/",
-      false));
+      "https://chrome.google.com/webstore/detail/", false));
 
   extension = LoadAndExpectSuccess("homepage_externally_hosted.json");
   EXPECT_EQ(GURL(), extensions::ManifestURL::GetHomepageURL(extension.get()));
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
index 56b3768..7b68bfa 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
@@ -481,6 +481,9 @@
       {IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ,
        {APIPermission::kWebNavigation},
        {}},
+      {IDS_EXTENSION_PROMPT_WARNING_PLATFORMKEYS,
+       {APIPermission::kPlatformKeys},
+       {}},
 
       // Permission messages for private permissions:
       {IDS_EXTENSION_PROMPT_WARNING_SCREENLOCK_PRIVATE,
diff --git a/chrome/common/local_discovery/local_domain_resolver_unittest.cc b/chrome/common/local_discovery/local_domain_resolver_unittest.cc
index 2a612833..f55783e8e4 100644
--- a/chrome/common/local_discovery/local_domain_resolver_unittest.cc
+++ b/chrome/common/local_discovery/local_domain_resolver_unittest.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/common/local_discovery/service_discovery_client_impl.h"
 #include "net/dns/mdns_client_impl.h"
 #include "net/dns/mock_mdns_socket_factory.h"
@@ -81,7 +84,7 @@
     base::CancelableCallback<void()> callback(base::Bind(
         &base::MessageLoop::Quit,
         base::Unretained(base::MessageLoop::current())));
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, callback.callback(), time_period);
 
     base::MessageLoop::current()->Run();
diff --git a/chrome/common/local_discovery/service_discovery_client_impl.cc b/chrome/common/local_discovery/service_discovery_client_impl.cc
index c86f726..733e166 100644
--- a/chrome/common/local_discovery/service_discovery_client_impl.cc
+++ b/chrome/common/local_discovery/service_discovery_client_impl.cc
@@ -4,10 +4,12 @@
 
 #include <utility>
 
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/common/local_discovery/service_discovery_client_impl.h"
 #include "net/dns/dns_protocol.h"
 #include "net/dns/record_rdata.h"
@@ -270,10 +272,9 @@
 
   if (found != services_.end() && !found->second->update_pending()) {
     found->second->set_update_pending(true);
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&ServiceWatcherImpl::DeliverDeferredUpdate, AsWeakPtr(),
-                   update_type, service_name));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&ServiceWatcherImpl::DeliverDeferredUpdate,
+                              AsWeakPtr(), update_type, service_name));
   }
 }
 
@@ -326,12 +327,10 @@
 
 void ServiceWatcherImpl::ScheduleQuery(int timeout_seconds) {
   if (timeout_seconds <= kMaxRequeryTimeSeconds) {
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&ServiceWatcherImpl::SendQuery,
-                   AsWeakPtr(),
-                   timeout_seconds * 2 /*next_timeout_seconds*/,
-                   false /*force_update*/),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&ServiceWatcherImpl::SendQuery, AsWeakPtr(),
+                              timeout_seconds * 2 /*next_timeout_seconds*/,
+                              false /*force_update*/),
         base::TimeDelta::FromSeconds(timeout_seconds));
   }
 }
@@ -560,9 +559,8 @@
         &LocalDomainResolverImpl::SendResolvedAddresses,
         base::Unretained(this)));
 
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        timeout_callback_.callback(),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, timeout_callback_.callback(),
         base::TimeDelta::FromMilliseconds(kLocalDomainSecondAddressTimeoutMs));
   } else if (transactions_finished_ == 2
       || address_family_ != net::ADDRESS_FAMILY_UNSPECIFIED) {
diff --git a/chrome/common/local_discovery/service_discovery_client_unittest.cc b/chrome/common/local_discovery/service_discovery_client_unittest.cc
index 878bca1c..ed6db5c6 100644
--- a/chrome/common/local_discovery/service_discovery_client_unittest.cc
+++ b/chrome/common/local_discovery/service_discovery_client_unittest.cc
@@ -2,8 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/common/local_discovery/service_discovery_client_impl.h"
 #include "net/base/net_errors.h"
 #include "net/dns/dns_protocol.h"
@@ -213,7 +216,7 @@
   void RunFor(base::TimeDelta time_period) {
     base::CancelableCallback<void()> callback(base::Bind(
         &ServiceDiscoveryTest::Stop, base::Unretained(this)));
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, callback.callback(), time_period);
 
     base::MessageLoop::current()->Run();
diff --git a/chrome/common/localized_error.cc b/chrome/common/localized_error.cc
index 880ed9c..cb3aaee 100644
--- a/chrome/common/localized_error.cc
+++ b/chrome/common/localized_error.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
+#include "base/metrics/field_trial.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -56,6 +57,11 @@
     "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html"
     "?answer=1721911";
 #endif  // defined(OS_CHROMEOS)
+static const char kCachedCopyButtonFieldTrial[] =
+    "EnableGoogleCachedCopyTextExperiment";
+static const char kCachedCopyButtonExpTypeControl[] = "control";
+static const char kCachedCopyButtonExpTypeCopy[] = "copy";
+static const int kGoogleCachedCopySuggestionType = 0;
 
 enum NAV_SUGGESTIONS {
   SUGGEST_NONE                  = 0,
@@ -664,6 +670,7 @@
   } else {
     suggestions = params->override_suggestions.release();
     use_default_suggestions = false;
+    EnableGoogleCachedCopyButtonExperiment(suggestions, error_strings);
   }
 
   error_strings->Set("suggestions", suggestions);
@@ -920,3 +927,47 @@
 #endif  // defined(OS_CHROMEOS)
 }
 #endif
+
+void LocalizedError::EnableGoogleCachedCopyButtonExperiment(
+    base::ListValue* suggestions,
+    base::DictionaryValue* error_strings) {
+  std::string field_trial_exp_type_ =
+      base::FieldTrialList::FindFullName(kCachedCopyButtonFieldTrial);
+
+  // If the first suggestion is for a Google cache copy. Promote the
+  // suggestion to a separate set of strings for displaying as a button.
+  if (!suggestions->empty() && !field_trial_exp_type_.empty() &&
+      field_trial_exp_type_ != kCachedCopyButtonExpTypeControl) {
+    base::DictionaryValue* suggestion;
+    suggestions->GetDictionary(0, &suggestion);
+    int type = -1;
+    suggestion->GetInteger("type", &type);
+
+    if (type == kGoogleCachedCopySuggestionType) {
+      base::string16 cache_url;
+      suggestion->GetString("urlCorrection", &cache_url);
+      int cache_tracking_id = -1;
+      suggestion->GetInteger("trackingId", &cache_tracking_id);
+
+      scoped_ptr<base::DictionaryValue> cache_button(new base::DictionaryValue);
+
+      if (field_trial_exp_type_ == kCachedCopyButtonExpTypeCopy) {
+        cache_button->SetString(
+            "msg",
+            l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_SHOW_CACHED_COPY));
+      } else {
+        // Default to "Show cached page" button label.
+        cache_button->SetString(
+            "msg",
+            l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_SHOW_CACHED_PAGE));
+      }
+      cache_button->SetString("cacheUrl", cache_url);
+      cache_button->SetInteger("trackingId", cache_tracking_id);
+      error_strings->Set("cacheButton", cache_button.release());
+
+      // Remove the item from suggestions dictionary so that it does not get
+      // displayed by the template in the details section.
+      suggestions->Remove(0, nullptr);
+    }
+  }
+}
diff --git a/chrome/common/localized_error.h b/chrome/common/localized_error.h
index 7d5e45a5..a71740b1 100644
--- a/chrome/common/localized_error.h
+++ b/chrome/common/localized_error.h
@@ -64,6 +64,13 @@
   static const char kHttpErrorDomain[];
 
  private:
+  // Sets up the Google Cached Copy button experiment if part of the
+  // field trial. This promotes the Google cached copy suggestion from under
+  // the details section to a blue button.
+  static void EnableGoogleCachedCopyButtonExperiment(
+      base::ListValue* suggestions,
+      base::DictionaryValue* error_strings);
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(LocalizedError);
 };
 
diff --git a/chrome/common/mac/OWNERS b/chrome/common/mac/OWNERS
index dc83bad2..190b469 100644
--- a/chrome/common/mac/OWNERS
+++ b/chrome/common/mac/OWNERS
@@ -1,4 +1,5 @@
 mark@chromium.org
+rsesek@chromium.org
+tapted@chromium.org
 thomasvl@chromium.org
 thakis@chromium.org
-rsesek@chromium.org
diff --git a/chrome/common/pref_names_util.cc b/chrome/common/pref_names_util.cc
index 7ab3db3..0857265 100644
--- a/chrome/common/pref_names_util.cc
+++ b/chrome/common/pref_names_util.cc
@@ -13,7 +13,7 @@
 bool ParseFontNamePrefPath(const std::string& pref_path,
                            std::string* generic_family,
                            std::string* script) {
-  if (!StartsWithASCII(pref_path, kWebKitFontPrefPrefix, true))
+  if (!base::StartsWithASCII(pref_path, kWebKitFontPrefPrefix, true))
     return false;
 
   size_t start = strlen(kWebKitFontPrefPrefix);
diff --git a/chrome/common/profiling.cc b/chrome/common/profiling.cc
index 07cc8de..6dc28c6a8 100644
--- a/chrome/common/profiling.cc
+++ b/chrome/common/profiling.cc
@@ -9,7 +9,8 @@
 #include "base/command_line.h"
 #include "base/debug/profiler.h"
 #include "base/lazy_instance.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread.h"
 #include "chrome/common/chrome_switches.h"
@@ -82,9 +83,8 @@
       flush_seconds = kProfilingFlushSeconds;
     }
   }
-  thread->message_loop()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&FlushProfilingData, thread),
+  thread->task_runner()->PostDelayedTask(
+      FROM_HERE, base::Bind(&FlushProfilingData, thread),
       base::TimeDelta::FromSeconds(flush_seconds));
 }
 
@@ -99,8 +99,8 @@
       return;
     thread_ = new base::Thread("Profiling_Flush");
     thread_->Start();
-    thread_->message_loop()->PostTask(
-        FROM_HERE, base::Bind(&FlushProfilingData, thread_));
+    thread_->task_runner()->PostTask(FROM_HERE,
+                                     base::Bind(&FlushProfilingData, thread_));
   }
 
   void Stop() {
diff --git a/chrome/common/safe_browsing/csd.proto b/chrome/common/safe_browsing/csd.proto
index 03a4beb..0167cfa 100644
--- a/chrome/common/safe_browsing/csd.proto
+++ b/chrome/common/safe_browsing/csd.proto
@@ -15,6 +15,18 @@
 
 package safe_browsing;
 
+// Protocol buffer describing the Chrome user population of the user reporting
+// data.
+message ChromeUserPopulation {
+  enum UserPopulation {
+    UNKNOWN_USER_POPULATION = 0;
+    SAFE_BROWSING = 1;
+    EXTENDED_REPORTING = 2;
+  }
+  optional UserPopulation user_population = 1;
+}
+
+
 message ClientPhishingRequest {
   // URL that the client visited.  The CGI parameters are stripped by the
   // client.
@@ -71,6 +83,12 @@
 
   // List of shingle hashes we extracted.
   repeated uint32 shingle_hashes = 12 [packed = true];
+
+  // The model filename (basename) that was used by the client.
+  optional string model_filename = 13;
+
+  // Population that the reporting user is part of.
+  optional ChromeUserPopulation population = 14;
 }
 
 message ClientPhishingResponse {
@@ -117,6 +135,9 @@
 
   // List of resource urls that match the malware IP list.
   repeated UrlInfo bad_ip_url_info = 7;
+
+  // Population that the reporting user is part of.
+  optional ChromeUserPopulation population = 9;
 }
 
 message ClientMalwareResponse {
@@ -278,6 +299,9 @@
   }
 
   repeated ArchivedBinary archived_binary = 22;
+
+  // Population that the reporting user is part of.
+  optional ChromeUserPopulation population = 24;
 }
 
 message ClientDownloadResponse {
@@ -490,6 +514,9 @@
   }
 
   optional EnvironmentData environment = 3;
+
+  // Population that the reporting user is part of.
+  optional ChromeUserPopulation population = 7;
 }
 
 message ClientIncidentResponse {
diff --git a/chrome/common/safe_browsing/mach_o_image_reader_mac.cc b/chrome/common/safe_browsing/mach_o_image_reader_mac.cc
new file mode 100644
index 0000000..f4e39e3
--- /dev/null
+++ b/chrome/common/safe_browsing/mach_o_image_reader_mac.cc
@@ -0,0 +1,235 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/mach_o_image_reader_mac.h"
+
+#include <libkern/OSByteOrder.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+
+namespace safe_browsing {
+
+// ByteSlice is a bounds-checking view of an arbitrary byte array.
+class ByteSlice {
+ public:
+  // Creates an invalid byte slice.
+  ByteSlice() : ByteSlice(nullptr, 0) {}
+
+  // Creates a slice for a given data array.
+  explicit ByteSlice(const uint8_t* data, size_t size)
+      : data_(data), size_(size) {}
+  ~ByteSlice() {}
+
+  bool IsValid() {
+    return data_ != nullptr;
+  }
+
+  // Creates a sub-slice from the current slice.
+  ByteSlice Slice(size_t at, size_t size) {
+    if (!RangeCheck(at, size))
+      return ByteSlice();
+    return ByteSlice(data_ + at, size);
+  }
+
+  // Casts an offset to a specific type.
+  template <typename T>
+  const T* GetPointerAt(size_t at) {
+    if (!RangeCheck(at, sizeof(T)))
+      return nullptr;
+    return reinterpret_cast<const T*>(data_ + at);
+  }
+
+  // Copies data from an offset to a buffer.
+  bool CopyDataAt(size_t at, size_t size, uint8_t* out_data) {
+    if (!RangeCheck(at, size))
+      return false;
+    memcpy(out_data, data_ + at, size);
+    return true;
+  }
+
+  bool RangeCheck(size_t offset, size_t size) {
+    if (offset >= size_)
+      return false;
+    base::CheckedNumeric<size_t> range(offset);
+    range += size;
+    if (!range.IsValid())
+      return false;
+    return range.ValueOrDie() <= size_;
+  }
+
+  const uint8_t* data() const { return data_; }
+  size_t size() const { return size_; }
+
+ private:
+  const uint8_t* data_;
+  size_t size_;
+
+  // Copy and assign allowed.
+};
+
+MachOImageReader::LoadCommand::LoadCommand() {}
+
+MachOImageReader::LoadCommand::~LoadCommand() {}
+
+MachOImageReader::MachOImageReader()
+    : data_(),
+      is_fat_(false),
+      is_64_bit_(false),
+      commands_() {
+}
+
+MachOImageReader::~MachOImageReader() {}
+
+bool MachOImageReader::Initialize(const uint8_t* image, size_t image_size) {
+  if (!image)
+    return false;
+
+  data_.reset(new ByteSlice(image, image_size));
+
+  const uint32_t* magic = data_->GetPointerAt<uint32_t>(0);
+  if (!magic)
+    return false;
+
+  // Check if this is a fat file. Note that the fat_header and fat_arch
+  // structs are always in big endian.
+  is_fat_ = *magic == FAT_MAGIC || *magic == FAT_CIGAM;
+  if (is_fat_) {
+    const fat_header* header = data_->GetPointerAt<fat_header>(0);
+    if (!header)
+      return false;
+
+    bool do_swap = header->magic == FAT_CIGAM;
+    uint32_t nfat_arch = do_swap ? OSSwapInt32(header->nfat_arch)
+                                 : header->nfat_arch;
+
+    size_t offset = sizeof(*header);
+    for (uint32_t i = 0; i < nfat_arch; ++i) {
+      const fat_arch* arch = data_->GetPointerAt<fat_arch>(offset);
+      if (!arch)
+        return false;
+
+      uint32_t arch_offset = do_swap ? OSSwapInt32(arch->offset) : arch->offset;
+      uint32_t arch_size = do_swap ? OSSwapInt32(arch->size) : arch->size;
+
+      ByteSlice slice = data_->Slice(arch_offset, arch_size);
+      if (!slice.IsValid())
+        return false;
+
+      fat_images_.push_back(new MachOImageReader());
+      if (!fat_images_.back()->Initialize(slice.data(), slice.size()))
+        return false;
+
+      offset += sizeof(*arch);
+    }
+
+    return true;
+  }
+
+  bool do_swap = *magic == MH_CIGAM || *magic == MH_CIGAM_64;
+
+  // Make sure this is a Mach-O file.
+  is_64_bit_ = *magic == MH_MAGIC_64 || *magic == MH_CIGAM_64;
+  if (!(is_64_bit_ || *magic == MH_MAGIC || do_swap))
+    return false;
+
+  // Read the full Mach-O image header.
+  if (is_64_bit_) {
+    if (!GetMachHeader64())
+      return false;
+  } else {
+    if (!GetMachHeader())
+      return false;
+  }
+
+  // Collect all the load commands for the binary.
+  const size_t load_command_size = sizeof(load_command);
+  size_t offset = is_64_bit_ ? sizeof(mach_header_64) : sizeof(mach_header);
+  const uint32_t num_commands = do_swap ? OSSwapInt32(GetMachHeader()->ncmds)
+                                        : GetMachHeader()->ncmds;
+  commands_.resize(num_commands);
+  for (uint32_t i = 0; i < num_commands; ++i) {
+    LoadCommand* command = &commands_[i];
+
+    command->data.resize(load_command_size);
+    if (!data_->CopyDataAt(offset, load_command_size, &command->data[0])) {
+      return false;
+    }
+
+    uint32_t cmdsize = do_swap ? OSSwapInt32(command->cmdsize())
+                               : command->cmdsize();
+    command->data.resize(cmdsize);
+    if (!data_->CopyDataAt(offset, cmdsize, &command->data[0])) {
+      return false;
+    }
+
+    offset += cmdsize;
+  }
+
+  return true;
+}
+
+bool MachOImageReader::IsFat() {
+  return is_fat_;
+}
+
+std::vector<MachOImageReader*> MachOImageReader::GetFatImages() {
+  DCHECK(is_fat_);
+  std::vector<MachOImageReader*> images;
+  for (auto it = fat_images_.begin(); it != fat_images_.end(); ++it)
+    images.push_back(*it);
+  return images;
+}
+
+bool MachOImageReader::Is64Bit() {
+  DCHECK(!is_fat_);
+  return is_64_bit_;
+}
+
+const mach_header* MachOImageReader::GetMachHeader() {
+  DCHECK(!is_fat_);
+  return data_->GetPointerAt<mach_header>(0);
+}
+
+const mach_header_64* MachOImageReader::GetMachHeader64() {
+  DCHECK(is_64_bit_);
+  DCHECK(!is_fat_);
+  return data_->GetPointerAt<mach_header_64>(0);
+}
+
+uint32_t MachOImageReader::GetFileType() {
+  DCHECK(!is_fat_);
+  return GetMachHeader()->filetype;
+}
+
+const std::vector<MachOImageReader::LoadCommand>&
+MachOImageReader::GetLoadCommands() {
+  DCHECK(!is_fat_);
+  return commands_;
+}
+
+bool MachOImageReader::GetCodeSignatureInfo(std::vector<uint8_t>* info) {
+  DCHECK(!is_fat_);
+  DCHECK(info->empty());
+
+  // Find the LC_CODE_SIGNATURE command and cast it to its linkedit format.
+  const linkedit_data_command* lc_code_signature = nullptr;
+  for (const auto& command : commands_) {
+    if (command.cmd() == LC_CODE_SIGNATURE) {
+      lc_code_signature = command.as_command<linkedit_data_command>();
+      break;
+    }
+  }
+  if (lc_code_signature == nullptr)
+    return false;
+
+  info->resize(lc_code_signature->datasize);
+  return data_->CopyDataAt(lc_code_signature->dataoff,
+                           lc_code_signature->datasize,
+                           &(*info)[0]);
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/common/safe_browsing/mach_o_image_reader_mac.h b/chrome/common/safe_browsing/mach_o_image_reader_mac.h
new file mode 100644
index 0000000..36d1e2573
--- /dev/null
+++ b/chrome/common/safe_browsing/mach_o_image_reader_mac.h
@@ -0,0 +1,101 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_MACH_O_IMAGE_READER_MAC_H_
+#define CHROME_COMMON_SAFE_BROWSING_MACH_O_IMAGE_READER_MAC_H_
+
+#include <mach-o/loader.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+
+namespace safe_browsing {
+
+class ByteSlice;
+
+// MachOImageReader is used to extract information about a Mach-O binary image.
+// This class supports fat and thin images. Initialize() must be called before
+// any other methods; if it returns false, it is illegal to call any other
+// methods on this class.
+class MachOImageReader {
+ public:
+  // Represents a Mach-O load command, including all of its data.
+  struct LoadCommand {
+    LoadCommand();
+    ~LoadCommand();
+
+    uint32_t cmd() const {
+      return as_command<load_command>()->cmd;
+    }
+
+    uint32_t cmdsize() const {
+      return as_command<load_command>()->cmdsize;
+    }
+
+    template <typename T>
+    const T* as_command() const {
+      const T* command = reinterpret_cast<const T*>(&data[0]);
+      if (data.size() < sizeof(T) || command->cmdsize < sizeof(T))
+        return nullptr;
+      return command;
+    }
+
+    std::vector<uint8_t> data;
+  };
+
+  MachOImageReader();
+  ~MachOImageReader();
+
+  // Initializes the instance and verifies that the data is a valid Mach-O
+  // image. This does not take ownership of the bytes, so the data must
+  // remain valid for the lifetime of this object. Returns true if the
+  // instance is initialized and valid, false if the file could not be parsed
+  // as a Mach-O image.
+  bool Initialize(const uint8_t* image, size_t image_size);
+
+  // Returns whether this is a fat Mach-O image. If this returns true, it is
+  // only valid to call GetFatImages() and none of the other methods.
+  bool IsFat();
+
+  // It is only valid to call this method if IsFat() returns true. This
+  // returns an image reader for each architecture in the fat file.
+  std::vector<MachOImageReader*> GetFatImages();
+
+  // Returns whether the image is a 64-bit image.
+  bool Is64Bit();
+
+  // Retrieves the mach_header structure for the appropriate architecture.
+  const mach_header* GetMachHeader();
+  const mach_header_64* GetMachHeader64();
+
+  // Returns the Mach-O filetype field from the header.
+  uint32_t GetFileType();
+
+  // Returns an array of all the load commands in the image.
+  const std::vector<MachOImageReader::LoadCommand>& GetLoadCommands();
+
+  // If the image has a LC_CODE_SIGNATURE command, this retreives the code
+  // signature blob in the __LINKEDIT segment.
+  bool GetCodeSignatureInfo(std::vector<uint8_t>* info);
+
+ private:
+  scoped_ptr<ByteSlice> data_;
+
+  bool is_fat_;
+  ScopedVector<MachOImageReader> fat_images_;
+
+  bool is_64_bit_;
+  std::vector<LoadCommand> commands_;
+
+  DISALLOW_COPY_AND_ASSIGN(MachOImageReader);
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_COMMON_SAFE_BROWSING_MACH_O_IMAGE_READER_MAC_H_
diff --git a/chrome/common/safe_browsing/mach_o_image_reader_mac_unittest.cc b/chrome/common/safe_browsing/mach_o_image_reader_mac_unittest.cc
new file mode 100644
index 0000000..2fa1bf3
--- /dev/null
+++ b/chrome/common/safe_browsing/mach_o_image_reader_mac_unittest.cc
@@ -0,0 +1,427 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/mach_o_image_reader_mac.h"
+
+#include <arpa/inet.h>
+#include <libkern/OSByteOrder.h>
+#include <mach-o/loader.h>
+#include <string.h>
+#include <uuid/uuid.h>
+
+#include "base/files/file_path.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+namespace {
+
+// Definitions from
+// <http://opensource.apple.com/source/xnu/xnu-2782.1.97/bsd/sys/codesign.h>.
+
+enum {
+  CSMAGIC_CODEDIRECTORY = 0xfade0c02,
+  CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0,
+
+  CSSLOT_CODEDIRECTORY = 0,
+};
+
+struct CodeSigningBlob {
+  uint32_t type;
+  uint32_t offset;
+};
+
+struct CodeSigningSuperBlob {
+  uint32_t magic;
+  uint32_t length;
+  uint32_t count;
+  CodeSigningBlob index[];
+};
+
+struct CodeSigningDirectory {
+  uint32_t magic;
+  uint32_t length;
+  uint32_t version;
+  uint32_t flags;
+  uint32_t hashOffset;
+  uint32_t identOffset;
+  uint32_t nSpecialSlots;
+  uint32_t nCodeSlots;
+  uint32_t codeLimit;
+  uint8_t hashSize;
+  uint8_t hashType;
+  uint8_t spare1;
+  uint8_t pageSize;
+  uint32_t spare2;
+  // Version 0x20100.
+  uint32_t scatterOffset;
+  // Version 0x20200.
+  uint32_t teamOffset;
+};
+
+class MachOImageReaderTest : public testing::Test {
+ protected:
+  void OpenTestFile(const char* file_name, base::MemoryMappedFile* file) {
+    base::FilePath test_data;
+    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data));
+
+    base::FilePath path = test_data.AppendASCII("safe_browsing")
+                                   .AppendASCII("mach_o")
+                                   .AppendASCII(file_name);
+
+    ASSERT_TRUE(file->Initialize(path));
+  }
+
+  // Returns the identity of the signed code data.
+  void GetSigningIdentity(const std::vector<uint8_t>& signature,
+                          std::string* identity) {
+    auto super_blob =
+        reinterpret_cast<const CodeSigningSuperBlob*>(&signature[0]);
+    EXPECT_EQ(CSMAGIC_EMBEDDED_SIGNATURE, ntohl(super_blob->magic));
+    ASSERT_EQ(CSSLOT_CODEDIRECTORY, ntohl(super_blob->index[0].type));
+    size_t dir_offset = ntohl(super_blob->index[0].offset);
+    auto directory =
+        reinterpret_cast<const CodeSigningDirectory*>(&signature[dir_offset]);
+    ASSERT_EQ(CSMAGIC_CODEDIRECTORY, ntohl(directory->magic));
+    size_t ident_offset = ntohl(directory->identOffset) + dir_offset;
+    *identity =
+        std::string(reinterpret_cast<const char*>(&signature[ident_offset]));
+  }
+
+  // Returns the hash of the code data itself. Note that this is not the
+  // CDHash, but is instead the hash in the CodeDirectory blob, which is
+  // over the contents of the signed data. This is visible as hash #0
+  // when using `codesign -d -vvvvvv`.
+  void GetCodeSignatureHash(const std::vector<uint8_t>& signature,
+                            std::vector<uint8_t>* hash) {
+    auto super_blob =
+        reinterpret_cast<const CodeSigningSuperBlob*>(&signature[0]);
+    EXPECT_EQ(CSMAGIC_EMBEDDED_SIGNATURE, ntohl(super_blob->magic));
+    ASSERT_EQ(CSSLOT_CODEDIRECTORY, ntohl(super_blob->index[0].type));
+    size_t dir_offset = ntohl(super_blob->index[0].offset);
+    auto directory =
+        reinterpret_cast<const CodeSigningDirectory*>(&signature[dir_offset]);
+    ASSERT_EQ(CSMAGIC_CODEDIRECTORY, ntohl(directory->magic));
+    size_t hash_offset = ntohl(directory->hashOffset) + dir_offset;
+    std::vector<uint8_t> actual_hash(&signature[hash_offset],
+        &signature[hash_offset + directory->hashSize]);
+    EXPECT_EQ(20u, actual_hash.size());
+    *hash = actual_hash;
+  }
+
+  void ExpectCodeSignatureHash(const std::vector<uint8_t>& signature,
+                               const char* expected) {
+    std::vector<uint8_t> actual_hash;
+    GetCodeSignatureHash(signature, &actual_hash);
+
+    std::vector<uint8_t> expected_hash;
+    ASSERT_TRUE(base::HexStringToBytes(expected, &expected_hash));
+    EXPECT_EQ(expected_hash, actual_hash);
+  }
+};
+
+TEST_F(MachOImageReaderTest, Executable32) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("executable32", &file));
+  MachOImageReader reader;
+  ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+  EXPECT_FALSE(reader.IsFat());
+  EXPECT_FALSE(reader.Is64Bit());
+  EXPECT_TRUE(reader.GetMachHeader());
+  EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.GetFileType());
+  EXPECT_EQ(15u, reader.GetLoadCommands().size());
+
+  std::vector<uint8_t> signature;
+  EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
+  EXPECT_TRUE(signature.empty());
+
+  // Test an arbitrary load command.
+  auto commands = reader.GetLoadCommands();
+  ASSERT_EQ(15u, commands.size());
+  auto command = commands[11];
+  ASSERT_EQ(static_cast<uint32_t>(LC_LOAD_DYLIB), command.cmd());
+  auto actual = command.as_command<dylib_command>();
+  EXPECT_EQ(2u, actual->dylib.timestamp);
+  EXPECT_EQ(0x4ad0101u, actual->dylib.current_version);
+  EXPECT_EQ(0x10000u, actual->dylib.compatibility_version);
+}
+
+TEST_F(MachOImageReaderTest, Executable64) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("executable64", &file));
+  MachOImageReader reader;
+  ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+  EXPECT_FALSE(reader.IsFat());
+  EXPECT_TRUE(reader.Is64Bit());
+  EXPECT_TRUE(reader.GetMachHeader());
+  EXPECT_TRUE(reader.GetMachHeader64());
+  EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.GetFileType());
+  EXPECT_EQ(15u, reader.GetLoadCommands().size());
+
+  std::vector<uint8_t> signature;
+  EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
+  EXPECT_TRUE(signature.empty());
+}
+
+TEST_F(MachOImageReaderTest, ExecutableFat) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("executablefat", &file));
+  MachOImageReader reader;
+  ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+  EXPECT_TRUE(reader.IsFat());
+  auto images = reader.GetFatImages();
+  ASSERT_EQ(2u, images.size());
+
+  // Note: this image is crafted to have 32-bit first.
+  {
+    EXPECT_FALSE(images[0]->IsFat());
+    EXPECT_FALSE(images[0]->Is64Bit());
+    EXPECT_TRUE(images[0]->GetMachHeader());
+    EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[0]->GetFileType());
+
+    std::vector<uint8_t> signature;
+    EXPECT_FALSE(images[0]->GetCodeSignatureInfo(&signature));
+    EXPECT_TRUE(signature.empty());
+  }
+
+  {
+    EXPECT_FALSE(images[1]->IsFat());
+    EXPECT_TRUE(images[1]->Is64Bit());
+    EXPECT_TRUE(images[1]->GetMachHeader());
+    EXPECT_TRUE(images[1]->GetMachHeader64());
+    EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[1]->GetFileType());
+
+    std::vector<uint8_t> signature;
+    EXPECT_FALSE(images[1]->GetCodeSignatureInfo(&signature));
+    EXPECT_TRUE(signature.empty());
+
+    // Test an arbitrary load command.
+    auto commands = images[1]->GetLoadCommands();
+    ASSERT_EQ(15u, commands.size());
+    auto command = commands[1];
+    ASSERT_EQ(static_cast<uint32_t>(LC_SEGMENT_64), command.cmd());
+    auto actual = command.as_command<segment_command_64>();
+    EXPECT_EQ("__TEXT", std::string(actual->segname));
+    EXPECT_EQ(0u, actual->fileoff);
+    EXPECT_EQ(4096u, actual->filesize);
+    EXPECT_EQ(0x7, actual->maxprot);
+    EXPECT_EQ(0x5, actual->initprot);
+    EXPECT_EQ(3u, actual->nsects);
+    EXPECT_EQ(0u, actual->flags);
+  }
+}
+
+TEST_F(MachOImageReaderTest, ExecutablePPC) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("executableppc", &file));
+  MachOImageReader reader;
+  ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+  EXPECT_FALSE(reader.IsFat());
+  EXPECT_FALSE(reader.Is64Bit());
+  EXPECT_TRUE(reader.GetMachHeader());
+  EXPECT_EQ(OSSwapInt32(MH_EXECUTE), reader.GetFileType());
+  EXPECT_EQ(10u, reader.GetLoadCommands().size());
+
+  std::vector<uint8_t> signature;
+  EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
+  EXPECT_TRUE(signature.empty());
+}
+
+TEST_F(MachOImageReaderTest, Dylib32) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("lib32.dylib", &file));
+  MachOImageReader reader;
+  ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+  EXPECT_FALSE(reader.IsFat());
+  EXPECT_FALSE(reader.Is64Bit());
+  EXPECT_TRUE(reader.GetMachHeader());
+  EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), reader.GetFileType());
+  EXPECT_EQ(13u, reader.GetLoadCommands().size());
+
+  std::vector<uint8_t> signature;
+  EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
+  EXPECT_TRUE(signature.empty());
+}
+
+TEST_F(MachOImageReaderTest, Dylib64) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("lib64.dylib", &file));
+  MachOImageReader reader;
+  ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+  EXPECT_FALSE(reader.IsFat());
+  EXPECT_TRUE(reader.Is64Bit());
+  EXPECT_TRUE(reader.GetMachHeader());
+  EXPECT_TRUE(reader.GetMachHeader64());
+  EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), reader.GetFileType());
+  EXPECT_EQ(13u, reader.GetLoadCommands().size());
+
+  std::vector<uint8_t> signature;
+  EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
+  EXPECT_TRUE(signature.empty());
+
+  // Test an arbitrary load command.
+  auto commands = reader.GetLoadCommands();
+  ASSERT_EQ(13u, commands.size());
+  auto command = commands[6];
+  ASSERT_EQ(static_cast<uint32_t>(LC_UUID), command.cmd());
+  uuid_t expected = {0xB6, 0xB5, 0x12, 0xD7,
+                     0x64, 0xE9,
+                     0x3F, 0x7A,
+                     0xAB, 0x4A,
+                     0x87, 0x46, 0x36, 0x76, 0x87, 0x47};
+  EXPECT_EQ(0, uuid_compare(expected,
+                            command.as_command<uuid_command>()->uuid));
+}
+
+TEST_F(MachOImageReaderTest, DylibFat) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("libfat.dylib", &file));
+  MachOImageReader reader;
+  ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+  EXPECT_TRUE(reader.IsFat());
+  auto images = reader.GetFatImages();
+  ASSERT_EQ(2u, images.size());
+
+  // Note: this image is crafted to have 64-bit first.
+  {
+    EXPECT_FALSE(images[0]->IsFat());
+    EXPECT_TRUE(images[0]->Is64Bit());
+    EXPECT_TRUE(images[0]->GetMachHeader());
+    EXPECT_TRUE(images[0]->GetMachHeader64());
+    EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), images[0]->GetFileType());
+
+    std::vector<uint8_t> signature;
+    EXPECT_FALSE(images[0]->GetCodeSignatureInfo(&signature));
+    EXPECT_TRUE(signature.empty());
+  }
+
+  {
+    EXPECT_FALSE(images[1]->IsFat());
+    EXPECT_FALSE(images[1]->Is64Bit());
+    EXPECT_TRUE(images[1]->GetMachHeader());
+    EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), images[1]->GetFileType());
+
+    std::vector<uint8_t> signature;
+    EXPECT_FALSE(images[1]->GetCodeSignatureInfo(&signature));
+    EXPECT_TRUE(signature.empty());
+  }
+}
+
+TEST_F(MachOImageReaderTest, SignedExecutable32) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("signedexecutable32", &file));
+  MachOImageReader reader;
+  ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+  EXPECT_FALSE(reader.IsFat());
+  EXPECT_FALSE(reader.Is64Bit());
+  EXPECT_TRUE(reader.GetMachHeader());
+  EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.GetFileType());
+  EXPECT_EQ(16u, reader.GetLoadCommands().size());
+
+  std::vector<uint8_t> signature;
+  EXPECT_TRUE(reader.GetCodeSignatureInfo(&signature));
+  EXPECT_EQ(9344u, signature.size());
+
+  std::string identity;
+  GetSigningIdentity(signature, &identity);
+  EXPECT_EQ("signedexecutable32", identity);
+
+  ExpectCodeSignatureHash(signature,
+                          "11fb88eb63c10dfc3d24a2545ea2a9c50c2921b5");
+}
+
+TEST_F(MachOImageReaderTest, SignedExecutableFat) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("signedexecutablefat", &file));
+  MachOImageReader reader;
+  ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+  EXPECT_TRUE(reader.IsFat());
+  auto images = reader.GetFatImages();
+  ASSERT_EQ(2u, images.size());
+
+  // Note: this image is crafted to have 32-bit first.
+  {
+    EXPECT_FALSE(images[0]->IsFat());
+    EXPECT_FALSE(images[0]->Is64Bit());
+    EXPECT_TRUE(images[0]->GetMachHeader());
+    EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[0]->GetFileType());
+
+    std::vector<uint8_t> signature;
+    EXPECT_TRUE(images[0]->GetCodeSignatureInfo(&signature));
+    EXPECT_EQ(9344u, signature.size());
+
+    std::string identity;
+    GetSigningIdentity(signature, &identity);
+    EXPECT_EQ("signedexecutablefat", identity);
+
+    ExpectCodeSignatureHash(signature,
+                            "11fb88eb63c10dfc3d24a2545ea2a9c50c2921b5");
+  }
+
+  {
+    EXPECT_FALSE(images[1]->IsFat());
+    EXPECT_TRUE(images[1]->Is64Bit());
+    EXPECT_TRUE(images[1]->GetMachHeader());
+    EXPECT_TRUE(images[1]->GetMachHeader64());
+    EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[1]->GetFileType());
+
+    std::vector<uint8_t> signature;
+    EXPECT_TRUE(images[1]->GetCodeSignatureInfo(&signature));
+    EXPECT_EQ(9344u, signature.size());
+
+    std::string identity;
+    GetSigningIdentity(signature, &identity);
+    EXPECT_EQ("signedexecutablefat", identity);
+
+    ExpectCodeSignatureHash(signature,
+                            "750a57326ba85857371094900475defd837f5e14");
+  }
+}
+
+TEST_F(MachOImageReaderTest, SignedDylib64) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("libsigned64.dylib", &file));
+  MachOImageReader reader;
+  ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+  EXPECT_FALSE(reader.IsFat());
+  EXPECT_TRUE(reader.Is64Bit());
+  EXPECT_TRUE(reader.GetMachHeader());
+  EXPECT_TRUE(reader.GetMachHeader64());
+  EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), reader.GetFileType());
+  EXPECT_EQ(14u, reader.GetLoadCommands().size());
+
+  std::vector<uint8_t> signature;
+  EXPECT_TRUE(reader.GetCodeSignatureInfo(&signature));
+  EXPECT_EQ(9328u, signature.size());
+
+  std::string identity;
+  GetSigningIdentity(signature, &identity);
+  EXPECT_EQ("libsigned64", identity);
+
+  ExpectCodeSignatureHash(signature,
+                          "8b1c79b60bb53a7f17b5618d5feb10dc8b88d806");
+}
+
+TEST_F(MachOImageReaderTest, NotMachO) {
+  base::MemoryMappedFile file;
+  ASSERT_NO_FATAL_FAILURE(OpenTestFile("src.c", &file));
+  MachOImageReader reader;
+  EXPECT_FALSE(reader.Initialize(file.data(), file.length()));
+}
+
+}  // namespace
+}  // namespace safe_browsing
diff --git a/chrome/common/service_process_util.h b/chrome/common/service_process_util.h
index 9067623..7783e76e 100644
--- a/chrome/common/service_process_util.h
+++ b/chrome/common/service_process_util.h
@@ -26,7 +26,7 @@
 
 namespace base {
 class CommandLine;
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 }
 
 // Return the IPC channel to connect to the service process.
@@ -88,11 +88,10 @@
   // This method is called when the service process is running and initialized.
   // |terminate_task| is invoked when we get a terminate request from another
   // process (in the same thread that called SignalReady). It can be NULL.
-  // |message_loop_proxy| must be of type IO and is the loop that POSIX uses
+  // |task_runner| must be of type IO and is the loop that POSIX uses
   // to monitor the service process.
-  bool SignalReady(
-      base::MessageLoopProxy* message_loop_proxy,
-      const base::Closure& terminate_task);
+  bool SignalReady(base::SingleThreadTaskRunner* task_runner,
+                   const base::Closure& terminate_task);
 
   // Signal that the service process is stopped.
   void SignalStopped();
diff --git a/chrome/common/service_process_util_posix.cc b/chrome/common/service_process_util_posix.cc
index 6a655ca..9ec327c 100644
--- a/chrome/common/service_process_util_posix.cc
+++ b/chrome/common/service_process_util_posix.cc
@@ -6,8 +6,9 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "chrome/common/multi_process_lock.h"
 
@@ -161,9 +162,8 @@
   state_->AddRef();
 }
 
-bool ServiceProcessState::SignalReady(
-    base::MessageLoopProxy* message_loop_proxy,
-    const base::Closure& terminate_task) {
+bool ServiceProcessState::SignalReady(base::SingleThreadTaskRunner* task_runner,
+                                      const base::Closure& terminate_task) {
   DCHECK(state_);
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
@@ -181,11 +181,9 @@
   base::WaitableEvent signal_ready(true, false);
   bool success = false;
 
-  message_loop_proxy->PostTask(FROM_HERE,
-      base::Bind(&ServiceProcessState::StateData::SignalReady,
-                 state_,
-                 &signal_ready,
-                 &success));
+  task_runner->PostTask(FROM_HERE,
+                        base::Bind(&ServiceProcessState::StateData::SignalReady,
+                                   state_, &signal_ready, &success));
   signal_ready.Wait();
   return success;
 }
diff --git a/chrome/common/service_process_util_unittest.cc b/chrome/common/service_process_util_unittest.cc
index 9e4ba36..18819241 100644
--- a/chrome/common/service_process_util_unittest.cc
+++ b/chrome/common/service_process_util_unittest.cc
@@ -8,8 +8,10 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/location.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_split.h"
 
 #if !defined(OS_MACOSX)
@@ -52,7 +54,7 @@
   // Quit the main message loop.
   ASSERT_FALSE(g_good_shutdown);
   g_good_shutdown = true;
-  loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+  loop->task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
 }
 
 }  // namespace
@@ -70,8 +72,8 @@
   ServiceProcessStateTest();
   ~ServiceProcessStateTest() override;
   void SetUp() override;
-  base::MessageLoopProxy* IOMessageLoopProxy() {
-    return io_thread_.message_loop_proxy().get();
+  base::SingleThreadTaskRunner* IOMessageLoopProxy() {
+    return io_thread_.task_runner().get();
   }
   void LaunchAndWait(const std::string& name);
 
@@ -228,11 +230,11 @@
   ServiceProcessState state;
   EXPECT_TRUE(state.Initialize());
   EXPECT_TRUE(state.SignalReady(
-      io_thread_.message_loop_proxy().get(),
+      io_thread_.task_runner().get(),
       base::Bind(&ShutdownTask, base::MessageLoop::current())));
-  message_loop.PostDelayedTask(FROM_HERE,
-                               base::MessageLoop::QuitClosure(),
-                               TestTimeouts::action_max_timeout());
+  message_loop.task_runner()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
+      TestTimeouts::action_max_timeout());
   EXPECT_FALSE(g_good_shutdown);
   message_loop.Run();
   EXPECT_TRUE(g_good_shutdown);
@@ -274,7 +276,7 @@
         new Launchd::ScopedInstance(mock_launchd_.get()));
     ASSERT_TRUE(service_process_state_.Initialize());
     ASSERT_TRUE(service_process_state_.SignalReady(
-        io_thread_.message_loop_proxy().get(), base::Closure()));
+        io_thread_.task_runner().get(), base::Closure()));
     loop_.PostDelayedTask(FROM_HERE,
                           base::MessageLoop::QuitClosure(),
                           TestTimeouts::action_max_timeout());
@@ -285,8 +287,8 @@
   const base::FilePath& bundle_path() const { return bundle_path_; }
   const base::FilePath& GetTempDirPath() const { return temp_dir_.path(); }
 
-  base::MessageLoopProxy* GetIOMessageLoopProxy() {
-    return io_thread_.message_loop_proxy().get();
+  base::SingleThreadTaskRunner* GetIOMessageLoopProxy() {
+    return io_thread_.task_runner().get();
   }
   void Run() { loop_.Run(); }
 
diff --git a/chrome/common/service_process_util_win.cc b/chrome/common/service_process_util_win.cc
index 6aac388..df7c039 100644
--- a/chrome/common/service_process_util_win.cc
+++ b/chrome/common/service_process_util_win.cc
@@ -132,9 +132,8 @@
   return true;
 }
 
-bool ServiceProcessState::SignalReady(
-    base::MessageLoopProxy* message_loop_proxy,
-    const base::Closure& terminate_task) {
+bool ServiceProcessState::SignalReady(base::SingleThreadTaskRunner* task_runner,
+                                      const base::Closure& terminate_task) {
   DCHECK(state_);
   DCHECK(state_->ready_event.IsValid());
   if (!SetEvent(state_->ready_event.Get())) {
diff --git a/chrome/common/variations/experiment_labels.cc b/chrome/common/variations/experiment_labels.cc
index 7ec0ea2..6c952440 100644
--- a/chrome/common/variations/experiment_labels.cc
+++ b/chrome/common/variations/experiment_labels.cc
@@ -79,7 +79,7 @@
   for (std::vector<base::string16>::const_iterator it = entries.begin();
        it != entries.end(); ++it) {
     if (it->empty() ||
-        StartsWith(*it, base::ASCIIToUTF16(kVariationPrefix), false)) {
+        base::StartsWith(*it, base::ASCIIToUTF16(kVariationPrefix), false)) {
       continue;
     }
 
@@ -95,9 +95,9 @@
 base::string16 CombineExperimentLabels(const base::string16& variation_labels,
                                        const base::string16& other_labels) {
   const base::string16 separator(1, google_update::kExperimentLabelSeparator);
-  DCHECK(!StartsWith(variation_labels, separator, false));
+  DCHECK(!base::StartsWith(variation_labels, separator, false));
   DCHECK(!EndsWith(variation_labels, separator, false));
-  DCHECK(!StartsWith(other_labels, separator, false));
+  DCHECK(!base::StartsWith(other_labels, separator, false));
   DCHECK(!EndsWith(other_labels, separator, false));
   // Note that if either label is empty, a separator is not necessary.
   base::string16 combined_labels = other_labels;
diff --git a/chrome/common/worker_thread_ticker.cc b/chrome/common/worker_thread_ticker.cc
index 1fa75e9..8b78d979 100644
--- a/chrome/common/worker_thread_ticker.cc
+++ b/chrome/common/worker_thread_ticker.cc
@@ -8,8 +8,9 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 
 WorkerThreadTicker::WorkerThreadTicker(int tick_interval)
@@ -76,7 +77,7 @@
 }
 
 void WorkerThreadTicker::ScheduleTimerTask() {
-  timer_thread_.message_loop()->PostDelayedTask(
+  timer_thread_.task_runner()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&WorkerThreadTicker::TimerTask, base::Unretained(this)),
       tick_interval_);
diff --git a/chrome/common/worker_thread_ticker_unittest.cc b/chrome/common/worker_thread_ticker_unittest.cc
index 4f7dc0d6..dbb2e01 100644
--- a/chrome/common/worker_thread_ticker_unittest.cc
+++ b/chrome/common/worker_thread_ticker_unittest.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/common/worker_thread_ticker.h"
 
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -18,7 +21,8 @@
     counter_++;
 
     // Finish the test faster.
-    message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+    message_loop_->task_runner()->PostTask(FROM_HERE,
+                                           base::MessageLoop::QuitClosure());
   }
 
   int counter() const { return counter_; }
@@ -36,9 +40,8 @@
 };
 
 void RunMessageLoopForAWhile() {
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       base::TimeDelta::FromMilliseconds(500));
   base::MessageLoop::current()->Run();
 }
diff --git a/chrome/installer/gcapi/gcapi.cc b/chrome/installer/gcapi/gcapi.cc
index 43b76c7..a560b7b 100644
--- a/chrome/installer/gcapi/gcapi.cc
+++ b/chrome/installer/gcapi/gcapi.cc
@@ -366,9 +366,9 @@
 
   if (!params->shunted_hwnds.count(hwnd) &&
       ::GetClassName(hwnd, window_class, arraysize(window_class)) &&
-      StartsWith(window_class, kChromeWindowClassPrefix, false) &&
-      ::SetWindowPos(hwnd, params->window_insert_after, params->x,
-                     params->y, params->width, params->height, params->flags)) {
+      base::StartsWith(window_class, kChromeWindowClassPrefix, false) &&
+      ::SetWindowPos(hwnd, params->window_insert_after, params->x, params->y,
+                     params->width, params->height, params->flags)) {
     params->shunted_hwnds.insert(hwnd);
     params->success = true;
   }
diff --git a/chrome/installer/gcapi/gcapi_omaha_experiment.cc b/chrome/installer/gcapi/gcapi_omaha_experiment.cc
index c49de3d..30c0137 100644
--- a/chrome/installer/gcapi/gcapi_omaha_experiment.cc
+++ b/chrome/installer/gcapi/gcapi_omaha_experiment.cc
@@ -50,7 +50,7 @@
   base::string16 new_labels;
   for (std::vector<base::string16>::const_iterator it = entries.begin();
        it != entries.end(); ++it) {
-    if (!it->empty() && !StartsWith(*it, label + L"=", true)) {
+    if (!it->empty() && !base::StartsWith(*it, label + L"=", true)) {
       new_labels += *it;
       new_labels += google_update::kExperimentLabelSeparator;
     }
diff --git a/chrome/installer/linux/common/installer.include b/chrome/installer/linux/common/installer.include
index 14171f76..7f4ef77 100644
--- a/chrome/installer/linux/common/installer.include
+++ b/chrome/installer/linux/common/installer.include
@@ -156,9 +156,6 @@
   find "${STAGEDIR}/${INSTALLDIR}/locales" -type f -exec chmod 644 '{}' \;
   find "${STAGEDIR}/${INSTALLDIR}/locales" -type d -exec chmod 755 '{}' \;
 
-  # ffmpeg libs
-  install -m 644 -s "${BUILDDIR}/libffmpegsumo.so" "${STAGEDIR}/${INSTALLDIR}/"
-
   # Widevine CDM.
   if [ -f "${BUILDDIR}/libwidevinecdmadapter.so" ]; then
     install -m 644 -s "${BUILDDIR}/libwidevinecdmadapter.so" "${STAGEDIR}/${INSTALLDIR}/"
diff --git a/chrome/installer/linux/rpm/expected_deps_i386 b/chrome/installer/linux/rpm/expected_deps_i386
index 00900a9..2875d40 100644
--- a/chrome/installer/linux/rpm/expected_deps_i386
+++ b/chrome/installer/linux/rpm/expected_deps_i386
@@ -13,6 +13,7 @@
 libc.so.6(GLIBC_2.2.3)
 libc.so.6(GLIBC_2.3)
 libc.so.6(GLIBC_2.3.2)
+libc.so.6(GLIBC_2.3.4)
 libc.so.6(GLIBC_2.4)
 libc.so.6(GLIBC_2.6)
 libc.so.6(GLIBC_2.7)
diff --git a/chrome/installer/linux/rpm/expected_deps_x86_64 b/chrome/installer/linux/rpm/expected_deps_x86_64
index f7085e2..9ffd93b 100644
--- a/chrome/installer/linux/rpm/expected_deps_x86_64
+++ b/chrome/installer/linux/rpm/expected_deps_x86_64
@@ -8,6 +8,7 @@
 libc.so.6(GLIBC_2.11)(64bit)
 libc.so.6(GLIBC_2.2.5)(64bit)
 libc.so.6(GLIBC_2.3.2)(64bit)
+libc.so.6(GLIBC_2.3.4)(64bit)
 libc.so.6(GLIBC_2.3)(64bit)
 libc.so.6(GLIBC_2.4)(64bit)
 libc.so.6(GLIBC_2.6)(64bit)
diff --git a/chrome/installer/mini_installer/chrome.release b/chrome/installer/mini_installer/chrome.release
index b6d3d483..07bc305 100644
--- a/chrome/installer/mini_installer/chrome.release
+++ b/chrome/installer/mini_installer/chrome.release
@@ -24,7 +24,6 @@
 chrome_elf.dll: %(VersionDir)s\
 chrome_watcher.dll: %(VersionDir)s\
 d3dcompiler_47.dll: %(VersionDir)s\
-ffmpegsumo.dll: %(VersionDir)s\
 kasko.dll: %(VersionDir)s\
 icudt.dll: %(VersionDir)s\
 icudtl.dat: %(VersionDir)s\
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc
index 7b40d98d..4824016 100644
--- a/chrome/installer/setup/install_worker.cc
+++ b/chrome/installer/setup/install_worker.cc
@@ -717,7 +717,7 @@
     // languages is a superset of Chrome's set of translations with this one
     // exception: what Chrome calls "en-us", Omaha calls "en".  sigh.
     base::string16 language(GetCurrentTranslation());
-    if (LowerCaseEqualsASCII(language, "en-us"))
+    if (base::LowerCaseEqualsASCII(language, "en-us"))
       language.resize(2);
     list->AddSetRegValueWorkItem(root,
                                  version_key,
diff --git a/chrome/installer/util/delete_after_reboot_helper.cc b/chrome/installer/util/delete_after_reboot_helper.cc
index b298d6a..513cd3c 100644
--- a/chrome/installer/util/delete_after_reboot_helper.cc
+++ b/chrome/installer/util/delete_after_reboot_helper.cc
@@ -330,7 +330,7 @@
 
   // First chomp the prefix since that will mess up GetShortPathName.
   std::wstring prefix(L"\\??\\");
-  if (StartsWith(match_path, prefix, false))
+  if (base::StartsWith(match_path, prefix, false))
     match_path = match_path.substr(4);
 
   // Get the short path name of the entry.
@@ -338,7 +338,8 @@
 
   // Now compare the paths. If it isn't one we're looking for, add it
   // to the list to keep.
-  return StartsWith(short_match_path.value(), short_form_needle.value(), false);
+  return base::StartsWith(short_match_path.value(), short_form_needle.value(),
+                          false);
 }
 
 // Removes all pending moves for the given |directory| and any contained
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index a3861b82..f7dccea 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -379,7 +379,7 @@
     NOTREACHED();
     return true;
   }
-  return !StartsWith(exe_path.value(), program_files_path.value(), false);
+  return !base::StartsWith(exe_path.value(), program_files_path.value(), false);
 }
 
 bool InstallUtil::IsMultiInstall(BrowserDistribution* dist,
diff --git a/chrome/installer/util/l10n_string_util.cc b/chrome/installer/util/l10n_string_util.cc
index bcd3a9e..3e38788 100644
--- a/chrome/installer/util/l10n_string_util.cc
+++ b/chrome/installer/util/l10n_string_util.cc
@@ -73,7 +73,7 @@
   // The resource names are more or less the upcased language names.
   std::wstring language(GetLanguageSelector().selected_translation());
   std::replace(language.begin(), language.end(), L'-', L'_');
-  StringToUpperASCII(&language);
+  base::StringToUpperASCII(&language);
 
   std::wstring resource(L"IDR_OEMPG_");
   resource.append(language).append(L".HTML");
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index 0294c43..68fc57d05 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -979,7 +979,7 @@
 TEST(ShellUtilTest, GetUserSpecificRegistrySuffix) {
   base::string16 suffix;
   ASSERT_TRUE(ShellUtil::GetUserSpecificRegistrySuffix(&suffix));
-  ASSERT_TRUE(StartsWith(suffix, L".", true));
+  ASSERT_TRUE(base::StartsWith(suffix, L".", true));
   ASSERT_EQ(27, suffix.length());
   ASSERT_TRUE(base::ContainsOnlyChars(suffix.substr(1),
                                       L"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"));
@@ -988,7 +988,7 @@
 TEST(ShellUtilTest, GetOldUserSpecificRegistrySuffix) {
   base::string16 suffix;
   ASSERT_TRUE(ShellUtil::GetOldUserSpecificRegistrySuffix(&suffix));
-  ASSERT_TRUE(StartsWith(suffix, L".", true));
+  ASSERT_TRUE(base::StartsWith(suffix, L".", true));
 
   wchar_t user_name[256];
   DWORD size = arraysize(user_name);
diff --git a/chrome/interactive_ui_tests.isolate b/chrome/interactive_ui_tests.isolate
index 084c69ab1..f013ef6 100644
--- a/chrome/interactive_ui_tests.isolate
+++ b/chrome/interactive_ui_tests.isolate
@@ -35,7 +35,6 @@
     ['OS=="linux"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
           '<(PRODUCT_DIR)/libppapi_tests.so',
           '<(PRODUCT_DIR)/pyproto/google/',
@@ -77,7 +76,6 @@
         'files': [
           '<(PRODUCT_DIR)/<(mac_product_name) Framework.framework/',
           '<(PRODUCT_DIR)/<(mac_product_name).app/',
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
           '<(PRODUCT_DIR)/osmesa.so',
           '<(PRODUCT_DIR)/ppapi_tests.plugin/Contents/MacOS/ppapi_tests',
         ],
@@ -88,7 +86,6 @@
         'files': [
           '<(PRODUCT_DIR)/<(mac_product_name) Framework.framework/',
           '<(PRODUCT_DIR)/<(mac_product_name).app.dSYM/',
-          '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
           '<(PRODUCT_DIR)/interactive_ui_tests.dSYM/',
           '<(PRODUCT_DIR)/osmesa.so.dSYM/',
           '<(PRODUCT_DIR)/ppapi_tests.plugin.dSYM/',
@@ -100,7 +97,6 @@
         'files': [
           '<(PRODUCT_DIR)/chrome_elf.dll',
           '<(PRODUCT_DIR)/d3dcompiler_47.dll',
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/libEGL.dll',
           '<(PRODUCT_DIR)/libGLESv2.dll',
           '<(PRODUCT_DIR)/osmesa.dll',
diff --git a/chrome/plugin/chrome_content_plugin_client.cc b/chrome/plugin/chrome_content_plugin_client.cc
index d54e0c4..3e254c6 100644
--- a/chrome/plugin/chrome_content_plugin_client.cc
+++ b/chrome/plugin/chrome_content_plugin_client.cc
@@ -44,11 +44,8 @@
     LOG(ERROR) << "Failed to load crypto32.dll: " << error.ToString();
 #endif // defined(OS_WIN)
 
-  // Load media libraries for the Chromoting client plugin.
-  base::FilePath media_path;
-  PathService::Get(content::DIR_MEDIA_LIBS, &media_path);
-  if (!media_path.empty())
-    media::InitializeMediaLibrary(media_path);
+  // Initialize media libraries for the Chromoting client plugin.
+  media::InitializeMediaLibrary();
 
 #endif // defined(ENABLE_REMOTING)
 }
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 8e92c8de..f34a5c7 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -40,7 +40,7 @@
 #include "chrome/renderer/net_benchmarking_extension.h"
 #include "chrome/renderer/page_load_histograms.h"
 #include "chrome/renderer/pepper/pepper_helper.h"
-#include "chrome/renderer/plugins/chrome_plugin_placeholder.h"
+#include "chrome/renderer/plugins/non_loadable_plugin_placeholder.h"
 #include "chrome/renderer/plugins/plugin_preroller.h"
 #include "chrome/renderer/plugins/plugin_uma.h"
 #include "chrome/renderer/plugins/shadow_dom_plugin_placeholder.h"
@@ -132,6 +132,10 @@
 #include "chrome/common/external_ipc_dumper.h"
 #endif
 
+#if defined(ENABLE_PLUGINS)
+#include "chrome/renderer/plugins/chrome_plugin_placeholder.h"
+#endif
+
 #if defined(ENABLE_PRINTING)
 #include "chrome/renderer/printing/chrome_print_web_view_helper_delegate.h"
 #include "components/printing/renderer/print_web_view_helper.h"
@@ -196,6 +200,7 @@
 };
 #endif
 
+#if defined(ENABLE_PLUGINS)
 void AppendParams(const std::vector<base::string16>& additional_names,
                   const std::vector<base::string16>& additional_values,
                   WebVector<WebString>* existing_names,
@@ -223,26 +228,6 @@
   existing_values->swap(values);
 }
 
-#if defined(ENABLE_SPELLCHECK)
-class SpellCheckReplacer : public content::RenderViewVisitor {
- public:
-  explicit SpellCheckReplacer(SpellCheck* spellcheck)
-      : spellcheck_(spellcheck) {}
-  bool Visit(content::RenderView* render_view) override;
-
- private:
-  SpellCheck* spellcheck_;  // New shared spellcheck for all views. Weak Ptr.
-  DISALLOW_COPY_AND_ASSIGN(SpellCheckReplacer);
-};
-
-bool SpellCheckReplacer::Visit(content::RenderView* render_view) {
-  SpellCheckProvider* provider = SpellCheckProvider::Get(render_view);
-  DCHECK(provider);
-  provider->set_spellcheck(spellcheck_);
-  return true;
-}
-#endif
-
 // For certain sandboxed Pepper plugins, use the JavaScript Content Settings.
 bool ShouldUseJavaScriptSettingForPlugin(const WebPluginInfo& plugin) {
   if (plugin.type != WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS &&
@@ -266,6 +251,27 @@
 
   return false;
 }
+#endif  // defined(ENABLE_PLUGINS)
+
+#if defined(ENABLE_SPELLCHECK)
+class SpellCheckReplacer : public content::RenderViewVisitor {
+ public:
+  explicit SpellCheckReplacer(SpellCheck* spellcheck)
+      : spellcheck_(spellcheck) {}
+  bool Visit(content::RenderView* render_view) override;
+
+ private:
+  SpellCheck* spellcheck_;  // New shared spellcheck for all views. Weak Ptr.
+  DISALLOW_COPY_AND_ASSIGN(SpellCheckReplacer);
+};
+
+bool SpellCheckReplacer::Visit(content::RenderView* render_view) {
+  SpellCheckProvider* provider = SpellCheckProvider::Get(render_view);
+  DCHECK(provider);
+  provider->set_spellcheck(spellcheck_);
+  return true;
+}
+#endif
 
 #if defined(ENABLE_EXTENSIONS)
 void IsGuestViewApiAvailableToScriptContext(
@@ -615,7 +621,7 @@
 #if defined(ENABLE_EXTENSIONS)
 const Extension* ChromeContentRendererClient::GetExtensionByOrigin(
     const WebSecurityOrigin& origin) const {
-  if (!EqualsASCII(origin.protocol(), extensions::kExtensionScheme))
+  if (!base::EqualsASCII(origin.protocol(), extensions::kExtensionScheme))
     return NULL;
 
   const std::string extension_id = origin.host().utf8().data();
@@ -650,25 +656,39 @@
   }
 #endif
 
-  ChromeViewHostMsg_GetPluginInfo_Output output;
+  GURL url(params.url);
 #if defined(ENABLE_PLUGINS)
+  ChromeViewHostMsg_GetPluginInfo_Output output;
   render_frame->Send(new ChromeViewHostMsg_GetPluginInfo(
-      render_frame->GetRoutingID(), GURL(params.url),
-      frame->top()->document().url(), orig_mime_type, &output));
-
-#else
-  output.status = ChromeViewHostMsg_GetPluginInfo_Status::kNotFound;
-#endif
+      render_frame->GetRoutingID(), url, frame->top()->document().url(),
+      orig_mime_type, &output));
   *plugin = CreatePlugin(render_frame, frame, params, output);
+#else  // !defined(ENABLE_PLUGINS)
+
+#if defined(OS_ANDROID)
+  if (plugins::MobileYouTubePlugin::IsYouTubeURL(url, orig_mime_type)) {
+    base::StringPiece template_html(
+        ResourceBundle::GetSharedInstance().GetRawDataResource(
+            IDR_MOBILE_YOUTUBE_PLUGIN_HTML));
+    *plugin = (new plugins::MobileYouTubePlugin(render_frame, frame, params,
+                                                template_html))->plugin();
+    return true;
+  }
+#endif  // defined(OS_ANDROID)
+
+  PluginUMAReporter::GetInstance()->ReportPluginMissing(orig_mime_type, url);
+  *plugin = NonLoadablePluginPlaceholder::CreateNotSupportedPlugin(
+                render_frame, frame, params)->plugin();
+
+#endif  // defined(ENABLE_PLUGINS)
   return true;
 }
 
 WebPlugin* ChromeContentRendererClient::CreatePluginReplacement(
     content::RenderFrame* render_frame,
     const base::FilePath& plugin_path) {
-  ChromePluginPlaceholder* placeholder =
-      ChromePluginPlaceholder::CreateErrorPlugin(render_frame, plugin_path);
-  return placeholder->plugin();
+  return NonLoadablePluginPlaceholder::CreateErrorPlugin(render_frame,
+                                                         plugin_path)->plugin();
 }
 
 void ChromeContentRendererClient::DeferMediaLoad(
@@ -689,6 +709,7 @@
 #endif
 }
 
+#if defined(ENABLE_PLUGINS)
 WebPlugin* ChromeContentRendererClient::CreatePlugin(
     content::RenderFrame* render_frame,
     blink::WebLocalFrame* frame,
@@ -708,22 +729,8 @@
   // OverrideCreatePlugin.
   if (status == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound ||
       orig_mime_type == content::kBrowserPluginMimeType) {
-#if defined(OS_ANDROID)
-    if (plugins::MobileYouTubePlugin::IsYouTubeURL(url, orig_mime_type)) {
-      base::StringPiece template_html(
-          ResourceBundle::GetSharedInstance().GetRawDataResource(
-              IDR_MOBILE_YOUTUBE_PLUGIN_HTML));
-      return (new plugins::MobileYouTubePlugin(
-                  render_frame,
-                  frame,
-                  original_params,
-                  template_html,
-                  GURL(ChromePluginPlaceholder::kPluginPlaceholderDataURL)))
-          ->plugin();
-    }
-#endif
     PluginUMAReporter::GetInstance()->ReportPluginMissing(orig_mime_type, url);
-    placeholder = ChromePluginPlaceholder::CreateMissingPlugin(
+    placeholder = ChromePluginPlaceholder::CreateLoadableMissingPlugin(
         render_frame, frame, original_params);
   } else {
     // TODO(bauerb): This should be in content/.
@@ -846,7 +853,6 @@
         }
 #endif  // !defined(DISABLE_NACL) && defined(ENABLE_EXTENSIONS)
 
-#if defined(ENABLE_PLUGINS)
         // Delay loading plugins if prerendering.
         // TODO(mmenke):  In the case of prerendering, feed into
         //                ChromeContentRendererClient::CreatePlugin instead, to
@@ -881,7 +887,6 @@
               blocked_for_background_tab);
           placeholder->set_blocked_for_prerendering(is_prerendering);
           placeholder->set_power_saver_enabled(power_saver_enabled);
-          placeholder->set_allow_loading(true);
           break;
         }
 
@@ -897,9 +902,6 @@
 
         return render_frame->CreatePlugin(frame, info, params,
                                           throttler.Pass());
-#else   // !defined(ENABLE_PLUGINS)
-        return render_frame->CreatePlugin(frame, info, params, nullptr);
-#endif  // defined(ENABLE_PLUGINS)
       }
       case ChromeViewHostMsg_GetPluginInfo_Status::kNPAPINotSupported: {
         RenderThread::Get()->RecordAction(
@@ -924,7 +926,6 @@
         placeholder = create_blocked_plugin(
             IDR_BLOCKED_PLUGIN_HTML,
             l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED, group_name));
-        placeholder->set_allow_loading(true);
         render_frame->Send(new ChromeViewHostMsg_BlockedOutdatedPlugin(
             render_frame->GetRoutingID(), placeholder->CreateRoutingId(),
             identifier));
@@ -943,7 +944,6 @@
         placeholder = create_blocked_plugin(
             IDR_BLOCKED_PLUGIN_HTML,
             l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, group_name));
-        placeholder->set_allow_loading(true);
         if (info.type != content::WebPluginInfo::PLUGIN_TYPE_NPAPI) {
           render_frame->Send(new ChromeViewHostMsg_BlockedUnauthorizedPlugin(
               render_frame->GetRoutingID(),
@@ -957,7 +957,6 @@
         placeholder = create_blocked_plugin(
             IDR_BLOCKED_PLUGIN_HTML,
             l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name));
-        placeholder->set_allow_loading(true);
         RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Blocked"));
         observer->DidBlockContentType(content_type, group_name);
         break;
@@ -967,7 +966,7 @@
             IDR_BLOCKED_PLUGIN_HTML,
             l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED_BY_POLICY,
                                        group_name));
-        placeholder->set_allow_loading(false);
+        placeholder->DisallowLoading();
         RenderThread::Get()->RecordAction(
             UserMetricsAction("Plugin_BlockedByPolicy"));
         observer->DidBlockContentType(content_type, group_name);
@@ -978,6 +977,7 @@
   placeholder->SetStatus(status);
   return placeholder->plugin();
 }
+#endif  // defined(ENABLE_PLUGINS)
 
 // For NaCl content handling plugins, the NaCl manifest is stored in an
 // additonal 'nacl' param associated with the MIME type.
@@ -1155,7 +1155,7 @@
   }
 #endif
 
-  bool is_post = EqualsASCII(failed_request.httpMethod(), "POST");
+  bool is_post = base::EqualsASCII(failed_request.httpMethod(), "POST");
 
   if (error_html) {
     bool extension_but_not_bookmark_app = false;
@@ -1234,7 +1234,7 @@
   return false;
 }
 
-bool ChromeContentRendererClient::ShouldFork(blink::WebFrame* frame,
+bool ChromeContentRendererClient::ShouldFork(blink::WebLocalFrame* frame,
                                              const GURL& url,
                                              const std::string& http_method,
                                              bool is_initial_navigation,
@@ -1305,8 +1305,11 @@
   // If this is a reload, check whether it has the wrong process type.  We
   // should send it to the browser if it's an extension URL (e.g., hosted app)
   // in a normal process, or if it's a process for an extension that has been
-  // uninstalled.
-  if (frame->top()->document().url() == url) {
+  // uninstalled.  Without --site-per-process mode, we never fork processes for
+  // subframes, so this check only makes sense for top-level frames.
+  // TODO(alexmos,nasko): Figure out how this check should work when reloading
+  // subframes in --site-per-process mode.
+  if (!frame->parent() && frame->document().url() == url) {
     if (is_extension_url != IsStandaloneExtensionProcess())
       return true;
   }
@@ -1509,7 +1512,7 @@
       (EndsWith(url_host, "talkgadget.google.com", false) ||
        EndsWith(url_host, "plus.google.com", false) ||
        EndsWith(url_host, "plus.sandbox.google.com", false)) &&
-      StartsWithASCII(url.path(), "/hangouts/", false)) {
+      base::StartsWithASCII(url.path(), "/hangouts/", false)) {
     return true;
   }
   // Allow access for tests.
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index c75ad31..93fe153a 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -109,7 +109,7 @@
                       const base::Closure& closure) override;
   bool RunIdleHandlerWhenWidgetsHidden() override;
   bool AllowPopup() override;
-  bool ShouldFork(blink::WebFrame* frame,
+  bool ShouldFork(blink::WebLocalFrame* frame,
                   const GURL& url,
                   const std::string& http_method,
                   bool is_initial_navigation,
@@ -168,11 +168,13 @@
   void SetSpellcheck(SpellCheck* spellcheck);
 #endif
 
+#if defined(ENABLE_PLUGINS)
   static blink::WebPlugin* CreatePlugin(
       content::RenderFrame* render_frame,
       blink::WebLocalFrame* frame,
       const blink::WebPluginParams& params,
       const ChromeViewHostMsg_GetPluginInfo_Output& output);
+#endif
 
 #if defined(ENABLE_PLUGINS) && defined(ENABLE_EXTENSIONS)
   static bool IsExtensionOrSharedModuleWhitelisted(
diff --git a/chrome/renderer/chrome_content_renderer_client_browsertest.cc b/chrome/renderer/chrome_content_renderer_client_browsertest.cc
index 14b2526..f373539 100644
--- a/chrome/renderer/chrome_content_renderer_client_browsertest.cc
+++ b/chrome/renderer/chrome_content_renderer_client_browsertest.cc
@@ -9,6 +9,7 @@
 
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/grit/generated_resources.h"
@@ -53,7 +54,7 @@
   ChromeContentRendererClient* client =
       static_cast<ChromeContentRendererClient*>(content_renderer_client_.get());
   chrome_render_thread_->set_io_message_loop_proxy(
-      base::MessageLoopProxy::current());
+      base::ThreadTaskRunnerHandle::Get());
   client->RenderThreadStarted();
   std::vector<GURL> search_urls;
   search_urls.push_back(GURL("http://example.com/search"));
diff --git a/chrome/renderer/chrome_mock_render_thread.cc b/chrome/renderer/chrome_mock_render_thread.cc
index e197222..64d809e 100644
--- a/chrome/renderer/chrome_mock_render_thread.cc
+++ b/chrome/renderer/chrome_mock_render_thread.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/renderer/chrome_mock_render_thread.h"
 
+#include "base/single_thread_task_runner.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(ENABLE_EXTENSIONS)
@@ -18,12 +19,12 @@
 
 scoped_refptr<base::SingleThreadTaskRunner>
 ChromeMockRenderThread::GetIOMessageLoopProxy() {
-  return io_message_loop_proxy_;
+  return io_task_runner_;
 }
 
 void ChromeMockRenderThread::set_io_message_loop_proxy(
-    const scoped_refptr<base::MessageLoopProxy>& proxy) {
-  io_message_loop_proxy_ = proxy;
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+  io_task_runner_ = task_runner;
 }
 
 bool ChromeMockRenderThread::OnMessageReceived(const IPC::Message& msg) {
diff --git a/chrome/renderer/chrome_mock_render_thread.h b/chrome/renderer/chrome_mock_render_thread.h
index f6e460f8..f15d584 100644
--- a/chrome/renderer/chrome_mock_render_thread.h
+++ b/chrome/renderer/chrome_mock_render_thread.h
@@ -25,7 +25,7 @@
 
   // Set IO message loop proxy.
   void set_io_message_loop_proxy(
-      const scoped_refptr<base::MessageLoopProxy>& proxy);
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
 
  private:
   // Overrides base class implementation to add custom handling for
@@ -41,7 +41,7 @@
                                 int* port_id);
 #endif
 
-  scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeMockRenderThread);
 };
diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc
index 3fcc1c4c..2d2edce 100644
--- a/chrome/renderer/chrome_render_process_observer.cc
+++ b/chrome/renderer/chrome_render_process_observer.cc
@@ -11,14 +11,16 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/native_library.h"
 #include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
 #include "chrome/common/child_process_logging.h"
 #include "chrome/common/chrome_paths.h"
@@ -38,13 +40,13 @@
 #include "crypto/nss_util.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_module.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
 #include "third_party/WebKit/public/web/WebCache.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
 #include "third_party/WebKit/public/web/WebView.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
 
 #if defined(ENABLE_EXTENSIONS)
 #include "chrome/renderer/extensions/extension_localization_peer.h"
@@ -72,7 +74,7 @@
     // Update the browser about our cache.
     // Rate limit informing the host of our cache stats.
     if (!weak_factory_.HasWeakPtrs()) {
-      base::MessageLoop::current()->PostDelayedTask(
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE,
           base::Bind(&RendererResourceDelegate::InformHostOfCacheStats,
                      weak_factory_.GetWeakPtr()),
@@ -168,12 +170,12 @@
     usage_data_->v8_bytes_used = heap_stats.used_heap_size();
     base::Closure collect = base::Bind(
         &ResourceUsageReporterImpl::CollectOnWorkerThread,
-        base::MessageLoopProxy::current(), weak_factory_.GetWeakPtr());
+        base::ThreadTaskRunnerHandle::Get(), weak_factory_.GetWeakPtr());
     workers_to_go_ = RenderThread::Get()->PostTaskToAllWebWorkers(collect);
     if (workers_to_go_) {
       // The guard task to send out partial stats
       // in case some workers are not responsive.
-      base::MessageLoopProxy::current()->PostDelayedTask(
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE, base::Bind(&ResourceUsageReporterImpl::SendResults,
                                 weak_factory_.GetWeakPtr()),
           base::TimeDelta::FromMilliseconds(kWaitForWorkersStatsTimeoutMS));
diff --git a/chrome/renderer/chrome_render_view_observer.cc b/chrome/renderer/chrome_render_view_observer.cc
index 6f77594b..20ba1d534 100644
--- a/chrome/renderer/chrome_render_view_observer.cc
+++ b/chrome/renderer/chrome_render_view_observer.cc
@@ -485,7 +485,7 @@
     if (!element.hasHTMLTagName(tag_name))
       continue;
     WebString value = element.getAttribute(attribute_name);
-    if (value.isNull() || !LowerCaseEqualsASCII(value, "refresh"))
+    if (value.isNull() || !base::LowerCaseEqualsASCII(value, "refresh"))
       continue;
     return true;
   }
diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc
index 332e29a..af4158b 100644
--- a/chrome/renderer/content_settings_observer.cc
+++ b/chrome/renderer/content_settings_observer.cc
@@ -474,18 +474,19 @@
   GURL frame_gurl(frame->document().url());
   if (IsHostInDomain(origin_host, kGoogleDotCom)) {
     SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE);
-    if (StartsWithASCII(frame_gurl.path(), kGoogleSupportPathPrefix, false)) {
+    if (base::StartsWithASCII(frame_gurl.path(), kGoogleSupportPathPrefix,
+                              false)) {
       SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_SUPPORT);
-    } else if (StartsWithASCII(frame_gurl.path(),
-                               kGoogleIntlPathPrefix,
-                               false)) {
+    } else if (base::StartsWithASCII(frame_gurl.path(), kGoogleIntlPathPrefix,
+                                     false)) {
       SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_INTL);
     }
   }
 
   if (origin_host == kWWWDotGoogleDotCom) {
     SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_WWW_GOOGLE);
-    if (StartsWithASCII(frame_gurl.path(), kGoogleReaderPathPrefix, false))
+    if (base::StartsWithASCII(frame_gurl.path(), kGoogleReaderPathPrefix,
+                              false))
       SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_READER);
   } else if (origin_host == kMailDotGoogleDotCom) {
     SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_MAIL_GOOGLE);
@@ -531,18 +532,19 @@
   bool is_google = IsHostInDomain(origin_host, kGoogleDotCom);
   if (is_google) {
     SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE);
-    if (StartsWithASCII(frame_gurl.path(), kGoogleSupportPathPrefix, false)) {
+    if (base::StartsWithASCII(frame_gurl.path(), kGoogleSupportPathPrefix,
+                              false)) {
       SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE_SUPPORT);
-    } else if (StartsWithASCII(frame_gurl.path(),
-                               kGoogleIntlPathPrefix,
-                               false)) {
+    } else if (base::StartsWithASCII(frame_gurl.path(), kGoogleIntlPathPrefix,
+                                     false)) {
       SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE_INTL);
     }
   }
 
   if (origin_host == kWWWDotGoogleDotCom) {
     SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_WWW_GOOGLE);
-    if (StartsWithASCII(frame_gurl.path(), kGoogleReaderPathPrefix, false))
+    if (base::StartsWithASCII(frame_gurl.path(), kGoogleReaderPathPrefix,
+                              false))
       SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE_READER);
   } else if (origin_host == kMailDotGoogleDotCom) {
     SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_MAIL_GOOGLE);
@@ -663,7 +665,7 @@
 #if defined(ENABLE_EXTENSIONS)
 const extensions::Extension* ContentSettingsObserver::GetExtension(
     const WebSecurityOrigin& origin) const {
-  if (!EqualsASCII(origin.protocol(), extensions::kExtensionScheme))
+  if (!base::EqualsASCII(origin.protocol(), extensions::kExtensionScheme))
     return NULL;
 
   const std::string extension_id = origin.host().utf8().data();
@@ -697,14 +699,14 @@
   if (origin.isUnique())
     return false;  // Uninitialized document?
 
-  if (EqualsASCII(origin.protocol(), content::kChromeUIScheme))
+  if (base::EqualsASCII(origin.protocol(), content::kChromeUIScheme))
     return true;  // Browser UI elements should still work.
 
-  if (EqualsASCII(origin.protocol(), content::kChromeDevToolsScheme))
+  if (base::EqualsASCII(origin.protocol(), content::kChromeDevToolsScheme))
     return true;  // DevTools UI elements should still work.
 
 #if defined(ENABLE_EXTENSIONS)
-  if (EqualsASCII(origin.protocol(), extensions::kExtensionScheme))
+  if (base::EqualsASCII(origin.protocol(), extensions::kExtensionScheme))
     return true;
 #endif
 
@@ -715,7 +717,7 @@
 
   // If the scheme is file:, an empty file name indicates a directory listing,
   // which requires JavaScript to function properly.
-  if (EqualsASCII(origin.protocol(), url::kFileScheme)) {
+  if (base::EqualsASCII(origin.protocol(), url::kFileScheme)) {
     return document_url.SchemeIs(url::kFileScheme) &&
            document_url.ExtractFileName().empty();
   }
diff --git a/chrome/renderer/extensions/app_bindings.cc b/chrome/renderer/extensions/app_bindings.cc
index 472d931..af65cc9 100644
--- a/chrome/renderer/extensions/app_bindings.cc
+++ b/chrome/renderer/extensions/app_bindings.cc
@@ -39,7 +39,7 @@
   if (checkout_url_prefix.empty())
     checkout_url_prefix = "https://checkout.google.com/";
 
-  return StartsWithASCII(url_spec, checkout_url_prefix, false);
+  return base::StartsWithASCII(url_spec, checkout_url_prefix, false);
 }
 
 bool CheckAccessToAppDetails(WebFrame* frame, v8::Isolate* isolate) {
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.cc b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
index 60f6647..ea8cb57 100644
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.cc
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
@@ -7,12 +7,17 @@
 #include "base/bind.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
+#include "chrome/common/extensions/chrome_extension_messages.h"
 #include "chrome/common/extensions/manifest_handlers/automation.h"
 #include "content/public/child/v8_value_converter.h"
+#include "content/public/renderer/render_thread.h"
+#include "content/public/renderer/render_view.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest.h"
 #include "extensions/renderer/script_context.h"
+#include "ipc/message_filter.h"
 #include "ui/accessibility/ax_enums.h"
+#include "ui/accessibility/ax_node.h"
 
 namespace {
 
@@ -34,8 +39,55 @@
 
 namespace extensions {
 
+class AutomationMessageFilter : public IPC::MessageFilter {
+ public:
+  explicit AutomationMessageFilter(AutomationInternalCustomBindings* owner)
+      : owner_(owner),
+        removed_(false) {
+    DCHECK(owner);
+    content::RenderThread::Get()->AddFilter(this);
+  }
+
+  void Detach() {
+    owner_ = nullptr;
+    Remove();
+  }
+
+  // IPC::MessageFilter
+  bool OnMessageReceived(const IPC::Message& message) override {
+    if (owner_)
+      return owner_->OnMessageReceived(message);
+    else
+      return false;
+  }
+
+  void OnFilterRemoved() override {
+    removed_ = true;
+  }
+
+private:
+  ~AutomationMessageFilter() override {
+    Remove();
+  }
+
+  void Remove() {
+    if (!removed_) {
+      removed_ = true;
+      content::RenderThread::Get()->RemoveFilter(this);
+    }
+  }
+
+  AutomationInternalCustomBindings* owner_;
+  bool removed_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutomationMessageFilter);
+};
+
 AutomationInternalCustomBindings::AutomationInternalCustomBindings(
     ScriptContext* context) : ObjectBackedNativeHandler(context) {
+  // It's safe to use base::Unretained(this) here because these bindings
+  // will only be called on a valid AutomationInternalCustomBindings instance
+  // and none of the functions have any side effects.
   RouteFunction(
       "IsInteractPermitted",
       base::Bind(&AutomationInternalCustomBindings::IsInteractPermitted,
@@ -44,9 +96,27 @@
       "GetSchemaAdditions",
       base::Bind(&AutomationInternalCustomBindings::GetSchemaAdditions,
                  base::Unretained(this)));
+  RouteFunction(
+      "GetRoutingID",
+      base::Bind(&AutomationInternalCustomBindings::GetRoutingID,
+                 base::Unretained(this)));
+
+  message_filter_ = new AutomationMessageFilter(this);
 }
 
 AutomationInternalCustomBindings::~AutomationInternalCustomBindings() {
+  message_filter_->Detach();
+}
+
+bool AutomationInternalCustomBindings::OnMessageReceived(
+    const IPC::Message& message) {
+  IPC_BEGIN_MESSAGE_MAP(AutomationInternalCustomBindings, message)
+    IPC_MESSAGE_HANDLER(ExtensionMsg_AccessibilityEvent, OnAccessibilityEvent)
+  IPC_END_MESSAGE_MAP()
+
+  // Always return false in case there are multiple
+  // AutomationInternalCustomBindings instances attached to the same thread.
+  return false;
 }
 
 void AutomationInternalCustomBindings::IsInteractPermitted(
@@ -59,6 +129,12 @@
       v8::Boolean::New(GetIsolate(), automation_info->interact));
 }
 
+void AutomationInternalCustomBindings::GetRoutingID(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  int routing_id = context()->GetRenderView()->GetRoutingID();
+  args.GetReturnValue().Set(v8::Integer::New(GetIsolate(), routing_id));
+}
+
 void AutomationInternalCustomBindings::GetSchemaAdditions(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::Local<v8::Object> additions = v8::Object::New(GetIsolate());
@@ -82,4 +158,9 @@
   args.GetReturnValue().Set(additions);
 }
 
+void AutomationInternalCustomBindings::OnAccessibilityEvent(
+    const ExtensionMsg_AccessibilityEventParams& params) {
+  // TODO(dmazzoni): finish implementing this.
+}
+
 }  // namespace extensions
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.h b/chrome/renderer/extensions/automation_internal_custom_bindings.h
index ffa7085..1bc8a795 100644
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.h
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.h
@@ -7,10 +7,16 @@
 
 #include "base/compiler_specific.h"
 #include "extensions/renderer/object_backed_native_handler.h"
+#include "ipc/ipc_message.h"
+#include "ui/accessibility/ax_tree.h"
 #include "v8/include/v8.h"
 
+struct ExtensionMsg_AccessibilityEventParams;
+
 namespace extensions {
 
+class AutomationMessageFilter;
+
 // The native component of custom bindings for the chrome.automationInternal
 // API.
 class AutomationInternalCustomBindings : public ObjectBackedNativeHandler {
@@ -19,6 +25,8 @@
 
   ~AutomationInternalCustomBindings() override;
 
+  bool OnMessageReceived(const IPC::Message& message);
+
  private:
   // Returns whether this extension has the "interact" permission set (either
   // explicitly or implicitly after manifest parsing).
@@ -28,6 +36,15 @@
   // chrome.automation namespace.
   void GetSchemaAdditions(const v8::FunctionCallbackInfo<v8::Value>& args);
 
+  // Get the routing ID for the extension.
+  void GetRoutingID(const v8::FunctionCallbackInfo<v8::Value>& args);
+
+  // Handle accessibility events from the browser process.
+  void OnAccessibilityEvent(
+      const ExtensionMsg_AccessibilityEventParams& params);
+
+  scoped_refptr<AutomationMessageFilter> message_filter_;
+
   DISALLOW_COPY_AND_ASSIGN(AutomationInternalCustomBindings);
 };
 
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.cc b/chrome/renderer/extensions/cast_streaming_native_handler.cc
index 5275f2dd..66fb8a7 100644
--- a/chrome/renderer/extensions/cast_streaming_native_handler.cc
+++ b/chrome/renderer/extensions/cast_streaming_native_handler.cc
@@ -7,9 +7,11 @@
 #include <functional>
 #include <iterator>
 
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/common/extensions/api/cast_streaming_receiver_session.h"
 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h"
 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h"
@@ -259,14 +261,11 @@
   // invalid context when the callback is invoked.
   create_callback_.Reset(isolate, args[2].As<v8::Function>());
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(
-          &CastStreamingNativeHandler::CallCreateCallback,
-          weak_factory_.GetWeakPtr(),
-          base::Passed(&stream1),
-          base::Passed(&stream2),
-          base::Passed(&udp_transport)));
+      base::Bind(&CastStreamingNativeHandler::CallCreateCallback,
+                 weak_factory_.GetWeakPtr(), base::Passed(&stream1),
+                 base::Passed(&stream2), base::Passed(&udp_transport)));
 }
 
 void CastStreamingNativeHandler::CallCreateCallback(
diff --git a/chrome/renderer/extensions/extension_localization_peer.cc b/chrome/renderer/extensions/extension_localization_peer.cc
index 7208c2af..17b9756 100644
--- a/chrome/renderer/extensions/extension_localization_peer.cc
+++ b/chrome/renderer/extensions/extension_localization_peer.cc
@@ -55,8 +55,9 @@
   // Return NULL if content is not text/css or it doesn't belong to extension
   // scheme.
   return (request_url.SchemeIs(extensions::kExtensionScheme) &&
-          StartsWithASCII(mime_type, "text/css", false)) ?
-      new ExtensionLocalizationPeer(peer, message_sender, request_url) : NULL;
+          base::StartsWithASCII(mime_type, "text/css", false))
+             ? new ExtensionLocalizationPeer(peer, message_sender, request_url)
+             : NULL;
 }
 
 void ExtensionLocalizationPeer::OnUploadProgress(
diff --git a/chrome/renderer/extensions/webstore_bindings.cc b/chrome/renderer/extensions/webstore_bindings.cc
index 239ebb0..a7b4b1c 100644
--- a/chrome/renderer/extensions/webstore_bindings.cc
+++ b/chrome/renderer/extensions/webstore_bindings.cc
@@ -142,7 +142,7 @@
       continue;
 
     std::string rel = elem.getAttribute("rel").utf8();
-    if (!LowerCaseEqualsASCII(rel, kWebstoreLinkRelation))
+    if (!base::LowerCaseEqualsASCII(rel, kWebstoreLinkRelation))
       continue;
 
     std::string webstore_url_string(elem.getAttribute("href").utf8());
@@ -160,8 +160,8 @@
 
     if (webstore_url.scheme() != webstore_base_url.scheme() ||
         webstore_url.host() != webstore_base_url.host() ||
-        !StartsWithASCII(
-            webstore_url.path(), webstore_base_url.path(), true)) {
+        !base::StartsWithASCII(webstore_url.path(), webstore_base_url.path(),
+                               true)) {
       *error = kInvalidWebstoreItemUrlError;
       return false;
     }
diff --git a/chrome/renderer/media/cast_receiver_session.cc b/chrome/renderer/media/cast_receiver_session.cc
index f374549..404fb03 100644
--- a/chrome/renderer/media/cast_receiver_session.cc
+++ b/chrome/renderer/media/cast_receiver_session.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/renderer/media/cast_receiver_session.h"
 
+#include "base/location.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/renderer/media/cast_receiver_audio_valve.h"
 #include "content/public/renderer/render_thread.h"
 #include "media/base/audio_capturer_source.h"
@@ -92,9 +94,8 @@
       new CastReceiverSession::AudioCapturerSource(this));
   scoped_ptr<media::VideoCapturerSource> video(
       new CastReceiverSession::VideoCapturerSource(this));
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(start_callback, audio, base::Passed(&video)));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(start_callback, audio, base::Passed(&video)));
 }
 
 void CastReceiverSession::StartAudio(
diff --git a/chrome/renderer/media/cast_session_browsertest.cc b/chrome/renderer/media/cast_session_browsertest.cc
index c9b0c436..f5db9b7 100644
--- a/chrome/renderer/media/cast_session_browsertest.cc
+++ b/chrome/renderer/media/cast_session_browsertest.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/renderer/media/cast_session.h"
 
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/renderer/chrome_content_renderer_client.h"
 #include "chrome/test/base/chrome_render_view_test.h"
 
@@ -17,7 +17,7 @@
 // chrome renderer.
 TEST_F(CastSessionBrowserTest, CreateAndDestroy) {
   chrome_render_thread_->set_io_message_loop_proxy(
-      base::MessageLoopProxy::current());
+      base::ThreadTaskRunnerHandle::Get());
   ChromeContentRendererClient* client =
       static_cast<ChromeContentRendererClient*>(content_renderer_client_.get());
   client->RenderThreadStarted();
diff --git a/chrome/renderer/media/cast_threads.cc b/chrome/renderer/media/cast_threads.cc
index 9162ff2a..b6c808c 100644
--- a/chrome/renderer/media/cast_threads.cc
+++ b/chrome/renderer/media/cast_threads.cc
@@ -5,6 +5,7 @@
 #include "chrome/renderer/media/cast_threads.h"
 
 #include "base/logging.h"
+#include "base/single_thread_task_runner.h"
 
 CastThreads::CastThreads()
     : audio_encode_thread_("CastAudioEncodeThread"),
@@ -15,10 +16,10 @@
 
 scoped_refptr<base::SingleThreadTaskRunner>
 CastThreads::GetAudioEncodeMessageLoopProxy() {
-  return audio_encode_thread_.message_loop_proxy();
+  return audio_encode_thread_.task_runner();
 }
 
 scoped_refptr<base::SingleThreadTaskRunner>
 CastThreads::GetVideoEncodeMessageLoopProxy() {
-  return video_encode_thread_.message_loop_proxy();
+  return video_encode_thread_.task_runner();
 }
diff --git a/chrome/renderer/media/cast_transport_sender_ipc.h b/chrome/renderer/media/cast_transport_sender_ipc.h
index 21f87bd..ce18964 100644
--- a/chrome/renderer/media/cast_transport_sender_ipc.h
+++ b/chrome/renderer/media/cast_transport_sender_ipc.h
@@ -7,7 +7,7 @@
 
 #include <map>
 
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 #include "ipc/ipc_channel_proxy.h"
 #include "media/cast/logging/logging_defines.h"
 #include "media/cast/net/cast_transport_sender.h"
diff --git a/chrome/renderer/media/chrome_webrtc_log_message_delegate_unittest.cc b/chrome/renderer/media/chrome_webrtc_log_message_delegate_unittest.cc
index 37603474..6680c7ea 100644
--- a/chrome/renderer/media/chrome_webrtc_log_message_delegate_unittest.cc
+++ b/chrome/renderer/media/chrome_webrtc_log_message_delegate_unittest.cc
@@ -5,7 +5,9 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "chrome/renderer/media/chrome_webrtc_log_message_delegate.h"
 #include "chrome/renderer/media/mock_webrtc_logging_message_filter.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -14,7 +16,7 @@
   const char kTestString[] = "abcdefghijklmnopqrstuvwxyz";
   base::MessageLoopForIO message_loop;
   scoped_refptr<MockWebRtcLoggingMessageFilter> log_message_filter(
-      new MockWebRtcLoggingMessageFilter(message_loop.message_loop_proxy()));
+      new MockWebRtcLoggingMessageFilter(message_loop.task_runner()));
   // Run message loop to initialize delegate.
   // TODO(vrk): Fix this so that we can construct a delegate without needing to
   // construct a message filter.
@@ -24,10 +26,9 @@
       log_message_filter->log_message_delegate();
 
   // Start logging on the IO loop.
-  message_loop.message_loop_proxy()->PostTask(
-      FROM_HERE, base::Bind(
-          &ChromeWebRtcLogMessageDelegate::OnStartLogging,
-          base::Unretained(log_message_delegate)));
+  message_loop.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&ChromeWebRtcLogMessageDelegate::OnStartLogging,
+                            base::Unretained(log_message_delegate)));
 
   // These log messages should be added to the log buffer outside of the IO
   // loop.
@@ -35,10 +36,9 @@
   log_message_delegate->LogMessage(kTestString);
 
   // Stop logging on IO loop.
-  message_loop.message_loop_proxy()->PostTask(
-      FROM_HERE, base::Bind(
-          &ChromeWebRtcLogMessageDelegate::OnStopLogging,
-          base::Unretained(log_message_delegate)));
+  message_loop.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&ChromeWebRtcLogMessageDelegate::OnStopLogging,
+                            base::Unretained(log_message_delegate)));
 
   // This log message should not be added to the log buffer.
   log_message_delegate->LogMessage(kTestString);
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc
index a3ab4e55..2873d03 100644
--- a/chrome/renderer/net/net_error_helper.cc
+++ b/chrome/renderer/net/net_error_helper.cc
@@ -304,7 +304,8 @@
 
 void NetErrorHelper::LoadPageFromCache(const GURL& page_url) {
   blink::WebFrame* web_frame = render_frame()->GetWebFrame();
-  DCHECK(!EqualsASCII(web_frame->dataSource()->request().httpMethod(), "POST"));
+  DCHECK(!base::EqualsASCII(web_frame->dataSource()->request().httpMethod(),
+                            "POST"));
 
   blink::WebURLRequest request(page_url);
   request.setCachePolicy(blink::WebURLRequest::ReturnCacheDataDontLoad);
diff --git a/chrome/renderer/page_load_histograms.cc b/chrome/renderer/page_load_histograms.cc
index 0723709..729677c 100644
--- a/chrome/renderer/page_load_histograms.cc
+++ b/chrome/renderer/page_load_histograms.cc
@@ -179,17 +179,16 @@
 // purposes.
 // TODO(pmeenan): Remove the fuzzy logic when the referrer is reliable
 bool IsFromGoogleSearchResult(const GURL& url, const GURL& referrer) {
-  if (!StartsWithASCII(referrer.host(), "www.google.", true))
+  if (!base::StartsWithASCII(referrer.host(), "www.google.", true))
     return false;
-  if (StartsWithASCII(referrer.path(), "/url", true))
+  if (base::StartsWithASCII(referrer.path(), "/url", true))
     return true;
   bool is_possible_search_referrer =
-      referrer.path().empty() ||
-      referrer.path() == "/" ||
-      StartsWithASCII(referrer.path(), "/search", true) ||
-      StartsWithASCII(referrer.path(), "/webhp", true);
+      referrer.path().empty() || referrer.path() == "/" ||
+      base::StartsWithASCII(referrer.path(), "/search", true) ||
+      base::StartsWithASCII(referrer.path(), "/webhp", true);
   if (is_possible_search_referrer &&
-      !StartsWithASCII(url.host(), "www.google", true))
+      !base::StartsWithASCII(url.host(), "www.google", true))
     return true;
   return false;
 }
diff --git a/chrome/renderer/plugins/chrome_plugin_placeholder.cc b/chrome/renderer/plugins/chrome_plugin_placeholder.cc
index 402bfb6..165eebb950 100644
--- a/chrome/renderer/plugins/chrome_plugin_placeholder.cc
+++ b/chrome/renderer/plugins/chrome_plugin_placeholder.cc
@@ -16,7 +16,6 @@
 #include "chrome/renderer/plugins/plugin_preroller.h"
 #include "chrome/renderer/plugins/plugin_uma.h"
 #include "components/content_settings/content/common/content_settings_messages.h"
-#include "content/app/strings/grit/content_strings.h"
 #include "content/public/common/context_menu_params.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
@@ -45,13 +44,11 @@
 using content::RenderView;
 
 namespace {
-const plugins::PluginPlaceholder* g_last_active_menu = NULL;
+const ChromePluginPlaceholder* g_last_active_menu = NULL;
 }  // namespace
 
-// The placeholder is loaded in normal web renderer processes, so it should not
-// have a chrome:// scheme that might let it be confused with a WebUI page.
-const char ChromePluginPlaceholder::kPluginPlaceholderDataURL[] =
-    "data:text/html,pluginplaceholderdata";
+gin::WrapperInfo ChromePluginPlaceholder::kWrapperInfo = {
+    gin::kEmbedderNativeGin};
 
 ChromePluginPlaceholder::ChromePluginPlaceholder(
     content::RenderFrame* render_frame,
@@ -62,8 +59,7 @@
     : plugins::LoadablePluginPlaceholder(render_frame,
                                          frame,
                                          params,
-                                         html_data,
-                                         GURL(kPluginPlaceholderDataURL)),
+                                         html_data),
       status_(ChromeViewHostMsg_GetPluginInfo_Status::kAllowed),
       title_(title),
 #if defined(ENABLE_PLUGIN_INSTALLATION)
@@ -91,7 +87,7 @@
 }
 
 // static
-ChromePluginPlaceholder* ChromePluginPlaceholder::CreateMissingPlugin(
+ChromePluginPlaceholder* ChromePluginPlaceholder::CreateLoadableMissingPlugin(
     content::RenderFrame* render_frame,
     WebLocalFrame* frame,
     const WebPluginParams& params) {
@@ -105,34 +101,9 @@
 
   std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
 
-  // |missing_plugin| will destroy itself when its WebViewPlugin is going away.
-  ChromePluginPlaceholder* missing_plugin = new ChromePluginPlaceholder(
-      render_frame, frame, params, html_data, params.mimeType);
-  missing_plugin->set_allow_loading(true);
-  return missing_plugin;
-}
-
-// static
-ChromePluginPlaceholder* ChromePluginPlaceholder::CreateErrorPlugin(
-    content::RenderFrame* render_frame,
-    const base::FilePath& file_path) {
-  base::DictionaryValue values;
-  values.SetString("message",
-                   l10n_util::GetStringUTF8(IDS_PLUGIN_INITIALIZATION_ERROR));
-
-  const base::StringPiece template_html(
-      ResourceBundle::GetSharedInstance().GetRawDataResource(
-          IDR_BLOCKED_PLUGIN_HTML));
-  std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
-
-  WebPluginParams params;
-  // |missing_plugin| will destroy itself when its WebViewPlugin is going away.
-  ChromePluginPlaceholder* plugin = new ChromePluginPlaceholder(
-      render_frame, NULL, params, html_data, params.mimeType);
-
-  RenderThread::Get()->Send(new ChromeViewHostMsg_CouldNotLoadPlugin(
-      plugin->routing_id(), file_path));
-  return plugin;
+  // Will destroy itself when its WebViewPlugin is going away.
+  return new ChromePluginPlaceholder(render_frame, frame, params, html_data,
+                                     params.mimeType);
 }
 
 // static
@@ -176,10 +147,8 @@
   ChromePluginPlaceholder* blocked_plugin = new ChromePluginPlaceholder(
       render_frame, frame, params, html_data, name);
 
-#if defined(ENABLE_PLUGINS)
   if (!poster_info.poster_attribute.empty())
     blocked_plugin->BlockForPowerSaverPoster();
-#endif
   blocked_plugin->SetPluginInfo(info);
   blocked_plugin->SetIdentifier(identifier);
   return blocked_plugin;
@@ -305,10 +274,8 @@
   switch (action) {
     case chrome::MENU_COMMAND_PLUGIN_RUN: {
       RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Menu"));
-#if defined(ENABLE_PLUGINS)
       MarkPluginEssential(
           content::PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK);
-#endif
       LoadPlugin();
       break;
     }
@@ -327,8 +294,12 @@
   context_menu_request_id_ = 0;
 }
 
+v8::Local<v8::Value> ChromePluginPlaceholder::GetV8Handle(
+    v8::Isolate* isolate) {
+  return gin::CreateHandle(isolate, this).ToV8();
+}
+
 void ChromePluginPlaceholder::ShowContextMenu(const WebMouseEvent& event) {
-#if !defined(OS_ANDROID)  // The context menu is not applicable on Android.
   if (context_menu_request_id_)
     return;  // Don't allow nested context menu requests.
 
@@ -364,12 +335,10 @@
 
   context_menu_request_id_ = render_frame()->ShowContextMenu(this, params);
   g_last_active_menu = this;
-#endif  // OS_ANDROID
 }
 
 blink::WebPlugin* ChromePluginPlaceholder::CreatePlugin() {
   scoped_ptr<content::PluginInstanceThrottler> throttler;
-#if defined(ENABLE_PLUGINS)
   // If the plugin has already been marked essential in its placeholder form,
   // we shouldn't create a new throttler and start the process all over again.
   if (power_saver_enabled()) {
@@ -380,13 +349,21 @@
                         l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, title_),
                         throttler.get());
   }
-#endif
   return render_frame()->CreatePlugin(GetFrame(), GetPluginInfo(),
                                       GetPluginParams(), throttler.Pass());
 }
 
 gin::ObjectTemplateBuilder ChromePluginPlaceholder::GetObjectTemplateBuilder(
     v8::Isolate* isolate) {
-  return LoadablePluginPlaceholder::GetObjectTemplateBuilder(isolate).SetMethod(
-      "openAboutPlugins", &ChromePluginPlaceholder::OpenAboutPluginsCallback);
+  return gin::Wrappable<ChromePluginPlaceholder>::GetObjectTemplateBuilder(
+             isolate)
+      .SetMethod<void (ChromePluginPlaceholder::*)()>(
+           "hide", &ChromePluginPlaceholder::HideCallback)
+      .SetMethod<void (ChromePluginPlaceholder::*)()>(
+           "load", &ChromePluginPlaceholder::LoadCallback)
+      .SetMethod<void (ChromePluginPlaceholder::*)()>(
+           "didFinishLoading",
+           &ChromePluginPlaceholder::DidFinishLoadingCallback)
+      .SetMethod("openAboutPlugins",
+                 &ChromePluginPlaceholder::OpenAboutPluginsCallback);
 }
diff --git a/chrome/renderer/plugins/chrome_plugin_placeholder.h b/chrome/renderer/plugins/chrome_plugin_placeholder.h
index d5fb2f940..85d49b7f 100644
--- a/chrome/renderer/plugins/chrome_plugin_placeholder.h
+++ b/chrome/renderer/plugins/chrome_plugin_placeholder.h
@@ -28,11 +28,13 @@
   gfx::Size custom_poster_size;
 };
 
-class ChromePluginPlaceholder : public plugins::LoadablePluginPlaceholder,
-                                public content::RenderProcessObserver,
-                                public content::ContextMenuClient {
+class ChromePluginPlaceholder final
+    : public plugins::LoadablePluginPlaceholder,
+      public content::RenderProcessObserver,
+      public content::ContextMenuClient,
+      public gin::Wrappable<ChromePluginPlaceholder> {
  public:
-  static const char kPluginPlaceholderDataURL[];
+  static gin::WrapperInfo kWrapperInfo;
 
   static ChromePluginPlaceholder* CreateBlockedPlugin(
       content::RenderFrame* render_frame,
@@ -46,15 +48,11 @@
       const PlaceholderPosterInfo& poster_info);
 
   // Creates a new WebViewPlugin with a MissingPlugin as a delegate.
-  static ChromePluginPlaceholder* CreateMissingPlugin(
+  static ChromePluginPlaceholder* CreateLoadableMissingPlugin(
       content::RenderFrame* render_frame,
       blink::WebLocalFrame* frame,
       const blink::WebPluginParams& params);
 
-  static ChromePluginPlaceholder* CreateErrorPlugin(
-      content::RenderFrame* render_frame,
-      const base::FilePath& plugin_path);
-
   void SetStatus(ChromeViewHostMsg_GetPluginInfo_Status status);
 
 #if defined(ENABLE_PLUGIN_INSTALLATION)
@@ -74,12 +72,13 @@
 
   // gin::Wrappable (via PluginPlaceholder) method
   gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
+      v8::Isolate* isolate) final;
 
   // content::RenderViewObserver (via PluginPlaceholder) override:
   bool OnMessageReceived(const IPC::Message& message) override;
 
   // WebViewPlugin::Delegate (via PluginPlaceholder) methods:
+  v8::Local<v8::Value> GetV8Handle(v8::Isolate* isolate) override;
   void ShowContextMenu(const blink::WebMouseEvent&) override;
 
   // content::RenderProcessObserver methods:
diff --git a/chrome/renderer/plugins/non_loadable_plugin_placeholder.cc b/chrome/renderer/plugins/non_loadable_plugin_placeholder.cc
new file mode 100644
index 0000000..598ad16
--- /dev/null
+++ b/chrome/renderer/plugins/non_loadable_plugin_placeholder.cc
@@ -0,0 +1,60 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/plugins/non_loadable_plugin_placeholder.h"
+
+#include "base/files/file_path.h"
+#include "base/values.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/grit/renderer_resources.h"
+#include "components/plugins/renderer/plugin_placeholder.h"
+#include "content/app/strings/grit/content_strings.h"
+#include "content/public/renderer/render_thread.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/webui/jstemplate_builder.h"
+
+// static
+plugins::PluginPlaceholder*
+NonLoadablePluginPlaceholder::CreateNotSupportedPlugin(
+    content::RenderFrame* render_frame,
+    blink::WebLocalFrame* frame,
+    const blink::WebPluginParams& params) {
+  const base::StringPiece template_html(
+      ResourceBundle::GetSharedInstance().GetRawDataResource(
+          IDR_BLOCKED_PLUGIN_HTML));
+
+  base::DictionaryValue values;
+  values.SetString("message",
+                   l10n_util::GetStringUTF8(IDS_PLUGIN_NOT_SUPPORTED));
+
+  std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
+
+  // PluginPlaceholder will destroy itself when its WebViewPlugin is going away.
+  return new plugins::PluginPlaceholder(render_frame, frame, params, html_data);
+}
+
+// static
+plugins::PluginPlaceholder* NonLoadablePluginPlaceholder::CreateErrorPlugin(
+    content::RenderFrame* render_frame,
+    const base::FilePath& file_path) {
+  base::DictionaryValue values;
+  values.SetString("message",
+                   l10n_util::GetStringUTF8(IDS_PLUGIN_INITIALIZATION_ERROR));
+
+  const base::StringPiece template_html(
+      ResourceBundle::GetSharedInstance().GetRawDataResource(
+          IDR_BLOCKED_PLUGIN_HTML));
+  std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
+
+  blink::WebPluginParams params;
+  // PluginPlaceholder will destroy itself when its WebViewPlugin is going away.
+  plugins::PluginPlaceholder* plugin =
+      new plugins::PluginPlaceholder(render_frame, nullptr, params, html_data);
+
+  content::RenderThread::Get()->Send(new ChromeViewHostMsg_CouldNotLoadPlugin(
+      plugin->routing_id(), file_path));
+  return plugin;
+}
diff --git a/chrome/renderer/plugins/non_loadable_plugin_placeholder.h b/chrome/renderer/plugins/non_loadable_plugin_placeholder.h
new file mode 100644
index 0000000..e872e5e4
--- /dev/null
+++ b/chrome/renderer/plugins/non_loadable_plugin_placeholder.h
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_PLUGINS_NON_LOADABLE_PLUGIN_PLACEHOLDER_H_
+#define CHROME_RENDERER_PLUGINS_NON_LOADABLE_PLUGIN_PLACEHOLDER_H_
+
+#include "base/macros.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace blink {
+class WebLocalFrame;
+struct WebPluginParams;
+}
+
+namespace content {
+class RenderFrame;
+}
+
+namespace plugins {
+class PluginPlaceholder;
+}
+
+class NonLoadablePluginPlaceholder {
+ public:
+  // Creates a non-loadable plugin placeholder for platforms without plugins.
+  static plugins::PluginPlaceholder* CreateNotSupportedPlugin(
+      content::RenderFrame* render_frame,
+      blink::WebLocalFrame* frame,
+      const blink::WebPluginParams& params);
+
+  static plugins::PluginPlaceholder* CreateErrorPlugin(
+      content::RenderFrame* render_frame,
+      const base::FilePath& file_path);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(NonLoadablePluginPlaceholder);
+};
+
+#endif  // CHROME_RENDERER_PLUGINS_NON_LOADABLE_PLUGIN_PLACEHOLDER_H_
diff --git a/chrome/renderer/plugins/plugin_preroller.cc b/chrome/renderer/plugins/plugin_preroller.cc
index 2d42f4e..6c277937 100644
--- a/chrome/renderer/plugins/plugin_preroller.cc
+++ b/chrome/renderer/plugins/plugin_preroller.cc
@@ -68,7 +68,6 @@
           IDR_PLUGIN_POSTER_HTML, message_, poster_info);
   placeholder->SetPremadePlugin(throttler_);
   placeholder->set_power_saver_enabled(true);
-  placeholder->set_allow_loading(true);
 
   blink::WebPluginContainer* container =
       throttler_->GetWebPlugin()->container();
diff --git a/chrome/renderer/resources/blocked_plugin.html b/chrome/renderer/resources/blocked_plugin.html
index 7a92c1d..0d4dc4aa6 100644
--- a/chrome/renderer/resources/blocked_plugin.html
+++ b/chrome/renderer/resources/blocked_plugin.html
@@ -3,10 +3,8 @@
 <head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, user-scalable=no">
+<if expr="not is_android">
 <script>
-function debug(msg) {
-  document.getElementById('debug').textContent = msg;
-}
 function setMessage(msg) {
   document.getElementById('message').textContent = msg;
 }
@@ -15,6 +13,12 @@
     plugin.didFinishLoading();
 }
 </script>
+</if>
+<if expr="is_android">
+<script>
+function notifyDidFinishLoading() {}
+</script>
+</if>
 <link rel="stylesheet" href="plugin_placeholders.css"></link>
 <style>
 body {
@@ -37,7 +41,6 @@
   <img id="plugin_icon" src="plugin_blocked_android.png">
 </if>
 <h1 id="message" i18n-content="message"></h1>
-<p id="debug"> </p>
 </div>
 <div id="close" i18n-values="title:hide" onclick="plugin.hide();"></div>
 </div>
diff --git a/chrome/renderer/resources/extensions/automation/automation_node.js b/chrome/renderer/resources/extensions/automation/automation_node.js
index 3f348a3..11ac8d8a3 100644
--- a/chrome/renderer/resources/extensions/automation/automation_node.js
+++ b/chrome/renderer/resources/extensions/automation/automation_node.js
@@ -472,7 +472,7 @@
 var EditableTextMixinAttributes = {
   textSelStart: defaultIntAttribute(-1),
   textSelEnd: defaultIntAttribute(-1),
-  textInputType: defaultStringAttribute()
+  type: defaultHtmlAttribute()
 };
 
 var RangeMixinAttributes = {
diff --git a/chrome/renderer/resources/extensions/automation_custom_bindings.js b/chrome/renderer/resources/extensions/automation_custom_bindings.js
index 3d38afc..b2fc5c3b7 100644
--- a/chrome/renderer/resources/extensions/automation_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/automation_custom_bindings.js
@@ -13,7 +13,10 @@
 var forEach = require('utils').forEach;
 var lastError = require('lastError');
 var logging = requireNative('logging');
-var schema = requireNative('automationInternal').GetSchemaAdditions();
+var nativeAutomationInternal = requireNative('automationInternal');
+var GetRoutingID = nativeAutomationInternal.GetRoutingID;
+var GetSchemaAdditions = nativeAutomationInternal.GetSchemaAdditions;
+var schema = GetSchemaAdditions();
 
 /**
  * A namespace to export utility functions to other files in automation.
@@ -53,7 +56,9 @@
   var apiFunctions = bindingsAPI.apiFunctions;
 
   // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj.
-  apiFunctions.setHandleRequest('getTree', function getTree(tabId, callback) {
+  apiFunctions.setHandleRequest('getTree', function getTree(tabID, callback) {
+    var routingID = GetRoutingID();
+
     // enableTab() ensures the renderer for the active or specified tab has
     // accessibility enabled, and fetches its ax tree id to use as
     // a key in the idToAutomationRootNode map. The callback to
@@ -61,13 +66,15 @@
     // the tree is available (either due to having been cached earlier, or after
     // an accessibility event occurs which causes the tree to be populated), the
     // callback can be called.
-    automationInternal.enableTab(tabId, function onEnable(id) {
-      if (lastError.hasError(chrome)) {
-        callback();
-        return;
-      }
-      automationUtil.storeTreeCallback(id, callback);
-    });
+    var params = { routingID: routingID, tabID: tabID };
+    automationInternal.enableTab(params,
+        function onEnable(id) {
+          if (lastError.hasError(chrome)) {
+            callback();
+            return;
+          }
+          automationUtil.storeTreeCallback(id, callback);
+        });
   });
 
   var desktopTree = null;
@@ -80,9 +87,11 @@
       else
         idToCallback[DESKTOP_TREE_ID] = [callback];
 
+      var routingID = GetRoutingID();
+
       // TODO(dtseng): Disable desktop tree once desktop object goes out of
       // scope.
-      automationInternal.enableDesktop(function() {
+      automationInternal.enableDesktop(routingID, function() {
         if (lastError.hasError(chrome)) {
           delete idToAutomationRootNode[
               DESKTOP_TREE_ID];
diff --git a/chrome/renderer/resources/neterror.css b/chrome/renderer/resources/neterror.css
index 58e3f5e..e34958a 100644
--- a/chrome/renderer/resources/neterror.css
+++ b/chrome/renderer/resources/neterror.css
@@ -48,7 +48,6 @@
   content: -webkit-image-set(
       url(default_100_percent/common/error_network_generic.png) 1x,
       url(default_200_percent/common/error_network_generic.png) 2x);
-  padding-top: 20px;
 }
 
 .icon-offline {
diff --git a/chrome/renderer/resources/neterror.js b/chrome/renderer/resources/neterror.js
index 043a790..e468ab9 100644
--- a/chrome/renderer/resources/neterror.js
+++ b/chrome/renderer/resources/neterror.js
@@ -113,13 +113,30 @@
     errorPageController.detailsButtonClick();
 }
 
+/**
+ * Replace the reload button with the Google cached copy suggestion.
+ */
+function setUpCachedButton(buttonStrings) {
+  var reloadButton = document.getElementById('reload-button');
+
+  reloadButton.textContent = buttonStrings.msg;
+  var url = buttonStrings.cacheUrl;
+  var trackingId = buttonStrings.trackingId;
+  reloadButton.onclick = function(e) {
+    e.preventDefault();
+    trackClick(trackingId);
+    location = url;
+  };
+  reloadButton.style.display = '';
+  document.getElementById('control-buttons').hidden = false;
+}
+
 var primaryControlOnLeft = true;
 <if expr="is_macosx or is_ios or is_linux or is_android">
 primaryControlOnLeft = false;
 </if>
 
 function onDocumentLoad() {
-  var buttonsDiv = document.getElementById('buttons');
   var controlButtonDiv = document.getElementById('control-buttons');
   var reloadButton = document.getElementById('reload-button');
   var detailsButton = document.getElementById('details-button');
@@ -178,6 +195,11 @@
     p.innerHTML = loadTimeData.getString('primaryParagraph');
     p.hidden = false;
   }
+
+  // Check for Google cached copy suggestion.
+  if (loadTimeData.valueExists('cacheButton')) {
+    setUpCachedButton(loadTimeData.getValue('cacheButton'));
+  }
 }
 
 document.addEventListener('DOMContentLoaded', onDocumentLoad);
diff --git a/chrome/renderer/safe_browsing/phishing_classifier.cc b/chrome/renderer/safe_browsing/phishing_classifier.cc
index 78d67a2a..e1d1926 100644
--- a/chrome/renderer/safe_browsing/phishing_classifier.cc
+++ b/chrome/renderer/safe_browsing/phishing_classifier.cc
@@ -9,10 +9,12 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/renderer/safe_browsing/feature_extractor_clock.h"
@@ -98,10 +100,9 @@
   // asynchronously, rather than directly from this method.  To ensure that
   // this is the case, post a task to begin feature extraction on the next
   // iteration of the message loop.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&PhishingClassifier::BeginFeatureExtraction,
-                 weak_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&PhishingClassifier::BeginFeatureExtraction,
+                            weak_factory_.GetWeakPtr()));
 }
 
 void PhishingClassifier::BeginFeatureExtraction() {
@@ -126,7 +127,7 @@
   }
 
   blink::WebDataSource* ds = frame->dataSource();
-  if (!ds || !EqualsASCII(ds->request().httpMethod(), "GET")) {
+  if (!ds || !base::EqualsASCII(ds->request().httpMethod(), "GET")) {
     RunFailureCallback();
     return;
   }
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
index 50141be..fc973cd5 100644
--- a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
+++ b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
@@ -5,8 +5,10 @@
 #include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h"
 
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/browser.h"
@@ -118,7 +120,7 @@
         verdict->IsInitialized()) {
       verdict_.swap(verdict);
     }
-    waiting_message_loop_->PostTask(FROM_HERE, quit_closure_);
+    waiting_message_loop_->task_runner()->PostTask(FROM_HERE, quit_closure_);
   }
 
  private:
diff --git a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor.cc b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor.cc
index 9c92c9a..f47a186 100644
--- a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor.cc
+++ b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor.cc
@@ -7,10 +7,12 @@
 #include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/containers/hash_tables.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/renderer/safe_browsing/feature_extractor_clock.h"
 #include "chrome/renderer/safe_browsing/features.h"
@@ -133,7 +135,7 @@
     cur_document_ = web_view->mainFrame()->document();
   }
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&PhishingDOMFeatureExtractor::ExtractFeaturesWithTimeout,
                  weak_factory_.GetWeakPtr()));
@@ -213,7 +215,7 @@
           // clock granularity.
           UMA_HISTOGRAM_TIMES("SBClientPhishing.DOMFeatureChunkTime",
                               chunk_elapsed);
-          base::MessageLoop::current()->PostTask(
+          base::ThreadTaskRunnerHandle::Get()->PostTask(
               FROM_HERE,
               base::Bind(
                   &PhishingDOMFeatureExtractor::ExtractFeaturesWithTimeout,
diff --git a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc
index 83746a0..c15219f 100644
--- a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc
+++ b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc
@@ -13,9 +13,11 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -62,10 +64,9 @@
   // Helper for the SubframeRemoval test that posts a message to remove
   // the iframe "frame1" from the document.
   void ScheduleRemoveIframe() {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&PhishingDOMFeatureExtractorTest::RemoveIframe,
-                   weak_factory_.GetWeakPtr()));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&PhishingDOMFeatureExtractorTest::RemoveIframe,
+                              weak_factory_.GetWeakPtr()));
   }
 
  protected:
diff --git a/chrome/renderer/safe_browsing/phishing_term_feature_extractor.cc b/chrome/renderer/safe_browsing/phishing_term_feature_extractor.cc
index de488f4..31caf0be 100644
--- a/chrome/renderer/safe_browsing/phishing_term_feature_extractor.cc
+++ b/chrome/renderer/safe_browsing/phishing_term_feature_extractor.cc
@@ -11,11 +11,13 @@
 #include "base/compiler_specific.h"
 #include "base/i18n/break_iterator.h"
 #include "base/i18n/case_conversion.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/renderer/safe_browsing/feature_extractor_clock.h"
 #include "chrome/renderer/safe_browsing/features.h"
@@ -123,7 +125,7 @@
   done_callback_ = done_callback;
 
   state_.reset(new ExtractionState(*page_text_, clock_->Now()));
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&PhishingTermFeatureExtractor::ExtractFeaturesWithTimeout,
                  weak_factory_.GetWeakPtr()));
@@ -178,7 +180,7 @@
         // clock granularity.
         UMA_HISTOGRAM_TIMES("SBClientPhishing.TermFeatureChunkTime",
                             chunk_elapsed);
-        base::MessageLoop::current()->PostTask(
+        base::ThreadTaskRunnerHandle::Get()->PostTask(
             FROM_HERE,
             base::Bind(
                 &PhishingTermFeatureExtractor::ExtractFeaturesWithTimeout,
diff --git a/chrome/renderer/safe_browsing/phishing_term_feature_extractor_unittest.cc b/chrome/renderer/safe_browsing/phishing_term_feature_extractor_unittest.cc
index 4c15605..7896758 100644
--- a/chrome/renderer/safe_browsing/phishing_term_feature_extractor_unittest.cc
+++ b/chrome/renderer/safe_browsing/phishing_term_feature_extractor_unittest.cc
@@ -9,8 +9,10 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/containers/hash_tables.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -110,10 +112,9 @@
         shingle_hashes,
         base::Bind(&PhishingTermFeatureExtractorTest::ExtractionDone,
                    base::Unretained(this)));
-    msg_loop_.PostTask(
-        FROM_HERE,
-        base::Bind(&PhishingTermFeatureExtractorTest::QuitExtraction,
-                   base::Unretained(this)));
+    msg_loop_.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&PhishingTermFeatureExtractorTest::QuitExtraction,
+                              base::Unretained(this)));
     msg_loop_.RunUntilIdle();
   }
 
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index 1e77c45..277e5a1 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -76,7 +76,7 @@
   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableIconNtp))
     return true;
 
-  return StartsWithASCII(group_name, "Enabled", true);
+  return base::StartsWithASCII(group_name, "Enabled", true);
 }
 
 // Converts string16 to V8 String.
diff --git a/chrome/renderer/spellchecker/spellcheck.cc b/chrome/renderer/spellchecker/spellcheck.cc
index 4a0312a..a43c7277 100644
--- a/chrome/renderer/spellchecker/spellcheck.cc
+++ b/chrome/renderer/spellchecker/spellcheck.cc
@@ -10,6 +10,8 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/common/spellcheck_common.h"
 #include "chrome/common/spellcheck_messages.h"
 #include "chrome/common/spellcheck_result.h"
@@ -355,10 +357,9 @@
   if (!request)
     return;
 
-  base::MessageLoopProxy::current()->PostTask(FROM_HERE,
-      base::Bind(&SpellCheck::PerformSpellCheck,
-                 AsWeakPtr(),
-                 base::Owned(request)));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&SpellCheck::PerformSpellCheck, AsWeakPtr(),
+                            base::Owned(request)));
 }
 #endif
 
diff --git a/chrome/renderer/web_apps.cc b/chrome/renderer/web_apps.cc
index 6032524..aadacca 100644
--- a/chrome/renderer/web_apps.cc
+++ b/chrome/renderer/web_apps.cc
@@ -102,7 +102,7 @@
   std::vector<base::string16> size_strings;
   base::SplitStringAlongWhitespace(text, &size_strings);
   for (size_t i = 0; i < size_strings.size(); ++i) {
-    if (EqualsASCII(size_strings[i], "any")) {
+    if (base::EqualsASCII(size_strings[i], "any")) {
       *is_any = true;
     } else {
       gfx::Size size = ParseIconSize(size_strings[i]);
@@ -152,11 +152,11 @@
       bool bookmark_apps_enabled = !base::CommandLine::ForCurrentProcess()->
           HasSwitch(switches::kDisableNewBookmarkApps);
 #endif
-      if (LowerCaseEqualsASCII(rel, "icon") ||
-          LowerCaseEqualsASCII(rel, "shortcut icon") ||
+      if (base::LowerCaseEqualsASCII(rel, "icon") ||
+          base::LowerCaseEqualsASCII(rel, "shortcut icon") ||
           (bookmark_apps_enabled &&
-           (LowerCaseEqualsASCII(rel, "apple-touch-icon") ||
-            LowerCaseEqualsASCII(rel, "apple-touch-icon-precomposed")))) {
+           (base::LowerCaseEqualsASCII(rel, "apple-touch-icon") ||
+            base::LowerCaseEqualsASCII(rel, "apple-touch-icon-precomposed")))) {
         AddInstallIcon(elem, &app_info->icons);
       }
     } else if (elem.hasHTMLTagName("meta") && elem.hasAttribute("name")) {
@@ -173,10 +173,10 @@
         if (!app_info->app_url.is_valid())
           app_info->app_url = GURL();
       } else if (name == "mobile-web-app-capable" &&
-                 LowerCaseEqualsASCII(content, "yes")) {
+                 base::LowerCaseEqualsASCII(content, "yes")) {
         app_info->mobile_capable = WebApplicationInfo::MOBILE_CAPABLE;
       } else if (name == "apple-mobile-web-app-capable" &&
-                 LowerCaseEqualsASCII(content, "yes") &&
+                 base::LowerCaseEqualsASCII(content, "yes") &&
                  app_info->mobile_capable ==
                      WebApplicationInfo::MOBILE_CAPABLE_UNSPECIFIED) {
         app_info->mobile_capable = WebApplicationInfo::MOBILE_CAPABLE_APPLE;
diff --git a/chrome/service/cloud_print/cloud_print_auth.cc b/chrome/service/cloud_print/cloud_print_auth.cc
index b52ba0c..663aca7 100644
--- a/chrome/service/cloud_print/cloud_print_auth.cc
+++ b/chrome/service/cloud_print/cloud_print_auth.cc
@@ -5,8 +5,11 @@
 #include "chrome/service/cloud_print/cloud_print_auth.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/common/cloud_print/cloud_print_constants.h"
 #include "chrome/common/cloud_print/cloud_print_helpers.h"
 #include "chrome/service/cloud_print/cloud_print_token_store.h"
@@ -134,9 +137,8 @@
   DCHECK(expires_in_seconds > kTokenRefreshGracePeriodSecs);
   base::TimeDelta refresh_delay = base::TimeDelta::FromSeconds(
       expires_in_seconds - kTokenRefreshGracePeriodSecs);
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&CloudPrintAuth::RefreshAccessToken, this),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&CloudPrintAuth::RefreshAccessToken, this),
       refresh_delay);
 }
 
diff --git a/chrome/service/cloud_print/cloud_print_connector.cc b/chrome/service/cloud_print/cloud_print_connector.cc
index 4abc4b4b..e1e4c13 100644
--- a/chrome/service/cloud_print/cloud_print_connector.cc
+++ b/chrome/service/cloud_print/cloud_print_connector.cc
@@ -6,13 +6,16 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/md5.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/common/cloud_print/cloud_print_constants.h"
 #include "chrome/common/cloud_print/cloud_print_helpers.h"
@@ -51,10 +54,9 @@
 }
 
 void CloudPrintConnector::ScheduleStatsReport() {
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&CloudPrintConnector::ReportStats,
-                 stats_ptr_factory_.GetWeakPtr()),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&CloudPrintConnector::ReportStats,
+                            stats_ptr_factory_.GetWeakPtr()),
       base::TimeDelta::FromHours(1));
 }
 
@@ -416,7 +418,8 @@
     for (size_t index = 0; index < tags_list->GetSize(); index++) {
       std::string tag;
       if (tags_list->GetString(index, &tag) &&
-          StartsWithASCII(tag, kCloudPrintServiceTagsHashTagName, false)) {
+          base::StartsWithASCII(tag, kCloudPrintServiceTagsHashTagName,
+                                false)) {
         std::vector<std::string> tag_parts;
         base::SplitStringDontTrim(tag, '=', &tag_parts);
         DCHECK_EQ(tag_parts.size(), 2U);
@@ -492,7 +495,7 @@
   pending_tasks_.push_back(task);
   // If this is the only pending task, we need to start the process.
   if (pending_tasks_.size() == 1) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&CloudPrintConnector::ProcessPendingTask, this));
   }
 }
@@ -527,7 +530,7 @@
   // Delete current task and repost if we have more task available.
   pending_tasks_.pop_front();
   if (pending_tasks_.size() != 0) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&CloudPrintConnector::ProcessPendingTask, this));
   }
 }
diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc
index 233ff2e..f93215db 100644
--- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc
+++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc
@@ -10,9 +10,12 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/common/cloud_print/cloud_print_constants.h"
 #include "chrome/service/cloud_print/cloud_print_auth.h"
@@ -172,7 +175,7 @@
     const std::string& cloud_print_token) {
   if (!core_thread_.Start())
     return false;
-  core_thread_.message_loop()->PostTask(
+  core_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithToken,
                  core_.get(), cloud_print_token));
@@ -184,7 +187,7 @@
     const std::string& robot_email) {
   if (!core_thread_.Start())
     return false;
-  core_thread_.message_loop()->PostTask(
+  core_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithRobotToken,
                  core_.get(), robot_oauth_refresh_token, robot_email));
@@ -196,7 +199,7 @@
     const std::string& robot_email) {
   if (!core_thread_.Start())
     return false;
-  core_thread_.message_loop()->PostTask(
+  core_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode,
                  core_.get(), robot_oauth_auth_code, robot_email));
@@ -204,7 +207,7 @@
 }
 
 void CloudPrintProxyBackend::Shutdown() {
-  core_thread_.message_loop()->PostTask(
+  core_thread_.task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&CloudPrintProxyBackend::Core::DoShutdown, core_.get()));
   core_thread_.Stop();
@@ -212,10 +215,9 @@
 }
 
 void CloudPrintProxyBackend::UnregisterPrinters() {
-  core_thread_.message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&CloudPrintProxyBackend::Core::DoUnregisterPrinters,
-                 core_.get()));
+  core_thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&CloudPrintProxyBackend::Core::DoUnregisterPrinters,
+                            core_.get()));
 }
 
 CloudPrintProxyBackend::Core::Core(
@@ -282,7 +284,7 @@
   token_store->SetToken(access_token);
   robot_email_ = robot_email;
   // Let the frontend know that we have authenticated.
-  backend_->frontend_loop_->PostTask(
+  backend_->frontend_loop_->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&Core::NotifyAuthenticated, this, robot_oauth_refresh_token,
                  robot_email, user_email));
@@ -297,7 +299,7 @@
   if (!connector_->IsRunning()) {
     if (!connector_->Start()) {
       // Let the frontend know that we do not have a print system.
-      backend_->frontend_loop_->PostTask(
+      backend_->frontend_loop_->task_runner()->PostTask(
           FROM_HERE, base::Bind(&Core::NotifyPrintSystemUnavailable, this));
     }
   }
@@ -306,7 +308,7 @@
 void CloudPrintProxyBackend::Core::OnInvalidCredentials() {
   DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
   VLOG(1) << "CP_CONNECTOR: Auth Error";
-  backend_->frontend_loop_->PostTask(
+  backend_->frontend_loop_->task_runner()->PostTask(
       FROM_HERE, base::Bind(&Core::NotifyAuthenticationFailed, this));
 }
 
@@ -323,9 +325,8 @@
 
 void CloudPrintProxyBackend::Core::OnXmppPingUpdated(int ping_timeout) {
   settings_.SetXmppPingTimeoutSec(ping_timeout);
-  backend_->frontend_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&Core::NotifyXmppPingUpdated, this, ping_timeout));
+  backend_->frontend_loop_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&Core::NotifyXmppPingUpdated, this, ping_timeout));
 }
 
 void CloudPrintProxyBackend::Core::InitNotifications(
@@ -379,10 +380,9 @@
   std::list<std::string> printer_ids;
   connector_->GetPrinterIds(&printer_ids);
 
-  backend_->frontend_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&Core::NotifyUnregisterPrinters,
-                 this, access_token, printer_ids));
+  backend_->frontend_loop_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&Core::NotifyUnregisterPrinters, this, access_token,
+                            printer_ids));
 }
 
 void CloudPrintProxyBackend::Core::HandlePrinterNotification(
@@ -419,9 +419,8 @@
   if (!job_poll_scheduled_) {
     base::TimeDelta interval = base::TimeDelta::FromSeconds(
         base::RandInt(kMinJobPollIntervalSecs, kMaxJobPollIntervalSecs));
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&CloudPrintProxyBackend::Core::PollForJobs, this),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&CloudPrintProxyBackend::Core::PollForJobs, this),
         interval);
     job_poll_scheduled_ = true;
   }
@@ -438,7 +437,7 @@
   pending_xmpp_pings_++;
   if (pending_xmpp_pings_ >= kMaxFailedXmppPings) {
     // Check ping status when we close to the limit.
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&CloudPrintProxyBackend::Core::CheckXmppPingStatus, this),
         base::TimeDelta::FromSeconds(kXmppPingCheckIntervalSecs));
@@ -456,7 +455,7 @@
     base::TimeDelta interval = base::TimeDelta::FromSeconds(
       base::RandInt(settings_.xmpp_ping_timeout_sec() * 0.9,
                     settings_.xmpp_ping_timeout_sec() * 1.1));
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&CloudPrintProxyBackend::Core::PingXmppServer, this),
         interval);
diff --git a/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc b/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc
index 60e0378..7d7c657 100644
--- a/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc
+++ b/chrome/service/cloud_print/cloud_print_url_fetcher_unittest.cc
@@ -3,9 +3,11 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/values.h"
 #include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
@@ -31,9 +33,9 @@
     : public net::TestURLRequestContextGetter {
  public:
   explicit TrackingTestURLRequestContextGetter(
-      base::MessageLoopProxy* io_message_loop_proxy,
+      base::SingleThreadTaskRunner* io_task_runner,
       net::URLRequestThrottlerManager* throttler_manager)
-      : TestURLRequestContextGetter(io_message_loop_proxy),
+      : TestURLRequestContextGetter(io_task_runner),
         throttler_manager_(throttler_manager) {
     g_request_context_getter_instances++;
   }
@@ -61,13 +63,12 @@
 class TestCloudPrintURLFetcher : public CloudPrintURLFetcher {
  public:
   explicit TestCloudPrintURLFetcher(
-      base::MessageLoopProxy* io_message_loop_proxy)
-      : io_message_loop_proxy_(io_message_loop_proxy) {
-  }
+      base::SingleThreadTaskRunner* io_task_runner)
+      : io_task_runner_(io_task_runner) {}
 
   net::URLRequestContextGetter* GetRequestContextGetter() override {
-    return new TrackingTestURLRequestContextGetter(
-        io_message_loop_proxy_.get(), throttler_manager());
+    return new TrackingTestURLRequestContextGetter(io_task_runner_.get(),
+                                                   throttler_manager());
   }
 
   net::URLRequestThrottlerManager* throttler_manager() {
@@ -77,7 +78,7 @@
  private:
   ~TestCloudPrintURLFetcher() override {}
 
-  scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
 
   // We set this as the throttler manager for the
   // TestURLRequestContext we create.
@@ -108,15 +109,15 @@
 
   std::string GetAuthHeader() override { return std::string(); }
 
-  scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy() {
-    return io_message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner() {
+    return io_task_runner_;
   }
 
  protected:
   void SetUp() override {
     testing::Test::SetUp();
 
-    io_message_loop_proxy_ = base::MessageLoopProxy::current();
+    io_task_runner_ = base::ThreadTaskRunnerHandle::Get();
   }
 
   void TearDown() override {
@@ -133,7 +134,7 @@
   // dispatches its requests to.  When we wish to simulate being used from
   // a UI thread, we dispatch a worker thread to do so.
   base::MessageLoopForIO io_loop_;
-  scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
   int max_retries_;
   Time start_time_;
   scoped_refptr<TestCloudPrintURLFetcher> fetcher_;
@@ -210,7 +211,7 @@
 
 
 void CloudPrintURLFetcherTest::CreateFetcher(const GURL& url, int max_retries) {
-  fetcher_ = new TestCloudPrintURLFetcher(io_message_loop_proxy().get());
+  fetcher_ = new TestCloudPrintURLFetcher(io_task_runner().get());
 
   // Registers an entry for test url. It only allows 3 requests to be sent
   // in 200 milliseconds.
@@ -254,8 +255,7 @@
   if (handle_raw_response_) {
     // If the current message loop is not the IO loop, it will be shut down when
     // the main loop returns and this thread subsequently goes out of scope.
-    io_message_loop_proxy()->PostTask(FROM_HERE,
-                                      base::MessageLoop::QuitClosure());
+    io_task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
     return CloudPrintURLFetcher::STOP_PROCESSING;
   }
   return CloudPrintURLFetcher::CONTINUE_PROCESSING;
@@ -269,8 +269,7 @@
   // We should never get here if we returned true in HandleRawResponse
   EXPECT_FALSE(handle_raw_response_);
   if (handle_raw_data_) {
-    io_message_loop_proxy()->PostTask(FROM_HERE,
-                                      base::MessageLoop::QuitClosure());
+    io_task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
     return CloudPrintURLFetcher::STOP_PROCESSING;
   }
   return CloudPrintURLFetcher::CONTINUE_PROCESSING;
@@ -285,8 +284,7 @@
   // We should never get here if we returned true in one of the above methods.
   EXPECT_FALSE(handle_raw_response_);
   EXPECT_FALSE(handle_raw_data_);
-  io_message_loop_proxy()->PostTask(FROM_HERE,
-                                    base::MessageLoop::QuitClosure());
+  io_task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
   return CloudPrintURLFetcher::STOP_PROCESSING;
 }
 
@@ -304,8 +302,7 @@
     // We have already sent 20 requests continuously. And we expect that
     // it takes more than 1 second due to the overload protection settings.
     EXPECT_TRUE(Time::Now() - start_time_ >= one_second);
-    io_message_loop_proxy()->PostTask(FROM_HERE,
-                                      base::MessageLoop::QuitClosure());
+    io_task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
   }
   return CloudPrintURLFetcher::STOP_PROCESSING;
 }
@@ -324,8 +321,7 @@
 void CloudPrintURLFetcherRetryBackoffTest::OnRequestGiveUp() {
   // It takes more than 200 ms to finish all 11 requests.
   EXPECT_TRUE(Time::Now() - start_time_ >= TimeDelta::FromMilliseconds(200));
-  io_message_loop_proxy()->PostTask(FROM_HERE,
-                                    base::MessageLoop::QuitClosure());
+  io_task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
 }
 
 TEST_F(CloudPrintURLFetcherBasicTest, HandleRawResponse) {
diff --git a/chrome/service/cloud_print/connector_settings_unittest.cc b/chrome/service/cloud_print/connector_settings_unittest.cc
index 5239fd20..b8475fb 100644
--- a/chrome/service/cloud_print/connector_settings_unittest.cc
+++ b/chrome/service/cloud_print/connector_settings_unittest.cc
@@ -9,7 +9,8 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/common/cloud_print/cloud_print_constants.h"
 #include "chrome/service/service_process_prefs.h"
@@ -50,7 +51,7 @@
  protected:
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    message_loop_proxy_ = base::MessageLoopProxy::current();
+    task_runner_ = base::ThreadTaskRunnerHandle::Get();
   }
 
   ServiceProcessPrefs* CreateTestFile(const char* json) {
@@ -62,14 +63,14 @@
       base::WriteFile(file_name, content.c_str(), content.size());
     }
     ServiceProcessPrefs* prefs =
-        new ServiceProcessPrefs(file_name, message_loop_proxy_.get());
+        new ServiceProcessPrefs(file_name, task_runner_.get());
     prefs->ReadPrefs();
     return prefs;
   }
 
   base::ScopedTempDir temp_dir_;
   base::MessageLoop message_loop_;
-  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 };
 
 TEST_F(ConnectorSettingsTest, InitFromEmpty) {
diff --git a/chrome/service/cloud_print/job_status_updater.cc b/chrome/service/cloud_print/job_status_updater.cc
index dcdca08..840bfc0 100644
--- a/chrome/service/cloud_print/job_status_updater.cc
+++ b/chrome/service/cloud_print/job_status_updater.cc
@@ -6,9 +6,12 @@
 
 #include "base/bind.h"
 #include "base/json/json_reader.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/common/cloud_print/cloud_print_constants.h"
 #include "chrome/service/cloud_print/cloud_print_service_helpers.h"
@@ -100,7 +103,7 @@
       base::DictionaryValue* json_data,
       bool succeeded) {
   if (IsTerminalJobState(last_job_details_.status)) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&JobStatusUpdater::Stop, this));
   }
   return CloudPrintURLFetcher::STOP_PROCESSING;
diff --git a/chrome/service/cloud_print/print_system_cups.cc b/chrome/service/cloud_print/print_system_cups.cc
index 132a252b1..86b453a1 100644
--- a/chrome/service/cloud_print/print_system_cups.cc
+++ b/chrome/service/cloud_print/print_system_cups.cc
@@ -16,14 +16,16 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/json/json_reader.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/md5.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/common/cloud_print/cloud_print_constants.h"
 #include "chrome/common/crash_keys.h"
@@ -183,9 +185,8 @@
       PrintSystem::PrintServerWatcher::Delegate* delegate) override {
     delegate_ = delegate;
     printers_hash_ = GetPrintersHash();
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&PrintServerWatcherCUPS::CheckForUpdates, this),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&PrintServerWatcherCUPS::CheckForUpdates, this),
         print_system_->GetUpdateTimeout());
     return true;
   }
@@ -204,9 +205,8 @@
       printers_hash_ = new_hash;
       delegate_->OnPrinterAdded();
     }
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&PrintServerWatcherCUPS::CheckForUpdates, this),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&PrintServerWatcherCUPS::CheckForUpdates, this),
         print_system_->GetUpdateTimeout());
   }
 
@@ -260,15 +260,13 @@
     delegate_ = delegate;
     settings_hash_ = GetSettingsHash();
     // Schedule next job status update.
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&PrinterWatcherCUPS::JobStatusUpdate, this),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&PrinterWatcherCUPS::JobStatusUpdate, this),
         base::TimeDelta::FromSeconds(kJobUpdateTimeoutSeconds));
     // Schedule next printer check.
     // TODO(gene): Randomize time for the next printer update.
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&PrinterWatcherCUPS::PrinterUpdate, this),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&PrinterWatcherCUPS::PrinterUpdate, this),
         print_system_->GetUpdateTimeout());
     return true;
   }
@@ -292,9 +290,8 @@
     // jobs for this printer and check their status. If printer has no
     // outstanding jobs, OnJobChanged() will do nothing.
     delegate_->OnJobChanged();
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&PrinterWatcherCUPS::JobStatusUpdate, this),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&PrinterWatcherCUPS::JobStatusUpdate, this),
         base::TimeDelta::FromSeconds(kJobUpdateTimeoutSeconds));
   }
 
@@ -317,9 +314,8 @@
                 << ", printer name: " << printer_name_;
       }
     }
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&PrinterWatcherCUPS::PrinterUpdate, this),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&PrinterWatcherCUPS::PrinterUpdate, this),
         print_system_->GetUpdateTimeout());
   }
 
@@ -380,7 +376,7 @@
     int job_id = print_system_->SpoolPrintJob(
         print_ticket, print_data_file_path, print_data_mime_type,
         printer_name, job_title, tags, &dry_run);
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&JobSpoolerCUPS::NotifyDelegate, delegate, job_id, dry_run));
     return true;
@@ -498,9 +494,8 @@
   }
 
   // Schedule next update.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&PrintSystemCUPS::UpdatePrinters, this),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&PrintSystemCUPS::UpdatePrinters, this),
       GetUpdateTimeout());
 }
 
@@ -524,13 +519,9 @@
     const PrinterCapsAndDefaultsCallback& callback) {
   printing::PrinterCapsAndDefaults printer_info;
   bool succeeded = GetPrinterCapsAndDefaults(printer_name, &printer_info);
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&PrintSystemCUPS::RunCapsCallback,
-                 callback,
-                 succeeded,
-                 printer_name,
-                 printer_info));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&PrintSystemCUPS::RunCapsCallback, callback,
+                            succeeded, printer_name, printer_info));
 }
 
 bool PrintSystemCUPS::IsValidPrinter(const std::string& printer_name) {
diff --git a/chrome/service/cloud_print/print_system_win.cc b/chrome/service/cloud_print/print_system_win.cc
index 550a5633..58b5231 100644
--- a/chrome/service/cloud_print/print_system_win.cc
+++ b/chrome/service/cloud_print/print_system_win.cc
@@ -9,6 +9,7 @@
 #include "base/json/json_writer.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/win/object_watcher.h"
 #include "base/win/scoped_bstr.h"
 #include "base/win/scoped_comptr.h"
@@ -410,26 +411,24 @@
       int dc_width = GetDeviceCaps(printer_dc_.Get(), PHYSICALWIDTH);
       int dc_height = GetDeviceCaps(printer_dc_.Get(), PHYSICALHEIGHT);
       gfx::Rect render_area(0, 0, dc_width, dc_height);
-      g_service_process->io_thread()->message_loop_proxy()->PostTask(
+      g_service_process->io_thread()->task_runner()->PostTask(
           FROM_HERE,
-          base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox,
-                     this,
-                     print_data_file_path_,
-                     render_area,
-                     printer_dpi,
-                     base::MessageLoopProxy::current()));
+          base::Bind(&JobSpoolerWin::Core::RenderPDFPagesInSandbox, this,
+                     print_data_file_path_, render_area, printer_dpi,
+                     base::ThreadTaskRunnerHandle::Get()));
     }
 
     // Called on the service process IO thread.
-    void RenderPDFPagesInSandbox(const base::FilePath& pdf_path,
-                                 const gfx::Rect& render_area,
-                                 int render_dpi,
-                                 const scoped_refptr<base::MessageLoopProxy>&
-                                     client_message_loop_proxy) {
-      DCHECK(g_service_process->io_thread()->message_loop_proxy()->
-          BelongsToCurrentThread());
+    void RenderPDFPagesInSandbox(
+        const base::FilePath& pdf_path,
+        const gfx::Rect& render_area,
+        int render_dpi,
+        const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner) {
+      DCHECK(g_service_process->io_thread()
+                 ->task_runner()
+                 ->BelongsToCurrentThread());
       scoped_ptr<ServiceUtilityProcessHost> utility_host(
-          new ServiceUtilityProcessHost(this, client_message_loop_proxy.get()));
+          new ServiceUtilityProcessHost(this, client_task_runner.get()));
       // TODO(gene): For now we disabling autorotation for CloudPrinting.
       // Landscape/Portrait setting is passed in the print ticket and
       // server is generating portrait PDF always.
@@ -441,7 +440,7 @@
         // The object will self-destruct when the child process dies.
         utility_host.release();
       } else {
-        client_message_loop_proxy->PostTask(
+        client_task_runner->PostTask(
             FROM_HERE, base::Bind(&Core::PrintJobDone, this, false));
       }
     }
@@ -555,53 +554,51 @@
   }
 
   void StartGetPrinterCapsAndDefaults() {
-    g_service_process->io_thread()->message_loop_proxy()->PostTask(
+    g_service_process->io_thread()->task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&PrinterCapsHandler::GetPrinterCapsAndDefaultsImpl, this,
-                    base::MessageLoopProxy::current()));
+                   base::ThreadTaskRunnerHandle::Get()));
   }
 
   void StartGetPrinterSemanticCapsAndDefaults() {
-    g_service_process->io_thread()->message_loop_proxy()->PostTask(
+    g_service_process->io_thread()->task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&PrinterCapsHandler::GetPrinterSemanticCapsAndDefaultsImpl,
-                   this, base::MessageLoopProxy::current()));
+                   this, base::ThreadTaskRunnerHandle::Get()));
   }
 
  private:
   ~PrinterCapsHandler() override {}
 
   void GetPrinterCapsAndDefaultsImpl(
-      const scoped_refptr<base::MessageLoopProxy>&
-          client_message_loop_proxy) {
-    DCHECK(g_service_process->io_thread()->message_loop_proxy()->
-        BelongsToCurrentThread());
+      const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner) {
+    DCHECK(g_service_process->io_thread()
+               ->task_runner()
+               ->BelongsToCurrentThread());
     scoped_ptr<ServiceUtilityProcessHost> utility_host(
-        new ServiceUtilityProcessHost(this, client_message_loop_proxy.get()));
+        new ServiceUtilityProcessHost(this, client_task_runner.get()));
     if (utility_host->StartGetPrinterCapsAndDefaults(printer_name_)) {
       // The object will self-destruct when the child process dies.
       utility_host.release();
     } else {
-      client_message_loop_proxy->PostTask(
-          FROM_HERE,
-          base::Bind(&PrinterCapsHandler::OnChildDied, this));
+      client_task_runner->PostTask(
+          FROM_HERE, base::Bind(&PrinterCapsHandler::OnChildDied, this));
     }
   }
 
   void GetPrinterSemanticCapsAndDefaultsImpl(
-      const scoped_refptr<base::MessageLoopProxy>&
-          client_message_loop_proxy) {
-    DCHECK(g_service_process->io_thread()->message_loop_proxy()->
-        BelongsToCurrentThread());
+      const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner) {
+    DCHECK(g_service_process->io_thread()
+               ->task_runner()
+               ->BelongsToCurrentThread());
     scoped_ptr<ServiceUtilityProcessHost> utility_host(
-        new ServiceUtilityProcessHost(this, client_message_loop_proxy.get()));
+        new ServiceUtilityProcessHost(this, client_task_runner.get()));
     if (utility_host->StartGetPrinterSemanticCapsAndDefaults(printer_name_)) {
       // The object will self-destruct when the child process dies.
       utility_host.release();
     } else {
-      client_message_loop_proxy->PostTask(
-          FROM_HERE,
-          base::Bind(&PrinterCapsHandler::OnChildDied, this));
+      client_task_runner->PostTask(
+          FROM_HERE, base::Bind(&PrinterCapsHandler::OnChildDied, this));
     }
   }
 
diff --git a/chrome/service/cloud_print/printer_job_handler.cc b/chrome/service/cloud_print/printer_job_handler.cc
index 95dfb55..f57ceb6 100644
--- a/chrome/service/cloud_print/printer_job_handler.cc
+++ b/chrome/service/cloud_print/printer_job_handler.cc
@@ -8,10 +8,12 @@
 #include "base/bind_helpers.h"
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
+#include "base/location.h"
 #include "base/md5.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/common/cloud_print/cloud_print_constants.h"
 #include "chrome/common/cloud_print/cloud_print_helpers.h"
@@ -72,8 +74,7 @@
       next_json_data_handler_(NULL),
       next_data_handler_(NULL),
       print_thread_("Chrome_CloudPrintJobPrintThread"),
-      job_handler_message_loop_proxy_(
-          base::MessageLoopProxy::current()),
+      job_handler_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       shutting_down_(false),
       job_check_pending_(false),
       printer_update_pending_(true),
@@ -106,7 +107,7 @@
   job_fetch_reason_ = reason;
   job_check_pending_ = true;
   if (!task_in_progress_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&PrinterJobHandler::Start, this));
   }
 }
@@ -136,7 +137,7 @@
   if (next_data_handler_ == (&PrinterJobHandler::HandlePrintDataResponse) &&
       response_code == net::HTTP_UNSUPPORTED_MEDIA_TYPE) {
     VLOG(1) << "CP_CONNECTOR: Job failed (unsupported media type)";
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&PrinterJobHandler::JobFailed, this, JOB_DOWNLOAD_FAILED));
     return CloudPrintURLFetcher::STOP_PROCESSING;
@@ -167,12 +168,12 @@
   if (job_queue_handler_.JobFetchFailed(job_details_.job_id_)) {
     VLOG(1) << "CP_CONNECTOR: Job failed to load (scheduling retry)";
     CheckForJobs(kJobFetchReasonFailure);
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&PrinterJobHandler::Stop, this));
   } else {
     VLOG(1) << "CP_CONNECTOR: Job failed (giving up after " <<
         kNumRetriesBeforeAbandonJob << " retries)";
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&PrinterJobHandler::JobFailed, this, JOB_DOWNLOAD_FAILED));
   }
@@ -213,7 +214,7 @@
 }
 
 void PrinterJobHandler::OnAuthError() {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&PrinterJobHandler::Stop, this));
   if (delegate_)
     delegate_->OnAuthError();
@@ -227,7 +228,7 @@
 void PrinterJobHandler::OnPrinterChanged() {
   printer_update_pending_ = true;
   if (!task_in_progress_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&PrinterJobHandler::Start, this));
   }
 }
@@ -237,7 +238,7 @@
   // and have them check for updates.
   for (JobStatusUpdaterList::iterator index = job_status_updater_list_.begin();
        index != job_status_updater_list_.end(); index++) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&JobStatusUpdater::UpdateStatus, index->get()));
   }
 }
@@ -247,7 +248,7 @@
   job_spooler_->AddRef();
   print_thread_.message_loop()->ReleaseSoon(FROM_HERE, job_spooler_.get());
   job_spooler_ = NULL;
-  job_handler_message_loop_proxy_->PostTask(
+  job_handler_task_runner_->PostTask(
       FROM_HERE, base::Bind(&PrinterJobHandler::JobSpooled, this, job_id));
 }
 
@@ -257,7 +258,7 @@
   print_thread_.message_loop()->ReleaseSoon(FROM_HERE, job_spooler_.get());
   job_spooler_ = NULL;
   VLOG(1) << "CP_CONNECTOR: Job failed (spool failed)";
-  job_handler_message_loop_proxy_->PostTask(
+  job_handler_task_runner_->PostTask(
       FROM_HERE, base::Bind(&PrinterJobHandler::JobFailed, this, JOB_FAILED));
 }
 
@@ -288,7 +289,7 @@
   // We are done here. Go to the Stop state
   VLOG(1) << "CP_CONNECTOR: Stopping printer job handler"
           << ", printer id: " << printer_info_cloud_.printer_id;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&PrinterJobHandler::Stop, this));
   return CloudPrintURLFetcher::STOP_PROCESSING;
 }
@@ -329,7 +330,7 @@
         }
       } else {
         job_available = false;
-        base::MessageLoop::current()->PostDelayedTask(
+        base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
             FROM_HERE,
             base::Bind(&PrinterJobHandler::RunScheduledJobCheck, this),
             jobs[0].time_remaining_);
@@ -341,7 +342,7 @@
     // If no jobs are available, go to the Stop state.
     VLOG(1) << "CP_CONNECTOR: Stopping printer job handler"
             << ", printer id: " << printer_info_cloud_.printer_id;
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&PrinterJobHandler::Stop, this));
   }
   return CloudPrintURLFetcher::STOP_PROCESSING;
@@ -403,9 +404,9 @@
   // here.
   VLOG(1) << "CP_CONNECTOR: Error saving print data"
           << ", printer id: " << printer_info_cloud_.printer_id;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&PrinterJobHandler::JobFailed, this,
-                            JOB_DOWNLOAD_FAILED));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&PrinterJobHandler::JobFailed, this, JOB_DOWNLOAD_FAILED));
   return CloudPrintURLFetcher::STOP_PROCESSING;
 }
 
@@ -417,7 +418,7 @@
     bool succeeded) {
   VLOG(1) << "CP_CONNECTOR: Handling success status update response"
           << ", printer id: " << printer_info_cloud_.printer_id;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&PrinterJobHandler::StartPrinting, this));
   return CloudPrintURLFetcher::STOP_PROCESSING;
 }
@@ -430,7 +431,7 @@
     bool succeeded) {
   VLOG(1) << "CP_CONNECTOR: Handling failure status update response"
           << ", printer id: " << printer_info_cloud_.printer_id;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&PrinterJobHandler::Stop, this));
   return CloudPrintURLFetcher::STOP_PROCESSING;
 }
@@ -499,7 +500,7 @@
           << ", task in progress: " << task_in_progress_;
   Reset();
   if (HavePendingTasks()) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&PrinterJobHandler::Start, this));
   }
 }
@@ -520,7 +521,7 @@
               << ", printer id: " << printer_info_cloud_.printer_id;
       JobFailed(JOB_FAILED);
     } else {
-      print_thread_.message_loop()->PostTask(
+      print_thread_.task_runner()->PostTask(
           FROM_HERE, base::Bind(&PrinterJobHandler::DoPrint, this, job_details_,
                                 printer_info_.printer_name));
     }
@@ -619,7 +620,7 @@
                             local_job_id_, cloud_print_server_url_,
                             print_system_.get(), this));
   job_status_updater_list_.push_back(job_status_updater);
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&JobStatusUpdater::UpdateStatus, job_status_updater.get()));
 
@@ -627,7 +628,7 @@
 
   VLOG(1) << "CP_CONNECTOR: Stopping printer job handler"
           << ", printer id: " << printer_info_cloud_.printer_id;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&PrinterJobHandler::Stop, this));
 }
 
@@ -774,13 +775,13 @@
     // We are done here. Go to the Stop state
     VLOG(1) << "CP_CONNECTOR: Stopping printer job handler"
             << ", printer name: " << printer_name;
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&PrinterJobHandler::Stop, this));
   }
 }
 
 // The following methods are called on |print_thread_|. It is not safe to
-// access any members other than |job_handler_message_loop_proxy_|,
+// access any members other than |job_handler_task_runner_|,
 // |job_spooler_| and |print_system_|.
 void PrinterJobHandler::DoPrint(const JobDetails& job_details,
                                 const std::string& printer_name) {
diff --git a/chrome/service/cloud_print/printer_job_handler.h b/chrome/service/cloud_print/printer_job_handler.h
index 304e2bc0..c49ee45 100644
--- a/chrome/service/cloud_print/printer_job_handler.h
+++ b/chrome/service/cloud_print/printer_job_handler.h
@@ -12,7 +12,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
@@ -275,7 +275,7 @@
   scoped_refptr<PrintSystem::JobSpooler> job_spooler_;
   // The message loop proxy representing the thread on which this object
   // was created. Used by the print thread.
-  scoped_refptr<base::MessageLoopProxy> job_handler_message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> job_handler_task_runner_;
 
   // There may be pending tasks in the message queue when Shutdown is called.
   // We set this flag so as to do nothing in those tasks.
diff --git a/chrome/service/cloud_print/printer_job_handler_unittest.cc b/chrome/service/cloud_print/printer_job_handler_unittest.cc
index a7147ef..da396dd 100644
--- a/chrome/service/cloud_print/printer_job_handler_unittest.cc
+++ b/chrome/service/cloud_print/printer_job_handler_unittest.cc
@@ -3,12 +3,14 @@
 // found in the LICENSE file.
 
 #include "base/files/file_path.h"
+#include "base/location.h"
 #include "base/md5.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/common/cloud_print/cloud_print_constants.h"
 #include "chrome/service/cloud_print/cloud_print_service_helpers.h"
 #include "chrome/service/cloud_print/cloud_print_token_store.h"
@@ -247,9 +249,10 @@
 class CloudPrintURLFetcherNoServiceProcess
     : public CloudPrintURLFetcher {
  public:
-  CloudPrintURLFetcherNoServiceProcess() :
-      context_getter_(new net::TestURLRequestContextGetter(
-          base::MessageLoopProxy::current())) {}
+  CloudPrintURLFetcherNoServiceProcess()
+      : context_getter_(new net::TestURLRequestContextGetter(
+            base::ThreadTaskRunnerHandle::Get())) {}
+
  protected:
   net::URLRequestContextGetter* GetRequestContextGetter() override {
     return context_getter_.get();
@@ -522,7 +525,7 @@
 
 void PrinterJobHandlerTest::MessageLoopQuitSoonHelper(
     base::MessageLoop* message_loop) {
-  message_loop->message_loop_proxy()->PostTask(
+  message_loop->task_runner()->PostTask(
       FROM_HERE, base::Bind(&MessageLoopQuitNowHelper, message_loop));
 }
 
@@ -532,14 +535,14 @@
 }
 
 bool PrinterJobHandlerTest::PostSpoolSuccess() {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&PrinterJobHandler::OnJobSpoolSucceeded, job_handler_, 0));
 
   // Everything that would be posted on the printer thread queue
   // has been posted, we can tell the main message loop to quit when idle
   // and not worry about it idling while the print thread does work
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&MessageLoopQuitSoonHelper, &loop_));
   return true;
 }
@@ -769,15 +772,12 @@
                            net::HTTP_INTERNAL_SERVER_ERROR,
                            net::URLRequestStatus::FAILED);
 
-  loop_.PostDelayedTask(FROM_HERE,
-                        base::Bind(&net::FakeURLFetcherFactory::SetFakeResponse,
-                                   base::Unretained(&factory_),
-                                   TicketURI(1),
-                                   kExamplePrintTicket,
-                                   net::HTTP_OK,
-                                   net::URLRequestStatus::SUCCESS),
-                        base::TimeDelta::FromSeconds(1));
-
+  loop_.task_runner()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&net::FakeURLFetcherFactory::SetFakeResponse,
+                 base::Unretained(&factory_), TicketURI(1), kExamplePrintTicket,
+                 net::HTTP_OK, net::URLRequestStatus::SUCCESS),
+      base::TimeDelta::FromSeconds(1));
 
   BeginTest(5);
 }
diff --git a/chrome/service/net/service_url_request_context_getter.cc b/chrome/service/net/service_url_request_context_getter.cc
index cd752641..3dfbd2bb 100644
--- a/chrome/service/net/service_url_request_context_getter.cc
+++ b/chrome/service/net/service_url_request_context_getter.cc
@@ -9,7 +9,7 @@
 #endif
 
 #include "base/compiler_specific.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_info.h"
 #include "chrome/common/chrome_version_info.h"
@@ -96,14 +96,13 @@
 
 ServiceURLRequestContextGetter::ServiceURLRequestContextGetter()
     : user_agent_(MakeUserAgentForServiceProcess()),
-      network_task_runner_(
-          g_service_process->io_thread()->message_loop_proxy()) {
+      network_task_runner_(g_service_process->io_thread()->task_runner()) {
   // TODO(sanjeevr): Change CreateSystemProxyConfigService to accept a
-  // MessageLoopProxy* instead of MessageLoop*.
+  // SingleThreadTaskRunner* instead of MessageLoop*.
   DCHECK(g_service_process);
   proxy_config_service_.reset(net::ProxyService::CreateSystemProxyConfigService(
-      g_service_process->io_thread()->message_loop_proxy(),
-      g_service_process->file_thread()->message_loop_proxy()));
+      g_service_process->io_thread()->task_runner(),
+      g_service_process->file_thread()->task_runner()));
 }
 
 net::URLRequestContext*
diff --git a/chrome/service/net/service_url_request_context_getter.h b/chrome/service/net/service_url_request_context_getter.h
index cd50265..caf439c8 100644
--- a/chrome/service/net/service_url_request_context_getter.h
+++ b/chrome/service/net/service_url_request_context_getter.h
@@ -21,7 +21,7 @@
 #include "net/url_request/url_request_context_storage.h"
 
 namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 }
 
 namespace net {
diff --git a/chrome/service/service_ipc_server.cc b/chrome/service/service_ipc_server.cc
index 3265b9e..45582425 100644
--- a/chrome/service/service_ipc_server.cc
+++ b/chrome/service/service_ipc_server.cc
@@ -27,11 +27,8 @@
 void ServiceIPCServer::CreateChannel() {
   channel_.reset(NULL); // Tear down the existing channel, if any.
   channel_ = IPC::SyncChannel::Create(
-      channel_handle_,
-      IPC::Channel::MODE_NAMED_SERVER,
-      this,
-      g_service_process->io_thread()->message_loop_proxy().get(),
-      true,
+      channel_handle_, IPC::Channel::MODE_NAMED_SERVER, this,
+      g_service_process->io_thread()->task_runner().get(), true,
       g_service_process->shutdown_event());
   DCHECK(sync_message_filter_.get());
   channel_->AddFilter(sync_message_filter_.get());
diff --git a/chrome/service/service_process.cc b/chrome/service/service_process.cc
index 3bed9fe..79d3ba0 100644
--- a/chrome/service/service_process.cc
+++ b/chrome/service/service_process.cc
@@ -11,11 +11,14 @@
 #include "base/command_line.h"
 #include "base/environment.h"
 #include "base/i18n/rtl.h"
+#include "base/location.h"
 #include "base/memory/singleton.h"
 #include "base/path_service.h"
 #include "base/prefs/json_pref_store.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
@@ -193,7 +196,7 @@
   // After the IPC server has started we signal that the service process is
   // ready.
   if (!service_process_state_->SignalReady(
-          io_thread_->message_loop_proxy().get(),
+          io_thread_->task_runner().get(),
           base::Bind(&ServiceProcess::Terminate, base::Unretained(this)))) {
     return false;
   }
@@ -253,7 +256,8 @@
 }
 
 void ServiceProcess::Terminate() {
-  main_message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+  main_message_loop_->task_runner()->PostTask(FROM_HERE,
+                                              base::MessageLoop::QuitClosure());
 }
 
 bool ServiceProcess::HandleClientDisconnect() {
@@ -325,7 +329,7 @@
 }
 
 void ServiceProcess::ScheduleShutdownCheck() {
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&ServiceProcess::ShutdownIfNeeded, base::Unretained(this)),
       base::TimeDelta::FromSeconds(kShutdownDelaySeconds));
diff --git a/chrome/service/service_process.h b/chrome/service/service_process.h
index d5942d44..8f2aa4cd 100644
--- a/chrome/service/service_process.h
+++ b/chrome/service/service_process.h
@@ -46,17 +46,17 @@
   bool Teardown();
   // TODO(sanjeevr): Change various parts of the code such as
   // net::ProxyService::CreateSystemProxyConfigService to take in
-  // MessageLoopProxy* instead of MessageLoop*. When we have done that, we can
-  // remove the io_thread() and file_thread() accessors and replace them with
-  // io_message_loop_proxy() and file_message_loop_proxy() respectively.
+  // SingleThreadTaskRunner* instead of MessageLoop*. When we have done that,
+  // we can remove the io_thread() and file_thread() accessors and replace them
+  // with io_message_loop_proxy() and file_message_loop_proxy() respectively.
 
   // Returns the thread that we perform I/O coordination on (network requests,
   // communication with renderers, etc.
   // NOTE: You should ONLY use this to pass to IPC or other objects which must
   // need a MessageLoop*. If you just want to post a task, use the thread's
-  // message_loop_proxy() as it takes care of checking that a thread is still
-  // alive, race conditions, lifetime differences etc.
-  // If you still must use this, need to check the return value for NULL.
+  // task_runner() as it takes care of checking that a thread is still alive,
+  // race conditions, lifetime differences etc. If you still must use this,
+  // need to check the return value for NULL.
   base::Thread* io_thread() const {
     return io_thread_.get();
   }
diff --git a/chrome/service/service_process_prefs.cc b/chrome/service/service_process_prefs.cc
index 7f43943..7c69470 100644
--- a/chrome/service/service_process_prefs.cc
+++ b/chrome/service/service_process_prefs.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/service/service_process_prefs.h"
 
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/prefs/pref_filter.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 
 ServiceProcessPrefs::ServiceProcessPrefs(
diff --git a/chrome/service/service_process_prefs_unittest.cc b/chrome/service/service_process_prefs_unittest.cc
index 73284ca0..ed5ad04 100644
--- a/chrome/service/service_process_prefs_unittest.cc
+++ b/chrome/service/service_process_prefs_unittest.cc
@@ -18,7 +18,7 @@
 
     prefs_.reset(new ServiceProcessPrefs(
         temp_dir_.path().AppendASCII("service_process_prefs.txt"),
-        message_loop_.message_loop_proxy().get()));
+        message_loop_.task_runner().get()));
   }
 
   void TearDown() override { prefs_.reset(); }
diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc
index 765a4308..42a5a53 100644
--- a/chrome/service/service_utility_process_host.cc
+++ b/chrome/service/service_utility_process_host.cc
@@ -13,10 +13,10 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
 #include "base/process/launch.h"
 #include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_utility_printing_messages.h"
 #include "content/public/common/child_process_host.h"
@@ -150,9 +150,9 @@
 
 ServiceUtilityProcessHost::ServiceUtilityProcessHost(
     Client* client,
-    base::MessageLoopProxy* client_message_loop_proxy)
+    base::SingleThreadTaskRunner* client_task_runner)
     : client_(client),
-      client_message_loop_proxy_(client_message_loop_proxy),
+      client_task_runner_(client_task_runner),
       waiting_for_reply_(false),
       weak_ptr_factory_(this) {
   child_process_host_.reset(ChildProcessHost::Create(this));
@@ -258,7 +258,7 @@
   if (waiting_for_reply_) {
     // If we are yet to receive a reply then notify the client that the
     // child died.
-    client_message_loop_proxy_->PostTask(
+    client_task_runner_->PostTask(
         FROM_HERE, base::Bind(&Client::OnChildDied, client_.get()));
     ReportUmaEvent(SERVICE_UTILITY_DISCONNECTED);
     UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityDisconnectTime",
@@ -319,7 +319,7 @@
     return OnPDFToEmfFinished(false);
   base::File emf_file = pdf_to_emf_state_->TakeNextFile();
   base::PostTaskAndReplyWithResult(
-      client_message_loop_proxy_.get(), FROM_HERE,
+      client_task_runner_.get(), FROM_HERE,
       base::Bind(&Client::MetafileAvailable, client_.get(), scale_factor,
                  base::Passed(&emf_file)),
       base::Bind(&ServiceUtilityProcessHost::OnMetafileSpooled,
@@ -339,10 +339,9 @@
     UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityMetafileFailTime",
                         base::Time::Now() - start_time_);
   }
-  client_message_loop_proxy_->PostTask(
-      FROM_HERE,
-      base::Bind(
-          &Client::OnRenderPDFPagesToMetafileDone, client_.get(), success));
+  client_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&Client::OnRenderPDFPagesToMetafileDone,
+                            client_.get(), success));
   pdf_to_emf_state_.reset();
 }
 
@@ -354,10 +353,9 @@
   UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityCapsTime",
                       base::Time::Now() - start_time_);
   waiting_for_reply_ = false;
-  client_message_loop_proxy_->PostTask(
-      FROM_HERE,
-      base::Bind(&Client::OnGetPrinterCapsAndDefaults, client_.get(), true,
-                 printer_name, caps_and_defaults));
+  client_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&Client::OnGetPrinterCapsAndDefaults, client_.get(),
+                            true, printer_name, caps_and_defaults));
 }
 
 void ServiceUtilityProcessHost::OnGetPrinterSemanticCapsAndDefaultsSucceeded(
@@ -368,7 +366,7 @@
   UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilitySemanticCapsTime",
                       base::Time::Now() - start_time_);
   waiting_for_reply_ = false;
-  client_message_loop_proxy_->PostTask(
+  client_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&Client::OnGetPrinterSemanticCapsAndDefaults, client_.get(),
                  true, printer_name, caps_and_defaults));
@@ -381,7 +379,7 @@
   UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityCapsFailTime",
                       base::Time::Now() - start_time_);
   waiting_for_reply_ = false;
-  client_message_loop_proxy_->PostTask(
+  client_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&Client::OnGetPrinterCapsAndDefaults, client_.get(), false,
                  printer_name, printing::PrinterCapsAndDefaults()));
@@ -394,11 +392,10 @@
   UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilitySemanticCapsFailTime",
                       base::Time::Now() - start_time_);
   waiting_for_reply_ = false;
-  client_message_loop_proxy_->PostTask(
-      FROM_HERE,
-      base::Bind(&Client::OnGetPrinterSemanticCapsAndDefaults,
-                 client_.get(), false, printer_name,
-                 printing::PrinterSemanticCapsAndDefaults()));
+  client_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&Client::OnGetPrinterSemanticCapsAndDefaults,
+                            client_.get(), false, printer_name,
+                            printing::PrinterSemanticCapsAndDefaults()));
 }
 
 bool ServiceUtilityProcessHost::Client::MetafileAvailable(float scale_factor,
diff --git a/chrome/service/service_utility_process_host.h b/chrome/service/service_utility_process_host.h
index a69c7ac..18b561e 100644
--- a/chrome/service/service_utility_process_host.h
+++ b/chrome/service/service_utility_process_host.h
@@ -17,7 +17,6 @@
 class CommandLine;
 class File;
 class FilePath;
-class MessageLoopProxy;
 class ScopedTempDir;
 }  // namespace base
 
@@ -84,7 +83,7 @@
   };
 
   ServiceUtilityProcessHost(Client* client,
-                            base::MessageLoopProxy* client_message_loop_proxy);
+                            base::SingleThreadTaskRunner* client_task_runner);
   ~ServiceUtilityProcessHost() override;
 
   // Starts a process to render the specified pages in the given PDF file into
@@ -146,7 +145,7 @@
   base::Process process_;
   // A pointer to our client interface, who will be informed of progress.
   scoped_refptr<Client> client_;
-  scoped_refptr<base::MessageLoopProxy> client_message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> client_task_runner_;
   bool waiting_for_reply_;
 
   // Start time of operation.
diff --git a/chrome/sync_integration_tests.isolate b/chrome/sync_integration_tests.isolate
index 3ff1056..0b22cf6 100644
--- a/chrome/sync_integration_tests.isolate
+++ b/chrome/sync_integration_tests.isolate
@@ -29,7 +29,6 @@
     ['OS=="linux"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
         ],
       },
@@ -62,7 +61,6 @@
         'files': [
           '<(PRODUCT_DIR)/<(mac_product_name) Framework.framework/',
           '<(PRODUCT_DIR)/<(mac_product_name).app/',
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
         ],
       },
     }],
@@ -71,7 +69,6 @@
         'files': [
           '<(PRODUCT_DIR)/<(mac_product_name) Framework.framework.dSYM/',
           '<(PRODUCT_DIR)/<(mac_product_name).app.dSYM/',
-          '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
         ],
       },
     }],
@@ -79,7 +76,6 @@
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/chrome_elf.dll',
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
         ],
       },
     }],
diff --git a/chrome/telemetry.isolate b/chrome/telemetry.isolate
index e03a496..80775829 100644
--- a/chrome/telemetry.isolate
+++ b/chrome/telemetry.isolate
@@ -28,7 +28,6 @@
           '../third_party/android_testrunner/',
           '../third_party/flot/jquery.flot.min.js',
           '../third_party/webpagereplay/',
-          '../tools/crx_id/',
           '../tools/perf/unit-info.json',
           '../tools/telemetry/',
           '<(PRODUCT_DIR)/bitmaptools<(EXECUTABLE_SUFFIX)',
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockDocumentTabCreatorManager.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockDocumentTabCreatorManager.java
new file mode 100644
index 0000000..1e0fcc1c
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockDocumentTabCreatorManager.java
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.test.util.browser.tabmodel.document;
+
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
+
+/** Mocks out calls to the TabCreatorManager and TabCreators. */
+public class MockDocumentTabCreatorManager implements TabCreatorManager {
+    MockTabDelegate mRegularTabCreator = new MockTabDelegate();
+    MockTabDelegate mIncognitoTabCreator = new MockTabDelegate();
+
+    @Override
+    public MockTabDelegate getTabCreator(boolean incognito) {
+        return incognito ? mIncognitoTabCreator : mRegularTabCreator;
+    }
+}
\ No newline at end of file
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockTabDelegate.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockTabDelegate.java
index 00a132a..c9a8b196 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockTabDelegate.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockTabDelegate.java
@@ -7,9 +7,9 @@
 import android.app.Activity;
 
 import org.chromium.chrome.browser.Tab;
-import org.chromium.chrome.browser.document.PendingDocumentData;
+import org.chromium.chrome.browser.TabState;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.document.ActivityDelegate;
-import org.chromium.chrome.browser.tabmodel.document.DocumentTabModel.Entry;
 import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
@@ -19,26 +19,38 @@
  */
 public class MockTabDelegate implements TabDelegate {
     @Override
-    public Tab getActivityTab(boolean incognito, ActivityDelegate delgate, Activity activity) {
+    public Tab getActivityTab(ActivityDelegate delgate, Activity activity) {
         return null;
     }
 
     @Override
-    public void createTabInForeground(Activity parentActivity, boolean incognito,
-            LoadUrlParams loadUrlParams, PendingDocumentData documentParams) {
-    }
-
-    @Override
-    public Tab createFrozenTab(Entry entry) {
+    public Tab createNewTab(LoadUrlParams loadUrlParams, TabLaunchType type, Tab parent) {
         return null;
     }
 
     @Override
-    public void createTabWithWebContents(boolean isIncognito, WebContents webContents,
-            int parentTabId) {
+    public Tab createFrozenTab(TabState state, int id, int index) {
+        return null;
     }
 
     @Override
-    public void createTabForDevTools(String url) {
+    public Tab createTabWithWebContents(WebContents webContents, int parentId, TabLaunchType type) {
+        return null;
+    }
+
+    @Override
+    public Tab createTabWithWebContents(
+            WebContents webContents, int parentId, TabLaunchType type, int startedBy) {
+        return null;
+    }
+
+    @Override
+    public Tab launchUrl(String url, TabLaunchType type) {
+        return null;
+    }
+
+    @Override
+    public Tab launchNTP() {
+        return null;
     }
 }
\ No newline at end of file
diff --git a/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java b/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java
index 8c5d6b4d1..892ee908 100644
--- a/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java
+++ b/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java
@@ -18,7 +18,6 @@
 import android.provider.Browser;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.KeyEvent;
 import android.view.View;
 import android.widget.ListView;
 
@@ -37,7 +36,6 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.DeferredStartupHandler;
-import org.chromium.chrome.browser.EmptyTabObserver;
 import org.chromium.chrome.browser.Tab;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
 import org.chromium.chrome.browser.document.DocumentActivity;
@@ -68,13 +66,11 @@
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.MenuUtils;
 import org.chromium.chrome.test.util.NewTabPageTestUtils;
-import org.chromium.chrome.test.util.OmniboxTestUtils;
 import org.chromium.chrome.test.util.TestHttpServerClient;
 import org.chromium.content.browser.test.util.CallbackHelper;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.JavaScriptUtils;
-import org.chromium.content.browser.test.util.KeyUtils;
 import org.chromium.content.browser.test.util.RenderProcessLimit;
 import org.chromium.content.browser.test.util.TestTouchUtils;
 import org.chromium.content.browser.test.util.TouchCommon;
@@ -90,7 +86,6 @@
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -118,6 +113,8 @@
 
     private static final long OMNIBOX_FIND_SUGGESTION_TIMEOUT_MS = 10 * 1000;
 
+    private static final float FLOAT_EPSILON = 0.001f;
+
     public ChromeActivityTestCaseBase(Class<T> activityClass) {
         super(activityClass);
     }
@@ -692,67 +689,6 @@
     }
 
     /**
-     * Types the passed text in the omnibox to trigger a navigation. You can pass a URL or a search
-     * term.
-     * <p>
-     * Note that this code triggers suggestions and prerendering.  Unless you are testing these
-     * features specifically, you should use loadUrl() which is less prone to flakyness.
-     * @param url The Url to navigate to.
-     * @return the url in the UrlBar.
-     * @throws InterruptedException
-     */
-    public String typeInOmniboxAndNavigate(final String url) throws InterruptedException {
-        final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
-        assertNotNull("urlBar is null", urlBar);
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                urlBar.requestFocus();
-                urlBar.setText(url);
-            }
-        });
-        final LocationBarLayout locationBar =
-                (LocationBarLayout) getActivity().findViewById(R.id.location_bar);
-        assertTrue("Omnibox Suggestions never shown.",
-                OmniboxTestUtils.waitForOmniboxSuggestions(locationBar));
-
-        Tab currentTab = getActivity().getActivityTab();
-        final CallbackHelper loadedCallback = new CallbackHelper();
-        final AtomicBoolean tabCrashReceived = new AtomicBoolean();
-        currentTab.addObserver(new EmptyTabObserver() {
-            @Override
-            public void onPageLoadFinished(Tab tab) {
-                loadedCallback.notifyCalled();
-                tab.removeObserver(this);
-            }
-
-            @Override
-            public void onCrash(Tab tab, boolean sadTabShown) {
-                tabCrashReceived.set(true);
-                tab.removeObserver(this);
-            }
-        });
-
-        // Loads the url.
-        KeyUtils.singleKeyEventView(getInstrumentation(), urlBar, KeyEvent.KEYCODE_ENTER);
-
-        boolean pageLoadReceived = true;
-        try {
-            loadedCallback.waitForCallback(0);
-        } catch (TimeoutException ex) {
-            pageLoadReceived = false;
-        }
-
-        assertTrue("Neither PAGE_LOAD_FINISHED nor a TAB_CRASHED event was received",
-                pageLoadReceived || tabCrashReceived.get());
-        getInstrumentation().waitForIdleSync();
-
-        // The title has been set before the page notification was broadcast, so it is safe to
-        // access the title.
-        return urlBar.getText().toString();
-    }
-
-    /**
      * Looks up the Omnibox in the view hierarchy and types the specified
      * text into it, requesting focus and using an inter-character delay of
      * 200ms.
@@ -941,8 +877,8 @@
         boolean scaleFactorMatch = CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                return getActivity().getCurrentContentViewCore().getScale()
-                        == expectedScale;
+                return Math.abs(getActivity().getCurrentContentViewCore().getScale()
+                        - expectedScale) < FLOAT_EPSILON;
             }
         });
         assertTrue("Expecting scale factor of: " + expectedScale + ", got: "
diff --git a/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/MultiActivityTestBase.java b/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/MultiActivityTestBase.java
index 18859fc..f659e6e 100644
--- a/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/MultiActivityTestBase.java
+++ b/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/MultiActivityTestBase.java
@@ -63,6 +63,13 @@
     /** Finishes all tasks Chrome has listed in Android's Overview. */
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     private static void finishAllChromeTasks(final Context context) throws Exception {
+        // Go to the Home screen so that Android has no good reason to keep Chrome Activities alive.
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+        homeIntent.addCategory(Intent.CATEGORY_HOME);
+        homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(homeIntent);
+
+        // Close all of the tasks one by one.
         ActivityManager activityManager =
                 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
         for (ActivityManager.AppTask task : activityManager.getAppTasks()) {
diff --git a/chrome/test/base/browser_with_test_window_test.cc b/chrome/test/base/browser_with_test_window_test.cc
index 245c9b9b..b9e4203 100644
--- a/chrome/test/base/browser_with_test_window_test.cc
+++ b/chrome/test/base/browser_with_test_window_test.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/test/base/browser_with_test_window_test.h"
 
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/profiles/profile_destroyer.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_navigator.h"
@@ -117,8 +120,8 @@
 
   // A Task is leaked if we don't destroy everything, then run the message
   // loop.
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::MessageLoop::QuitClosure());
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::MessageLoop::QuitClosure());
   base::MessageLoop::current()->Run();
 
 #if defined(TOOLKIT_VIEWS)
diff --git a/chrome/test/base/chrome_render_view_host_test_harness.cc b/chrome/test/base/chrome_render_view_host_test_harness.cc
index ca3dce92..098403e 100644
--- a/chrome/test/base/chrome_render_view_host_test_harness.cc
+++ b/chrome/test/base/chrome_render_view_host_test_harness.cc
@@ -22,6 +22,26 @@
 using content::RenderViewHostTester;
 using content::RenderViewHostTestHarness;
 
+namespace {
+
+scoped_ptr<KeyedService> BuildSigninManagerFake(
+    content::BrowserContext* context) {
+  Profile* profile = static_cast<Profile*>(context);
+#if defined (OS_CHROMEOS)
+  scoped_ptr<SigninManagerBase> signin(new SigninManagerBase(
+      ChromeSigninClientFactory::GetInstance()->GetForProfile(profile),
+      AccountTrackerServiceFactory::GetInstance()->GetForProfile(profile)));
+  signin->Initialize(NULL);
+  return signin.Pass();
+#else
+  scoped_ptr<FakeSigninManager> manager(new FakeSigninManager(profile));
+  manager->Initialize(g_browser_process->local_state());
+  return manager.Pass();
+#endif
+}
+
+}  // namespace
+
 ChromeRenderViewHostTestHarness::ChromeRenderViewHostTestHarness() {
 }
 
@@ -32,21 +52,6 @@
   return static_cast<TestingProfile*>(browser_context());
 }
 
-static KeyedService* BuildSigninManagerFake(content::BrowserContext* context) {
-  Profile* profile = static_cast<Profile*>(context);
-#if defined (OS_CHROMEOS)
-  SigninManagerBase* signin = new SigninManagerBase(
-      ChromeSigninClientFactory::GetInstance()->GetForProfile(profile),
-      AccountTrackerServiceFactory::GetInstance()->GetForProfile(profile));
-  signin->Initialize(NULL);
-  return signin;
-#else
-  FakeSigninManager* manager = new FakeSigninManager(profile);
-  manager->Initialize(g_browser_process->local_state());
-  return manager;
-#endif
-}
-
 void ChromeRenderViewHostTestHarness::TearDown() {
   RenderViewHostTestHarness::TearDown();
 #if defined(USE_ASH)
diff --git a/chrome/test/base/chrome_test_suite.cc b/chrome/test/base/chrome_test_suite.cc
index a2258b5d..933d6a0 100644
--- a/chrome/test/base/chrome_test_suite.cc
+++ b/chrome/test/base/chrome_test_suite.cc
@@ -82,7 +82,7 @@
   // ChromeOS.  That means we are autotest and, if ASAN is used,
   // external libraries load crashes.
   if (!IsCrosPythonProcess())
-    media::InitializeMediaLibraryForTesting();
+    media::InitializeMediaLibrary();
 #endif
 
   // Initialize after overriding paths as some content paths depend on correct
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index 8c09bcc..cb63fb1 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -11,9 +11,12 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/test_file_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/non_thread_safe.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
@@ -576,8 +579,8 @@
   // Invoke AttemptExit on a running message loop.
   // AttemptExit exits the message loop after everything has been
   // shut down properly.
-  base::MessageLoopForUI::current()->PostTask(FROM_HERE,
-                                              base::Bind(&chrome::AttemptExit));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&chrome::AttemptExit));
   content::RunMessageLoop();
 
 #if defined(OS_MACOSX)
diff --git a/chrome/test/base/testing_io_thread_state.cc b/chrome/test/base/testing_io_thread_state.cc
index 30b90698..8ebd202b8 100644
--- a/chrome/test/base/testing_io_thread_state.cc
+++ b/chrome/test/base/testing_io_thread_state.cc
@@ -4,8 +4,10 @@
 
 #include "chrome/test/base/testing_io_thread_state.h"
 
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/tick_clock.h"
 #include "chrome/browser/io_thread.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -26,9 +28,8 @@
   } else {
     using base::Bind;
     using base::IgnoreResult;
-    return Bind(IgnoreResult(&base::MessageLoopProxy::PostTask),
-                base::MessageLoopProxy::current(),
-                FROM_HERE,
+    return Bind(IgnoreResult(&base::SingleThreadTaskRunner::PostTask),
+                base::ThreadTaskRunnerHandle::Get(), FROM_HERE,
                 run_loop->QuitClosure());
   }
 }
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index ad46abcb..01e7603 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -7,11 +7,13 @@
 #include "base/base_paths.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/path_service.h"
 #include "base/prefs/testing_pref_store.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
 #include "chrome/browser/autocomplete/in_memory_url_index.h"
 #include "chrome/browser/autocomplete/in_memory_url_index_factory.h"
@@ -21,7 +23,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/favicon/chrome_fallback_icon_client_factory.h"
-#include "chrome/browser/favicon/chrome_favicon_client_factory.h"
 #include "chrome/browser/favicon/fallback_icon_service_factory.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/chrome_history_client.h"
@@ -101,6 +102,7 @@
 #include "chrome/browser/extensions/test_extension_system.h"
 #include "components/guest_view/browser/guest_view_manager.h"
 #include "extensions/browser/event_router_factory.h"
+#include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_prefs_factory.h"
 #include "extensions/browser/extension_system.h"
 #endif
@@ -179,65 +181,60 @@
 };
 
 #if defined(ENABLE_NOTIFICATIONS)
-KeyedService* CreateTestDesktopNotificationService(
+scoped_ptr<KeyedService> CreateTestDesktopNotificationService(
     content::BrowserContext* profile) {
-  return new DesktopNotificationService(static_cast<Profile*>(profile));
+  return make_scoped_ptr(
+      new DesktopNotificationService(static_cast<Profile*>(profile)));
 }
 #endif
 
-KeyedService* BuildFaviconService(content::BrowserContext* context) {
+scoped_ptr<KeyedService> BuildHistoryService(content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
-  return new favicon::FaviconService(
-      ChromeFaviconClientFactory::GetForProfile(profile),
-      HistoryServiceFactory::GetForProfile(profile,
-                                           ServiceAccessType::EXPLICIT_ACCESS));
-}
-
-KeyedService* BuildHistoryService(content::BrowserContext* context) {
-  Profile* profile = Profile::FromBrowserContext(context);
-  history::HistoryService* history_service = new history::HistoryService(
+  return make_scoped_ptr(new history::HistoryService(
       ChromeHistoryClientFactory::GetForProfile(profile),
       scoped_ptr<history::VisitDelegate>(
-          new history::ContentVisitDelegate(profile)));
-  return history_service;
+          new history::ContentVisitDelegate(profile))));
 }
 
-KeyedService* BuildInMemoryURLIndex(content::BrowserContext* context) {
+scoped_ptr<KeyedService> BuildInMemoryURLIndex(
+    content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
-  InMemoryURLIndex* in_memory_url_index = new InMemoryURLIndex(
+  scoped_ptr<InMemoryURLIndex> in_memory_url_index(new InMemoryURLIndex(
       BookmarkModelFactory::GetForProfile(profile),
       HistoryServiceFactory::GetForProfile(profile,
                                            ServiceAccessType::IMPLICIT_ACCESS),
       profile->GetPath(),
-      profile->GetPrefs()->GetString(prefs::kAcceptLanguages));
+      profile->GetPrefs()->GetString(prefs::kAcceptLanguages)));
   in_memory_url_index->Init();
-  return in_memory_url_index;
+  return in_memory_url_index.Pass();
 }
 
-KeyedService* BuildBookmarkModel(content::BrowserContext* context) {
+scoped_ptr<KeyedService> BuildBookmarkModel(content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
   ChromeBookmarkClient* bookmark_client =
       ChromeBookmarkClientFactory::GetForProfile(profile);
-  BookmarkModel* bookmark_model = new BookmarkModel(bookmark_client);
-  bookmark_client->Init(bookmark_model);
+  scoped_ptr<BookmarkModel> bookmark_model(new BookmarkModel(bookmark_client));
+  bookmark_client->Init(bookmark_model.get());
   bookmark_model->Load(profile->GetPrefs(),
                        profile->GetPrefs()->GetString(prefs::kAcceptLanguages),
                        profile->GetPath(),
                        profile->GetIOTaskRunner(),
                        content::BrowserThread::GetMessageLoopProxyForThread(
                            content::BrowserThread::UI));
-  return bookmark_model;
+  return bookmark_model.Pass();
 }
 
-KeyedService* BuildChromeBookmarkClient(
+scoped_ptr<KeyedService> BuildChromeBookmarkClient(
     content::BrowserContext* context) {
-  return new ChromeBookmarkClient(static_cast<Profile*>(context));
+  return make_scoped_ptr(
+      new ChromeBookmarkClient(static_cast<Profile*>(context)));
 }
 
-KeyedService* BuildChromeHistoryClient(
+scoped_ptr<KeyedService> BuildChromeHistoryClient(
     content::BrowserContext* context) {
   Profile* profile = static_cast<Profile*>(context);
-  return new ChromeHistoryClient(BookmarkModelFactory::GetForProfile(profile));
+  return make_scoped_ptr(
+      new ChromeHistoryClient(BookmarkModelFactory::GetForProfile(profile)));
 }
 
 void TestProfileErrorCallback(WebDataServiceWrapper::ErrorType error_type,
@@ -245,14 +242,14 @@
   NOTREACHED();
 }
 
-KeyedService* BuildWebDataService(content::BrowserContext* context) {
+scoped_ptr<KeyedService> BuildWebDataService(content::BrowserContext* context) {
   const base::FilePath& context_path = context->GetPath();
-  return new WebDataServiceWrapper(
+  return make_scoped_ptr(new WebDataServiceWrapper(
       context_path, g_browser_process->GetApplicationLocale(),
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB),
       sync_start_util::GetFlareForSyncableService(context_path),
-      &TestProfileErrorCallback);
+      &TestProfileErrorCallback));
 }
 
 }  // namespace
@@ -315,7 +312,7 @@
       delegate_(delegate) {
   Init();
   if (delegate_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&TestingProfile::FinishInit, base::Unretained(this)));
   } else {
@@ -372,7 +369,7 @@
   // TODO(atwilson): See if this is still required once we convert the current
   // users of the constructor that takes a Delegate* param.
   if (delegate_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&TestingProfile::FinishInit, base::Unretained(this)));
   } else {
@@ -452,11 +449,11 @@
   extensions::TestExtensionSystem* test_extension_system =
       static_cast<extensions::TestExtensionSystem*>(
           extensions::ExtensionSystem::Get(this));
-  extensions::ExtensionPrefs* extension_prefs =
+  scoped_ptr<extensions::ExtensionPrefs> extension_prefs =
       test_extension_system->CreateExtensionPrefs(
           base::CommandLine::ForCurrentProcess(), extensions_path_);
   extensions::ExtensionPrefsFactory::GetInstance()->SetInstanceForTesting(
-      this, extension_prefs);
+      this, extension_prefs.Pass());
 
   extensions::EventRouterFactory::GetInstance()->SetTestingFactory(this,
                                                                    nullptr);
@@ -542,7 +539,7 @@
 void TestingProfile::CreateFaviconService() {
   // It is up to the caller to create the history service if one is needed.
   FaviconServiceFactory::GetInstance()->SetTestingFactory(
-      this, BuildFaviconService);
+      this, FaviconServiceFactory::GetDefaultFactory());
 }
 
 bool TestingProfile::CreateHistoryService(bool delete_file, bool no_db) {
@@ -592,8 +589,8 @@
 
   // Make sure we don't have any event pending that could disrupt the next
   // test.
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::MessageLoop::QuitClosure());
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::MessageLoop::QuitClosure());
   base::MessageLoop::current()->Run();
 }
 
@@ -650,7 +647,7 @@
 }
 
 scoped_refptr<base::SequencedTaskRunner> TestingProfile::GetIOTaskRunner() {
-  return base::MessageLoop::current()->message_loop_proxy();
+  return base::MessageLoop::current()->task_runner();
 }
 
 TestingPrefServiceSyncable* TestingProfile::GetTestingPrefService() {
diff --git a/chrome/test/base/tracing_browsertest.cc b/chrome/test/base/tracing_browsertest.cc
index e6128a3..3ebc610 100644
--- a/chrome/test/base/tracing_browsertest.cc
+++ b/chrome/test/base/tracing_browsertest.cc
@@ -4,8 +4,10 @@
 
 #include "chrome/test/base/tracing.h"
 
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -56,7 +58,8 @@
 
   // One event after wait.
   ASSERT_TRUE(BeginTracingWithWatch(g_category, g_category, g_event, 1));
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&AddEvents, 1));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(&AddEvents, 1));
   EXPECT_TRUE(WaitForWatchEvent(no_timeout));
   ASSERT_TRUE(EndTracing(&json_events));
 
@@ -74,7 +77,8 @@
 
   // Multi event after wait.
   ASSERT_TRUE(BeginTracingWithWatch(g_category, g_category, g_event, 5));
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&AddEvents, 5));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(&AddEvents, 5));
   EXPECT_TRUE(WaitForWatchEvent(no_timeout));
   ASSERT_TRUE(EndTracing(&json_events));
 
diff --git a/chrome/test/base/view_event_test_base.cc b/chrome/test/base/view_event_test_base.cc
index 0b007a3..1262582 100644
--- a/chrome/test/base/view_event_test_base.cc
+++ b/chrome/test/base/view_event_test_base.cc
@@ -5,7 +5,9 @@
 #include "chrome/test/base/view_event_test_base.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/test/base/chrome_unit_test_suite.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -68,7 +70,6 @@
 }
 
 void ViewEventTestBase::SetUp() {
-  views::ViewsDelegate::views_delegate = &views_delegate_;
   ui::InitializeInputMethodForTesting();
 
   // The ContextFactory must exist before any Compositors are created.
@@ -97,7 +98,6 @@
   ui::TerminateContextFactoryForTests();
 
   ui::ShutdownInputMethodForTesting();
-  views::ViewsDelegate::views_delegate = NULL;
 }
 
 bool ViewEventTestBase::CanResize() const {
@@ -137,7 +137,7 @@
 
   // Schedule a task that starts the test. Need to do this as we're going to
   // run the message loop.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&ViewEventTestBase::DoTestOnMessageLoop, this));
 
   content::RunThisRunLoop(&run_loop_);
@@ -152,7 +152,7 @@
     dnd_thread_.reset(new base::Thread("mouse-move-thread"));
     dnd_thread_->Start();
   }
-  dnd_thread_->message_loop()->PostDelayedTask(
+  dnd_thread_->task_runner()->PostDelayedTask(
       FROM_HERE,
       base::Bind(base::IgnoreResult(&ui_controls::SendMouseMove), x, y),
       base::TimeDelta::FromMilliseconds(kMouseMoveDelayMS));
diff --git a/chrome/test/chromedriver/chrome/adb_impl.h b/chrome/test/chromedriver/chrome/adb_impl.h
index 895bd789..5f82dd3 100644
--- a/chrome/test/chromedriver/chrome/adb_impl.h
+++ b/chrome/test/chromedriver/chrome/adb_impl.h
@@ -21,7 +21,7 @@
 class AdbImpl : public Adb {
  public:
   explicit AdbImpl(
-      const scoped_refptr<base::SingleThreadTaskRunner>& io_message_loop_proxy,
+      const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
       int port);
   ~AdbImpl() override;
 
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.cc b/chrome/test/chromedriver/chrome/web_view_impl.cc
index 93be27e..576bea2 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.cc
+++ b/chrome/test/chromedriver/chrome/web_view_impl.cc
@@ -155,7 +155,7 @@
 Status WebViewImpl::Load(const std::string& url) {
   // Javascript URLs will cause a hang while waiting for the page to stop
   // loading, so just disallow.
-  if (StartsWithASCII(url, "javascript:", false))
+  if (base::StartsWithASCII(url, "javascript:", false))
     return Status(kUnknownError, "unsupported protocol");
   base::DictionaryValue params;
   params.SetString("url", url);
diff --git a/chrome/test/chromedriver/commands.cc b/chrome/test/chromedriver/commands.cc
index 2a9b794b..667d5e99 100644
--- a/chrome/test/chromedriver/commands.cc
+++ b/chrome/test/chromedriver/commands.cc
@@ -10,13 +10,15 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/linked_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_info.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/test/chromedriver/capabilities.h"
 #include "chrome/test/chromedriver/chrome/browser_info.h"
@@ -65,7 +67,7 @@
     return;
   }
 
-  thread->message_loop()->PostTask(
+  thread->task_runner()->PostTask(
       FROM_HERE, base::Bind(&SetThreadLocalSession, base::Passed(&session)));
   session_thread_map
       ->insert(std::make_pair(new_id, make_linked_ptr(thread.release())));
@@ -126,10 +128,8 @@
                                                run_loop.QuitClosure(),
                                                session_list.get()));
   }
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      run_loop.QuitClosure(),
-      base::TimeDelta::FromSeconds(10));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(10));
   base::MessageLoop::current()->SetNestableTasksAllowed(true);
   run_loop.Run();
 
@@ -176,7 +176,7 @@
                                 weak_ptr_factory.GetWeakPtr(),
                                 run_loop.QuitClosure()));
   }
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(10));
   // Uses a nested run loop to block this thread until all the quit
   // commands have executed, or the timeout expires.
@@ -303,18 +303,13 @@
     Status status(return_ok_without_session ? kOk : kNoSuchSession);
     callback.Run(status, scoped_ptr<base::Value>(), session_id);
   } else {
-    iter->second->message_loop()
-        ->PostTask(FROM_HERE,
-                   base::Bind(&ExecuteSessionCommandOnSessionThread,
-                              command_name,
-                              command,
-                              return_ok_without_session,
+    iter->second->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ExecuteSessionCommandOnSessionThread,
+                              command_name, command, return_ok_without_session,
                               base::Passed(make_scoped_ptr(params.DeepCopy())),
-                              base::MessageLoopProxy::current(),
-                              callback,
+                              base::ThreadTaskRunnerHandle::Get(), callback,
                               base::Bind(&TerminateSessionThreadOnCommandThread,
-                                         session_thread_map,
-                                         session_id)));
+                                         session_thread_map, session_id)));
   }
 }
 
diff --git a/chrome/test/chromedriver/commands_unittest.cc b/chrome/test/chromedriver/commands_unittest.cc
index b5320c2..a0e0a5e 100644
--- a/chrome/test/chromedriver/commands_unittest.cc
+++ b/chrome/test/chromedriver/commands_unittest.cc
@@ -8,9 +8,10 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
 #include "base/values.h"
@@ -218,7 +219,7 @@
   linked_ptr<base::Thread> thread(new base::Thread("1"));
   ASSERT_TRUE(thread->Start());
   std::string id("id");
-  thread->message_loop()->PostTask(
+  thread->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&internal::CreateSessionOnSessionThreadForTesting, id));
   map[id] = thread;
@@ -700,7 +701,7 @@
   linked_ptr<base::Thread> thread(new base::Thread("1"));
   ASSERT_TRUE(thread->Start());
   std::string id("id");
-  thread->message_loop()->PostTask(
+  thread->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&internal::CreateSessionOnSessionThreadForTesting, id));
 
@@ -789,7 +790,7 @@
   linked_ptr<base::Thread> thread(new base::Thread("1"));
   ASSERT_TRUE(thread->Start());
   std::string id("id");
-  thread->message_loop()->PostTask(
+  thread->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&internal::CreateSessionOnSessionThreadForTesting, id));
   map[id] = thread;
@@ -798,9 +799,8 @@
   // was called before (as opposed to after) command execution. We don't need to
   // verify this again, so we can just add |listener| with PostTask.
   CommandListener* listener = new FailingCommandListener();
-  thread->message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&AddListenerToSessionIfSessionExists, listener));
+  thread->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&AddListenerToSessionIfSessionExists, listener));
 
   base::DictionaryValue params;
   // The command should never be executed if BeforeCommand fails for a listener.
@@ -818,7 +818,6 @@
       base::Bind(&OnFailBecauseErrorNotifyingListeners, &run_loop));
   run_loop.Run();
 
-  thread->message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&VerifySessionWasDeleted));
+  thread->task_runner()->PostTask(FROM_HERE,
+                                  base::Bind(&VerifySessionWasDeleted));
 }
diff --git a/chrome/test/chromedriver/element_util.cc b/chrome/test/chromedriver/element_util.cc
index e8714d3..6a3ee19 100644
--- a/chrome/test/chromedriver/element_util.cc
+++ b/chrome/test/chromedriver/element_util.cc
@@ -337,10 +337,12 @@
   if (status.IsError())
     return status;
   std::string actual_value;
-  if (result->GetAsString(&actual_value))
-    *is_equal = LowerCaseEqualsASCII(actual_value, attribute_value.c_str());
-  else
+  if (result->GetAsString(&actual_value)) {
+    *is_equal =
+        base::LowerCaseEqualsASCII(actual_value, attribute_value.c_str());
+  } else {
     *is_equal = false;
+  }
   return status;
 }
 
diff --git a/chrome/test/chromedriver/net/net_util_unittest.cc b/chrome/test/chromedriver/net/net_util_unittest.cc
index f0c3534..b976373 100644
--- a/chrome/test/chromedriver/net/net_util_unittest.cc
+++ b/chrome/test/chromedriver/net/net_util_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
@@ -34,22 +33,19 @@
         response_(kSendHello) {
     base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
     CHECK(io_thread_.StartWithOptions(options));
-    context_getter_ = new URLRequestContextGetter(
-        io_thread_.message_loop_proxy());
+    context_getter_ = new URLRequestContextGetter(io_thread_.task_runner());
     base::WaitableEvent event(false, false);
-    io_thread_.message_loop_proxy()->PostTask(
+    io_thread_.task_runner()->PostTask(
         FROM_HERE,
-        base::Bind(&FetchUrlTest::InitOnIO,
-                   base::Unretained(this), &event));
+        base::Bind(&FetchUrlTest::InitOnIO, base::Unretained(this), &event));
     event.Wait();
   }
 
   ~FetchUrlTest() override {
     base::WaitableEvent event(false, false);
-    io_thread_.message_loop_proxy()->PostTask(
-        FROM_HERE,
-        base::Bind(&FetchUrlTest::DestroyServerOnIO,
-                   base::Unretained(this), &event));
+    io_thread_.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&FetchUrlTest::DestroyServerOnIO,
+                              base::Unretained(this), &event));
     event.Wait();
   }
 
diff --git a/chrome/test/chromedriver/net/port_server_unittest.cc b/chrome/test/chromedriver/net/port_server_unittest.cc
index c9b88c8..d711710 100644
--- a/chrome/test/chromedriver/net/port_server_unittest.cc
+++ b/chrome/test/chromedriver/net/port_server_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/guid.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/sync_socket.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
@@ -124,10 +124,9 @@
                  const std::string& response,
                  std::string* request) {
     base::WaitableEvent listen_event(false, false);
-    thread_.message_loop()->PostTask(
+    thread_.task_runner()->PostTask(
         FROM_HERE,
-        base::Bind(
-            &RunServerOnThread, path, response, &listen_event, request));
+        base::Bind(&RunServerOnThread, path, response, &listen_event, request));
     ASSERT_TRUE(listen_event.TimedWait(base::TimeDelta::FromSeconds(5)));
   }
 
diff --git a/chrome/test/chromedriver/net/sync_websocket_impl_unittest.cc b/chrome/test/chromedriver/net/sync_websocket_impl_unittest.cc
index 28b808a..b7d27b57 100644
--- a/chrome/test/chromedriver/net/sync_websocket_impl_unittest.cc
+++ b/chrome/test/chromedriver/net/sync_websocket_impl_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
@@ -30,8 +29,7 @@
   void SetUp() override {
     base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
     ASSERT_TRUE(client_thread_.StartWithOptions(options));
-    context_getter_ = new URLRequestContextGetter(
-        client_thread_.message_loop_proxy());
+    context_getter_ = new URLRequestContextGetter(client_thread_.task_runner());
     ASSERT_TRUE(server_.Start());
   }
 
diff --git a/chrome/test/chromedriver/net/test_http_server.cc b/chrome/test/chromedriver/net/test_http_server.cc
index 6b8a4bc..a3d8e38 100644
--- a/chrome/test/chromedriver/net/test_http_server.cc
+++ b/chrome/test/chromedriver/net/test_http_server.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "net/base/ip_endpoint.h"
@@ -36,10 +36,9 @@
     return false;
   bool success;
   base::WaitableEvent event(false, false);
-  thread_.message_loop_proxy()->PostTask(
-      FROM_HERE,
-      base::Bind(&TestHttpServer::StartOnServerThread,
-                 base::Unretained(this), &success, &event));
+  thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&TestHttpServer::StartOnServerThread,
+                            base::Unretained(this), &success, &event));
   event.Wait();
   return success;
 }
@@ -48,10 +47,9 @@
   if (!thread_.IsRunning())
     return;
   base::WaitableEvent event(false, false);
-  thread_.message_loop_proxy()->PostTask(
-      FROM_HERE,
-      base::Bind(&TestHttpServer::StopOnServerThread,
-                 base::Unretained(this), &event));
+  thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&TestHttpServer::StopOnServerThread,
+                            base::Unretained(this), &event));
   event.Wait();
   thread_.Stop();
 }
diff --git a/chrome/test/chromedriver/net/websocket_unittest.cc b/chrome/test/chromedriver/net/websocket_unittest.cc
index 835b240..2922c7f 100644
--- a/chrome/test/chromedriver/net/websocket_unittest.cc
+++ b/chrome/test/chromedriver/net/websocket_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
@@ -31,7 +30,7 @@
 
 void RunPending(base::MessageLoop* loop) {
   base::RunLoop run_loop;
-  loop->PostTask(FROM_HERE, run_loop.QuitClosure());
+  loop->task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure());
   run_loop.Run();
 }
 
@@ -92,9 +91,8 @@
     scoped_ptr<WebSocket> sock(new WebSocket(url, listener));
     base::RunLoop run_loop;
     sock->Connect(base::Bind(&OnConnectFinished, &run_loop, &error));
-    loop_.PostDelayedTask(
-        FROM_HERE, run_loop.QuitClosure(),
-        base::TimeDelta::FromSeconds(10));
+    loop_.task_runner()->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
+                                         base::TimeDelta::FromSeconds(10));
     run_loop.Run();
     if (error == net::OK)
       return sock.Pass();
@@ -113,9 +111,8 @@
       ASSERT_TRUE(sock->Send(messages[i]));
     }
     base::RunLoop run_loop;
-    loop_.PostDelayedTask(
-        FROM_HERE, run_loop.QuitClosure(),
-        base::TimeDelta::FromSeconds(10));
+    loop_.task_runner()->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
+                                         base::TimeDelta::FromSeconds(10));
     run_loop.Run();
   }
 
@@ -163,9 +160,8 @@
   scoped_ptr<WebSocket> sock(CreateConnectedWebSocket(&listener));
   ASSERT_TRUE(sock);
   ASSERT_TRUE(sock->Send("hi"));
-  loop_.PostDelayedTask(
-      FROM_HERE, run_loop.QuitClosure(),
-      base::TimeDelta::FromSeconds(10));
+  loop_.task_runner()->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
+                                       base::TimeDelta::FromSeconds(10));
   run_loop.Run();
 }
 
@@ -177,9 +173,8 @@
   server_.Stop();
 
   sock->Send("hi");
-  loop_.PostDelayedTask(
-      FROM_HERE, run_loop.QuitClosure(),
-      base::TimeDelta::FromSeconds(10));
+  loop_.task_runner()->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
+                                       base::TimeDelta::FromSeconds(10));
   run_loop.Run();
   ASSERT_FALSE(sock->Send("hi"));
 }
diff --git a/chrome/test/chromedriver/performance_logger.cc b/chrome/test/chromedriver/performance_logger.cc
index 800e8ec..2dceef9 100644
--- a/chrome/test/chromedriver/performance_logger.cc
+++ b/chrome/test/chromedriver/performance_logger.cc
@@ -52,7 +52,8 @@
 // Returns whether the event belongs to one of kDomains.
 bool ShouldLogEvent(const std::string& method) {
   for (size_t i_domain = 0; i_domain < arraysize(kDomains); ++i_domain) {
-    if (StartsWithASCII(method, kDomains[i_domain], true /* case_sensitive */))
+    if (base::StartsWithASCII(method, kDomains[i_domain],
+                              true /* case_sensitive */))
       return true;
   }
   return false;
diff --git a/chrome/test/chromedriver/server/chromedriver_server.cc b/chrome/test/chromedriver/server/chromedriver_server.cc
index 2d73020..4782eb6 100644
--- a/chrome/test/chromedriver/server/chromedriver_server.cc
+++ b/chrome/test/chromedriver/server/chromedriver_server.cc
@@ -22,6 +22,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_local.h"
 #include "chrome/test/chromedriver/logging.h"
@@ -136,12 +137,10 @@
     const net::HttpServerRequestInfo& request,
     const HttpResponseSenderFunc& send_response_func) {
   cmd_task_runner->PostTask(
-      FROM_HERE,
-      base::Bind(handle_request_on_cmd_func,
-                 request,
-                 base::Bind(&SendResponseOnCmdThread,
-                            base::MessageLoopProxy::current(),
-                            send_response_func)));
+      FROM_HERE, base::Bind(handle_request_on_cmd_func, request,
+                            base::Bind(&SendResponseOnCmdThread,
+                                       base::ThreadTaskRunnerHandle::Get(),
+                                       send_response_func)));
 }
 
 base::LazyInstance<base::ThreadLocalPointer<HttpServer> >
@@ -177,22 +176,16 @@
 
   base::MessageLoop cmd_loop;
   base::RunLoop cmd_run_loop;
-  HttpHandler handler(cmd_run_loop.QuitClosure(),
-                      io_thread.message_loop_proxy(),
-                      url_base,
-                      adb_port,
-                      port_server.Pass());
+  HttpHandler handler(cmd_run_loop.QuitClosure(), io_thread.task_runner(),
+                      url_base, adb_port, port_server.Pass());
   HttpRequestHandlerFunc handle_request_func =
       base::Bind(&HandleRequestOnCmdThread, &handler, whitelisted_ips);
 
-  io_thread.message_loop()
-      ->PostTask(FROM_HERE,
-                 base::Bind(&StartServerOnIOThread,
-                            port,
-                            allow_remote,
-                            base::Bind(&HandleRequestOnIOThread,
-                                       cmd_loop.message_loop_proxy(),
-                                       handle_request_func)));
+  io_thread.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&StartServerOnIOThread, port, allow_remote,
+                 base::Bind(&HandleRequestOnIOThread, cmd_loop.task_runner(),
+                            handle_request_func)));
   // Run the command loop. This loop is quit after the response for a shutdown
   // request is posted to the IO loop. After the command loop quits, a task
   // is posted to the IO loop to stop the server. Lastly, the IO thread is
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index 78b2cc0a..77bed02 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -11,11 +11,11 @@
 #include "base/logging.h"  // For CHECK macros.
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_info.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/test/chromedriver/alert_commands.h"
 #include "chrome/test/chromedriver/chrome/adb_impl.h"
@@ -580,7 +580,7 @@
     return;
 
   std::string path = request.path;
-  if (!StartsWithASCII(path, url_base_, true)) {
+  if (!base::StartsWithASCII(path, url_base_, true)) {
     scoped_ptr<net::HttpServerResponseInfo> response(
         new net::HttpServerResponseInfo(net::HTTP_BAD_REQUEST));
     response->SetBody("unhandled request", "text/plain");
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index 5c56d827d8..99f5f028 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -11,9 +11,9 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"  // For CHECK macros.
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/test/chromedriver/basic_types.h"
 #include "chrome/test/chromedriver/capabilities.h"
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 9b0c008..9d9258e 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -142,6 +142,8 @@
         'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly',
         # Android doesn't support multiple sessions on one device.
         'SessionHandlingTest.testGetSessions',
+        # Android doesn't use the chrome://print dialog.
+        'ChromeDriverTest.testCanSwitchToPrintPreviewDialog',
     ]
 )
 _ANDROID_NEGATIVE_FILTER['chrome_stable'] = (
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 8866cda..3446457 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -183,7 +183,7 @@
     'ClickTest.testCanClickOnALinkThatContainsEmbeddedBlockElements',
 
     # https://code.google.com/p/chromedriver/issues/detail?id=604
-    'I18nTest.*',
+    'I18nTest.testShouldBeAbleToActivateIMEEngine',
 
     # https://code.google.com/p/chromium/issues/detail?id=418590
     'ClearTest.testContentEditableAreaShouldClear',
@@ -192,14 +192,8 @@
     'TypingTest.testShouldBeAbleToTypeIntoEmptyContentEditableElement',
 
     # https://code.google.com/p/chromedriver/issues/detail?id=922
-    'CorrectEventFiringTest.testShouldFireClickEventWhenClicking',
-    'CorrectEventFiringTest.testShouldEmitOnChangeEventsWhenChangingTheStateOfACheckbox',
-    'CorrectEventFiringTest.testShouldIssueMouseUpEvents',
-    'CorrectEventFiringTest.testsShouldIssueMouseDownEvents',
-    'CorrectEventFiringTest.testMouseEventsShouldBubbleUpToContainingElements',
-
-    # https://code.google.com/p/chromedriver/issues/detail?id=955
-    'TypingTest.testShiftSelectionDeletes',
+    'CorrectEventFiringTest.testShouldEmitOnClickEventsWhenSelectingElements',
+    'CorrectEventFiringTest.testSendingKeysToAnotherElementShouldCauseTheBlurEventToFire',
 
     # https://code.google.com/p/chromedriver/issues/detail?id=998
     'ImplicitWaitTest.testShouldImplicitlyWaitForASingleElement',
diff --git a/chrome/test/chromeos/autotest/files/client/deps/chrome_test/setup_test_links.sh b/chrome/test/chromeos/autotest/files/client/deps/chrome_test/setup_test_links.sh
index a47b005f..7e212e1 100755
--- a/chrome/test/chromeos/autotest/files/client/deps/chrome_test/setup_test_links.sh
+++ b/chrome/test/chromeos/autotest/files/client/deps/chrome_test/setup_test_links.sh
@@ -53,7 +53,6 @@
     "$pyauto_dep_dir/test_src/out/Release/pyproto" \
     "$pyauto_dep_dir/test_src/out/Release/suid-python" \
     "$pyauto_dep_dir/test_src/out/Release/_pyautolib.so" \
-    "$pyauto_dep_dir/test_src/out/Release/libffmpegsumo.so" \
     "$pyauto_dep_dir/test_src/third_party"/*
 
 # Make sure the test files are owned by chronos as some browser_tests emit
diff --git a/chrome/test/chromeos/autotest/files/client/deps/pyauto_dep/setup_test_links.sh b/chrome/test/chromeos/autotest/files/client/deps/pyauto_dep/setup_test_links.sh
index 2be6bd2..4a08de63 100755
--- a/chrome/test/chromeos/autotest/files/client/deps/pyauto_dep/setup_test_links.sh
+++ b/chrome/test/chromeos/autotest/files/client/deps/pyauto_dep/setup_test_links.sh
@@ -12,4 +12,3 @@
 [ -L $(dirname $0)/resources ] || ln -f -s /opt/google/chrome/resources \
     $(dirname $0)/resources
 ln -f -s /opt/google/chrome/*.pak $(dirname $0)/
-ln -f -s /opt/google/chrome/libffmpegsumo.so $(dirname $0)/libffmpegsumo.so
diff --git a/chrome/test/data/android/google.html b/chrome/test/data/android/google.html
index 6ca163ee..35773de 100644
--- a/chrome/test/data/android/google.html
+++ b/chrome/test/data/android/google.html
@@ -2,7 +2,7 @@
 
 <head>
 <title>The Google</title>
-
+<meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5" />
 </head>
 
 <body>
diff --git a/chrome/test/data/extensions/api_test/bookmark_manager/edit_disabled/test.js b/chrome/test/data/extensions/api_test/bookmark_manager/edit_disabled/test.js
index 81c400e4..bc27b5b 100644
--- a/chrome/test/data/extensions/api_test/bookmark_manager/edit_disabled/test.js
+++ b/chrome/test/data/extensions/api_test/bookmark_manager/edit_disabled/test.js
@@ -69,7 +69,9 @@
   },
 
   function canPasteDisabled() {
-    bookmarkManager.canPaste(folder.id, fail(ERROR));
+    bookmarkManager.canPaste(folder.id, pass(function(result) {
+      assertFalse(result, 'Should not be able to paste bookmarks');
+    }));
   },
 
   function pasteDisabled() {
diff --git a/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/manifest.json b/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/manifest.json
new file mode 100644
index 0000000..ec7efb3
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/manifest.json
@@ -0,0 +1,10 @@
+{
+  "name": "chrome.tts",
+  "version": "0.1",
+  "manifest_version": 2,
+  "description": "browser test for chrome.tts API",
+  "background": {
+    "page": "test.html"
+  },
+  "permissions": ["tts"]
+}
diff --git a/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/test.html b/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/test.html
new file mode 100644
index 0000000..3efb342
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/test.html
@@ -0,0 +1,6 @@
+<!--
+ * Copyright (c) 2011 The Chromium Authors. All rights reserved.  Use of this
+ * source code is governed by a BSD-style license that can be found in the
+ * LICENSE file.
+-->
+<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/test.js b/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/test.js
new file mode 100644
index 0000000..6762b1e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/tts/pause_speak_no_enqueue/test.js
@@ -0,0 +1,42 @@
+// 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.
+
+// TTS api test for Chrome.
+// browser_tests.exe --gtest_filter="TtsApiTest.*"
+
+chrome.test.runTests([
+  function testPauseCancel() {
+    var callbacks = 0;
+    chrome.tts.pause();
+    chrome.tts.speak(
+        'text 1',
+        {
+         'enqueue': true,
+         'onEvent': function(event) {
+            chrome.test.assertEq('cancelled', event.type);
+            callbacks++;
+         }
+        },
+        function() {
+          chrome.test.assertNoLastError();
+          callbacks++;
+        });
+    chrome.tts.speak(
+        'text 2',
+        {
+         'enqueue': false,
+         'onEvent': function(event) {
+           chrome.test.assertEq('cancelled', event.type);
+           callbacks++;
+           if (callbacks == 4) {
+             chrome.test.succeed();
+           }
+         }
+        },
+        function() {
+          chrome.test.assertNoLastError();
+          callbacks++;
+        });
+  }
+]);
diff --git a/chrome/test/data/nacl/debug_stub_browser_tests.py b/chrome/test/data/nacl/debug_stub_browser_tests.py
index 8c74c86..c128507a 100644
--- a/chrome/test/data/nacl/debug_stub_browser_tests.py
+++ b/chrome/test/data/nacl/debug_stub_browser_tests.py
@@ -9,6 +9,15 @@
 import gdb_rsp
 
 
+def AssertRaises(exc_class, func):
+  try:
+    func()
+  except exc_class:
+    pass
+  else:
+    raise AssertionError('Function did not raise %r' % exc_class)
+
+
 def GetTargetArch(connection):
   """Get the CPU architecture of the NaCl application."""
   reply = connection.RspRequest('qXfer:features:read:target.xml:0,fff')
@@ -46,11 +55,11 @@
 
 
 def TestContinue(connection):
-  result = connection.RspRequest('vCont;c')
   # Once the NaCl test module reports that the test passed, the NaCl <embed>
-  # element is removed from the page and so the NaCl module is killed by
-  # the browser what is reported as exit due to SIGKILL (X09).
-  assert result == 'X09', result
+  # element is removed from the page.  The NaCl module will be killed by the
+  # browser which will appear as EOF (end-of-file) on the debug stub socket.
+  AssertRaises(gdb_rsp.EofOnReplyException,
+               lambda: connection.RspRequest('vCont;c'))
 
 
 def TestBreakpoint(connection):
@@ -78,8 +87,8 @@
   assert result == 'T05thread:%s;' % thread, result
   assert pc != GetProgCtrString(connection, arch)
   # Check that we terminate normally
-  result = connection.RspRequest('vCont;c')
-  assert result == 'X09', result
+  AssertRaises(gdb_rsp.EofOnReplyException,
+               lambda: connection.RspRequest('vCont;c'))
 
 
 def Main(args):
diff --git a/chrome/test/data/nacl/gdb_rsp.py b/chrome/test/data/nacl/gdb_rsp.py
index 28680df0..7882517 100644
--- a/chrome/test/data/nacl/gdb_rsp.py
+++ b/chrome/test/data/nacl/gdb_rsp.py
@@ -16,6 +16,11 @@
   return checksum
 
 
+class EofOnReplyException(Exception):
+
+  pass
+
+
 class GdbRspConnection(object):
 
   def __init__(self, addr):
@@ -47,6 +52,8 @@
     while True:
       data = self._socket.recv(1024)
       if len(data) == 0:
+        if reply == '+':
+          raise EofOnReplyException()
         raise AssertionError('EOF on socket reached with '
                              'incomplete reply message: %r' % reply)
       reply += data
diff --git a/chrome/test/data/nacl/nacl_test_data.gyp b/chrome/test/data/nacl/nacl_test_data.gyp
index 78d3aa6..7cdeee82 100644
--- a/chrome/test/data/nacl/nacl_test_data.gyp
+++ b/chrome/test/data/nacl/nacl_test_data.gyp
@@ -650,16 +650,22 @@
       'target_name': 'pnacl_error_handling_test',
       'type': 'none',
       'variables': {
+        'nexe_target': 'pnacl_errors',
+        'extra_args': ['--nonstable-pnacl'],
         'build_pnacl_newlib': 1,
         'nexe_destination_dir': 'nacl_test_data',
-        # Use prebuilt NMF files.
+        'sources': [
+          'simple.cc',
+        ],
         'generate_nmf': 0,
         'test_files': [
           'pnacl_error_handling/pnacl_error_handling.html',
           'pnacl_error_handling/bad.pexe',
           'pnacl_error_handling/pnacl_bad_pexe.nmf',
+          'pnacl_error_handling/pnacl_bad_pexe_O0.nmf',
           'pnacl_error_handling/pnacl_bad_doesnotexist.nmf',
           'pnacl_error_handling/pnacl_illformed_manifest.nmf',
+          'pnacl_error_handling/pnacl_nonfinal_pexe_O0.nmf',
         ],
       },
     },
diff --git a/chrome/test/data/nacl/pnacl_error_handling/pnacl_bad_pexe_O0.nmf b/chrome/test/data/nacl/pnacl_error_handling/pnacl_bad_pexe_O0.nmf
new file mode 100644
index 0000000..5da5f12c
--- /dev/null
+++ b/chrome/test/data/nacl/pnacl_error_handling/pnacl_bad_pexe_O0.nmf
@@ -0,0 +1,10 @@
+{
+  "program": {
+    "portable": {
+      "pnacl-translate": {
+        "optlevel": 0,
+        "url": "bad.pexe"
+      }
+    }
+  }
+}
diff --git a/chrome/test/data/nacl/pnacl_error_handling/pnacl_error_handling.html b/chrome/test/data/nacl/pnacl_error_handling/pnacl_error_handling.html
index d8d506e3..fdbf54c 100644
--- a/chrome/test/data/nacl/pnacl_error_handling/pnacl_error_handling.html
+++ b/chrome/test/data/nacl/pnacl_error_handling/pnacl_error_handling.html
@@ -29,8 +29,31 @@
       'application/x-pnacl',
       // Use a regular expression here: the translator outputs debug information
       // in the error message.
-      new RegExp('NaCl module load failed: PnaclCoordinator: ' +
-                 'PNaCl Translator Error: .*' +
+      new RegExp('NaCl module load failed: PnaclCoordinator:.*' +
+                 'Invalid PNaCl bitcode header'));
+
+  // 'bad_pexe_O0' loads a manifest, then loads a pexe that is invalid
+  // using the O0 translator (which may have a different codepath from O2).
+  badLoadTest(
+      tester,
+      'bad_pexe_O0',
+      'pnacl_bad_pexe_O0.nmf',
+      'application/x-pnacl',
+      // Use a regular expression here: the translator outputs debug information
+      // in the error message.
+      new RegExp('NaCl module load failed: PnaclCoordinator:.*' +
+                 'Invalid PNaCl bitcode header'));
+
+  // 'bad_nonfinal_pexe_O0' loads a manifest, then loads a non-finalized pexe
+  // using the O0 translator (which may have a different codepath from O2).
+  badLoadTest(
+      tester,
+      'bad_nonfinal_pexe_O0',
+      'pnacl_nonfinal_pexe_O0.nmf',
+      'application/x-pnacl',
+      // Use a regular expression here: the translator outputs debug information
+      // in the error message.
+      new RegExp('NaCl module load failed: PnaclCoordinator:.*' +
                  'Invalid PNaCl bitcode header'));
 
   // 'nonexistent_pexe' loads a manifest, then tries to to load a nonexistent
diff --git a/chrome/test/data/nacl/pnacl_error_handling/pnacl_nonfinal_pexe_O0.nmf b/chrome/test/data/nacl/pnacl_error_handling/pnacl_nonfinal_pexe_O0.nmf
new file mode 100644
index 0000000..b1d335b
--- /dev/null
+++ b/chrome/test/data/nacl/pnacl_error_handling/pnacl_nonfinal_pexe_O0.nmf
@@ -0,0 +1,10 @@
+{
+  "program": {
+    "portable": {
+      "pnacl-translate": {
+        "optlevel": 0,
+        "url": "pnacl_errors_newlib_pnacl.pexe"
+      }
+    }
+  }
+}
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index c7fe44b1..38d4f2d2 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -1713,6 +1713,9 @@
     ]
   },
 
+  "SSLVersionMin": {
+  },
+
   "SSLVersionFallbackMin": {
     "os": ["win", "linux", "mac", "chromeos"],
     "test_policy": { "SSLVersionFallbackMin": "tls1.2" },
diff --git a/chrome/test/data/safe_browsing/mach_o/Makefile b/chrome/test/data/safe_browsing/mach_o/Makefile
new file mode 100644
index 0000000..faa2feca
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/Makefile
@@ -0,0 +1,59 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+KEYCHAIN_PASSWORD=g0atMaster
+# This must match the commonName in codesign.cfg.
+KEYCHAIN_IDENTITY=untrusted@goat.local
+
+executable32: src.c
+	clang -m32 -o $@ $^
+
+executable64: src.c
+	clang -m64 -o $@ $^
+
+executablefat: executable32 executable64
+	lipo -create -output $@ $^
+
+lib32.dylib: src.c
+	clang -m32 -shared -o $@ $^
+
+lib64.dylib: src.c
+	clang -m64 -shared -o $@ $^
+
+libfat.dylib: lib64.dylib lib32.dylib
+	lipo -create -output $@ $^
+
+codesign.key:
+	openssl genrsa -out $@ 2048
+
+codesign.csr: codesign.key codesign.cfg
+	openssl req -new -key $< -out $@ -config codesign.cfg
+
+codesign.crt: codesign.csr codesign.key codesign.cfg
+	openssl x509 -req -signkey codesign.key -sha256 \
+		-extfile codesign.cfg -extensions req_attrs -in $< -out $@
+
+codesign.keychain: codesign.key codesign.crt
+	security create-keychain -p $(KEYCHAIN_PASSWORD) $(PWD)/$@
+	security unlock-keychain -p $(KEYCHAIN_PASSWORD) $(PWD)/$@
+	certtool i ./codesign.crt k=$(PWD)/$@ r=./codesign.key
+
+signedexecutable32: executable32 codesign.keychain
+	cp $< $@
+	security unlock-keychain -p $(KEYCHAIN_PASSWORD) \
+		$(PWD)/codesign.keychain
+	codesign -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain $@
+
+libsigned64.dylib: lib64.dylib codesign.keychain
+	cp $< $@
+	security unlock-keychain -p $(KEYCHAIN_PASSWORD) \
+		$(PWD)/codesign.keychain
+	codesign -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain $@
+
+signedexecutablefat: executablefat codesign.keychain
+	cp $< $@
+	security unlock-keychain -p $(KEYCHAIN_PASSWORD) \
+		$(PWD)/codesign.keychain
+	codesign -s $(KEYCHAIN_IDENTITY) --keychain $(PWD)/codesign.keychain \
+		$@ --all-architectures
diff --git a/chrome/test/data/safe_browsing/mach_o/README b/chrome/test/data/safe_browsing/mach_o/README
new file mode 100644
index 0000000..60b51d1
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/README
@@ -0,0 +1,14 @@
+This directory contains test data for //chrome/common/safe_browsing unit tests
+on Mac OS X. The compiled binaries are checked in because the tests check
+specific values in the load commands, which will change on being recompiled.
+
+In the event that the tests need to evolve, a Makefile is provided to recreate
+the binaries. Note that recompiling or re-code-signing the binaries will
+require updating the test's assertions.
+
+Note that the executable bit has been removed from all of executable files,
+since they do not have a common extension (for checkperms.py) and they are
+only ever treated as data.
+
+The `executableppc' file has no Makefile target, as modern Macs cannot build
+for PPC. This file was created in a 10.6 VM with Xcode 3.2.6.
diff --git a/chrome/test/data/safe_browsing/mach_o/codesign.cfg b/chrome/test/data/safe_browsing/mach_o/codesign.cfg
new file mode 100644
index 0000000..ecb0c0d8
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/codesign.cfg
@@ -0,0 +1,28 @@
+# 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.
+
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+default_md = sha256
+copy_extensions = copy
+x509_extensions = req_attrs
+
+[ req ]
+distinguished_name = req_distinguished_name
+prompt = no
+req_extensions = req_attrs
+default_md = sha256
+
+[ req_distinguished_name ]
+countryName = US
+commonName = untrusted@goat.local
+localityName = New York
+stateOrProvinceName = New York
+organizationName = Untrusted Goat
+
+[ req_attrs ]
+extendedKeyUsage = codeSigning
+keyUsage = digitalSignature
diff --git a/chrome/test/data/safe_browsing/mach_o/codesign.crt b/chrome/test/data/safe_browsing/mach_o/codesign.crt
new file mode 100644
index 0000000..9870244a
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/codesign.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIJAKzs2ufO0WuBMA0GCSqGSIb3DQEBCwUAMGsxCzAJBgNV
+BAYTAlVTMR0wGwYDVQQDDBR1bnRydXN0ZWRAZ29hdC5sb2NhbDERMA8GA1UEBwwI
+TmV3IFlvcmsxETAPBgNVBAgMCE5ldyBZb3JrMRcwFQYDVQQKDA5VbnRydXN0ZWQg
+R29hdDAeFw0xNTA2MDQxODUxNDdaFw0xNTA3MDQxODUxNDdaMGsxCzAJBgNVBAYT
+AlVTMR0wGwYDVQQDDBR1bnRydXN0ZWRAZ29hdC5sb2NhbDERMA8GA1UEBwwITmV3
+IFlvcmsxETAPBgNVBAgMCE5ldyBZb3JrMRcwFQYDVQQKDA5VbnRydXN0ZWQgR29h
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMolOFEuV1GiKLjZkFg4
++VBVcdJm+WmETt1Qn2tndQFyMqskPJsnuCgcr+lEXh8d0c7pCt/0tlLjAbxqd7uz
+SRt8l/Y39qkpPGthKL06KjKNOnViYGsk1eWKbH21NwFTJ5ZeA86o1V4SSLPlw75F
+nh/S0RBsff2IjMDYbPKOya52zODHESAQWeLq9/e+PZMWJfvr12668DTT+HeXobfX
+WEzWetXhuwZB+VJ/M6YJn/IVJahlO3L/8L65dBPPp+gQn52hGnxV0YOaY/G4DdPO
+mDfq7GQC6//N/Qg/1u9fg0ecSF1zs0zxOMtvuMLpi3ysycMhSKcuD0b34enzk5Mw
+7McCAwEAAaMkMCIwEwYDVR0lBAwwCgYIKwYBBQUHAwMwCwYDVR0PBAQDAgeAMA0G
+CSqGSIb3DQEBCwUAA4IBAQAxzlc6L7UIF+mwGYloAn5AMTsnjPY8li9g0896FCl7
+f3bDroDmj8NAd9EPYRnVOFGcj6JVAhitxjcnPhsdMs5Cy/vSyHSp3rHnx+DNQ+iq
+2LzWXVSusiungZb1y7sgo9CD0zI3HA3SLxGDwHw80HAkxnaR8FAer+1E9zXoj3NG
+crNO9AlqZdghlLsktEpHw0/Srkmc1bRyEHymiy/6qh8oM0zqkEuOLe1BrfHbLlI1
+yrlsu3EwKMkBhKPSHQr4oYhpqd4YEmIl6+r/sPFl92HrYFXEOtUINp/Bn7wYKU9V
+sNA1SKHZSrb1+tqMlHEdMOa3a+uOAgA5WyJCjgNrvjzU
+-----END CERTIFICATE-----
diff --git a/chrome/test/data/safe_browsing/mach_o/codesign.csr b/chrome/test/data/safe_browsing/mach_o/codesign.csr
new file mode 100644
index 0000000..1bd5fe9
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/codesign.csr
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIC4zCCAcsCAQAwazELMAkGA1UEBhMCVVMxHTAbBgNVBAMMFHVudHJ1c3RlZEBn
+b2F0LmxvY2FsMREwDwYDVQQHDAhOZXcgWW9yazERMA8GA1UECAwITmV3IFlvcmsx
+FzAVBgNVBAoMDlVudHJ1c3RlZCBHb2F0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAyiU4US5XUaIouNmQWDj5UFVx0mb5aYRO3VCfa2d1AXIyqyQ8mye4
+KByv6UReHx3RzukK3/S2UuMBvGp3u7NJG3yX9jf2qSk8a2EovToqMo06dWJgayTV
+5YpsfbU3AVMnll4DzqjVXhJIs+XDvkWeH9LREGx9/YiMwNhs8o7JrnbM4McRIBBZ
+4ur39749kxYl++vXbrrwNNP4d5eht9dYTNZ61eG7BkH5Un8zpgmf8hUlqGU7cv/w
+vrl0E8+n6BCfnaEafFXRg5pj8bgN086YN+rsZALr/839CD/W71+DR5xIXXOzTPE4
+y2+4wumLfKzJwyFIpy4PRvfh6fOTkzDsxwIDAQABoDMwMQYJKoZIhvcNAQkOMSQw
+IjATBgNVHSUEDDAKBggrBgEFBQcDAzALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEL
+BQADggEBAIYiz8jYnpskHbSZ4KqfghWc+vBPA4VUrnnP8/yX4RnLAMzAfWbHH290
+xtgMxdRe/DjtojRjXYLXTIE2jKGp3pgC0JBBSFvsjRo0J5ZilVmPn6/MLN+QlL+5
+LcjQva8FIVV6lD47IQKRJjd8ZMi/8DfHboa//ePlJ2FX+pGcCwfV2sJcO6KqsxhY
+oczjX7ug5z7flwnn1VO8uPUGdpAgbNcrkJcmDDq2hnk+tscwwrSVN4X6g+1aEfmu
+X75ytcGKzQzVMkwwHeUBwjGbQ6+Di4CToMz1zo3o8QqLtiNd0kXqr5AT4sYvCD5U
+egzUGdmI6EcJADN316tavyXdSj6my+A=
+-----END CERTIFICATE REQUEST-----
diff --git a/chrome/test/data/safe_browsing/mach_o/codesign.key b/chrome/test/data/safe_browsing/mach_o/codesign.key
new file mode 100644
index 0000000..2c2240e
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/codesign.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAyiU4US5XUaIouNmQWDj5UFVx0mb5aYRO3VCfa2d1AXIyqyQ8
+mye4KByv6UReHx3RzukK3/S2UuMBvGp3u7NJG3yX9jf2qSk8a2EovToqMo06dWJg
+ayTV5YpsfbU3AVMnll4DzqjVXhJIs+XDvkWeH9LREGx9/YiMwNhs8o7JrnbM4McR
+IBBZ4ur39749kxYl++vXbrrwNNP4d5eht9dYTNZ61eG7BkH5Un8zpgmf8hUlqGU7
+cv/wvrl0E8+n6BCfnaEafFXRg5pj8bgN086YN+rsZALr/839CD/W71+DR5xIXXOz
+TPE4y2+4wumLfKzJwyFIpy4PRvfh6fOTkzDsxwIDAQABAoIBAQDJ2jTMS7wB1i1X
+uFi839eE8m2ALjdruCSQNsuaEmryELir0Ll8LUNlOpAmHJDn/XzeYjLrw460Yd3/
+6Ui6c6LTAa00vllePcEJcLGfkw9D/2aahKvHEbdNSNZhCK1uczyamDKxEEJPd26F
+xS+bNiVZncgJ4GxG2S3D+9l+tDqMLGqnl3+gR6dIoUh75K9TcMTmFA/5DPIERLuu
+qLJX8ajdysX1jD6fcKeA8Rgl82J0mAnem+EdNq4S/HBEvFL7hcjJWUmGY2FkYpSL
+73aKoZN9GBgC9e9PlJaDFlcoHwYOkPfCborPvtXQS0ODk3ra1NdmSxWVut4Xneb0
+kY99PZ/hAoGBAOiT3WzCUBSIspajt+m4MT6/WmQewSaxlOvqujdIQaI3JQ6ClyAs
+xOYuBjyI3jIw5t+k6PNZ5HWTwaipN9xrA35ukJZ9rNVQly0l6GcN8r9QEic0Ej2U
++3gDxT6eO5u2k4HgEN7dFbeuxFGzf9BAHpEZoRJNU2kP7LjqLxXedN/JAoGBAN6A
+xohBpqxjxVH3NRPNP8xF0eLr2BoTnU818x9nZLNHNfc9+pNLB30FwRaBpsqlT4vE
+c2Mb7rlyK20ey161QwCn/NflyvLj1CqW0C59mTJQAW8DPlKnnPFAi8xjzJNSgsr3
+oWosjSTHoxo0Wk0j0XEdGCxFVqnt7FEaBZ2PoVAPAoGBAJpjDWlU07PNyj8VDtCm
+5ImynF45zB3TY/f3KQXpgSgdUwv+xDMnhM0HYDxu3pCSxa9P2RMxaOZj3voG2n4G
+y5rx6ij74+72QGRH9a3zJGC61lIPzsvySbuxRQ38G7WRzPk5s/k86V21NbzGWuHy
+rlfDm5h6nBPx7kIRso/hy9OBAoGAMLIQQSvVFW90dN7cf+vwpX02VSp2jiZyzC4r
+elj/gfj4x5aJ64iFKAiFXK6dWUZapWUmN6+aTH2/IU+XBLA47MDXJk0FYKkZ+wQs
+pbAZQhieZ7RXBHHoeCg/MEk7MZbiRxdw/TKo5T7H5GlGxhEruky6yJ2YPPJ0QL+o
+MPaJQGMCgYB+frROpf77X+0gdVZit9yYST03SziVwno5OX9puaO+DvQj+RE1NqaJ
+UgE001ohgeOlasRpra1eB0qPrzq1AplkzcapwIsEIt1SATxaGFQzQ/9S/d/vVFki
+dGaxlkAN2iPPlkdAldxRVjCpHnkskjtGO0Rq7ekzUekZluGBs47Bog==
+-----END RSA PRIVATE KEY-----
diff --git a/chrome/test/data/safe_browsing/mach_o/codesign.keychain b/chrome/test/data/safe_browsing/mach_o/codesign.keychain
new file mode 100644
index 0000000..0e4bf37
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/codesign.keychain
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/executable32 b/chrome/test/data/safe_browsing/mach_o/executable32
new file mode 100644
index 0000000..9337b20
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/executable32
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/executable64 b/chrome/test/data/safe_browsing/mach_o/executable64
new file mode 100644
index 0000000..7191667
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/executable64
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/executablefat b/chrome/test/data/safe_browsing/mach_o/executablefat
new file mode 100644
index 0000000..32a0ec42
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/executablefat
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/executableppc b/chrome/test/data/safe_browsing/mach_o/executableppc
new file mode 100644
index 0000000..8ea835d
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/executableppc
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/lib32.dylib b/chrome/test/data/safe_browsing/mach_o/lib32.dylib
new file mode 100755
index 0000000..d5a79afe
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/lib32.dylib
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/lib64.dylib b/chrome/test/data/safe_browsing/mach_o/lib64.dylib
new file mode 100755
index 0000000..30b84c0
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/lib64.dylib
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/libfat.dylib b/chrome/test/data/safe_browsing/mach_o/libfat.dylib
new file mode 100755
index 0000000..603ddce
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/libfat.dylib
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/libsigned64.dylib b/chrome/test/data/safe_browsing/mach_o/libsigned64.dylib
new file mode 100755
index 0000000..77b77db
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/libsigned64.dylib
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/signedexecutable32 b/chrome/test/data/safe_browsing/mach_o/signedexecutable32
new file mode 100644
index 0000000..417166a6
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/signedexecutable32
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/signedexecutablefat b/chrome/test/data/safe_browsing/mach_o/signedexecutablefat
new file mode 100644
index 0000000..f52bda3
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/signedexecutablefat
Binary files differ
diff --git a/chrome/test/data/safe_browsing/mach_o/src.c b/chrome/test/data/safe_browsing/mach_o/src.c
new file mode 100644
index 0000000..284756e
--- /dev/null
+++ b/chrome/test/data/safe_browsing/mach_o/src.c
@@ -0,0 +1,11 @@
+// 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.
+
+int DoAThing() {
+  return 42;
+}
+
+int main() {
+  return 0;
+}
diff --git a/chrome/test/data/webrtc/getusermedia.js b/chrome/test/data/webrtc/getusermedia.js
index b1af494..20d2602 100644
--- a/chrome/test/data/webrtc/getusermedia.js
+++ b/chrome/test/data/webrtc/getusermedia.js
@@ -39,11 +39,11 @@
 };
 
 /**
- * This function asks permission to use the webcam and mic from the browser. It
- * will return ok-requested to the test. This does not mean the request was
- * approved though. The test will then have to click past the dialog that
- * appears in Chrome, which will run either the OK or failed callback as a
- * a result. To see which callback was called, use obtainGetUserMediaResult().
+ * This function asks permission to use the webcam and mic from the browser.
+ * Its callbacks will return either request-callback-granted or
+ * request-callback-denied depending on the outcome. If the caller does not
+ * successfully resolve the request by granting or denying, the test will hang.
+ * To verify which callback was called, use obtainGetUserMediaResult().
  *
  * @param {!object} constraints Defines what to be requested, with mandatory
  *     and optional constraints defined. The contents of this parameter depends
@@ -62,7 +62,6 @@
                  getUserMediaOkCallback_(stream);
                },
                getUserMediaFailedCallback_);
-  returnToTest('ok-requested');
 }
 
 /**
@@ -156,6 +155,8 @@
   gRequestWebcamAndMicrophoneResult = 'ok-got-stream';
 
   attachMediaStream($('local-view'), stream);
+
+  returnToTest('request-callback-granted');
 }
 
 /**
@@ -169,4 +170,6 @@
   debug('GetUserMedia FAILED: Maybe the camera is in use by another process?');
   gRequestWebcamAndMicrophoneResult = 'failed-with-error-' + errorName;
   debug(gRequestWebcamAndMicrophoneResult);
+
+  returnToTest('request-callback-denied');
 }
diff --git a/chrome/test/data/webui/cr_test.html b/chrome/test/data/webui/cr_test.html
index 834c252..b592cac 100644
--- a/chrome/test/data/webui/cr_test.html
+++ b/chrome/test/data/webui/cr_test.html
@@ -263,6 +263,88 @@
   assertEquals(1, foo.v);
 }
 
+/**
+ * Executes a function given a potentially namespaced function name, e.g.,
+ * cr.webUIListenerCallback.
+ * @param {string} functionName The name of the function, including any
+ *     namespaces, to execute.
+ */
+function executeFunctionByName(functionName) {
+  var args = Array.prototype.slice.call(arguments, 1);
+  var func = (0, eval)(functionName);
+  func.apply(undefined, args);
+}
+
+/**
+ * Tests that cr.sendWithCallback correctly handles the case where the JS sends
+ * no arguments to the WebUI handler.
+ */
+function testSendWithCallback_PassesJSArgs() {
+ var testMethodName = 'getFullscreenState';
+
+ // Mock out chrome.send to emulate a WebUI handler calling back with the
+ // result of a getFullscreenState call.
+ window.chrome = {};
+ window.chrome.send = function(method, args) {
+   assertEquals(testMethodName, method);
+   var callbackName = args[0];
+   var id = args[1];
+   executeFunctionByName(callbackName, id, /* fullscreen */ true);
+ };
+
+ var callbackResponse;
+ cr.sendWithCallback(testMethodName, undefined, function(fullscreen) {
+   callbackResponse = fullscreen;
+ });
+
+ assertTrue(callbackResponse);
+}
+
+/**
+ * Tests that cr.sendWithCallback passes arguments from JS to the WebUI
+ * handler.
+ */
+function testSendWithCallback_PassesJSArgs() {
+  var testMethodName = 'getSquareOfX';
+
+  // Mock out chrome.send to emulate a WebUI handler calling back with the
+  // result of a getSquareOfX call.
+  window.chrome = {};
+  window.chrome.send = function(method, args) {
+    assertEquals(testMethodName, method);
+    var callbackName = args[0];
+    var id = args[1];
+    var x = args[2];
+    executeFunctionByName(callbackName, id, x * x);
+  };
+
+  var callbackResponse;
+  cr.sendWithCallback(testMethodName, [5], function(square) {
+    callbackResponse = square;
+  });
+
+  assertEquals(25, callbackResponse);
+}
+
+/**
+ * Tests that an event fired by a WebUI handler is sent to all listeners. 
+ */
+function testAddWebUIListener() {
+  var responses = new Map();
+  cr.addWebUIListener('fullscreen-enabled', function(enabled) {
+    responses.set('first', enabled);
+  });
+  cr.addWebUIListener('fullscreen-enabled', function(enabled) {
+    responses.set('second', enabled);
+  });
+
+  executeFunctionByName(
+      'cr.webUIListenerCallback', 'fullscreen-enabled', true);
+
+  assertTrue(responses.get('first'));
+  assertTrue(responses.get('second'));
+}
+
 </script>
 
 </body>
diff --git a/chrome/test/data/webui/net_internals/sdch_view.js b/chrome/test/data/webui/net_internals/sdch_view.js
index cba9eed..f1878ac 100644
--- a/chrome/test/data/webui/net_internals/sdch_view.js
+++ b/chrome/test/data/webui/net_internals/sdch_view.js
@@ -22,8 +22,6 @@
 function checkDisplay(sdchInfo) {
   expectEquals(sdchInfo.sdch_enabled,
                $(SdchView.SDCH_ENABLED_SPAN_ID).innerText === 'true');
-  expectEquals(sdchInfo.secure_scheme_support,
-               $(SdchView.SECURE_SCHEME_SUPPORT_SPAN_ID).innerText === 'true');
   NetInternalsTest.checkTbodyRows(SdchView.BLACKLIST_TBODY_ID,
                                   sdchInfo.blacklisted.length);
   NetInternalsTest.checkTbodyRows(SdchView.DICTIONARIES_TBODY_ID,
diff --git a/chrome/test/data/webui/webui_resource_browsertest.cc b/chrome/test/data/webui/webui_resource_browsertest.cc
index 6fe54c5..fe333e5 100644
--- a/chrome/test/data/webui/webui_resource_browsertest.cc
+++ b/chrome/test/data/webui/webui_resource_browsertest.cc
@@ -59,7 +59,7 @@
   RunTest(base::FilePath(FILE_PATH_LITERAL("array_data_model_test.html")));
 }
 
-IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, PropertyTest) {
+IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, CrTest) {
   AddLibrary(IDR_WEBUI_JS_CR);
   AddLibrary(IDR_WEBUI_JS_CR_EVENT_TARGET);
   RunTest(base::FilePath(FILE_PATH_LITERAL("cr_test.html")));
diff --git a/chrome/test/nacl/nacl_browsertest.cc b/chrome/test/nacl/nacl_browsertest.cc
index 35c43de..5ce68d8 100644
--- a/chrome/test/nacl/nacl_browsertest.cc
+++ b/chrome/test/nacl/nacl_browsertest.cc
@@ -381,13 +381,20 @@
   RunNaClIntegrationTest(FILE_PATH_LITERAL("pnacl_error_handling.html"));
 }
 
+// Test Subzero. Subzero is triggered by the O0 option so reuse
+// test harnesses that use "optlevel": 0.
+IN_PROC_BROWSER_TEST_F(NaClBrowserTestPnaclSubzero,
+                       MAYBE_PNACL(PnaclErrorHandling)) {
+  RunNaClIntegrationTest(FILE_PATH_LITERAL("pnacl_error_handling.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(NaClBrowserTestPnacl,
                        MAYBE_PNACL(PnaclNMFOptionsO0)) {
   RunLoadTest(FILE_PATH_LITERAL("pnacl_options.html?use_nmf=o_0"));
 }
 
-// Test Subzero. Subzero is triggered by the O0 option so reuse that test
-// pexe and test harness.
+// Test Subzero. Subzero is triggered by the O0 option so reuse
+// test harnesses that use "optlevel": 0.
 IN_PROC_BROWSER_TEST_F(NaClBrowserTestPnaclSubzero,
                        MAYBE_PNACL(PnaclNMFOptionsO0)) {
   RunLoadTest(FILE_PATH_LITERAL("pnacl_options.html?use_nmf=o_0"));
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index e1bf78e..79a6d7c9 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -526,13 +526,25 @@
 #define MAYBE_URLLoader_BasicFilePOST URLLoader_BasicFilePOST
 #endif
 
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, URLLoader0) {
+#if defined(OS_MACOSX) && defined(ADDRESS_SANITIZER)
+// Flaky on Mac ASAN: http://crbug.com/437411.
+#define MAYBE_URLLoader0 DISABLED_URLLoader0
+#else
+#define MAYBE_URLLoader0 URLLoader0
+#endif
+IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_URLLoader0) {
   RUN_URLLOADER_SUBTESTS_0;
 }
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, URLLoader1) {
   RUN_URLLOADER_SUBTESTS_1;
 }
-IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, URLLoader2) {
+#if defined(OS_MACOSX) && defined(ADDRESS_SANITIZER)
+// Flaky on Mac ASAN: http://crbug.com/437411.
+#define MAYBE_URLLoader2 DISABLED_URLLoader2
+#else
+#define MAYBE_URLLoader2 URLLoader2
+#endif
+IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, MAYBE_URLLoader2) {
   RUN_URLLOADER_SUBTESTS_2;
 }
 IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, URLLoader3) {
diff --git a/chrome/test/ppapi/ppapi_test.cc b/chrome/test/ppapi/ppapi_test.cc
index 48d758a..6e9fc03 100644
--- a/chrome/test/ppapi/ppapi_test.cc
+++ b/chrome/test/ppapi/ppapi_test.cc
@@ -6,9 +6,12 @@
 
 #include "base/command_line.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
@@ -93,9 +96,9 @@
   // It's not safe to remove the infobar here, since other observers (e.g. the
   // InfoBarContainer) may still need to access it.  Instead, post a task to
   // do all necessary infobar manipulation as soon as this call stack returns.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&InfoBarObserver::VerifyInfoBarState,
-                            base::Unretained(this)));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&InfoBarObserver::VerifyInfoBarState, base::Unretained(this)));
 }
 
 void PPAPITestBase::InfoBarObserver::VerifyInfoBarState() {
diff --git a/chrome/tools/build/chromeos/FILES.cfg b/chrome/tools/build/chromeos/FILES.cfg
index 9bed5dd..1089fd2 100644
--- a/chrome/tools/build/chromeos/FILES.cfg
+++ b/chrome/tools/build/chromeos/FILES.cfg
@@ -61,10 +61,6 @@
     'buildtype': ['dev', 'official'],
   },
   {
-    'filename': 'libffmpegsumo.so',
-    'buildtype': ['dev', 'official'],
-  },
-  {
     'filename': 'lib/libexif.so',
     'buildtype': ['dev', 'official'],
   },
diff --git a/chrome/tools/build/linux/FILES.cfg b/chrome/tools/build/linux/FILES.cfg
index 8ec10a5d..52a09f20 100644
--- a/chrome/tools/build/linux/FILES.cfg
+++ b/chrome/tools/build/linux/FILES.cfg
@@ -72,10 +72,6 @@
     'buildtype': ['official'],
   },
   {
-    'filename': 'libffmpegsumo.so',
-    'buildtype': ['dev', 'official'],
-  },
-  {
     'filename': 'lib/libpeerconnection.so',
     'buildtype': ['dev', 'official'],
     'optional': ['dev', 'official'],
diff --git a/chrome/tools/build/mac/TESTS b/chrome/tools/build/mac/TESTS
index 4a81ea9..d77adcf 100644
--- a/chrome/tools/build/mac/TESTS
+++ b/chrome/tools/build/mac/TESTS
@@ -1,3 +1,2 @@
 sync_integration_tests
 exif.so
-ffmpegsumo.so
diff --git a/chrome/tools/build/mac/dump_product_syms b/chrome/tools/build/mac/dump_product_syms
index c9ef590..0673a1e 100755
--- a/chrome/tools/build/mac/dump_product_syms
+++ b/chrome/tools/build/mac/dump_product_syms
@@ -81,7 +81,6 @@
     "${SRC_APP_NAME} Helper.app"
     "crashpad_handler"
     "exif.so"
-    "ffmpegsumo.so"
 )
 
 # PDF.plugin is optional. Only include it if present.
diff --git a/chrome/tools/build/win/FILES.cfg b/chrome/tools/build/win/FILES.cfg
index 6c779d5..2dcef76 100644
--- a/chrome/tools/build/win/FILES.cfg
+++ b/chrome/tools/build/win/FILES.cfg
@@ -41,11 +41,6 @@
     'archive':  'sync_integration_tests.exe',
   },
   {
-    'filename': 'ffmpegsumo.dll',
-    'buildtype': ['dev', 'official'],
-    'filegroup': ['default', 'symsrc'],
-  },
-  {
     'filename': 'chrome.exe',
     'buildtype': ['dev', 'official'],
     'filegroup': ['default', 'symsrc'],
diff --git a/chrome/tools/profile_reset/jtl_compiler_unittest.cc b/chrome/tools/profile_reset/jtl_compiler_unittest.cc
index cb6fea2..c39e59a4 100644
--- a/chrome/tools/profile_reset/jtl_compiler_unittest.cc
+++ b/chrome/tools/profile_reset/jtl_compiler_unittest.cc
@@ -113,7 +113,8 @@
   JtlCompiler::CompileError error;
   EXPECT_FALSE(
       JtlCompiler::Compile(kSourceCode, kTestHashSeed, &bytecode, &error));
-  EXPECT_THAT(error.context, testing::StartsWith("non_existent_instruction"));
+  EXPECT_THAT(error.context,
+              testing::base::StartsWith("non_existent_instruction"));
   EXPECT_EQ(2u, error.line_number);
   EXPECT_EQ(JtlCompiler::CompileError::INVALID_OPERATION_NAME,
             error.error_code);
@@ -130,7 +131,7 @@
     JtlCompiler::CompileError error;
     EXPECT_FALSE(JtlCompiler::Compile(
         kSourceCodes[i], kTestHashSeed, &bytecode, &error));
-    EXPECT_THAT(error.context, testing::StartsWith("store_bool"));
+    EXPECT_THAT(error.context, testing::base::StartsWith("store_bool"));
     EXPECT_EQ(1u, error.line_number);
     EXPECT_EQ(JtlCompiler::CompileError::INVALID_ARGUMENT_COUNT,
               error.error_code);
@@ -162,7 +163,7 @@
     EXPECT_FALSE(JtlCompiler::Compile(
         cases[i].source_code, kTestHashSeed, &bytecode, &error));
     EXPECT_THAT(error.context,
-                testing::StartsWith(cases[i].expected_context_prefix));
+                testing::base::StartsWith(cases[i].expected_context_prefix));
     EXPECT_EQ(2u, error.line_number);
     EXPECT_EQ(JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE,
               error.error_code);
@@ -183,7 +184,7 @@
     EXPECT_FALSE(JtlCompiler::Compile(
         cases[i].source_code, kTestHashSeed, &bytecode, &error));
     EXPECT_THAT(error.context,
-                testing::StartsWith(cases[i].expected_context_prefix));
+                testing::base::StartsWith(cases[i].expected_context_prefix));
     EXPECT_EQ(0u, error.line_number);
     EXPECT_EQ(JtlCompiler::CompileError::INVALID_ARGUMENT_VALUE,
               error.error_code);
@@ -209,7 +210,7 @@
   JtlCompiler::CompileError error;
   EXPECT_FALSE(
       JtlCompiler::Compile(kSourceCode, kTestHashSeed, &bytecode, &error));
-  EXPECT_THAT(error.context, testing::StartsWith("go"));
+  EXPECT_THAT(error.context, testing::base::StartsWith("go"));
   EXPECT_EQ(1u, error.line_number);
   EXPECT_EQ(JtlCompiler::CompileError::PARSING_ERROR, error.error_code);
 }
diff --git a/chrome/tools/profile_reset/jtl_parser_unittest.cc b/chrome/tools/profile_reset/jtl_parser_unittest.cc
index 76f6171b..87b7ebc5 100644
--- a/chrome/tools/profile_reset/jtl_parser_unittest.cc
+++ b/chrome/tools/profile_reset/jtl_parser_unittest.cc
@@ -43,7 +43,7 @@
   EXPECT_FALSE(parser->ParseNextOperation(
       &actual_name, &actual_args, &actual_ends_sentence));
   EXPECT_THAT(parser->GetLastContext(),
-              testing::StartsWith(expected_context_prefix));
+              testing::base::StartsWith(expected_context_prefix));
   EXPECT_EQ(expected_line_number, parser->GetLastLineNumber());
 }
 
diff --git a/chrome/unit_tests.isolate b/chrome/unit_tests.isolate
index 146ca41..8c17738 100644
--- a/chrome/unit_tests.isolate
+++ b/chrome/unit_tests.isolate
@@ -73,7 +73,6 @@
     ['OS=="linux"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
           '<(PRODUCT_DIR)/locales/fr.pak',
         ],
@@ -102,7 +101,6 @@
         'files': [
           '<(PRODUCT_DIR)/<(mac_product_name) Framework.framework/',
           '<(PRODUCT_DIR)/exif.so',
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
           '<(PRODUCT_DIR)/osmesa.so',
         ],
       },
@@ -112,7 +110,6 @@
         'files': [
           '<(PRODUCT_DIR)/<(mac_product_name) Framework.framework.dSYM/',
           '<(PRODUCT_DIR)/exif.so.dSYM/',
-          '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
           '<(PRODUCT_DIR)/osmesa.so.dSYM/',
           '<(PRODUCT_DIR)/unit_tests.dSYM/',
         ],
@@ -126,7 +123,6 @@
           '../ui/base/glib/',
           '<(PRODUCT_DIR)/blacklist_test_dll_1.dll',
           '<(PRODUCT_DIR)/chrome_elf.dll',
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/libexif.dll',
           '<(PRODUCT_DIR)/osmesa.dll',
           '<(PRODUCT_DIR)/verifier_test_dll_1.dll',
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index fbe9073..803b289 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -31,12 +31,7 @@
     "//chrome/common",
   ]
 
-  if (is_android) {
-    if (use_seccomp_bpf) {
-      deps += [ "//sandbox/linux:seccomp_bpf" ]
-      defines += [ "USE_SECCOMP_BPF" ]
-    }
-  } else {
+  if (!is_android) {
     deps += [
       "//chrome/common:mojo_bindings",
       "//net:net_utility_services",
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS
index fb25cd1..e621c4f4 100644
--- a/chrome/utility/DEPS
+++ b/chrome/utility/DEPS
@@ -6,7 +6,6 @@
   "+components/safe_json_parser",
   "+courgette",
   "+extensions/common",
-  "+sandbox/linux/seccomp-bpf/sandbox_bpf.h",
   "+skia/ext",
   "+media",
   "+third_party/zlib/google",
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index 700e6a0d..9671be8 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -38,10 +38,6 @@
 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
 #endif
 
-#if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
-#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
-#endif
-
 #if defined(OS_WIN)
 #include "chrome/utility/font_cache_handler_win.h"
 #include "chrome/utility/shell_handler_win.h"
@@ -204,10 +200,6 @@
 #if defined(OS_CHROMEOS)
     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
 #endif
-#if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
-    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DetectSeccompSupport,
-                        OnDetectSeccompSupport)
-#endif
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -334,21 +326,6 @@
 }
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
-void ChromeContentUtilityClient::OnDetectSeccompSupport() {
-  bool supports_prctl = sandbox::SandboxBPF::SupportsSeccompSandbox(
-      sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED);
-  Send(new ChromeUtilityHostMsg_DetectSeccompSupport_ResultPrctl(
-      supports_prctl));
-
-  // Probing for the seccomp syscall can provoke kernel panics in certain LGE
-  // devices. For now, this data will not be collected. In the future, this
-  // should detect SeccompLevel::MULTI_THREADED. http://crbug.com/478478
-
-  ReleaseProcessIfNeeded();
-}
-#endif  // defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
-
 #if defined(OS_CHROMEOS)
 void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
     const std::vector<unsigned char>& encoded_data,
diff --git a/chrome/utility/chrome_content_utility_client.h b/chrome/utility/chrome_content_utility_client.h
index b442d14..1205c7b 100644
--- a/chrome/utility/chrome_content_utility_client.h
+++ b/chrome/utility/chrome_content_utility_client.h
@@ -58,10 +58,6 @@
                        const base::FileDescriptor& dest_fd);
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
-  void OnDetectSeccompSupport();
-#endif
-
   void OnPatchFileBsdiff(const base::FilePath& input_file,
                          const base::FilePath& patch_file,
                          const base::FilePath& output_file);
diff --git a/chrome/utility/extensions/extensions_handler.cc b/chrome/utility/extensions/extensions_handler.cc
index 982045f..942545e 100644
--- a/chrome/utility/extensions/extensions_handler.cc
+++ b/chrome/utility/extensions/extensions_handler.cc
@@ -65,11 +65,8 @@
   // Initialize libexif for image metadata parsing.
   metadata::ImageMetadataExtractor::InitializeLibrary();
 
-  // Load media libraries for media file validation.
-  base::FilePath media_path;
-  PathService::Get(content::DIR_MEDIA_LIBS, &media_path);
-  if (!media_path.empty())
-    media::InitializeMediaLibrary(media_path);
+  // Initialize media libraries for media file validation.
+  media::InitializeMediaLibrary();
 }
 
 bool ExtensionsHandler::OnMessageReceived(const IPC::Message& message) {
diff --git a/chrome/utility/font_cache_handler_win.cc b/chrome/utility/font_cache_handler_win.cc
index cd7aa70..cf850c07 100644
--- a/chrome/utility/font_cache_handler_win.cc
+++ b/chrome/utility/font_cache_handler_win.cc
@@ -29,7 +29,7 @@
 void FontCacheHandler::OnBuildFontCache(const base::FilePath& full_path) {
   DCHECK(!cache_thread_);
 
-  utility_task_runner_ = base::MessageLoop::current()->message_loop_proxy();
+  utility_task_runner_ = base::MessageLoop::current()->task_runner();
 
   // Create worker thread for building font cache.
   cache_thread_.reset(new base::Thread("font_cache_thread"));
diff --git a/chrome/utility/image_writer/image_writer.cc b/chrome/utility/image_writer/image_writer.cc
index 2a2b8a1..1df1513 100644
--- a/chrome/utility/image_writer/image_writer.cc
+++ b/chrome/utility/image_writer/image_writer.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/utility/image_writer/image_writer.h"
 
+#include "base/location.h"
 #include "base/memory/aligned_memory.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/utility/image_writer/error_messages.h"
 #include "chrome/utility/image_writer/image_writer_handler.h"
 #include "content/public/utility/utility_thread.h"
@@ -69,7 +72,7 @@
 const base::FilePath& ImageWriter::GetDevicePath() { return device_path_; }
 
 void ImageWriter::PostTask(const base::Closure& task) {
-  base::MessageLoop::current()->PostTask(FROM_HERE, task);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
 }
 
 void ImageWriter::PostProgress(int64 progress) {
diff --git a/chrome/utility/importer/bookmark_html_reader.cc b/chrome/utility/importer/bookmark_html_reader.cc
index eed15fa1..0fa2c92 100644
--- a/chrome/utility/importer/bookmark_html_reader.cc
+++ b/chrome/utility/importer/bookmark_html_reader.cc
@@ -119,7 +119,7 @@
     // multiple "<HR>" tags at the beginning of a single line.
     // See http://crbug.com/257474.
     static const char kHrTag[] = "<HR>";
-    while (StartsWithASCII(line, kHrTag, false)) {
+    while (base::StartsWithASCII(line, kHrTag, false)) {
       line.erase(0, arraysize(kHrTag) - 1);
       base::TrimString(line, " ", &line);
     }
@@ -205,7 +205,7 @@
     }
 
     // Bookmarks in sub-folder are encapsulated with <DL> tag.
-    if (StartsWithASCII(line, "<DL>", false)) {
+    if (base::StartsWithASCII(line, "<DL>", false)) {
       has_subfolder = true;
       if (!last_folder.empty()) {
         path.push_back(last_folder);
@@ -216,7 +216,7 @@
 
       // Mark next folder empty as initial state.
       last_folder_is_empty = true;
-    } else if (StartsWithASCII(line, "</DL>", false)) {
+    } else if (base::StartsWithASCII(line, "</DL>", false)) {
       if (path.empty())
         break;  // Mismatch <DL>.
 
@@ -278,9 +278,9 @@
 
 bool ParseCharsetFromLine(const std::string& line, std::string* charset) {
   const char kCharset[] = "charset=";
-  if (StartsWithASCII(line, "<META", false) &&
+  if (base::StartsWithASCII(line, "<META", false) &&
       (line.find("CONTENT=\"") != std::string::npos ||
-          line.find("content=\"") != std::string::npos)) {
+       line.find("content=\"") != std::string::npos)) {
     size_t begin = line.find(kCharset);
     if (begin == std::string::npos)
       return false;
@@ -302,7 +302,7 @@
   const char kToolbarFolderAttribute[] = "PERSONAL_TOOLBAR_FOLDER";
   const char kAddDateAttribute[] = "ADD_DATE";
 
-  if (!StartsWithASCII(line, kFolderOpen, true))
+  if (!base::StartsWithASCII(line, kFolderOpen, true))
     return false;
 
   size_t end = line.find(kFolderClose);
@@ -329,7 +329,7 @@
   }
 
   if (GetAttribute(attribute_list, kToolbarFolderAttribute, &value) &&
-      LowerCaseEqualsASCII(value, "true"))
+      base::LowerCaseEqualsASCII(value, "true"))
     *is_toolbar_folder = true;
   else
     *is_toolbar_folder = false;
@@ -361,7 +361,7 @@
   post_data->clear();
   *add_date = base::Time();
 
-  if (!StartsWithASCII(line, kItemOpen, true))
+  if (!base::StartsWithASCII(line, kItemOpen, true))
     return false;
 
   size_t end = line.find(kItemClose);
@@ -437,7 +437,7 @@
   *url = GURL();
 
   // Case-insensitive check of open tag.
-  if (!StartsWithASCII(line, kItemOpen, false))
+  if (!base::StartsWithASCII(line, kItemOpen, false))
     return false;
 
   // Find any close tag.
diff --git a/chrome/utility/importer/ie_importer_win.cc b/chrome/utility/importer/ie_importer_win.cc
index e1f5e4fb..8933592 100644
--- a/chrome/utility/importer/ie_importer_win.cc
+++ b/chrome/utility/importer/ie_importer_win.cc
@@ -613,8 +613,8 @@
       continue;
 
     GURL url(ac_list[i].key.c_str());
-    if (!(LowerCaseEqualsASCII(url.scheme(), url::kHttpScheme) ||
-          LowerCaseEqualsASCII(url.scheme(), url::kHttpsScheme))) {
+    if (!(base::LowerCaseEqualsASCII(url.scheme(), url::kHttpScheme) ||
+          base::LowerCaseEqualsASCII(url.scheme(), url::kHttpsScheme))) {
       continue;
     }
 
@@ -823,7 +823,7 @@
   for (std::vector<base::FilePath::StringType>::iterator it = file_list.begin();
        it != file_list.end(); ++it) {
     base::FilePath shortcut(*it);
-    if (!LowerCaseEqualsASCII(shortcut.Extension(), ".url"))
+    if (!base::LowerCaseEqualsASCII(shortcut.Extension(), ".url"))
       continue;
 
     // Skip the bookmark with invalid URL.
diff --git a/chrome/utility/local_discovery/service_discovery_message_handler.cc b/chrome/utility/local_discovery/service_discovery_message_handler.cc
index 3110c94..429257a 100644
--- a/chrome/utility/local_discovery/service_discovery_message_handler.cc
+++ b/chrome/utility/local_discovery/service_discovery_message_handler.cc
@@ -7,6 +7,8 @@
 #include <algorithm>
 
 #include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "chrome/common/local_discovery/local_discovery_messages.h"
 #include "chrome/common/local_discovery/service_discovery_client_impl.h"
 #include "content/public/utility/utility_thread.h"
@@ -202,11 +204,11 @@
     return true;
   if (discovery_thread_)
     return false;
-  utility_task_runner_ = base::MessageLoop::current()->message_loop_proxy();
+  utility_task_runner_ = base::MessageLoop::current()->task_runner();
   discovery_thread_.reset(new base::Thread("ServiceDiscoveryThread"));
   base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
   if (discovery_thread_->StartWithOptions(thread_options)) {
-    discovery_task_runner_ = discovery_thread_->message_loop_proxy();
+    discovery_task_runner_ = discovery_thread_->task_runner();
     discovery_task_runner_->PostTask(FROM_HERE,
         base::Bind(&ServiceDiscoveryMessageHandler::InitializeMdns,
                     base::Unretained(this)));
diff --git a/chrome/utility/media_galleries/media_metadata_parser.cc b/chrome/utility/media_galleries/media_metadata_parser.cc
index dbce009..a39324ec 100644
--- a/chrome/utility/media_galleries/media_metadata_parser.cc
+++ b/chrome/utility/media_galleries/media_metadata_parser.cc
@@ -7,8 +7,8 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/linked_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
 #include "base/task_runner_util.h"
 #include "base/threading/thread.h"
@@ -166,8 +166,8 @@
 MediaMetadataParser::~MediaMetadataParser() {}
 
 void MediaMetadataParser::Start(const MetadataCallback& callback) {
-  if (StartsWithASCII(mime_type_, "audio/", true) ||
-      StartsWithASCII(mime_type_, "video/", true)) {
+  if (base::StartsWithASCII(mime_type_, "audio/", true) ||
+      base::StartsWithASCII(mime_type_, "video/", true)) {
     MediaMetadata* metadata = new MediaMetadata;
     metadata->mime_type = mime_type_;
     std::vector<AttachedImage>* attached_images =
@@ -175,16 +175,15 @@
 
     media_thread_.reset(new base::Thread("media_thread"));
     CHECK(media_thread_->Start());
-    media_thread_->message_loop_proxy()->PostTaskAndReply(
-        FROM_HERE,
-        base::Bind(&ParseAudioVideoMetadata, source_, get_attached_images_,
-                   metadata, attached_images),
+    media_thread_->task_runner()->PostTaskAndReply(
+        FROM_HERE, base::Bind(&ParseAudioVideoMetadata, source_,
+                              get_attached_images_, metadata, attached_images),
         base::Bind(&FinishParseAudioVideoMetadata, callback,
                    base::Owned(metadata), base::Owned(attached_images)));
     return;
   }
 
-  if (StartsWithASCII(mime_type_, "image/", true)) {
+  if (base::StartsWithASCII(mime_type_, "image/", true)) {
     ImageMetadataExtractor* extractor = new ImageMetadataExtractor;
     extractor->Extract(
         source_,
diff --git a/chrome/utility/media_galleries/picasa_album_table_reader.cc b/chrome/utility/media_galleries/picasa_album_table_reader.cc
index f5a5b2b..94b4aa5d 100644
--- a/chrome/utility/media_galleries/picasa_album_table_reader.cc
+++ b/chrome/utility/media_galleries/picasa_album_table_reader.cc
@@ -91,7 +91,7 @@
     if (category == kAlbumCategoryAlbum) {
       std::string token;
       if (!token_column.ReadString(i, &token) || token.empty() ||
-          !StartsWithASCII(token, kAlbumTokenPrefix, false)) {
+          !base::StartsWithASCII(token, kAlbumTokenPrefix, false)) {
         continue;
       }
 
diff --git a/chrome/utility/profile_import_handler.cc b/chrome/utility/profile_import_handler.cc
index 30941e5a8..62ad7390 100644
--- a/chrome/utility/profile_import_handler.cc
+++ b/chrome/utility/profile_import_handler.cc
@@ -5,7 +5,9 @@
 #include "chrome/utility/profile_import_handler.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "chrome/common/importer/profile_import_process_messages.h"
@@ -64,7 +66,7 @@
     NOTREACHED();
     ImporterCleanup();
   }
-  import_thread_->message_loop()->PostTask(
+  import_thread_->task_runner()->PostTask(
       FROM_HERE, base::Bind(&Importer::StartImport, importer_.get(),
                             source_profile, items, bridge_));
 }
diff --git a/chromecast/base/process_utils.cc b/chromecast/base/process_utils.cc
index 901d53d..523fb1c 100644
--- a/chromecast/base/process_utils.cc
+++ b/chromecast/base/process_utils.cc
@@ -8,7 +8,7 @@
 #include <stdio.h>
 
 #include "base/logging.h"
-#include "base/safe_strerror_posix.h"
+#include "base/posix/safe_strerror.h"
 #include "base/strings/string_util.h"
 
 namespace chromecast {
@@ -22,7 +22,8 @@
   // Open the process.
   FILE* fp = popen(command.c_str(), "r");
   if (!fp) {
-    LOG(ERROR) << "popen (" << command << ") failed: " << safe_strerror(errno);
+    LOG(ERROR) << "popen (" << command << ") failed: "
+               << base::safe_strerror(errno);
     return false;
   }
 
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index f4ea8567..8ade28f 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -42,6 +42,7 @@
 #include "media/audio/audio_manager.h"
 #include "media/audio/audio_manager_factory.h"
 #include "media/base/browser_cdm_factory.h"
+#include "media/base/media.h"
 #include "ui/compositor/compositor_switches.h"
 
 #if defined(OS_ANDROID)
@@ -321,6 +322,7 @@
       make_scoped_ptr(new RemoteDebuggingServer()));
 
   media::CastMediaShlib::Initialize(cmd_line->argv());
+  ::media::InitializeMediaLibrary();
 
   cast_browser_process_->SetCastService(CastService::Create(
       cast_browser_process_->browser_context(),
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 9e265ae..8593825 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -65,11 +65,35 @@
       url_request_context_factory_.release());
 }
 
+void CastContentBrowserClient::AppendExtraCommandLineSwitches(
+    base::CommandLine* command_line) {
+}
+
+std::vector<scoped_refptr<content::BrowserMessageFilter>>
+CastContentBrowserClient::GetBrowserMessageFilters() {
+  return std::vector<scoped_refptr<content::BrowserMessageFilter>>();
+}
+
+scoped_ptr<::media::AudioManagerFactory>
+CastContentBrowserClient::CreateAudioManagerFactory() {
+  // Return nullptr. The factory will not be set, and the statically linked
+  // implementation of AudioManager will be used.
+  return scoped_ptr<::media::AudioManagerFactory>();
+}
+
+#if !defined(OS_ANDROID)
+scoped_ptr<media::MediaPipelineDevice>
+CastContentBrowserClient::CreateMediaPipelineDevice(
+    const media::MediaPipelineDeviceParams& params) {
+  return media::CreateMediaPipelineDevice(params);
+}
+#endif
+
 content::BrowserMainParts* CastContentBrowserClient::CreateBrowserMainParts(
     const content::MainFunctionParams& parameters) {
   return new CastBrowserMainParts(parameters,
                                   url_request_context_factory_.get(),
-                                  PlatformCreateAudioManagerFactory());
+                                  CreateAudioManagerFactory());
 }
 
 void CastContentBrowserClient::RenderProcessWillLaunch(
@@ -79,7 +103,7 @@
       new media::CmaMessageFilterHost(
           host->GetID(),
           base::Bind(
-              &CastContentBrowserClient::PlatformCreateMediaPipelineDevice,
+              &CastContentBrowserClient::CreateMediaPipelineDevice,
               base::Unretained(this))));
   host->AddFilter(cma_message_filter.get());
 #endif  // !defined(OS_ANDROID)
@@ -94,7 +118,7 @@
       base::Bind(&CastContentBrowserClient::AddNetworkHintsMessageFilter,
                  base::Unretained(this), host->GetID()));
 
-  auto extra_filters = PlatformGetBrowserMessageFilters();
+  auto extra_filters = GetBrowserMessageFilters();
   for (auto const& filter : extra_filters) {
     host->AddFilter(filter.get());
   }
@@ -199,7 +223,7 @@
   }
 #endif
 
-  PlatformAppendExtraCommandLineSwitches(command_line);
+  AppendExtraCommandLineSwitches(command_line);
 }
 
 content::AccessTokenStore* CastContentBrowserClient::CreateAccessTokenStore() {
@@ -317,7 +341,8 @@
     bool opener_suppressed,
     content::ResourceContext* context,
     int render_process_id,
-    int opener_id,
+    int opener_render_view_id,
+    int opener_render_frame_id,
     bool* no_javascript_access) {
   *no_javascript_access = true;
   return false;
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h
index fa71076..092d0a7 100644
--- a/chromecast/browser/cast_content_browser_client.h
+++ b/chromecast/browser/cast_content_browser_client.h
@@ -49,17 +49,20 @@
   ~CastContentBrowserClient() override;
 
   // Appends extra command line arguments before launching a new process.
-  void PlatformAppendExtraCommandLineSwitches(base::CommandLine* command_line);
+  virtual void AppendExtraCommandLineSwitches(base::CommandLine* command_line);
 
-  // Returns any BrowserMessageFilters from the platform implementation that
-  // should be added when launching a new render process.
-  std::vector<scoped_refptr<content::BrowserMessageFilter>>
-  PlatformGetBrowserMessageFilters();
+  // Returns any BrowserMessageFilters that should be added when launching a
+  // new render process.
+  virtual std::vector<scoped_refptr<content::BrowserMessageFilter>>
+  GetBrowserMessageFilters();
+
+  // Provide an AudioManagerFactory instance for WebAudio playback.
+  virtual scoped_ptr<::media::AudioManagerFactory> CreateAudioManagerFactory();
 
 #if !defined(OS_ANDROID)
   // Creates a MediaPipelineDevice (CMA backend) for media playback, called
   // once per media player instance.
-  scoped_ptr<media::MediaPipelineDevice> PlatformCreateMediaPipelineDevice(
+  virtual scoped_ptr<media::MediaPipelineDevice> CreateMediaPipelineDevice(
       const media::MediaPipelineDeviceParams& params);
 #endif
 
@@ -112,7 +115,8 @@
       bool opener_suppressed,
       content::ResourceContext* context,
       int render_process_id,
-      int opener_id,
+      int opener_render_view_id,
+      int opener_render_frame_id,
       bool* no_javascript_access) override;
   void GetAdditionalMappedFilesForChildProcess(
       const base::CommandLine& command_line,
@@ -135,8 +139,6 @@
       GURL requesting_url,
       int render_process_id);
 
-  scoped_ptr<::media::AudioManagerFactory> PlatformCreateAudioManagerFactory();
-
 #if !defined(OS_ANDROID)
   // Returns the crash signal FD corresponding to the current process type.
   int GetCrashSignalFD(const base::CommandLine& command_line);
diff --git a/chromecast/browser/cast_content_browser_client_simple.cc b/chromecast/browser/cast_content_browser_client_simple.cc
index 63a47040..c88e9f6d 100644
--- a/chromecast/browser/cast_content_browser_client_simple.cc
+++ b/chromecast/browser/cast_content_browser_client_simple.cc
@@ -17,29 +17,5 @@
   return make_scoped_ptr(new CastContentBrowserClient());
 }
 
-void CastContentBrowserClient::PlatformAppendExtraCommandLineSwitches(
-    base::CommandLine* command_line) {
-}
-
-std::vector<scoped_refptr<content::BrowserMessageFilter>>
-CastContentBrowserClient::PlatformGetBrowserMessageFilters() {
-  return std::vector<scoped_refptr<content::BrowserMessageFilter>>();
-}
-
-scoped_ptr<::media::AudioManagerFactory>
-CastContentBrowserClient::PlatformCreateAudioManagerFactory() {
-  // Return nullptr. The factory will not be set, and the statically linked
-  // implementation of AudioManager will be used.
-  return scoped_ptr<::media::AudioManagerFactory>();
-}
-
-#if !defined(OS_ANDROID)
-scoped_ptr<media::MediaPipelineDevice>
-CastContentBrowserClient::PlatformCreateMediaPipelineDevice(
-    const media::MediaPipelineDeviceParams& params) {
-  return media::CreateMediaPipelineDevice(params);
-}
-#endif
-
 }  // namespace shell
 }  // namespace chromecast
diff --git a/chromecast/chromecast.gyp b/chromecast/chromecast.gyp
index 9519c65..325f47b 100644
--- a/chromecast/chromecast.gyp
+++ b/chromecast/chromecast.gyp
@@ -310,7 +310,6 @@
             'browser/pref_service_helper_simple.cc',
             'common/platform_client_auth_simple.cc',
             'renderer/cast_content_renderer_client_simple.cc',
-            'renderer/key_systems_cast_simple.cc',
           ],
           'conditions': [
             ['OS=="android"', {
diff --git a/chromecast/chromecast_tests.gypi b/chromecast/chromecast_tests.gypi
index 5f9aa93..08efa7dc 100644
--- a/chromecast/chromecast_tests.gypi
+++ b/chromecast/chromecast_tests.gypi
@@ -122,6 +122,14 @@
             ],
           },
         }],
+        ['disable_display==1', {
+          'variables': {
+            'filters': [
+              # These are not supported by the backend right now. b/21737919
+              'cast_media_unittests --gtest_filter=-AudioVideoPipelineDeviceTest.VorbisPlayback:AudioVideoPipelineDeviceTest.WebmPlayback',
+            ],
+          }
+        }],
       ],
       'includes': ['build/tests/test_list.gypi'],
     },
diff --git a/chromecast/media/BUILD.gn b/chromecast/media/BUILD.gn
index 6a8c6a6..d99640b8 100644
--- a/chromecast/media/BUILD.gn
+++ b/chromecast/media/BUILD.gn
@@ -20,10 +20,13 @@
     "cma/base/buffering_controller_unittest.cc",
     "cma/base/buffering_frame_provider_unittest.cc",
     "cma/filters/demuxer_stream_adapter_unittest.cc",
+    "cma/filters/multi_demuxer_stream_adapter_unittest.cc",
     "cma/ipc/media_message_fifo_unittest.cc",
     "cma/ipc/media_message_unittest.cc",
     "cma/ipc_streamer/av_streamer_unittest.cc",
     "cma/pipeline/audio_video_pipeline_impl_unittest.cc",
+    "cma/test/demuxer_stream_for_test.cc",
+    "cma/test/demuxer_stream_for_test.h",
     "cma/test/frame_generator_for_test.cc",
     "cma/test/frame_generator_for_test.h",
     "cma/test/frame_segmenter_for_test.cc",
diff --git a/chromecast/media/cdm/chromecast_init_data.cc b/chromecast/media/cdm/chromecast_init_data.cc
index ba27d2ef..d9e76a5 100644
--- a/chromecast/media/cdm/chromecast_init_data.cc
+++ b/chromecast/media/cdm/chromecast_init_data.cc
@@ -107,6 +107,11 @@
     RCHECK(reader.SkipBits(16 * 8));
     box_bytes_read += 16;
 
+    uint32_t data_size;
+    RCHECK(reader.ReadBits(4 * 8, &data_size));
+    box_bytes_read += 4;
+    RCHECK(data_size == box_size - box_bytes_read);
+
     uint16_t msg_type;
     RCHECK(reader.ReadBits(2 * 8, &msg_type));
     box_bytes_read += 2;
diff --git a/chromecast/media/cdm/chromecast_init_data_unittest.cc b/chromecast/media/cdm/chromecast_init_data_unittest.cc
index 763d797..8a4ad3254 100644
--- a/chromecast/media/cdm/chromecast_init_data_unittest.cc
+++ b/chromecast/media/cdm/chromecast_init_data_unittest.cc
@@ -62,11 +62,12 @@
 
 TEST(ChromecastInitDataTest, TestPsshCustomData) {
   const uint8_t kInitDataBlob[] = {
-      0x00, 0x00, 0x00, 0x2E,  // length
+      0x00, 0x00, 0x00, 0x32,  // length
       0x70, 0x73, 0x73, 0x68,  // 'pssh'
       0x00, 0x00, 0x00, 0x00,  // version / flags
       0x2B, 0xF8, 0x66, 0x80, 0xC6, 0xE5, 0x4E, 0x24, 0xBE,
       0x23, 0x0F, 0x81, 0x5A, 0x60, 0x6E, 0xB2,  // UUID
+      0x00, 0x00, 0x00, 0x12,                    // data size
       0x00, 0x01,                                // message type (CUSTOM_DATA)
       0x54, 0x65, 0x73, 0x74, 0x20, 0x63, 0x75, 0x73, 0x74,
       0x6F, 0x6D, 0x20, 0x64, 0x61, 0x74, 0x61  // 'Test custom data'
@@ -84,13 +85,34 @@
             std::string(init_data.data.begin(), init_data.data.end()));
 }
 
+TEST(ChromecastInitDataTest, TestPsshCustomData_NoSize) {
+  const uint8_t kInitDataBlob[] = {
+      0x00, 0x00, 0x00, 0x2E,  // length
+      0x70, 0x73, 0x73, 0x68,  // 'pssh'
+      0x00, 0x00, 0x00, 0x00,  // version / flags
+      0x2B, 0xF8, 0x66, 0x80, 0xC6, 0xE5, 0x4E, 0x24, 0xBE,
+      0x23, 0x0F, 0x81, 0x5A, 0x60, 0x6E, 0xB2,  // UUID
+      // [missing size should be present here].
+      0x00, 0x01,                                // message type (CUSTOM_DATA)
+      0x54, 0x65, 0x73, 0x74, 0x20, 0x63, 0x75, 0x73, 0x74,
+      0x6F, 0x6D, 0x20, 0x64, 0x61, 0x74, 0x61  // 'Test custom data'
+  };
+
+  ChromecastInitData init_data;
+  EXPECT_FALSE(FindChromecastInitData(
+      std::vector<uint8_t>(kInitDataBlob,
+                           kInitDataBlob + sizeof(kInitDataBlob)),
+      InitDataMessageType::CUSTOM_DATA, &init_data));
+}
+
 TEST(ChromecastInitDataTest, TestPsshSecureStop) {
   const uint8_t kInitDataBlob[] = {
-      0x00, 0x00, 0x00, 0x1E,  // length
+      0x00, 0x00, 0x00, 0x22,  // length
       0x70, 0x73, 0x73, 0x68,  // 'pssh'
       0x00, 0x00, 0x00, 0x00,  // version / flags
       0x2B, 0xF8, 0x66, 0x80, 0xC6, 0xE5, 0x4E, 0x24,
       0xBE, 0x23, 0x0F, 0x81, 0x5A, 0x60, 0x6E, 0xB2,  // UUID
+      0x00, 0x00, 0x00, 0x02, // data size
       0x00, 0x02,  // message type (ENABLE_SECURE_STOP)
   };
 
@@ -104,5 +126,23 @@
   EXPECT_EQ(0u, init_data.data.size());
 }
 
+TEST(ChromecastInitDataTest, TestPsshSecureStop_NoSize) {
+  const uint8_t kInitDataBlob[] = {
+      0x00, 0x00, 0x00, 0x1E,  // length
+      0x70, 0x73, 0x73, 0x68,  // 'pssh'
+      0x00, 0x00, 0x00, 0x00,  // version / flags
+      0x2B, 0xF8, 0x66, 0x80, 0xC6, 0xE5, 0x4E, 0x24,
+      0xBE, 0x23, 0x0F, 0x81, 0x5A, 0x60, 0x6E, 0xB2,  // UUID
+      // [missing size should be present here].
+      0x00, 0x02,  // message type (ENABLE_SECURE_STOP)
+  };
+
+  ChromecastInitData init_data;
+  EXPECT_FALSE(FindChromecastInitData(
+      std::vector<uint8_t>(kInitDataBlob,
+                           kInitDataBlob + sizeof(kInitDataBlob)),
+      InitDataMessageType::ENABLE_SECURE_STOP, &init_data));
+}
+
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc b/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc
index 78452968..02e29d4 100644
--- a/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc
+++ b/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc
@@ -189,6 +189,13 @@
   expected_task_timestamps_.pop_front();
 
   contexts_[task_runner_id].is_pending_task = false;
+
+  // Release task runner if the task has ended
+  // otherwise, the task runner may may block other streams
+  auto& context = contexts_[task_runner_id];
+  if (context.task_index >= context.task_timestamp_list.size()) {
+    context.media_task_runner = nullptr;
+  }
 }
 
 void BalancedMediaTaskRunnerTest::OnTestTimeout() {
@@ -258,5 +265,29 @@
   EXPECT_TRUE(expected_task_timestamps_.empty());
 }
 
+TEST_F(BalancedMediaTaskRunnerTest, TwoStreamsOfDifferentLength) {
+  scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
+
+  std::vector<std::vector<int>> timestamps = {
+      // One longer stream and one shorter stream.
+      // The longer stream runs first, then the shorter stream begins.
+      // After shorter stream ends, it shouldn't block the longer one.
+      {0, 20, 40, 60, 80, 100, 120, 140, 160},
+      {51, 61, 71, 81},
+  };
+
+  std::vector<int> expected_timestamps = {
+      0, 20, 40, 60, 51, 80, 61, 71, 81, 100, 120, 140, 160};
+
+  std::vector<size_t> scheduling_pattern = {
+      0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0};
+
+  SetupTest(base::TimeDelta::FromMilliseconds(30), timestamps,
+            scheduling_pattern, expected_timestamps);
+  ProcessAllTasks();
+  message_loop->Run();
+  EXPECT_TRUE(expected_task_timestamps_.empty());
+}
+
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc b/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
index 5242c40..f7d668a1 100644
--- a/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
+++ b/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
@@ -8,12 +8,14 @@
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
 #include "chromecast/media/cma/base/decoder_buffer_base.h"
 #include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
+#include "chromecast/media/cma/test/demuxer_stream_for_test.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/demuxer_stream.h"
@@ -23,133 +25,6 @@
 namespace chromecast {
 namespace media {
 
-namespace {
-
-class DummyDemuxerStream : public ::media::DemuxerStream {
- public:
-  // Creates a demuxer stream which provides frames either with a delay
-  // or instantly. The scheduling pattern is the following:
-  // - provides |delayed_frame_count| frames with a delay,
-  // - then provides the following |cycle_count| - |delayed_frame_count|
-  //   instantly,
-  // - then provides |delayed_frame_count| frames with a delay,
-  // - ... and so on.
-  // Special cases:
-  // - all frames are delayed: |delayed_frame_count| = |cycle_count|
-  // - all frames are provided instantly: |delayed_frame_count| = 0
-  // |config_idx| is a list of frame index before which there is
-  // a change of decoder configuration.
-  DummyDemuxerStream(int cycle_count,
-                     int delayed_frame_count,
-                     const std::list<int>& config_idx);
-  ~DummyDemuxerStream() override;
-
-  // ::media::DemuxerStream implementation.
-  void Read(const ReadCB& read_cb) override;
-  ::media::AudioDecoderConfig audio_decoder_config() override;
-  ::media::VideoDecoderConfig video_decoder_config() override;
-  Type type() const override;
-  bool SupportsConfigChanges() override;
-  ::media::VideoRotation video_rotation() override;
-
-  bool has_pending_read() const {
-    return has_pending_read_;
-  }
-
- private:
-  void DoRead(const ReadCB& read_cb);
-
-  // Demuxer configuration.
-  const int cycle_count_;
-  const int delayed_frame_count_;
-  std::list<int> config_idx_;
-
-  // Number of frames sent so far.
-  int frame_count_;
-
-  bool has_pending_read_;
-
-  DISALLOW_COPY_AND_ASSIGN(DummyDemuxerStream);
-};
-
-DummyDemuxerStream::DummyDemuxerStream(
-    int cycle_count,
-    int delayed_frame_count,
-    const std::list<int>& config_idx)
-  : cycle_count_(cycle_count),
-    delayed_frame_count_(delayed_frame_count),
-    config_idx_(config_idx),
-    frame_count_(0),
-    has_pending_read_(false) {
-  DCHECK_LE(delayed_frame_count, cycle_count);
-}
-
-DummyDemuxerStream::~DummyDemuxerStream() {
-}
-
-void DummyDemuxerStream::Read(const ReadCB& read_cb) {
-  has_pending_read_ = true;
-  if (!config_idx_.empty() && config_idx_.front() == frame_count_) {
-    config_idx_.pop_front();
-    has_pending_read_ = false;
-    read_cb.Run(kConfigChanged,
-                scoped_refptr<::media::DecoderBuffer>());
-    return;
-  }
-
-  if ((frame_count_ % cycle_count_) < delayed_frame_count_) {
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, base::Bind(&DummyDemuxerStream::DoRead,
-                              base::Unretained(this), read_cb),
-        base::TimeDelta::FromMilliseconds(20));
-    return;
-  }
-  DoRead(read_cb);
-}
-
-::media::AudioDecoderConfig DummyDemuxerStream::audio_decoder_config() {
-  LOG(FATAL) << "DummyDemuxerStream is a video DemuxerStream";
-  return ::media::AudioDecoderConfig();
-}
-
-::media::VideoDecoderConfig DummyDemuxerStream::video_decoder_config() {
-  gfx::Size coded_size(640, 480);
-  gfx::Rect visible_rect(640, 480);
-  gfx::Size natural_size(640, 480);
-  return ::media::VideoDecoderConfig(
-      ::media::kCodecH264,
-      ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
-      ::media::VideoFrame::YV12,
-      coded_size,
-      visible_rect,
-      natural_size,
-      NULL, 0,
-      false);
-}
-
-::media::DemuxerStream::Type DummyDemuxerStream::type() const {
-  return VIDEO;
-}
-
-bool DummyDemuxerStream::SupportsConfigChanges() {
-  return true;
-}
-
-::media::VideoRotation DummyDemuxerStream::video_rotation() {
-  return ::media::VIDEO_ROTATION_0;
-}
-
-void DummyDemuxerStream::DoRead(const ReadCB& read_cb) {
-  has_pending_read_ = false;
-  scoped_refptr<::media::DecoderBuffer> buffer(
-      new ::media::DecoderBuffer(16));
-  buffer->set_timestamp(frame_count_ * base::TimeDelta::FromMilliseconds(40));
-  frame_count_++;
-  read_cb.Run(kOk, buffer);
-}
-
-}  // namespace
-
 class DemuxerStreamAdapterTest : public testing::Test {
  public:
   DemuxerStreamAdapterTest();
@@ -181,7 +56,7 @@
   // List of expected frame indices with decoder config changes.
   std::list<int> config_idx_;
 
-  scoped_ptr<DummyDemuxerStream> demuxer_stream_;
+  scoped_ptr<DemuxerStreamForTest> demuxer_stream_;
 
   scoped_ptr<CodedFrameProvider> coded_frame_provider_;
 
@@ -284,9 +159,8 @@
 
   int cycle_count = 1;
   int delayed_frame_count = 0;
-  demuxer_stream_.reset(
-      new DummyDemuxerStream(
-          cycle_count, delayed_frame_count, config_idx_));
+  demuxer_stream_.reset(new DemuxerStreamForTest(
+      -1, cycle_count, delayed_frame_count, config_idx_));
 
   scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
   Initialize(demuxer_stream_.get());
@@ -305,9 +179,8 @@
 
   int cycle_count = 1;
   int delayed_frame_count = 1;
-  demuxer_stream_.reset(
-      new DummyDemuxerStream(
-          cycle_count, delayed_frame_count, config_idx_));
+  demuxer_stream_.reset(new DemuxerStreamForTest(
+      -1, cycle_count, delayed_frame_count, config_idx_));
 
   scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
   Initialize(demuxer_stream_.get());
@@ -327,9 +200,8 @@
 
   int cycle_count = 1;
   int delayed_frame_count = 1;
-  demuxer_stream_.reset(
-      new DummyDemuxerStream(
-          cycle_count, delayed_frame_count, config_idx_));
+  demuxer_stream_.reset(new DemuxerStreamForTest(
+      -1, cycle_count, delayed_frame_count, config_idx_));
 
   scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
   Initialize(demuxer_stream_.get());
diff --git a/chromecast/media/cma/filters/multi_demuxer_stream_adapter_unittest.cc b/chromecast/media/cma/filters/multi_demuxer_stream_adapter_unittest.cc
new file mode 100644
index 0000000..6aaf213
--- /dev/null
+++ b/chromecast/media/cma/filters/multi_demuxer_stream_adapter_unittest.cc
@@ -0,0 +1,162 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
+#include "chromecast/media/cma/base/decoder_buffer_base.h"
+#include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
+#include "chromecast/media/cma/test/demuxer_stream_for_test.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/demuxer_stream.h"
+#include "media/base/video_decoder_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+// Maximum pts diff between frames
+const int kMaxPtsDiffMs = 2000;
+}  // namespace
+
+// Test for multiple streams
+class MultiDemuxerStreamAdaptersTest : public testing::Test {
+ public:
+  MultiDemuxerStreamAdaptersTest();
+  ~MultiDemuxerStreamAdaptersTest() override;
+
+  void Start();
+
+ protected:
+  void OnTestTimeout();
+  void OnNewFrame(CodedFrameProvider* frame_provider,
+                  const scoped_refptr<DecoderBufferBase>& buffer,
+                  const ::media::AudioDecoderConfig& audio_config,
+                  const ::media::VideoDecoderConfig& video_config);
+
+  // Number of expected read frames.
+  int total_expected_frames_;
+
+  // Number of frames actually read so far.
+  int frame_received_count_;
+
+  // List of expected frame indices with decoder config changes.
+  std::list<int> config_idx_;
+
+  ScopedVector<DemuxerStreamForTest> demuxer_streams_;
+
+  ScopedVector<CodedFrameProvider> coded_frame_providers_;
+
+ private:
+  // exit if all of the streams end
+  void OnEos();
+
+  // Number of reading-streams
+  int running_stream_count_;
+
+  scoped_refptr<BalancedMediaTaskRunnerFactory> media_task_runner_factory_;
+  DISALLOW_COPY_AND_ASSIGN(MultiDemuxerStreamAdaptersTest);
+};
+
+MultiDemuxerStreamAdaptersTest::MultiDemuxerStreamAdaptersTest() {
+}
+
+MultiDemuxerStreamAdaptersTest::~MultiDemuxerStreamAdaptersTest() {
+}
+
+void MultiDemuxerStreamAdaptersTest::Start() {
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&MultiDemuxerStreamAdaptersTest::OnTestTimeout,
+                            base::Unretained(this)),
+      base::TimeDelta::FromSeconds(5));
+
+  media_task_runner_factory_ = new BalancedMediaTaskRunnerFactory(
+      base::TimeDelta::FromMilliseconds(kMaxPtsDiffMs));
+
+  coded_frame_providers_.clear();
+  frame_received_count_ = 0;
+
+  for (auto& stream : demuxer_streams_) {
+    coded_frame_providers_.push_back(make_scoped_ptr(
+        new DemuxerStreamAdapter(base::ThreadTaskRunnerHandle::Get(),
+                                 media_task_runner_factory_, stream)));
+  }
+  running_stream_count_ = coded_frame_providers_.size();
+
+  // read each stream
+  for (auto& code_frame_provider : coded_frame_providers_) {
+    auto read_cb = base::Bind(&MultiDemuxerStreamAdaptersTest::OnNewFrame,
+                              base::Unretained(this), code_frame_provider);
+
+    base::Closure task =
+        base::Bind(&CodedFrameProvider::Read,
+                   base::Unretained(code_frame_provider), read_cb);
+
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
+  }
+}
+
+void MultiDemuxerStreamAdaptersTest::OnTestTimeout() {
+  if (running_stream_count_ != 0) {
+    ADD_FAILURE() << "Test timed out";
+  }
+}
+
+void MultiDemuxerStreamAdaptersTest::OnNewFrame(
+    CodedFrameProvider* frame_provider,
+    const scoped_refptr<DecoderBufferBase>& buffer,
+    const ::media::AudioDecoderConfig& audio_config,
+    const ::media::VideoDecoderConfig& video_config) {
+  if (buffer->end_of_stream()) {
+    OnEos();
+    return;
+  }
+
+  frame_received_count_++;
+  auto read_cb = base::Bind(&MultiDemuxerStreamAdaptersTest::OnNewFrame,
+                            base::Unretained(this), frame_provider);
+  frame_provider->Read(read_cb);
+}
+
+void MultiDemuxerStreamAdaptersTest::OnEos() {
+  running_stream_count_--;
+  ASSERT_GE(running_stream_count_, 0);
+  if (running_stream_count_ == 0) {
+    ASSERT_EQ(frame_received_count_, total_expected_frames_);
+    base::MessageLoop::current()->QuitWhenIdle();
+  }
+}
+
+TEST_F(MultiDemuxerStreamAdaptersTest, EarlyEos) {
+  // We have more than one streams here. One of them is much shorter than the
+  // others. When the shortest stream reaches EOS, other streams should still
+  // run as usually. BalancedTaskRunner should not be blocked.
+  int frame_count_short = 2;
+  int frame_count_long =
+      frame_count_short +
+      kMaxPtsDiffMs / DemuxerStreamForTest::kDemuxerStreamForTestFrameDuration +
+      100;
+  demuxer_streams_.push_back(scoped_ptr<DemuxerStreamForTest>(
+      new DemuxerStreamForTest(frame_count_short, 2, 0, config_idx_)));
+  demuxer_streams_.push_back(scoped_ptr<DemuxerStreamForTest>(
+      new DemuxerStreamForTest(frame_count_long, 10, 0, config_idx_)));
+
+  total_expected_frames_ = frame_count_short + frame_count_long;
+
+  scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
+  message_loop->PostTask(FROM_HERE,
+                         base::Bind(&MultiDemuxerStreamAdaptersTest::Start,
+                                    base::Unretained(this)));
+  message_loop->Run();
+}
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc b/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc
index 30ff8952..93d6625 100644
--- a/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc
+++ b/chromecast/media/cma/ipc_streamer/av_streamer_proxy.cc
@@ -56,15 +56,22 @@
 }
 
 void AvStreamerProxy::StopAndFlush(const base::Closure& done_cb) {
-  is_running_ = false;
-
   pending_av_data_ = false;
   pending_audio_config_ = ::media::AudioDecoderConfig();
   pending_video_config_ = ::media::VideoDecoderConfig();
   pending_buffer_ = scoped_refptr<DecoderBufferBase>();
 
   pending_read_ = false;
-  frame_provider_->Flush(done_cb);
+
+  // StopAndFlush may happen twice in a row when Stop happens while a previous
+  // pending Seek (which requires Flush). We only need to perform Flush once
+  // when entering stopped state. Chromium pipeline will call Start eventually
+  // to set is_running_, after Seek (next state of Seek is Play), which
+  // guarantees Flush be called when there is no pending tasks.
+  if (is_running_) {
+    frame_provider_->Flush(done_cb);
+  }
+  is_running_ = false;
 }
 
 void AvStreamerProxy::OnFifoReadEvent() {
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
index fd20ea6..fe5a2ebd 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -162,7 +162,7 @@
   CMALOG(kLogControl) << __FUNCTION__ << " t0=" << time.InMilliseconds();
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(has_audio_ || has_video_);
-  DCHECK(!pending_callbacks_);
+  DCHECK(!pending_flush_callbacks_);
 
   // Reset the start of the timeline.
   DCHECK_EQ(clock_device_->GetState(), MediaClockDevice::kStateIdle);
@@ -209,7 +209,7 @@
   CMALOG(kLogControl) << __FUNCTION__;
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(has_audio_ || has_video_);
-  DCHECK(!pending_callbacks_);
+  DCHECK(!pending_flush_callbacks_);
 
   // No need to update media time anymore.
   enable_time_update_ = false;
@@ -236,7 +236,7 @@
   }
   ::media::PipelineStatusCB transition_cb =
       base::Bind(&MediaPipelineImpl::StateTransition, weak_this_, status_cb);
-  pending_callbacks_ =
+  pending_flush_callbacks_ =
       ::media::SerialRunner::Run(bound_fns, transition_cb);
 }
 
@@ -244,7 +244,11 @@
   CMALOG(kLogControl) << __FUNCTION__;
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(has_audio_ || has_video_);
-  DCHECK(!pending_callbacks_);
+
+  // Cancel pending flush callbacks since we are about to stop/shutdown
+  // audio/video pipelines. This will ensure A/V Flush won't happen in
+  // stopped state.
+  pending_flush_callbacks_.reset();
 
   // No need to update media time anymore.
   enable_time_update_ = false;
@@ -282,7 +286,7 @@
 void MediaPipelineImpl::StateTransition(
     const ::media::PipelineStatusCB& status_cb,
     ::media::PipelineStatus status) {
-  pending_callbacks_.reset();
+  pending_flush_callbacks_.reset();
   status_cb.Run(status);
 }
 
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.h b/chromecast/media/cma/pipeline/media_pipeline_impl.h
index 794437a..71a5384 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.h
@@ -83,7 +83,7 @@
   bool has_video_;
   scoped_ptr<AudioPipelineImpl> audio_pipeline_;
   scoped_ptr<VideoPipelineImpl> video_pipeline_;
-  scoped_ptr<::media::SerialRunner> pending_callbacks_;
+  scoped_ptr< ::media::SerialRunner> pending_flush_callbacks_;
 
   // Playback rate set by the upper layer.
   float target_playback_rate_;
diff --git a/chromecast/media/cma/test/demuxer_stream_for_test.cc b/chromecast/media/cma/test/demuxer_stream_for_test.cc
new file mode 100644
index 0000000..145e5d46
--- /dev/null
+++ b/chromecast/media/cma/test/demuxer_stream_for_test.cc
@@ -0,0 +1,90 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread.h"
+#include "chromecast/media/cma/test/demuxer_stream_for_test.h"
+
+namespace chromecast {
+namespace media {
+
+DemuxerStreamForTest::DemuxerStreamForTest(int total_frames,
+                                           int cycle_count,
+                                           int delayed_frame_count,
+                                           const std::list<int>& config_idx)
+    : total_frame_count_(total_frames),
+      cycle_count_(cycle_count),
+      delayed_frame_count_(delayed_frame_count),
+      config_idx_(config_idx),
+      frame_count_(0),
+      has_pending_read_(false) {
+  DCHECK_LE(delayed_frame_count, cycle_count);
+}
+
+DemuxerStreamForTest::~DemuxerStreamForTest() {
+}
+
+void DemuxerStreamForTest::Read(const ReadCB& read_cb) {
+  has_pending_read_ = true;
+  if (!config_idx_.empty() && config_idx_.front() == frame_count_) {
+    config_idx_.pop_front();
+    has_pending_read_ = false;
+    read_cb.Run(kConfigChanged, scoped_refptr<::media::DecoderBuffer>());
+    return;
+  }
+
+  if ((frame_count_ % cycle_count_) < delayed_frame_count_) {
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&DemuxerStreamForTest::DoRead,
+                              base::Unretained(this), read_cb),
+        base::TimeDelta::FromMilliseconds(20));
+    return;
+  }
+  DoRead(read_cb);
+}
+
+::media::AudioDecoderConfig DemuxerStreamForTest::audio_decoder_config() {
+  NOTREACHED() << "DemuxerStreamForTest is a video DemuxerStream";
+  return ::media::AudioDecoderConfig();
+}
+
+::media::VideoDecoderConfig DemuxerStreamForTest::video_decoder_config() {
+  gfx::Size coded_size(640, 480);
+  gfx::Rect visible_rect(640, 480);
+  gfx::Size natural_size(640, 480);
+  return ::media::VideoDecoderConfig(
+      ::media::kCodecH264, ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
+      ::media::VideoFrame::YV12, coded_size, visible_rect, natural_size, NULL,
+      0, false);
+}
+
+::media::DemuxerStream::Type DemuxerStreamForTest::type() const {
+  return VIDEO;
+}
+
+bool DemuxerStreamForTest::SupportsConfigChanges() {
+  return true;
+}
+
+::media::VideoRotation DemuxerStreamForTest::video_rotation() {
+  return ::media::VIDEO_ROTATION_0;
+}
+
+void DemuxerStreamForTest::DoRead(const ReadCB& read_cb) {
+  has_pending_read_ = false;
+
+  if (total_frame_count_ != -1 && frame_count_ >= total_frame_count_) {
+    // End of stream
+    read_cb.Run(kOk, ::media::DecoderBuffer::CreateEOSBuffer());
+    return;
+  }
+
+  scoped_refptr<::media::DecoderBuffer> buffer(new ::media::DecoderBuffer(16));
+  buffer->set_timestamp(frame_count_ * base::TimeDelta::FromMilliseconds(
+                                           kDemuxerStreamForTestFrameDuration));
+  frame_count_++;
+  read_cb.Run(kOk, buffer);
+}
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/media/cma/test/demuxer_stream_for_test.h b/chromecast/media/cma/test/demuxer_stream_for_test.h
new file mode 100644
index 0000000..afa7aae
--- /dev/null
+++ b/chromecast/media/cma/test/demuxer_stream_for_test.h
@@ -0,0 +1,74 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_MEDIA_CMA_TEST_DUMMY_DEMUXER_STREAM_H_
+#define CHROMECAST_MEDIA_CMA_TEST_DUMMY_DEMUXER_STREAM_H_
+
+#include <list>
+
+#include "base/bind.h"
+#include "base/thread_task_runner_handle.h"
+#include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/demuxer_stream.h"
+
+namespace chromecast {
+namespace media {
+
+class DemuxerStreamForTest : public ::media::DemuxerStream {
+ public:
+  // Creates a demuxer stream which provides frames either with a delay
+  // or instantly.
+  // - |total_frames| is the number of frames to generate before EOS frame.
+  //   -1 means keep generating frames and never produce EOS.
+  // The scheduling pattern is the following:
+  // - provides |delayed_frame_count| frames with a delay,
+  // - then provides the following |cycle_count| - |delayed_frame_count|
+  //   instantly,
+  // - then provides |delayed_frame_count| frames with a delay,
+  // - ... and so on.
+  // Special cases:
+  // - all frames are delayed: |delayed_frame_count| = |cycle_count|
+  // - all frames are provided instantly: |delayed_frame_count| = 0
+  // |config_idx| is a list of frame index before which there is
+  // a change of decoder configuration.
+  DemuxerStreamForTest(int total_frames,
+                       int cycle_count,
+                       int delayed_frame_count,
+                       const std::list<int>& config_idx);
+  ~DemuxerStreamForTest() override;
+
+  // ::media::DemuxerStream implementation.
+  void Read(const ReadCB& read_cb) override;
+  ::media::AudioDecoderConfig audio_decoder_config() override;
+  ::media::VideoDecoderConfig video_decoder_config() override;
+  Type type() const override;
+  bool SupportsConfigChanges() override;
+  ::media::VideoRotation video_rotation() override;
+
+  bool has_pending_read() const { return has_pending_read_; }
+
+  // Frame duration
+  static const int kDemuxerStreamForTestFrameDuration = 40;
+
+ private:
+  void DoRead(const ReadCB& read_cb);
+
+  // Demuxer configuration.
+  int total_frame_count_;
+  const int cycle_count_;
+  const int delayed_frame_count_;
+  std::list<int> config_idx_;
+
+  // Number of frames sent so far.
+  int frame_count_;
+
+  bool has_pending_read_;
+
+  DISALLOW_COPY_AND_ASSIGN(DemuxerStreamForTest);
+};
+
+}  // namespace media
+}  // namespace chromecast
+#endif
diff --git a/chromecast/media/cma/test/frame_segmenter_for_test.cc b/chromecast/media/cma/test/frame_segmenter_for_test.cc
index 97adfe0..ec16b21 100644
--- a/chromecast/media/cma/test/frame_segmenter_for_test.cc
+++ b/chromecast/media/cma/test/frame_segmenter_for_test.cc
@@ -4,10 +4,11 @@
 
 #include "chromecast/media/cma/test/frame_segmenter_for_test.h"
 
+#include <stdint.h>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
-#include "base/port.h"
 #include "base/run_loop.h"
 #include "base/thread_task_runner_handle.h"
 #include "chromecast/media/cma/base/decoder_buffer_adapter.h"
@@ -83,7 +84,7 @@
   return header;
 }
 
-}
+}  // namespace
 
 BufferList Mp3SegmenterForTest(const uint8* data, size_t data_size) {
   size_t offset = 0;
@@ -108,7 +109,7 @@
 
     // 1152 samples in an MP3 frame.
     timestamp += base::TimeDelta::FromMicroseconds(
-        (GG_UINT64_C(1152) * 1000 * 1000) / header.sampling_frequency);
+        (UINT64_C(1152) * 1000 * 1000) / header.sampling_frequency);
   }
   return audio_frames;
 }
diff --git a/chromecast/media/cma/test/run_all_unittests.cc b/chromecast/media/cma/test/run_all_unittests.cc
index 4820fb0f7..133f8bed 100644
--- a/chromecast/media/cma/test/run_all_unittests.cc
+++ b/chromecast/media/cma/test/run_all_unittests.cc
@@ -33,7 +33,7 @@
 
   // Initialize the FFMpeg library.
   // Note: at this time, AtExitManager is already present.
-  media::InitializeMediaLibraryForTesting();
+  media::InitializeMediaLibrary();
 }
 
 int main(int argc, char** argv) {
diff --git a/chromecast/media/media.gyp b/chromecast/media/media.gyp
index 348ca37..11e4d08a 100644
--- a/chromecast/media/media.gyp
+++ b/chromecast/media/media.gyp
@@ -285,11 +285,14 @@
         'cma/base/buffering_controller_unittest.cc',
         'cma/base/buffering_frame_provider_unittest.cc',
         'cma/filters/demuxer_stream_adapter_unittest.cc',
+        'cma/filters/multi_demuxer_stream_adapter_unittest.cc',
         'cma/ipc/media_message_fifo_unittest.cc',
         'cma/ipc/media_message_unittest.cc',
         'cma/ipc_streamer/av_streamer_unittest.cc',
         'cma/pipeline/audio_video_pipeline_impl_unittest.cc',
         'cma/test/cma_end_to_end_test.cc',
+        'cma/test/demuxer_stream_for_test.cc',
+        'cma/test/demuxer_stream_for_test.h',
         'cma/test/frame_generator_for_test.cc',
         'cma/test/frame_generator_for_test.h',
         'cma/test/frame_segmenter_for_test.cc',
diff --git a/chromecast/net/connectivity_checker_impl.cc b/chromecast/net/connectivity_checker_impl.cc
index d10d06a1..7d302b4 100644
--- a/chromecast/net/connectivity_checker_impl.cc
+++ b/chromecast/net/connectivity_checker_impl.cc
@@ -28,6 +28,9 @@
 // to offline.
 const unsigned int kNumErrorsToNotifyOffline = 3;
 
+// Request timeout value in seconds.
+const unsigned int kRequestTimeoutInSeconds = 3;
+
 // Default url for connectivity checking.
 const char kDefaultConnectivityCheckUrl[] =
     "https://clients3.google.com/generate_204";
@@ -106,6 +109,13 @@
       *connectivity_check_url_, net::MAXIMUM_PRIORITY, this);
   url_request_->set_method("HEAD");
   url_request_->Start();
+
+  timeout_.Reset(base::Bind(&ConnectivityCheckerImpl::OnUrlRequestTimeout,
+                            this));
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      timeout_.callback(),
+      base::TimeDelta::FromSeconds(kRequestTimeoutInSeconds));
 }
 
 void ConnectivityCheckerImpl::OnNetworkChanged(
@@ -122,6 +132,7 @@
 }
 
 void ConnectivityCheckerImpl::OnResponseStarted(net::URLRequest* request) {
+  timeout_.Cancel();
   int http_response_code =
       (request->status().is_success() &&
        request->response_info().headers.get() != NULL)
@@ -141,11 +152,17 @@
   OnUrlRequestError();
 }
 
+void ConnectivityCheckerImpl::OnReadCompleted(net::URLRequest* request,
+                                              int bytes_read) {
+  NOTREACHED();
+}
+
 void ConnectivityCheckerImpl::OnSSLCertificateError(
     net::URLRequest* request,
     const net::SSLInfo& ssl_info,
     bool fatal) {
   LOG(ERROR) << "OnSSLCertificateError";
+  timeout_.Cancel();
   OnUrlRequestError();
 }
 
@@ -162,16 +179,17 @@
       base::TimeDelta::FromSeconds(kConnectivityPeriodSeconds));
 }
 
-void ConnectivityCheckerImpl::OnReadCompleted(net::URLRequest* request,
-                                              int bytes_read) {
-  NOTREACHED();
+void ConnectivityCheckerImpl::OnUrlRequestTimeout() {
+  LOG(ERROR) << "time out";
+  OnUrlRequestError();
 }
 
 void ConnectivityCheckerImpl::Cancel() {
-  if (url_request_.get()) {
-    VLOG(2) << "Cancel connectivity check in progress";
-    url_request_.reset(NULL);  // URLRequest::Cancel() is called in destructor.
-  }
+  if (!url_request_.get())
+    return;
+  VLOG(2) << "Cancel connectivity check in progress";
+  timeout_.Cancel();
+  url_request_.reset(NULL);  // URLRequest::Cancel() is called in destructor.
 }
 
 }  // namespace chromecast
diff --git a/chromecast/net/connectivity_checker_impl.h b/chromecast/net/connectivity_checker_impl.h
index f356234..da15039 100644
--- a/chromecast/net/connectivity_checker_impl.h
+++ b/chromecast/net/connectivity_checker_impl.h
@@ -5,6 +5,7 @@
 #ifndef CHROMECAST_NET_CONNECTIVITY_CHECKER_IMPL_H_
 #define CHROMECAST_NET_CONNECTIVITY_CHECKER_IMPL_H_
 
+#include "base/cancelable_callback.h"
 #include "chromecast/net/connectivity_checker.h"
 #include "net/base/network_change_notifier.h"
 #include "net/url_request/url_request.h"
@@ -64,6 +65,9 @@
   // Called when URL request failed.
   void OnUrlRequestError();
 
+  // Called when URL request timed out.
+  void OnUrlRequestTimeout();
+
   scoped_ptr<GURL> connectivity_check_url_;
   scoped_ptr<net::URLRequestContext> url_request_context_;
   scoped_ptr<net::URLRequest> url_request_;
@@ -71,6 +75,7 @@
   bool connected_;
   // Number of connectivity check errors.
   unsigned int check_errors_;
+  base::CancelableCallback<void()> timeout_;
 
   DISALLOW_COPY_AND_ASSIGN(ConnectivityCheckerImpl);
 };
diff --git a/chromecast/renderer/cast_content_renderer_client.cc b/chromecast/renderer/cast_content_renderer_client.cc
index 3e8170f..3f48cb4 100644
--- a/chromecast/renderer/cast_content_renderer_client.cc
+++ b/chromecast/renderer/cast_content_renderer_client.cc
@@ -72,18 +72,27 @@
 
 class CastRenderViewObserver : content::RenderViewObserver {
  public:
-  explicit CastRenderViewObserver(content::RenderView* render_view);
+  CastRenderViewObserver(CastContentRendererClient* client,
+                         content::RenderView* render_view);
   ~CastRenderViewObserver() override {}
 
   void DidClearWindowObject(blink::WebLocalFrame* frame) override;
+
+ private:
+  CastContentRendererClient* const client_;
+
+  DISALLOW_COPY_AND_ASSIGN(CastRenderViewObserver);
 };
 
-CastRenderViewObserver::CastRenderViewObserver(content::RenderView* render_view)
-    : content::RenderViewObserver(render_view) {
+CastRenderViewObserver::CastRenderViewObserver(
+    CastContentRendererClient* client,
+    content::RenderView* render_view)
+    : content::RenderViewObserver(render_view),
+      client_(client) {
 }
 
 void CastRenderViewObserver::DidClearWindowObject(blink::WebLocalFrame* frame) {
-  PlatformAddRendererNativeBindings(frame);
+  client_->AddRendererNativeBindings(frame);
 }
 
 }  // namespace
@@ -94,6 +103,15 @@
 CastContentRendererClient::~CastContentRendererClient() {
 }
 
+void CastContentRendererClient::AddRendererNativeBindings(
+    blink::WebLocalFrame* frame) {
+}
+
+std::vector<scoped_refptr<IPC::MessageFilter>>
+CastContentRendererClient::GetRendererMessageFilters() {
+  return std::vector<scoped_refptr<IPC::MessageFilter>>();
+}
+
 void CastContentRendererClient::RenderThreadStarted() {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
 #if defined(USE_NSS_CERTS)
@@ -121,7 +139,7 @@
   }
 
   cast_observer_.reset(
-      new CastRenderProcessObserver(PlatformGetRendererMessageFilters()));
+      new CastRenderProcessObserver(GetRendererMessageFilters()));
 
   prescient_networking_dispatcher_.reset(
       new network_hints::PrescientNetworkingDispatcher());
@@ -161,13 +179,12 @@
   }
 
   // Note: RenderView will own the lifetime of its observer.
-  new CastRenderViewObserver(render_view);
+  new CastRenderViewObserver(this, render_view);
 }
 
 void CastContentRendererClient::AddKeySystems(
     std::vector< ::media::KeySystemInfo>* key_systems) {
   AddChromecastKeySystems(key_systems);
-  AddChromecastPlatformKeySystems(key_systems);
 }
 
 #if !defined(OS_ANDROID)
diff --git a/chromecast/renderer/cast_content_renderer_client.h b/chromecast/renderer/cast_content_renderer_client.h
index f8539f61..a29d2d1 100644
--- a/chromecast/renderer/cast_content_renderer_client.h
+++ b/chromecast/renderer/cast_content_renderer_client.h
@@ -22,9 +22,6 @@
 namespace shell {
 class CastRenderProcessObserver;
 
-// Adds any platform-specific bindings to the current frame.
-void PlatformAddRendererNativeBindings(blink::WebLocalFrame* frame);
-
 class CastContentRendererClient : public content::ContentRendererClient {
  public:
   // Creates an implementation of CastContentRendererClient. Platform should
@@ -33,10 +30,13 @@
 
   ~CastContentRendererClient() override;
 
+  // Adds any platform-specific bindings to the current frame.
+  virtual void AddRendererNativeBindings(blink::WebLocalFrame* frame);
+
   // Returns any MessageFilters from the platform implementation that should
   // be added to the render process.
-  std::vector<scoped_refptr<IPC::MessageFilter>>
-  PlatformGetRendererMessageFilters();
+  virtual std::vector<scoped_refptr<IPC::MessageFilter>>
+  GetRendererMessageFilters();
 
   // ContentRendererClient implementation:
   void RenderThreadStarted() override;
diff --git a/chromecast/renderer/cast_content_renderer_client_simple.cc b/chromecast/renderer/cast_content_renderer_client_simple.cc
index f1d4cf2c..5f94e08e 100644
--- a/chromecast/renderer/cast_content_renderer_client_simple.cc
+++ b/chromecast/renderer/cast_content_renderer_client_simple.cc
@@ -15,13 +15,5 @@
   return make_scoped_ptr(new CastContentRendererClient());
 }
 
-void PlatformAddRendererNativeBindings(blink::WebLocalFrame* frame) {
-}
-
-std::vector<scoped_refptr<IPC::MessageFilter>>
-CastContentRendererClient::PlatformGetRendererMessageFilters() {
-  return std::vector<scoped_refptr<IPC::MessageFilter>>();
-}
-
 }  // namespace shell
 }  // namespace chromecast
diff --git a/chromecast/renderer/key_systems_cast.h b/chromecast/renderer/key_systems_cast.h
index c64eb1d..d59993f 100644
--- a/chromecast/renderer/key_systems_cast.h
+++ b/chromecast/renderer/key_systems_cast.h
@@ -22,10 +22,6 @@
 void AddChromecastKeySystems(
     std::vector<::media::KeySystemInfo>* key_systems_info);
 
-// TODO(gunsch): Remove when prefixed EME is removed.
-void AddChromecastPlatformKeySystems(
-    std::vector<::media::KeySystemInfo>* key_systems_info);
-
 }  // namespace shell
 }  // namespace chromecast
 
diff --git a/chromecast/renderer/key_systems_cast_simple.cc b/chromecast/renderer/key_systems_cast_simple.cc
deleted file mode 100644
index e5ca3783..0000000
--- a/chromecast/renderer/key_systems_cast_simple.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromecast/renderer/key_systems_cast.h"
-
-namespace chromecast {
-namespace shell {
-
-void AddChromecastPlatformKeySystems(
-    std::vector< ::media::KeySystemInfo>* key_systems_info) {
-  // Intentional no-op for public build.
-}
-
-}  // namespace shell
-}  // namespace chromecast
diff --git a/chromecast/renderer/media/media_pipeline_proxy.cc b/chromecast/renderer/media/media_pipeline_proxy.cc
index 559f2e07..38a69980 100644
--- a/chromecast/renderer/media/media_pipeline_proxy.cc
+++ b/chromecast/renderer/media/media_pipeline_proxy.cc
@@ -246,7 +246,7 @@
   }
   ::media::PipelineStatusCB cb =
       base::Bind(&MediaPipelineProxy::OnProxyFlushDone, weak_this_, status_cb);
-  pending_callbacks_ = ::media::SerialRunner::Run(bound_fns, cb);
+  pending_flush_callbacks_ = ::media::SerialRunner::Run(bound_fns, cb);
 }
 
 void MediaPipelineProxy::OnProxyFlushDone(
@@ -254,7 +254,7 @@
     ::media::PipelineStatus status) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(status, ::media::PIPELINE_OK);
-  pending_callbacks_.reset();
+  pending_flush_callbacks_.reset();
   FORWARD_ON_IO_THREAD(Flush, status_cb);
 }
 
@@ -262,6 +262,11 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(has_audio_ || has_video_);
 
+  // Cancel pending flush callbacks since we are about to stop/shutdown
+  // audio/video pipelines. This will ensure A/V Flush won't happen in
+  // stopped state.
+  pending_flush_callbacks_.reset();
+
   if (has_audio_)
     audio_pipeline_->Stop();
   if (has_video_)
@@ -276,4 +281,4 @@
 }
 
 }  // namespace cma
-}  // namespace chromecast
\ No newline at end of file
+}  // namespace chromecast
diff --git a/chromecast/renderer/media/media_pipeline_proxy.h b/chromecast/renderer/media/media_pipeline_proxy.h
index a39ef1c..1e8e9e6 100644
--- a/chromecast/renderer/media/media_pipeline_proxy.h
+++ b/chromecast/renderer/media/media_pipeline_proxy.h
@@ -70,7 +70,7 @@
   bool has_video_;
   scoped_ptr<AudioPipelineProxy> audio_pipeline_;
   scoped_ptr<VideoPipelineProxy> video_pipeline_;
-  scoped_ptr<::media::SerialRunner> pending_callbacks_;
+  scoped_ptr< ::media::SerialRunner> pending_flush_callbacks_;
 
   base::WeakPtr<MediaPipelineProxy> weak_this_;
   base::WeakPtrFactory<MediaPipelineProxy> weak_factory_;
@@ -81,4 +81,4 @@
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_RENDERER_MEDIA_MEDIA_PIPELINE_PROXY_H_
\ No newline at end of file
+#endif  // CHROMECAST_RENDERER_MEDIA_MEDIA_PIPELINE_PROXY_H_
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 0d14601..cae59e49 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7142.0.0
\ No newline at end of file
+7158.0.0
\ No newline at end of file
diff --git a/chromeos/accelerometer/accelerometer_reader.cc b/chromeos/accelerometer/accelerometer_reader.cc
index a89cdd6e..bca962fe3 100644
--- a/chromeos/accelerometer/accelerometer_reader.cc
+++ b/chromeos/accelerometer/accelerometer_reader.cc
@@ -10,12 +10,13 @@
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/task_runner.h"
 #include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 
 namespace chromeos {
@@ -265,10 +266,9 @@
   }
 
   // Trigger another read after the current sampling delay.
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&AccelerometerReader::TriggerRead,
-                 weak_factory_.GetWeakPtr()),
+      base::Bind(&AccelerometerReader::TriggerRead, weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromMilliseconds(kDelayBetweenReadsMs));
 }
 
diff --git a/chromeos/cert_loader.cc b/chromeos/cert_loader.cc
index 747f6256..0940f52 100644
--- a/chromeos/cert_loader.cc
+++ b/chromeos/cert_loader.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task_runner_util.h"
 #include "base/threading/worker_pool.h"
diff --git a/chromeos/cryptohome/async_method_caller.cc b/chromeos/cryptohome/async_method_caller.cc
index 8348fd2..eab0bd5 100644
--- a/chromeos/cryptohome/async_method_caller.cc
+++ b/chromeos/cryptohome/async_method_caller.cc
@@ -7,7 +7,8 @@
 #include "base/bind.h"
 #include "base/containers/hash_tables.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 
 using chromeos::DBusThreadManager;
@@ -252,10 +253,9 @@
     CallbackElement() {}
     explicit CallbackElement(const AsyncMethodCaller::Callback& callback)
         : callback(callback),
-          proxy(base::MessageLoopProxy::current()) {
-    }
+          task_runner(base::ThreadTaskRunnerHandle::Get()) {}
     AsyncMethodCaller::Callback callback;
-    scoped_refptr<base::MessageLoopProxy> proxy;
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner;
   };
 
   struct DataCallbackElement {
@@ -263,10 +263,9 @@
     explicit DataCallbackElement(
         const AsyncMethodCaller::DataCallback& callback)
         : data_callback(callback),
-          proxy(base::MessageLoopProxy::current()) {
-    }
+          task_runner(base::ThreadTaskRunnerHandle::Get()) {}
     AsyncMethodCaller::DataCallback data_callback;
-    scoped_refptr<base::MessageLoopProxy> proxy;
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner;
   };
 
   typedef base::hash_map<int, CallbackElement> CallbackMap;
@@ -287,10 +286,9 @@
       LOG(ERROR) << "Received signal for unknown async_id " << async_id;
       return;
     }
-    it->second.proxy->PostTask(FROM_HERE,
-        base::Bind(it->second.callback,
-                   return_status,
-                   static_cast<MountError>(return_code)));
+    it->second.task_runner->PostTask(
+        FROM_HERE, base::Bind(it->second.callback, return_status,
+                              static_cast<MountError>(return_code)));
     callback_map_.erase(it);
   }
 
@@ -303,7 +301,8 @@
       LOG(ERROR) << "Received signal for unknown async_id " << async_id;
       return;
     }
-    it->second.proxy->PostTask(FROM_HERE,
+    it->second.task_runner->PostTask(
+        FROM_HERE,
         base::Bind(it->second.data_callback, return_status, return_data));
     data_callback_map_.erase(it);
   }
@@ -311,7 +310,7 @@
   void RegisterAsyncCallback(
       Callback callback, const char* error, int async_id) {
     if (async_id == chromeos::CryptohomeClient::kNotReadyAsyncId) {
-      base::MessageLoopProxy::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(callback,
                                 false,  // return status
                                 cryptohome::MOUNT_ERROR_FATAL));
@@ -332,7 +331,7 @@
   void RegisterAsyncDataCallback(
       DataCallback callback, const char* error, int async_id) {
     if (async_id == chromeos::CryptohomeClient::kNotReadyAsyncId) {
-      base::MessageLoopProxy::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(callback,
                                 false,  // return status
                                 std::string()));
diff --git a/chromeos/cryptohome/system_salt_getter.cc b/chromeos/cryptohome/system_salt_getter.cc
index 3b2f970..9c2e2449 100644
--- a/chromeos/cryptohome/system_salt_getter.cc
+++ b/chromeos/cryptohome/system_salt_getter.cc
@@ -6,9 +6,10 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 
@@ -28,7 +29,7 @@
 void SystemSaltGetter::GetSystemSalt(
     const GetSystemSaltCallback& callback) {
   if (!system_salt_.empty()) {
-    base::MessageLoopProxy::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, system_salt_));
     return;
   }
diff --git a/chromeos/dbus/ap_manager_client.cc b/chromeos/dbus/ap_manager_client.cc
index 35c1af563..1a191c7 100644
--- a/chromeos/dbus/ap_manager_client.cc
+++ b/chromeos/dbus/ap_manager_client.cc
@@ -5,10 +5,12 @@
 #include "chromeos/dbus/ap_manager_client.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
 #include "dbus/object_manager.h"
@@ -146,7 +148,7 @@
   dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
       dbus::ObjectPath(apmanager::kApManagerManagerPath));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ApManagerClientImpl::OnObjectPathDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -168,7 +170,7 @@
   dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
       dbus::ObjectPath(apmanager::kApManagerManagerPath));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ApManagerClientImpl::OnVoidDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -190,7 +192,7 @@
   dbus::ObjectProxy* object_proxy =
       object_manager_->GetObjectProxy(object_path);
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ApManagerClientImpl::OnVoidDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -211,7 +213,7 @@
   dbus::ObjectProxy* object_proxy =
       object_manager_->GetObjectProxy(object_path);
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ApManagerClientImpl::OnVoidDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
diff --git a/chromeos/dbus/bluetooth_gatt_characteristic_service_provider.cc b/chromeos/dbus/bluetooth_gatt_characteristic_service_provider.cc
index 39c95bf..d4e4c38 100644
--- a/chromeos/dbus/bluetooth_gatt_characteristic_service_provider.cc
+++ b/chromeos/dbus/bluetooth_gatt_characteristic_service_provider.cc
@@ -52,8 +52,8 @@
     DCHECK(!uuid_.empty());
     DCHECK(object_path_.IsValid());
     DCHECK(service_path_.IsValid());
-    DCHECK(StartsWithASCII(
-        object_path_.value(), service_path_.value() + "/", true));
+    DCHECK(base::StartsWithASCII(object_path_.value(),
+                                 service_path_.value() + "/", true));
 
     exported_object_ = bus_->GetExportedObject(object_path_);
 
diff --git a/chromeos/dbus/bluetooth_gatt_descriptor_service_provider.cc b/chromeos/dbus/bluetooth_gatt_descriptor_service_provider.cc
index 8c49459..d09fd5e7 100644
--- a/chromeos/dbus/bluetooth_gatt_descriptor_service_provider.cc
+++ b/chromeos/dbus/bluetooth_gatt_descriptor_service_provider.cc
@@ -50,8 +50,8 @@
     DCHECK(!uuid_.empty());
     DCHECK(object_path_.IsValid());
     DCHECK(characteristic_path_.IsValid());
-    DCHECK(StartsWithASCII(
-        object_path_.value(), characteristic_path_.value() + "/", true));
+    DCHECK(base::StartsWithASCII(object_path_.value(),
+                                 characteristic_path_.value() + "/", true));
 
     exported_object_ = bus_->GetExportedObject(object_path_);
 
diff --git a/chromeos/dbus/cros_disks_client.cc b/chromeos/dbus/cros_disks_client.cc
index 71a71ea..fafbdec 100644
--- a/chromeos/dbus/cros_disks_client.cc
+++ b/chromeos/dbus/cros_disks_client.cc
@@ -10,7 +10,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_info.h"
diff --git a/chromeos/dbus/dbus_client_bundle.cc b/chromeos/dbus/dbus_client_bundle.cc
index 3296736..a18a611 100644
--- a/chromeos/dbus/dbus_client_bundle.cc
+++ b/chromeos/dbus/dbus_client_bundle.cc
@@ -141,7 +141,8 @@
 DBusClientBundle::DBusClientType GetDBusClientType(
     const std::string& client_type_name) {
   for (size_t i = 0; i < arraysize(client_type_map); i++) {
-    if (LowerCaseEqualsASCII(client_type_name, client_type_map[i].param_name))
+    if (base::LowerCaseEqualsASCII(client_type_name,
+                                   client_type_map[i].param_name))
       return client_type_map[i].client_type;
   }
   return DBusClientBundle::NO_CLIENT;
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index aafb25d..b096f356 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -79,7 +79,7 @@
     dbus::Bus::Options system_bus_options;
     system_bus_options.bus_type = dbus::Bus::SYSTEM;
     system_bus_options.connection_type = dbus::Bus::PRIVATE;
-    system_bus_options.dbus_task_runner = dbus_thread_->message_loop_proxy();
+    system_bus_options.dbus_task_runner = dbus_thread_->task_runner();
     system_bus_ = new dbus::Bus(system_bus_options);
   }
 }
diff --git a/chromeos/dbus/fake_amplifier_client.cc b/chromeos/dbus/fake_amplifier_client.cc
index ab8129d..032dd755 100644
--- a/chromeos/dbus/fake_amplifier_client.cc
+++ b/chromeos/dbus/fake_amplifier_client.cc
@@ -5,7 +5,9 @@
 #include "chromeos/dbus/fake_amplifier_client.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace chromeos {
 
@@ -37,20 +39,20 @@
 }
 
 void FakeAmplifierClient::Initialize(const BoolDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnBoolDBusMethod, callback));
 }
 
 void FakeAmplifierClient::SetStandbyMode(
     bool standby,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnVoidDBusMethod, callback));
 }
 
 void FakeAmplifierClient::SetVolume(double db_spl,
                                     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnVoidDBusMethod, callback));
 }
 
diff --git a/chromeos/dbus/fake_ap_manager_client.cc b/chromeos/dbus/fake_ap_manager_client.cc
index 79ed780..9c52e94 100644
--- a/chromeos/dbus/fake_ap_manager_client.cc
+++ b/chromeos/dbus/fake_ap_manager_client.cc
@@ -4,7 +4,8 @@
 
 #include "chromeos/dbus/fake_ap_manager_client.h"
 
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace chromeos {
 
@@ -36,26 +37,26 @@
 
 void FakeApManagerClient::CreateService(
     const ObjectPathDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&ObjectPathDBBusMethodCallbackThunk, callback));
 }
 
 void FakeApManagerClient::RemoveService(
     const dbus::ObjectPath& object_path,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&VoidDBBusMethodCallbackThunk, callback));
 }
 
 void FakeApManagerClient::StartService(const dbus::ObjectPath& object_path,
                                        const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&VoidDBBusMethodCallbackThunk, callback));
 }
 
 void FakeApManagerClient::StopService(const dbus::ObjectPath& object_path,
                                       const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&VoidDBBusMethodCallbackThunk, callback));
 }
 
diff --git a/chromeos/dbus/fake_audio_dsp_client.cc b/chromeos/dbus/fake_audio_dsp_client.cc
index ec9fbf0..f58b9f7 100644
--- a/chromeos/dbus/fake_audio_dsp_client.cc
+++ b/chromeos/dbus/fake_audio_dsp_client.cc
@@ -5,7 +5,9 @@
 #include "chromeos/dbus/fake_audio_dsp_client.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace chromeos {
 
@@ -53,53 +55,53 @@
 }
 
 void FakeAudioDspClient::Initialize(const BoolDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnBoolDBusMethod, callback));
 }
 
 void FakeAudioDspClient::SetStandbyMode(
     bool standby,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnVoidDBusMethod, callback));
 }
 
 void FakeAudioDspClient::SetNightMode(bool standby,
                                       const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnVoidDBusMethod, callback));
 }
 
 void FakeAudioDspClient::GetNightMode(const BoolDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnBoolDBusMethod, callback));
 }
 
 void FakeAudioDspClient::SetTreble(double db_fs,
                                    const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnVoidDBusMethod, callback));
 }
 
 void FakeAudioDspClient::GetTreble(const DoubleDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnDoubleDBusMethod, callback));
 }
 
 void FakeAudioDspClient::SetBass(double db_fs,
                                  const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnVoidDBusMethod, callback));
 }
 
 void FakeAudioDspClient::GetBass(const DoubleDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnDoubleDBusMethod, callback));
 }
 
 void FakeAudioDspClient::GetCapabilitiesOEM(
     const ThreeStringDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnThreeStringDBusMethod, callback));
 }
 
@@ -108,14 +110,14 @@
     const std::string& speaker_capabilities,
     const std::string& driver_capabilities,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnVoidDBusMethod, callback));
 }
 
 void FakeAudioDspClient::GetFilterConfigOEM(
     uint32 speaker_id,
     const TwoStringDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnTwoStringDBusMethod, callback));
 }
 
@@ -123,20 +125,20 @@
     const std::string& speaker_config,
     const std::string& driver_config,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnVoidDBusMethod, callback));
 }
 
 void FakeAudioDspClient::SetSourceType(uint16 source_type,
                                        const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnVoidDBusMethod, callback));
 }
 
 void FakeAudioDspClient::AmplifierVolumeChanged(
     double db_spl,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&OnVoidDBusMethod, callback));
 }
 
diff --git a/chromeos/dbus/fake_bluetooth_adapter_client.cc b/chromeos/dbus/fake_bluetooth_adapter_client.cc
index 51a5cf8..054a691 100644
--- a/chromeos/dbus/fake_bluetooth_adapter_client.cc
+++ b/chromeos/dbus/fake_bluetooth_adapter_client.cc
@@ -4,8 +4,10 @@
 
 #include "chromeos/dbus/fake_bluetooth_adapter_client.h"
 
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_bluetooth_device_client.h"
@@ -297,7 +299,7 @@
 
 void FakeBluetoothAdapterClient::PostDelayedTask(
     const base::Closure& callback) {
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, callback,
       base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
 }
diff --git a/chromeos/dbus/fake_bluetooth_device_client.cc b/chromeos/dbus/fake_bluetooth_device_client.cc
index be41342f..4bc3708 100644
--- a/chromeos/dbus/fake_bluetooth_device_client.cc
+++ b/chromeos/dbus/fake_bluetooth_device_client.cc
@@ -5,19 +5,21 @@
 #include "chromeos/dbus/fake_bluetooth_device_client.h"
 
 #include <fcntl.h>
-#include <unistd.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include <algorithm>
 #include <string>
 #include <utility>
 
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/worker_pool.h"
 #include "base/time/time.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -517,7 +519,7 @@
 
   discovery_simulation_step_ = 1;
 
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&FakeBluetoothDeviceClient::DiscoverySimulationTimer,
                  base::Unretained(this)),
@@ -536,7 +538,7 @@
 
   incoming_pairing_simulation_step_ = 1;
 
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&FakeBluetoothDeviceClient::IncomingPairingSimulationTimer,
                  base::Unretained(this)),
@@ -777,7 +779,7 @@
   }
 
   ++discovery_simulation_step_;
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&FakeBluetoothDeviceClient::DiscoverySimulationTimer,
                  base::Unretained(this)),
@@ -838,7 +840,7 @@
   }
 
   ++incoming_pairing_simulation_step_;
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&FakeBluetoothDeviceClient::IncomingPairingSimulationTimer,
                  base::Unretained(this)),
@@ -865,11 +867,11 @@
       object_path == dbus::ObjectPath(kLowEnergyPath)) {
     // No need to call anything on the pairing delegate, just wait 3 times
     // the interval before acting as if the other end accepted it.
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, callback, error_callback),
+                   base::Unretained(this), object_path, callback,
+                   error_callback),
         base::TimeDelta::FromMilliseconds(3 * simulation_interval_ms_));
 
   } else if (object_path == dbus::ObjectPath(kDisplayPinCodePath)) {
@@ -877,20 +879,19 @@
     // if the other end accepted it.
     agent_service_provider->DisplayPinCode(object_path, "123456");
 
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, callback, error_callback),
+                   base::Unretained(this), object_path, callback,
+                   error_callback),
         base::TimeDelta::FromMilliseconds(7 * simulation_interval_ms_));
 
   } else if (object_path == dbus::ObjectPath(kVanishingDevicePath)) {
     // The vanishing device simulates being too far away, and thus times out.
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::TimeoutSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, error_callback),
+                   base::Unretained(this), object_path, error_callback),
         base::TimeDelta::FromMilliseconds(4 * simulation_interval_ms_));
 
   } else if (object_path == dbus::ObjectPath(kDisplayPasskeyPath)) {
@@ -898,11 +899,10 @@
     // for it.
     agent_service_provider->DisplayPasskey(object_path, 123456, 0);
 
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&FakeBluetoothDeviceClient::SimulateKeypress,
-                   base::Unretained(this),
-                   1, object_path, callback, error_callback),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&FakeBluetoothDeviceClient::SimulateKeypress,
+                              base::Unretained(this), 1, object_path, callback,
+                              error_callback),
         base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
 
   } else if (object_path == dbus::ObjectPath(kRequestPinCodePath)) {
@@ -937,11 +937,10 @@
 
   } else if (object_path == dbus::ObjectPath(kUnpairableDevicePath)) {
     // Fails the pairing with an org.bluez.Error.Failed error.
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::FailSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, error_callback),
+                   base::Unretained(this), object_path, error_callback),
         base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
 
   } else if (object_path == dbus::ObjectPath(kJustWorksPath)) {
@@ -957,13 +956,12 @@
     } else {
       // No need to call anything on the pairing delegate, just wait 3 times
       // the interval before acting as if the other end accepted it.
-      base::MessageLoop::current()->PostDelayedTask(
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE,
           base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
-                     base::Unretained(this),
-                     object_path, callback, error_callback),
+                     base::Unretained(this), object_path, callback,
+                     error_callback),
           base::TimeDelta::FromMilliseconds(3 * simulation_interval_ms_));
-
     }
 
   } else {
@@ -1070,29 +1068,26 @@
   VLOG(1) << "PinCodeCallback: " << object_path.value();
 
   if (status == BluetoothAgentServiceProvider::Delegate::SUCCESS) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, callback, error_callback),
+                   base::Unretained(this), object_path, callback,
+                   error_callback),
         base::TimeDelta::FromMilliseconds(3 * simulation_interval_ms_));
 
   } else if (status == BluetoothAgentServiceProvider::Delegate::CANCELLED) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::CancelSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, error_callback),
+                   base::Unretained(this), object_path, error_callback),
         base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
 
   } else if (status == BluetoothAgentServiceProvider::Delegate::REJECTED) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::RejectSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, error_callback),
+                   base::Unretained(this), object_path, error_callback),
         base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
-
   }
 }
 
@@ -1105,29 +1100,26 @@
   VLOG(1) << "PasskeyCallback: " << object_path.value();
 
   if (status == BluetoothAgentServiceProvider::Delegate::SUCCESS) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, callback, error_callback),
+                   base::Unretained(this), object_path, callback,
+                   error_callback),
         base::TimeDelta::FromMilliseconds(3 * simulation_interval_ms_));
 
   } else if (status == BluetoothAgentServiceProvider::Delegate::CANCELLED) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::CancelSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, error_callback),
+                   base::Unretained(this), object_path, error_callback),
         base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
 
   } else if (status == BluetoothAgentServiceProvider::Delegate::REJECTED) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::RejectSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, error_callback),
+                   base::Unretained(this), object_path, error_callback),
         base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
-
   }
 }
 
@@ -1139,29 +1131,26 @@
   VLOG(1) << "ConfirmationCallback: " << object_path.value();
 
   if (status == BluetoothAgentServiceProvider::Delegate::SUCCESS) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, callback, error_callback),
+                   base::Unretained(this), object_path, callback,
+                   error_callback),
         base::TimeDelta::FromMilliseconds(3 * simulation_interval_ms_));
 
   } else if (status == BluetoothAgentServiceProvider::Delegate::CANCELLED) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::CancelSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, error_callback),
+                   base::Unretained(this), object_path, error_callback),
         base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
 
   } else if (status == BluetoothAgentServiceProvider::Delegate::REJECTED) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::RejectSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, error_callback),
+                   base::Unretained(this), object_path, error_callback),
         base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
-
   }
 }
 
@@ -1186,21 +1175,19 @@
   agent_service_provider->DisplayPasskey(object_path, 123456, entered);
 
   if (entered < 7) {
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&FakeBluetoothDeviceClient::SimulateKeypress,
-                   base::Unretained(this),
-                   entered + 1, object_path, callback, error_callback),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&FakeBluetoothDeviceClient::SimulateKeypress,
+                              base::Unretained(this), entered + 1, object_path,
+                              callback, error_callback),
         base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
 
   } else {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&FakeBluetoothDeviceClient::CompleteSimulatedPairing,
-                   base::Unretained(this),
-                   object_path, callback, error_callback),
+                   base::Unretained(this), object_path, callback,
+                   error_callback),
         base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
-
   }
 }
 
diff --git a/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.cc b/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.cc
index 1f3a9bf..71a03c8 100644
--- a/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.cc
+++ b/chromeos/dbus/fake_bluetooth_gatt_characteristic_client.cc
@@ -5,8 +5,10 @@
 #include "chromeos/dbus/fake_bluetooth_gatt_characteristic_client.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_bluetooth_gatt_descriptor_client.h"
@@ -291,9 +293,8 @@
   ScheduleHeartRateMeasurementValueChange();
 
   // Respond asynchronously.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      callback,
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, callback,
       base::TimeDelta::FromMilliseconds(kStartNotifyResponseIntervalMs));
 }
 
@@ -493,13 +494,12 @@
   std::vector<uint8> measurement = GetHeartRateMeasurementValue();
   heart_rate_measurement_properties_->value.ReplaceValue(measurement);
 
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&FakeBluetoothGattCharacteristicClient::
-                     ScheduleHeartRateMeasurementValueChange,
-                 weak_ptr_factory_.GetWeakPtr()),
-                 base::TimeDelta::FromMilliseconds(
-                     kHeartRateMeasurementNotificationIntervalMs));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&FakeBluetoothGattCharacteristicClient::
+                                ScheduleHeartRateMeasurementValueChange,
+                            weak_ptr_factory_.GetWeakPtr()),
+      base::TimeDelta::FromMilliseconds(
+          kHeartRateMeasurementNotificationIntervalMs));
 }
 
 void FakeBluetoothGattCharacteristicClient::DelayedReadValueCallback(
diff --git a/chromeos/dbus/fake_bluetooth_gatt_characteristic_service_provider.cc b/chromeos/dbus/fake_bluetooth_gatt_characteristic_service_provider.cc
index 6301210..d77dc711 100644
--- a/chromeos/dbus/fake_bluetooth_gatt_characteristic_service_provider.cc
+++ b/chromeos/dbus/fake_bluetooth_gatt_characteristic_service_provider.cc
@@ -29,8 +29,8 @@
   DCHECK(service_path_.IsValid());
   DCHECK(!uuid.empty());
   DCHECK(delegate_);
-  DCHECK(StartsWithASCII(
-      object_path_.value(), service_path_.value() + "/", true));
+  DCHECK(base::StartsWithASCII(object_path_.value(),
+                               service_path_.value() + "/", true));
 
   // TODO(armansito): Do something with |flags| and |permissions|.
 
diff --git a/chromeos/dbus/fake_bluetooth_gatt_descriptor_service_provider.cc b/chromeos/dbus/fake_bluetooth_gatt_descriptor_service_provider.cc
index 83ea686..bb4c55e 100644
--- a/chromeos/dbus/fake_bluetooth_gatt_descriptor_service_provider.cc
+++ b/chromeos/dbus/fake_bluetooth_gatt_descriptor_service_provider.cc
@@ -29,8 +29,8 @@
   DCHECK(characteristic_path_.IsValid());
   DCHECK(!uuid.empty());
   DCHECK(delegate_);
-  DCHECK(StartsWithASCII(
-      object_path_.value(), characteristic_path_.value() + "/", true));
+  DCHECK(base::StartsWithASCII(object_path_.value(),
+                               characteristic_path_.value() + "/", true));
 
   // TODO(armansito): Do something with |permissions|.
 
diff --git a/chromeos/dbus/fake_bluetooth_gatt_service_client.cc b/chromeos/dbus/fake_bluetooth_gatt_service_client.cc
index 2bb68c2c..1a56642 100644
--- a/chromeos/dbus/fake_bluetooth_gatt_service_client.cc
+++ b/chromeos/dbus/fake_bluetooth_gatt_service_client.cc
@@ -5,7 +5,9 @@
 #include "chromeos/dbus/fake_bluetooth_gatt_service_client.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_bluetooth_gatt_characteristic_client.h"
@@ -109,13 +111,12 @@
 
   NotifyServiceAdded(dbus::ObjectPath(heart_rate_service_path_));
 
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(
           &FakeBluetoothGattServiceClient::ExposeHeartRateCharacteristics,
           weak_ptr_factory_.GetWeakPtr()),
-          base::TimeDelta::FromMilliseconds(
-              kExposeCharacteristicsDelayIntervalMs));
+      base::TimeDelta::FromMilliseconds(kExposeCharacteristicsDelayIntervalMs));
 }
 
 void FakeBluetoothGattServiceClient::HideHeartRateService() {
diff --git a/chromeos/dbus/fake_bluetooth_le_advertising_manager_client.cc b/chromeos/dbus/fake_bluetooth_le_advertising_manager_client.cc
index 5702832..88dafcb 100644
--- a/chromeos/dbus/fake_bluetooth_le_advertising_manager_client.cc
+++ b/chromeos/dbus/fake_bluetooth_le_advertising_manager_client.cc
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
 #include "dbus/object_proxy.h"
@@ -56,7 +58,7 @@
                        "Maximum advertisements reached");
   } else {
     currently_registered_ = advertisement_object_path;
-    base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
   }
 }
 
@@ -82,7 +84,7 @@
                        "Does not exist");
   } else {
     currently_registered_ = dbus::ObjectPath("");
-    base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
   }
 }
 
diff --git a/chromeos/dbus/fake_bluetooth_profile_manager_client.cc b/chromeos/dbus/fake_bluetooth_profile_manager_client.cc
index e8726ea..d9910a4 100644
--- a/chromeos/dbus/fake_bluetooth_profile_manager_client.cc
+++ b/chromeos/dbus/fake_bluetooth_profile_manager_client.cc
@@ -4,9 +4,10 @@
 
 #include "chromeos/dbus/fake_bluetooth_profile_manager_client.h"
 
-
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/fake_bluetooth_profile_service_provider.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
@@ -40,7 +41,7 @@
   VLOG(1) << "RegisterProfile: " << profile_path.value() << ": " << uuid;
 
   if (uuid == kUnregisterableUuid) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(error_callback,
                               bluetooth_profile_manager::kErrorInvalidArguments,
                               "Can't register this UUID"));
@@ -60,7 +61,7 @@
                          "Profile already registered");
     } else {
       profile_map_[uuid] = profile_path;
-      base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
     }
   }
 }
@@ -84,7 +85,7 @@
       }
     }
 
-    base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
   }
 }
 
diff --git a/chromeos/dbus/fake_cros_disks_client.cc b/chromeos/dbus/fake_cros_disks_client.cc
index ab0dce0..dd33f80 100644
--- a/chromeos/dbus/fake_cros_disks_client.cc
+++ b/chromeos/dbus/fake_cros_disks_client.cc
@@ -6,9 +6,11 @@
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/worker_pool.h"
 
 namespace chromeos {
@@ -48,15 +50,14 @@
               const base::FilePath& mounted_path,
               MountError mount_error) {
   // Tell the caller of Mount() that the mount request was accepted.
-  base::MessageLoopProxy::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 
   // Tell the caller of Mount() that the mount completed.
   if (!mount_completed_handler.is_null()) {
-    base::MessageLoopProxy::current()->PostTask(
-        FROM_HERE,
-        base::Bind(mount_completed_handler,
-                   MountEntry(mount_error, source_path, type,
-                              mounted_path.AsUTF8Unsafe())));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(mount_completed_handler,
+                              MountEntry(mount_error, source_path, type,
+                                         mounted_path.AsUTF8Unsafe())));
   }
 }
 
@@ -121,7 +122,7 @@
   unmount_call_count_++;
   last_unmount_device_path_ = device_path;
   last_unmount_options_ = options;
-  base::MessageLoopProxy::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, unmount_success_ ? callback : error_callback);
   if (!unmount_listener_.is_null())
     unmount_listener_.Run();
@@ -148,9 +149,9 @@
   last_format_device_path_ = device_path;
   last_format_filesystem_ = filesystem;
   if (format_success_) {
-    base::MessageLoopProxy::current()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
   } else {
-    base::MessageLoopProxy::current()->PostTask(FROM_HERE, error_callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, error_callback);
   }
 }
 
diff --git a/chromeos/dbus/fake_debug_daemon_client.cc b/chromeos/dbus/fake_debug_daemon_client.cc
index d59ca93d..e7f6ba41 100644
--- a/chromeos/dbus/fake_debug_daemon_client.cc
+++ b/chromeos/dbus/fake_debug_daemon_client.cc
@@ -11,7 +11,8 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/chromeos_switches.h"
 
 namespace chromeos {
@@ -51,74 +52,75 @@
                                       bool ipv6,
                                       const GetRoutesCallback& callback) {
   std::vector<std::string> empty;
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false, empty));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, empty));
 }
 
 void FakeDebugDaemonClient::GetNetworkStatus(
     const GetNetworkStatusCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false, ""));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, ""));
 }
 
 void FakeDebugDaemonClient::GetModemStatus(
     const GetModemStatusCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false, ""));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, ""));
 }
 
 void FakeDebugDaemonClient::GetWiMaxStatus(
     const GetWiMaxStatusCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false, ""));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, ""));
 }
 
 void FakeDebugDaemonClient::GetNetworkInterfaces(
     const GetNetworkInterfacesCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false, ""));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, ""));
 }
 
 void FakeDebugDaemonClient::GetPerfData(uint32_t duration,
                                         const GetPerfDataCallback& callback) {
   std::vector<uint8> data;
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, data));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, data));
 }
 
 void FakeDebugDaemonClient::GetScrubbedLogs(const GetLogsCallback& callback) {
   std::map<std::string, std::string> sample;
   sample["Sample Scrubbed Log"] = "Your email address is xxxxxxxx";
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false, sample));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, sample));
 }
 
 void FakeDebugDaemonClient::GetAllLogs(const GetLogsCallback& callback) {
   std::map<std::string, std::string> sample;
   sample["Sample Log"] = "Your email address is abc@abc.com";
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false, sample));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, sample));
 }
 
 void FakeDebugDaemonClient::GetUserLogFiles(const GetLogsCallback& callback) {
   std::map<std::string, std::string> user_logs;
   user_logs["preferences"] = "Preferences";
   user_logs["invalid_file"] = "Invalid File";
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, true, user_logs));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, true, user_logs));
 }
 
 void FakeDebugDaemonClient::TestICMP(const std::string& ip_address,
                                      const TestICMPCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false, ""));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, ""));
 }
 
 void FakeDebugDaemonClient::TestICMPWithOptions(
     const std::string& ip_address,
     const std::map<std::string, std::string>& options,
     const TestICMPCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false, ""));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, ""));
 }
 
 void FakeDebugDaemonClient::UploadCrashes() {
@@ -127,15 +129,15 @@
 void FakeDebugDaemonClient::EnableDebuggingFeatures(
     const std::string& password,
     const DebugDaemonClient::EnableDebuggingCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, true));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, true));
 }
 
 void FakeDebugDaemonClient::QueryDebuggingFeatures(
     const DebugDaemonClient::QueryDevFeaturesCallback& callback) {
   bool supported = base::CommandLine::ForCurrentProcess()->HasSwitch(
       chromeos::switches::kSystemDevMode);
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(
           callback, true,
@@ -146,15 +148,15 @@
 
 void FakeDebugDaemonClient::RemoveRootfsVerification(
     const DebugDaemonClient::EnableDebuggingCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, true));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, true));
 }
 
 void FakeDebugDaemonClient::WaitForServiceToBeAvailable(
     const WaitForServiceToBeAvailableCallback& callback) {
   if (service_is_available_) {
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::Bind(callback, true));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback, true));
   } else {
     pending_wait_for_service_to_be_available_callbacks_.push_back(callback);
   }
diff --git a/chromeos/dbus/fake_gsm_sms_client.cc b/chromeos/dbus/fake_gsm_sms_client.cc
index 4d4452f..ba1286bd 100644
--- a/chromeos/dbus/fake_gsm_sms_client.cc
+++ b/chromeos/dbus/fake_gsm_sms_client.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/fake_gsm_sms_client.h"
 
 namespace chromeos {
@@ -78,10 +80,9 @@
   test_index_ = 0;
   // Call PushTestMessageChain asynchronously so that the handler_ callback
   // does not get called from the update request.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&FakeGsmSMSClient::PushTestMessageChain,
-                 weak_ptr_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&FakeGsmSMSClient::PushTestMessageChain,
+                            weak_ptr_factory_.GetWeakPtr()));
 }
 
 void FakeGsmSMSClient::PushTestMessageChain() {
@@ -91,10 +92,9 @@
 
 void FakeGsmSMSClient::PushTestMessageDelayed() {
   const int kSmsMessageDelaySeconds = 5;
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&FakeGsmSMSClient::PushTestMessageChain,
-                 weak_ptr_factory_.GetWeakPtr()),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&FakeGsmSMSClient::PushTestMessageChain,
+                            weak_ptr_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(kSmsMessageDelaySeconds));
 }
 
diff --git a/chromeos/dbus/fake_leadership_daemon_manager_client.cc b/chromeos/dbus/fake_leadership_daemon_manager_client.cc
index 7104aff..02cea41 100644
--- a/chromeos/dbus/fake_leadership_daemon_manager_client.cc
+++ b/chromeos/dbus/fake_leadership_daemon_manager_client.cc
@@ -4,7 +4,8 @@
 
 #include "chromeos/dbus/fake_leadership_daemon_manager_client.h"
 
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace chromeos {
 
@@ -42,14 +43,14 @@
     const std::string& group,
     const base::DictionaryValue& options,
     const ObjectPathDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&ObjectPathDBBusMethodCallbackThunk, callback));
 }
 
 void FakeLeadershipDaemonManagerClient::LeaveGroup(
     const std::string& object_path,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&VoidDBBusMethodCallbackThunk, callback));
 }
 
@@ -57,20 +58,20 @@
     const std::string& object_path,
     int score,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&VoidDBBusMethodCallbackThunk, callback));
 }
 
 void FakeLeadershipDaemonManagerClient::PokeLeader(
     const std::string& object_path,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&VoidDBBusMethodCallbackThunk, callback));
 }
 
 void FakeLeadershipDaemonManagerClient::Ping(
     const StringDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&StringDBBusMethodCallbackThunk, callback));
 }
 
diff --git a/chromeos/dbus/fake_lorgnette_manager_client.cc b/chromeos/dbus/fake_lorgnette_manager_client.cc
index 3487ea4..16427bbf 100644
--- a/chromeos/dbus/fake_lorgnette_manager_client.cc
+++ b/chromeos/dbus/fake_lorgnette_manager_client.cc
@@ -11,7 +11,8 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace chromeos {
 
@@ -24,8 +25,8 @@
 void FakeLorgnetteManagerClient::ListScanners(
     const ListScannersCallback& callback) {
   std::map<std::string, ScannerTableEntry> scanners;
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false, scanners));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, scanners));
 }
 
 void FakeLorgnetteManagerClient::ScanImageToFile(
@@ -33,17 +34,16 @@
     const ScanProperties& properties,
     const ScanImageToFileCallback& callback,
     base::File* file) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, false));
 }
 
 void FakeLorgnetteManagerClient::ScanImageToString(
     std::string device_name,
     const ScanProperties& properties,
     const ScanImageToStringCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, false,
-                                                    std::string()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, false, std::string()));
 }
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/fake_nfc_device_client.cc b/chromeos/dbus/fake_nfc_device_client.cc
index df036c1..6c1ec23 100644
--- a/chromeos/dbus/fake_nfc_device_client.cc
+++ b/chromeos/dbus/fake_nfc_device_client.cc
@@ -5,8 +5,10 @@
 #include "chromeos/dbus/fake_nfc_device_client.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_nfc_adapter_client.h"
@@ -116,11 +118,9 @@
 
   pairing_started_ = true;
 
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&FakeNfcDeviceClient::MakeDeviceVisible,
-                 base::Unretained(this),
-                 record_push_delay),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&FakeNfcDeviceClient::MakeDeviceVisible,
+                            base::Unretained(this), record_push_delay),
       base::TimeDelta::FromMilliseconds(visibility_delay));
 }
 
@@ -195,19 +195,17 @@
   if (record_push_delay < 0) {
     // Don't simulate record push. Instead, skip directly to the timeout step.
     if (simulation_timeout_ >= 0) {
-      base::MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          base::Bind(&FakeNfcDeviceClient::HandleSimulationTimeout,
-                     base::Unretained(this)),
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+          FROM_HERE, base::Bind(&FakeNfcDeviceClient::HandleSimulationTimeout,
+                                base::Unretained(this)),
           base::TimeDelta::FromMilliseconds(simulation_timeout_));
     }
     return;
   }
 
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&FakeNfcDeviceClient::MakeRecordsVisible,
-                 base::Unretained(this)),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&FakeNfcDeviceClient::MakeRecordsVisible,
+                            base::Unretained(this)),
       base::TimeDelta::FromMilliseconds(record_push_delay));
 }
 
@@ -225,10 +223,9 @@
   if (simulation_timeout_ < 0)
     return;
 
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&FakeNfcDeviceClient::HandleSimulationTimeout,
-                 base::Unretained(this)),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&FakeNfcDeviceClient::HandleSimulationTimeout,
+                            base::Unretained(this)),
       base::TimeDelta::FromMilliseconds(simulation_timeout_));
 }
 
diff --git a/chromeos/dbus/fake_nfc_tag_client.cc b/chromeos/dbus/fake_nfc_tag_client.cc
index 670d8f9..7b63c3b 100644
--- a/chromeos/dbus/fake_nfc_tag_client.cc
+++ b/chromeos/dbus/fake_nfc_tag_client.cc
@@ -4,8 +4,10 @@
 
 #include "chromeos/dbus/fake_nfc_tag_client.h"
 
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_nfc_adapter_client.h"
@@ -122,10 +124,9 @@
 
   pairing_started_ = true;
 
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&FakeNfcTagClient::MakeTagVisible,
-                 base::Unretained(this)),
+      base::Bind(&FakeNfcTagClient::MakeTagVisible, base::Unretained(this)),
       base::TimeDelta::FromMilliseconds(visibility_delay));
 }
 
@@ -207,10 +208,9 @@
                     TagPropertiesReceived(dbus::ObjectPath(kTagPath)));
 
   if (simulation_timeout_ >= 0) {
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&FakeNfcTagClient::HandleSimulationTimeout,
-                   base::Unretained(this)),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&FakeNfcTagClient::HandleSimulationTimeout,
+                              base::Unretained(this)),
         base::TimeDelta::FromMilliseconds(simulation_timeout_));
     return;
   }
diff --git a/chromeos/dbus/fake_privet_daemon_manager_client.cc b/chromeos/dbus/fake_privet_daemon_manager_client.cc
index 2a5d8e6..98d0fba 100644
--- a/chromeos/dbus/fake_privet_daemon_manager_client.cc
+++ b/chromeos/dbus/fake_privet_daemon_manager_client.cc
@@ -4,7 +4,8 @@
 
 #include "chromeos/dbus/fake_privet_daemon_manager_client.h"
 
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace chromeos {
 
@@ -26,7 +27,7 @@
 void FakePrivetDaemonManagerClient::SetDescription(
     const std::string& description,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS));
 }
 
diff --git a/chromeos/dbus/fake_session_manager_client.cc b/chromeos/dbus/fake_session_manager_client.cc
index 27fe2df..c1745cf 100644
--- a/chromeos/dbus/fake_session_manager_client.cc
+++ b/chromeos/dbus/fake_session_manager_client.cc
@@ -6,8 +6,9 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/cryptohome_client.h"
 
 namespace chromeos {
@@ -83,20 +84,20 @@
 
 void FakeSessionManagerClient::RetrieveActiveSessions(
       const ActiveSessionsCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, user_sessions_, true));
 }
 
 void FakeSessionManagerClient::RetrieveDevicePolicy(
     const RetrievePolicyCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, device_policy_));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, device_policy_));
 }
 
 void FakeSessionManagerClient::RetrievePolicyForUser(
     const std::string& username,
     const RetrievePolicyCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, user_policies_[username]));
 }
 
@@ -108,7 +109,7 @@
 void FakeSessionManagerClient::RetrieveDeviceLocalAccountPolicy(
     const std::string& account_id,
     const RetrievePolicyCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(callback, device_local_account_policy_[account_id]));
 }
@@ -117,7 +118,8 @@
     const std::string& policy_blob,
     const StorePolicyCallback& callback) {
   device_policy_ = policy_blob;
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, true));
   FOR_EACH_OBSERVER(Observer, observers_, PropertyChangeComplete(true));
 }
 
@@ -126,7 +128,8 @@
     const std::string& policy_blob,
     const StorePolicyCallback& callback) {
   user_policies_[username] = policy_blob;
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, true));
 }
 
 void FakeSessionManagerClient::StoreDeviceLocalAccountPolicy(
@@ -134,7 +137,8 @@
     const std::string& policy_blob,
     const StorePolicyCallback& callback) {
   device_local_account_policy_[account_id] = policy_blob;
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, true));
 }
 
 void FakeSessionManagerClient::SetFlagsForUser(
@@ -144,7 +148,7 @@
 
 void FakeSessionManagerClient::GetServerBackedStateKeys(
     const StateKeysCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, server_backed_state_keys_));
 }
 
diff --git a/chromeos/dbus/fake_shill_device_client.cc b/chromeos/dbus/fake_shill_device_client.cc
index 6fe675c..dec9711 100644
--- a/chromeos/dbus/fake_shill_device_client.cc
+++ b/chromeos/dbus/fake_shill_device_client.cc
@@ -7,8 +7,10 @@
 #include <algorithm>
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_manager_client.h"
@@ -37,7 +39,7 @@
 
 void PostError(const std::string& error,
                const ShillDeviceClient::ErrorCallback& error_callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(error_callback, error, kFailedMessage));
 }
 
@@ -83,11 +85,10 @@
 void FakeShillDeviceClient::GetProperties(
     const dbus::ObjectPath& device_path,
     const DictionaryValueCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&FakeShillDeviceClient::PassStubDeviceProperties,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 device_path, callback));
+                 weak_ptr_factory_.GetWeakPtr(), device_path, callback));
 }
 
 void FakeShillDeviceClient::ProposeScan(
@@ -119,11 +120,11 @@
     return;
   }
   device_properties->SetWithoutPathExpansion(name, value.DeepCopy());
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&FakeShillDeviceClient::NotifyObserversPropertyChanged,
                  weak_ptr_factory_.GetWeakPtr(), device_path, name));
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillDeviceClient::ClearProperty(
@@ -144,10 +145,9 @@
     const dbus::ObjectPath& device_path,
     const std::string& method,
     const ObjectPathDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback,
-                                                    DBUS_METHOD_CALL_SUCCESS,
-                                                    dbus::ObjectPath()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(callback, DBUS_METHOD_CALL_SUCCESS, dbus::ObjectPath()));
 }
 
 void FakeShillDeviceClient::RequirePin(const dbus::ObjectPath& device_path,
@@ -157,7 +157,7 @@
                                        const ErrorCallback& error_callback) {
   VLOG(1) << "RequirePin: " << device_path.value();
   if (pin != kSimPin) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(error_callback, shill::kErrorResultIncorrectPin, ""));
     return;
@@ -183,7 +183,7 @@
   simlock_dict->SetInteger(shill::kSIMLockRetriesLeftProperty, 5);
 
   NotifyObserversPropertyChanged(device_path, shill::kSIMLockStatusProperty);
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillDeviceClient::EnterPin(const dbus::ObjectPath& device_path,
@@ -192,7 +192,7 @@
                                      const ErrorCallback& error_callback) {
   VLOG(1) << "EnterPin: " << device_path.value();
   if (pin != kSimPin) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(error_callback, shill::kErrorResultIncorrectPin, ""));
     return;
@@ -201,7 +201,7 @@
     PostNotFoundError(error_callback);
     return;
   }
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillDeviceClient::UnblockPin(const dbus::ObjectPath& device_path,
@@ -214,7 +214,7 @@
     PostNotFoundError(error_callback);
     return;
   }
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillDeviceClient::ChangePin(const dbus::ObjectPath& device_path,
@@ -227,7 +227,7 @@
     PostNotFoundError(error_callback);
     return;
   }
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillDeviceClient::Register(const dbus::ObjectPath& device_path,
@@ -238,7 +238,7 @@
     PostNotFoundError(error_callback);
     return;
   }
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillDeviceClient::SetCarrier(const dbus::ObjectPath& device_path,
@@ -256,7 +256,7 @@
     PostNotFoundError(error_callback);
     return;
   }
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillDeviceClient::PerformTDLSOperation(
@@ -271,14 +271,14 @@
   }
   // Use -1 to emulate a TDLS failure.
   if (tdls_busy_count_ == -1) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(error_callback, shill::kErrorDhcpFailed, "Failed"));
     return;
   }
   if (operation != shill::kTDLSStatusOperation && tdls_busy_count_ > 0) {
     --tdls_busy_count_;
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(error_callback, shill::kErrorResultInProgress,
                               "In-Progress"));
     return;
@@ -300,8 +300,8 @@
     result = tdls_state_;
   }
 
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, result));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, result));
 }
 
 void FakeShillDeviceClient::AddWakeOnPacketConnection(
@@ -316,7 +316,7 @@
 
   wake_on_packet_connections_[device_path].insert(ip_endpoint);
 
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillDeviceClient::RemoveWakeOnPacketConnection(
@@ -339,7 +339,7 @@
 
   device_iter->second.erase(endpoint_iter);
 
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillDeviceClient::RemoveAllWakeOnPacketConnections(
@@ -355,7 +355,7 @@
 
   wake_on_packet_connections_.erase(iter);
 
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 ShillDeviceClient::TestInterface* FakeShillDeviceClient::GetTestInterface() {
@@ -449,8 +449,8 @@
 void FakeShillDeviceClient::PostVoidCallback(
     const VoidDBusMethodCallback& callback,
     DBusMethodCallStatus status) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, status));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, status));
 }
 
 void FakeShillDeviceClient::NotifyObserversPropertyChanged(
diff --git a/chromeos/dbus/fake_shill_ipconfig_client.cc b/chromeos/dbus/fake_shill_ipconfig_client.cc
index ccb2e5e..442f51ff3 100644
--- a/chromeos/dbus/fake_shill_ipconfig_client.cc
+++ b/chromeos/dbus/fake_shill_ipconfig_client.cc
@@ -5,8 +5,10 @@
 #include "chromeos/dbus/fake_shill_ipconfig_client.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chromeos/dbus/shill_property_changed_observer.h"
 #include "dbus/bus.h"
@@ -48,11 +50,9 @@
   if (!ipconfigs_.GetDictionaryWithoutPathExpansion(ipconfig_path.value(),
                                                     &dict))
     return;
-  base::MessageLoop::current()->PostTask(
-        FROM_HERE, base::Bind(&FakeShillIPConfigClient::PassProperties,
-                              weak_ptr_factory_.GetWeakPtr(),
-                              dict,
-                              callback));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&FakeShillIPConfigClient::PassProperties,
+                            weak_ptr_factory_.GetWeakPtr(), dict, callback));
 }
 
 void FakeShillIPConfigClient::SetProperty(
@@ -72,7 +72,7 @@
     ipconfigs_.SetWithoutPathExpansion(ipconfig_path.value(),
                                        dvalue);
   }
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS));
 }
 
@@ -80,13 +80,13 @@
     const dbus::ObjectPath& ipconfig_path,
     const std::string& name,
     const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS));
 }
 
 void FakeShillIPConfigClient::Remove(const dbus::ObjectPath& ipconfig_path,
                                      const VoidDBusMethodCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS));
 }
 
diff --git a/chromeos/dbus/fake_shill_manager_client.cc b/chromeos/dbus/fake_shill_manager_client.cc
index 4dc7671..6a6cc3e9 100644
--- a/chromeos/dbus/fake_shill_manager_client.cc
+++ b/chromeos/dbus/fake_shill_manager_client.cc
@@ -6,11 +6,14 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -157,20 +160,16 @@
 void FakeShillManagerClient::GetProperties(
     const DictionaryValueCallback& callback) {
   VLOG(1) << "Manager.GetProperties";
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(
-          &FakeShillManagerClient::PassStubProperties,
-          weak_ptr_factory_.GetWeakPtr(),
-          callback));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&FakeShillManagerClient::PassStubProperties,
+                            weak_ptr_factory_.GetWeakPtr(), callback));
 }
 
 void FakeShillManagerClient::GetNetworksForGeolocation(
     const DictionaryValueCallback& callback) {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(
-          &FakeShillManagerClient::PassStubGeoNetworks,
-          weak_ptr_factory_.GetWeakPtr(),
-          callback));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&FakeShillManagerClient::PassStubGeoNetworks,
+                            weak_ptr_factory_.GetWeakPtr(), callback));
 }
 
 void FakeShillManagerClient::SetProperty(const std::string& name,
@@ -180,7 +179,7 @@
   VLOG(2) << "SetProperty: " << name;
   stub_properties_.SetWithoutPathExpansion(name, value.DeepCopy());
   CallNotifyObserversPropertyChanged(name);
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillManagerClient::RequestScan(const std::string& type,
@@ -197,12 +196,10 @@
     device_client->SetDeviceProperty(
         device_path, shill::kScanningProperty, base::FundamentalValue(true));
   }
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&FakeShillManagerClient::ScanCompleted,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 device_path,
-                 callback),
+                 weak_ptr_factory_.GetWeakPtr(), device_path, callback),
       base::TimeDelta::FromSeconds(interactive_delay_));
 }
 
@@ -213,19 +210,16 @@
   base::ListValue* enabled_list = NULL;
   if (!stub_properties_.GetListWithoutPathExpansion(
           shill::kAvailableTechnologiesProperty, &enabled_list)) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, callback);
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(error_callback, "StubError", "Property not found"));
     return;
   }
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&FakeShillManagerClient::SetTechnologyEnabled,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 type,
-                 callback,
-                 true),
+                 weak_ptr_factory_.GetWeakPtr(), type, callback, true),
       base::TimeDelta::FromSeconds(interactive_delay_));
 }
 
@@ -236,18 +230,15 @@
   base::ListValue* enabled_list = NULL;
   if (!stub_properties_.GetListWithoutPathExpansion(
           shill::kAvailableTechnologiesProperty, &enabled_list)) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(error_callback, "StubError", "Property not found"));
     return;
   }
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&FakeShillManagerClient::SetTechnologyEnabled,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 type,
-                 callback,
-                 false),
+                 weak_ptr_factory_.GetWeakPtr(), type, callback, false),
       base::TimeDelta::FromSeconds(interactive_delay_));
 }
 
@@ -265,7 +256,7 @@
     LOG(ERROR) << "ConfigureService requires GUID and Type to be defined";
     // If the properties aren't filled out completely, then just return an empty
     // object path.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, dbus::ObjectPath()));
     return;
   }
@@ -313,7 +304,7 @@
         AddService(profile_path, service_path);
   }
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, dbus::ObjectPath(service_path)));
 }
 
@@ -334,7 +325,7 @@
     const base::DictionaryValue& properties,
     const ObjectPathCallback& callback,
     const ErrorCallback& error_callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, dbus::ObjectPath()));
 }
 
@@ -342,7 +333,8 @@
     const VerificationProperties& properties,
     const BooleanCallback& callback,
     const ErrorCallback& error_callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, true));
 }
 
 void FakeShillManagerClient::VerifyAndEncryptCredentials(
@@ -350,7 +342,7 @@
     const std::string& service_path,
     const StringCallback& callback,
     const ErrorCallback& error_callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, "encrypted_credentials"));
 }
 
@@ -359,7 +351,7 @@
     const std::string& data,
     const StringCallback& callback,
     const ErrorCallback& error_callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, "encrypted_data"));
 }
 
@@ -587,7 +579,7 @@
 void FakeShillManagerClient::SetupDefaultEnvironment() {
   // Bail out from setup if there is no message loop. This will be the common
   // case for tests that are not testing Shill.
-  if (!base::MessageLoop::current())
+  if (!base::ThreadTaskRunnerHandle::IsSet())
     return;
 
   DBusThreadManager* dbus_manager = DBusThreadManager::Get();
@@ -912,11 +904,10 @@
   // initial setup).
   if (!observer_list_.might_have_observers())
     return;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&FakeShillManagerClient::NotifyObserversPropertyChanged,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 property));
+                 weak_ptr_factory_.GetWeakPtr(), property));
 }
 
 void FakeShillManagerClient::NotifyObserversPropertyChanged(
@@ -978,7 +969,7 @@
     enabled_list->Remove(base::StringValue(type), NULL);
   CallNotifyObserversPropertyChanged(
       shill::kEnabledTechnologiesProperty);
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
   // May affect available services.
   SortManagerServices(true);
 }
@@ -1020,7 +1011,7 @@
   }
   VLOG(2) << "ScanCompleted";
   CallNotifyObserversPropertyChanged(shill::kServiceCompleteListProperty);
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillManagerClient::ParseCommandLineSwitch() {
diff --git a/chromeos/dbus/fake_shill_profile_client.cc b/chromeos/dbus/fake_shill_profile_client.cc
index fb0d2fc7..69f52c0 100644
--- a/chromeos/dbus/fake_shill_profile_client.cc
+++ b/chromeos/dbus/fake_shill_profile_client.cc
@@ -6,8 +6,10 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_property_changed_observer.h"
@@ -71,7 +73,7 @@
     entry_paths->AppendString(it.key());
   }
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&PassDictionary, callback, base::Owned(properties.release())));
 }
@@ -92,7 +94,7 @@
     return;
   }
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&PassDictionary, callback, base::Owned(entry->DeepCopy())));
 }
@@ -116,7 +118,7 @@
                          shill::kProfileProperty,
                          profile_path_value);
 
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 ShillProfileClient::TestInterface* FakeShillProfileClient::GetTestInterface() {
diff --git a/chromeos/dbus/fake_shill_service_client.cc b/chromeos/dbus/fake_shill_service_client.cc
index fdae9dbd..990a37b5 100644
--- a/chromeos/dbus/fake_shill_service_client.cc
+++ b/chromeos/dbus/fake_shill_service_client.cc
@@ -6,9 +6,11 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_device_client.h"
@@ -96,12 +98,9 @@
     call_status = DBUS_METHOD_CALL_FAILURE;
   }
 
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&PassStubServiceProperties,
-                 callback,
-                 call_status,
-                 base::Owned(result_properties.release())));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&PassStubServiceProperties, callback, call_status,
+                            base::Owned(result_properties.release())));
 }
 
 void FakeShillServiceClient::SetProperty(const dbus::ObjectPath& service_path,
@@ -114,7 +113,7 @@
     error_callback.Run("Error.InvalidService", "Invalid Service");
     return;
   }
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillServiceClient::SetProperties(
@@ -130,7 +129,7 @@
       return;
     }
   }
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillServiceClient::ClearProperty(
@@ -146,7 +145,7 @@
   }
   dict->RemoveWithoutPathExpansion(name, NULL);
   // Note: Shill does not send notifications when properties are cleared.
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillServiceClient::ClearProperties(
@@ -167,10 +166,9 @@
     // Note: Shill does not send notifications when properties are cleared.
     results->AppendBoolean(true);
   }
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(&PassStubListValue,
-                 callback, base::Owned(results.release())));
+      base::Bind(&PassStubListValue, callback, base::Owned(results.release())));
 }
 
 void FakeShillServiceClient::Connect(const dbus::ObjectPath& service_path,
@@ -199,13 +197,13 @@
                      associating_value);
 
   // Stay Associating until the state is changed again after a delay.
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&FakeShillServiceClient::ContinueConnect,
                  weak_ptr_factory_.GetWeakPtr(), service_path.value()),
       base::TimeDelta::FromSeconds(GetInteractiveDelay()));
 
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillServiceClient::Disconnect(const dbus::ObjectPath& service_path,
@@ -218,15 +216,11 @@
   }
   // Set Idle after a delay
   base::StringValue idle_value(shill::kStateIdle);
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&FakeShillServiceClient::SetProperty,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 service_path,
-                 shill::kStateProperty,
-                 idle_value,
-                 base::Bind(&base::DoNothing),
-                 error_callback),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&FakeShillServiceClient::SetProperty,
+                            weak_ptr_factory_.GetWeakPtr(), service_path,
+                            shill::kStateProperty, idle_value,
+                            base::Bind(&base::DoNothing), error_callback),
       base::TimeDelta::FromSeconds(GetInteractiveDelay()));
   callback.Run();
 }
@@ -234,7 +228,7 @@
 void FakeShillServiceClient::Remove(const dbus::ObjectPath& service_path,
                                     const base::Closure& callback,
                                     const ErrorCallback& error_callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillServiceClient::ActivateCellularModem(
@@ -252,22 +246,20 @@
                      shill::kActivationStateProperty,
                      base::StringValue(shill::kActivationStateActivating));
   // Set Activated after a delay
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&FakeShillServiceClient::SetCellularActivated,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 service_path,
-                 error_callback),
+                 weak_ptr_factory_.GetWeakPtr(), service_path, error_callback),
       base::TimeDelta::FromSeconds(GetInteractiveDelay()));
 
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillServiceClient::CompleteCellularActivation(
     const dbus::ObjectPath& service_path,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillServiceClient::GetLoadableProfileEntries(
@@ -291,12 +283,9 @@
   }
 
   DBusMethodCallStatus call_status = DBUS_METHOD_CALL_SUCCESS;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&PassStubServiceProperties,
-                 callback,
-                 call_status,
-                 base::Owned(result_properties.release())));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&PassStubServiceProperties, callback, call_status,
+                            base::Owned(result_properties.release())));
 }
 
 ShillServiceClient::TestInterface* FakeShillServiceClient::GetTestInterface() {
@@ -419,15 +408,15 @@
   base::DictionaryValue new_properties;
   std::string changed_property;
   bool case_sensitive = true;
-  if (StartsWithASCII(property, "Provider.", case_sensitive) ||
-      StartsWithASCII(property, "OpenVPN.", case_sensitive) ||
-      StartsWithASCII(property, "L2TPIPsec.", case_sensitive)) {
+  if (base::StartsWithASCII(property, "Provider.", case_sensitive) ||
+      base::StartsWithASCII(property, "OpenVPN.", case_sensitive) ||
+      base::StartsWithASCII(property, "L2TPIPsec.", case_sensitive)) {
     // These properties are only nested within the Provider dictionary if read
     // from Shill. Properties that start with "Provider" need to have that
     // stripped off, other properties are nested in the "Provider" dictionary
     // as-is.
     std::string key = property;
-    if (StartsWithASCII(property, "Provider.", case_sensitive))
+    if (base::StartsWithASCII(property, "Provider.", case_sensitive))
       key = property.substr(strlen("Provider."));
     base::DictionaryValue* provider = new base::DictionaryValue;
     provider->SetWithoutPathExpansion(key, value.DeepCopy());
@@ -486,16 +475,16 @@
   // change and the DefaultService property may change.
   if (property == shill::kStateProperty ||
       property == shill::kVisibleProperty) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&CallSortManagerServices));
   }
 
   // Notifiy Chrome of the property change.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&FakeShillServiceClient::NotifyObserversPropertyChanged,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 dbus::ObjectPath(service_path), changed_property));
+                 weak_ptr_factory_.GetWeakPtr(), dbus::ObjectPath(service_path),
+                 changed_property));
   return true;
 }
 
@@ -633,7 +622,7 @@
                        base::StringValue(shill::kErrorBadPassphrase));
     SetServiceProperty(service_path, shill::kStateProperty,
                        base::StringValue(shill::kStateFailure));
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(
             base::IgnoreResult(&FakeShillServiceClient::SetServiceProperty),
diff --git a/chromeos/dbus/fake_shill_third_party_vpn_driver_client.cc b/chromeos/dbus/fake_shill_third_party_vpn_driver_client.cc
index b5e45b9..b68d0b3 100644
--- a/chromeos/dbus/fake_shill_third_party_vpn_driver_client.cc
+++ b/chromeos/dbus/fake_shill_third_party_vpn_driver_client.cc
@@ -5,7 +5,9 @@
 #include "chromeos/dbus/fake_shill_third_party_vpn_driver_client.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/shill_third_party_vpn_observer.h"
 #include "dbus/object_proxy.h"
 
@@ -44,8 +46,8 @@
     const base::DictionaryValue& parameters,
     const ShillClientHelper::StringCallback& callback,
     const ShillClientHelper::ErrorCallback& error_callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, std::string()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, std::string()));
 }
 
 void FakeShillThirdPartyVpnDriverClient::UpdateConnectionState(
@@ -53,7 +55,7 @@
     const uint32_t connection_state,
     const base::Closure& callback,
     const ShillClientHelper::ErrorCallback& error_callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillThirdPartyVpnDriverClient::SendPacket(
@@ -61,7 +63,7 @@
     const std::vector<char>& ip_packet,
     const base::Closure& callback,
     const ShillClientHelper::ErrorCallback& error_callback) {
-  base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void FakeShillThirdPartyVpnDriverClient::OnPacketReceived(
diff --git a/chromeos/dbus/fake_sms_client.cc b/chromeos/dbus/fake_sms_client.cc
index 6f2c9968..211e5c4 100644
--- a/chromeos/dbus/fake_sms_client.cc
+++ b/chromeos/dbus/fake_sms_client.cc
@@ -9,7 +9,8 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/fake_sms_client.h"
@@ -39,12 +40,10 @@
   // Run callback asynchronously.
   if (callback.is_null())
     return;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(&FakeSMSClient::OnGetAll,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::Owned(sms),
-                 callback));
+      base::Bind(&FakeSMSClient::OnGetAll, weak_ptr_factory_.GetWeakPtr(),
+                 base::Owned(sms), callback));
 }
 
 void FakeSMSClient::OnGetAll(base::DictionaryValue* sms,
diff --git a/chromeos/dbus/gsm_sms_client_unittest.cc b/chromeos/dbus/gsm_sms_client_unittest.cc
index 88c6537..8b0c46f 100644
--- a/chromeos/dbus/gsm_sms_client_unittest.cc
+++ b/chromeos/dbus/gsm_sms_client_unittest.cc
@@ -5,7 +5,9 @@
 #include "chromeos/dbus/gsm_sms_client.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/values.h"
 #include "dbus/message.h"
 #include "dbus/mock_bus.h"
@@ -118,7 +120,8 @@
     EXPECT_EQ(expected_index_, index);
     EXPECT_FALSE(reader.HasMoreData());
 
-    message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_));
+    message_loop_.task_runner()->PostTask(FROM_HERE,
+                                          base::Bind(callback, response_));
   }
 
   // Handles Get method call.
@@ -134,7 +137,8 @@
     EXPECT_EQ(expected_index_, index);
     EXPECT_FALSE(reader.HasMoreData());
 
-    message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_));
+    message_loop_.task_runner()->PostTask(FROM_HERE,
+                                          base::Bind(callback, response_));
   }
 
   // Handles List method call.
@@ -147,7 +151,8 @@
     dbus::MessageReader reader(method_call);
     EXPECT_FALSE(reader.HasMoreData());
 
-    message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_));
+    message_loop_.task_runner()->PostTask(FROM_HERE,
+                                          base::Bind(callback, response_));
   }
 
   // Checks the results of Get and List.
@@ -182,10 +187,9 @@
       const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) {
     sms_received_callback_ = signal_callback;
     const bool success = true;
-    message_loop_.PostTask(FROM_HERE, base::Bind(on_connected_callback,
-                                                 interface_name,
-                                                 signal_name,
-                                                 success));
+    message_loop_.task_runner()->PostTask(
+        FROM_HERE, base::Bind(on_connected_callback, interface_name,
+                              signal_name, success));
   }
 };
 
diff --git a/chromeos/dbus/leadership_daemon_manager_client.cc b/chromeos/dbus/leadership_daemon_manager_client.cc
index ed714e5..e2cbe0da 100644
--- a/chromeos/dbus/leadership_daemon_manager_client.cc
+++ b/chromeos/dbus/leadership_daemon_manager_client.cc
@@ -5,10 +5,12 @@
 #include "chromeos/dbus/leadership_daemon_manager_client.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
 #include "dbus/object_manager.h"
@@ -128,7 +130,7 @@
   dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
       dbus::ObjectPath(leaderd::kLeaderdManagerPath));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&LeadershipDaemonManagerClientImpl::OnObjectPathDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -152,7 +154,7 @@
   dbus::ObjectProxy* object_proxy =
       object_manager_->GetObjectProxy(dbus::ObjectPath(object_path));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&LeadershipDaemonManagerClientImpl::OnVoidDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -175,7 +177,7 @@
   dbus::ObjectProxy* object_proxy =
       object_manager_->GetObjectProxy(dbus::ObjectPath(object_path));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&LeadershipDaemonManagerClientImpl::OnVoidDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -198,7 +200,7 @@
   dbus::ObjectProxy* object_proxy =
       object_manager_->GetObjectProxy(dbus::ObjectPath(object_path));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&LeadershipDaemonManagerClientImpl::OnVoidDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -219,7 +221,7 @@
   dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
       dbus::ObjectPath(leaderd::kLeaderdManagerPath));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&LeadershipDaemonManagerClientImpl::OnStringDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
diff --git a/chromeos/dbus/modem_messaging_client_unittest.cc b/chromeos/dbus/modem_messaging_client_unittest.cc
index fc049325..a37284a 100644
--- a/chromeos/dbus/modem_messaging_client_unittest.cc
+++ b/chromeos/dbus/modem_messaging_client_unittest.cc
@@ -5,7 +5,9 @@
 #include "chromeos/dbus/modem_messaging_client.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/values.h"
 #include "dbus/message.h"
 #include "dbus/mock_bus.h"
@@ -104,7 +106,8 @@
     EXPECT_EQ(expected_sms_path_, sms_path);
     EXPECT_FALSE(reader.HasMoreData());
 
-    message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_));
+    message_loop_.task_runner()->PostTask(FROM_HERE,
+                                          base::Bind(callback, response_));
   }
 
   // Handles List method call.
@@ -117,7 +120,8 @@
     dbus::MessageReader reader(method_call);
     EXPECT_FALSE(reader.HasMoreData());
 
-    message_loop_.PostTask(FROM_HERE, base::Bind(callback, response_));
+    message_loop_.task_runner()->PostTask(FROM_HERE,
+                                          base::Bind(callback, response_));
   }
 
   // Checks the results of List.
@@ -152,10 +156,9 @@
       const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) {
     sms_received_callback_ = signal_callback;
     const bool success = true;
-    message_loop_.PostTask(FROM_HERE, base::Bind(on_connected_callback,
-                                                 interface_name,
-                                                 signal_name,
-                                                 success));
+    message_loop_.task_runner()->PostTask(
+        FROM_HERE, base::Bind(on_connected_callback, interface_name,
+                              signal_name, success));
   }
 };
 
diff --git a/chromeos/dbus/nfc_client_unittest.cc b/chromeos/dbus/nfc_client_unittest.cc
index 736853b..12cb0b07 100644
--- a/chromeos/dbus/nfc_client_unittest.cc
+++ b/chromeos/dbus/nfc_client_unittest.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "chromeos/dbus/nfc_adapter_client.h"
 #include "chromeos/dbus/nfc_client_helpers.h"
 #include "chromeos/dbus/nfc_device_client.h"
@@ -378,10 +380,9 @@
       else if (signal_name == nfc_manager::kAdapterRemovedSignal)
         manager_adapter_removed_signal_callback_ = signal_callback;
     }
-    message_loop_.PostTask(FROM_HERE, base::Bind(on_connected_callback,
-                                                 interface_name,
-                                                 signal_name,
-                                                 true));
+    message_loop_.task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(on_connected_callback, interface_name, signal_name, true));
   }
 };
 
diff --git a/chromeos/dbus/peer_daemon_manager_client.cc b/chromeos/dbus/peer_daemon_manager_client.cc
index b4d1acb..e30f294 100644
--- a/chromeos/dbus/peer_daemon_manager_client.cc
+++ b/chromeos/dbus/peer_daemon_manager_client.cc
@@ -6,10 +6,12 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
 #include "dbus/object_manager.h"
@@ -149,7 +151,7 @@
   dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
       dbus::ObjectPath(peerd::kPeerdManagerPath));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&PeerDaemonManagerClientImpl::OnStringDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -173,7 +175,7 @@
   dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
       dbus::ObjectPath(peerd::kPeerdManagerPath));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&PeerDaemonManagerClientImpl::OnVoidDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -198,7 +200,7 @@
   dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
       dbus::ObjectPath(peerd::kPeerdManagerPath));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&PeerDaemonManagerClientImpl::OnStringDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -236,7 +238,7 @@
   dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
       dbus::ObjectPath(peerd::kPeerdManagerPath));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&PeerDaemonManagerClientImpl::OnVoidDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
@@ -257,7 +259,7 @@
   dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy(
       dbus::ObjectPath(peerd::kPeerdManagerPath));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&PeerDaemonManagerClientImpl::OnStringDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
diff --git a/chromeos/dbus/privet_daemon_manager_client.cc b/chromeos/dbus/privet_daemon_manager_client.cc
index 6decce8..de61cc88 100644
--- a/chromeos/dbus/privet_daemon_manager_client.cc
+++ b/chromeos/dbus/privet_daemon_manager_client.cc
@@ -5,10 +5,12 @@
 #include "chromeos/dbus/privet_daemon_manager_client.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
 #include "dbus/object_manager.h"
@@ -103,7 +105,7 @@
   dbus::ObjectProxy* object_proxy =
       object_manager_->GetObjectProxy(dbus::ObjectPath(kPrivetdManagerPath));
   if (!object_proxy) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&PrivetDaemonManagerClientImpl::OnVoidDBusMethod,
                    weak_ptr_factory_.GetWeakPtr(), callback, nullptr));
diff --git a/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc b/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc
index 0e55c25..ff0ce4d 100644
--- a/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc
+++ b/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc
@@ -5,8 +5,9 @@
 #include "chromeos/dbus/services/proxy_resolution_service_provider.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/services/service_provider_test_helper.h"
 #include "dbus/message.h"
 #include "net/url_request/url_request_test_util.h"
@@ -51,7 +52,7 @@
     // resolver injected.
     service_provider_.reset(ProxyResolutionServiceProvider::Create(
         make_scoped_ptr(new TestProxyResolverDelegate(
-            base::MessageLoopProxy::current()))));
+            base::ThreadTaskRunnerHandle::Get()))));
 
     test_helper_.SetUp(kResolveNetworkProxy, service_provider_.get());
 
diff --git a/chromeos/dbus/session_manager_client.cc b/chromeos/dbus/session_manager_client.cc
index 0e0d72a..a60a631 100644
--- a/chromeos/dbus/session_manager_client.cc
+++ b/chromeos/dbus/session_manager_client.cc
@@ -565,7 +565,7 @@
       LOG(ERROR) << "Invalid signal: " << signal->ToString();
       return;
     }
-    const bool success = StartsWithASCII(result_string, "success", false);
+    const bool success = base::StartsWithASCII(result_string, "success", false);
     FOR_EACH_OBSERVER(Observer, observers_, OwnerKeySet(success));
   }
 
@@ -577,7 +577,7 @@
       LOG(ERROR) << "Invalid signal: " << signal->ToString();
       return;
     }
-    const bool success = StartsWithASCII(result_string, "success", false);
+    const bool success = base::StartsWithASCII(result_string, "success", false);
     FOR_EACH_OBSERVER(Observer, observers_, PropertyChangeComplete(success));
   }
 
diff --git a/chromeos/dbus/shill_client_unittest_base.cc b/chromeos/dbus/shill_client_unittest_base.cc
index de82bf0..c6c60f94 100644
--- a/chromeos/dbus/shill_client_unittest_base.cc
+++ b/chromeos/dbus/shill_client_unittest_base.cc
@@ -6,6 +6,8 @@
 
 #include "base/bind.h"
 #include "base/json/json_writer.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/values.h"
 #include "chromeos/network/shill_property_util.h"
 #include "dbus/message.h"
@@ -167,7 +169,7 @@
   // Set an expectation so mock_bus's GetDBusTaskRunner will return the current
   // task runner.
   EXPECT_CALL(*mock_bus_.get(), GetDBusTaskRunner())
-      .WillRepeatedly(Return(message_loop_.message_loop_proxy().get()));
+      .WillRepeatedly(Return(message_loop_.task_runner().get()));
 
   // ShutdownAndBlock() will be called in TearDown().
   EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock()).WillOnce(Return());
@@ -415,11 +417,9 @@
     const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) {
   platform_message_handler_ = signal_callback;
   const bool success = true;
-  message_loop_.PostTask(FROM_HERE,
-                         base::Bind(on_connected_callback,
-                                    interface_name,
-                                    signal_name,
-                                    success));
+  message_loop_.task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(on_connected_callback, interface_name, signal_name, success));
 }
 
 void ShillClientUnittestBase::OnConnectToPacketReceived(
@@ -429,11 +429,9 @@
     const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) {
   packet_receieved__handler_ = signal_callback;
   const bool success = true;
-  message_loop_.PostTask(FROM_HERE,
-                         base::Bind(on_connected_callback,
-                                    interface_name,
-                                    signal_name,
-                                    success));
+  message_loop_.task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(on_connected_callback, interface_name, signal_name, success));
 }
 
 void ShillClientUnittestBase::OnConnectToPropertyChanged(
@@ -443,11 +441,9 @@
     const dbus::ObjectProxy::OnConnectedCallback& on_connected_callback) {
   property_changed_handler_ = signal_callback;
   const bool success = true;
-  message_loop_.PostTask(FROM_HERE,
-                         base::Bind(on_connected_callback,
-                                    interface_name,
-                                    signal_name,
-                                    success));
+  message_loop_.task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(on_connected_callback, interface_name, signal_name, success));
 }
 
 void ShillClientUnittestBase::OnCallMethod(
@@ -458,8 +454,8 @@
   EXPECT_EQ(expected_method_name_, method_call->GetMember());
   dbus::MessageReader reader(method_call);
   argument_checker_.Run(&reader);
-  message_loop_.PostTask(FROM_HERE,
-                         base::Bind(response_callback, response_));
+  message_loop_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(response_callback, response_));
 }
 
 void ShillClientUnittestBase::OnCallMethodWithErrorCallback(
diff --git a/chromeos/dbus/update_engine_client.cc b/chromeos/dbus/update_engine_client.cc
index 7a0bb4c..f77c5de4 100644
--- a/chromeos/dbus/update_engine_client.cc
+++ b/chromeos/dbus/update_engine_client.cc
@@ -8,9 +8,11 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/chromeos_switches.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
@@ -471,10 +473,9 @@
     last_status_.download_progress = 0.0;
     last_status_.last_checked_time = 0;
     last_status_.new_size = 0;
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
-                   weak_factory_.GetWeakPtr()),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
+                              weak_factory_.GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(kStateTransitionDefaultDelayMs));
   }
 
@@ -517,10 +518,9 @@
     last_status_.status = next_status;
     FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(last_status_));
     if (last_status_.status != UPDATE_STATUS_IDLE) {
-      base::MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
-                     weak_factory_.GetWeakPtr()),
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+          FROM_HERE, base::Bind(&UpdateEngineClientFakeImpl::StateTransition,
+                                weak_factory_.GetWeakPtr()),
           base::TimeDelta::FromMilliseconds(delay_ms));
     }
   }
diff --git a/chromeos/disks/disk_mount_manager.cc b/chromeos/disks/disk_mount_manager.cc
index 9264a33..36e4c46f 100644
--- a/chromeos/disks/disk_mount_manager.cc
+++ b/chromeos/disks/disk_mount_manager.cc
@@ -273,8 +273,8 @@
     for (MountPointMap::iterator it = mount_points_.begin();
          it != mount_points_.end();
          ++it) {
-      if (StartsWithASCII(it->second.source_path, mount_path,
-                          true /*case sensitive*/)) {
+      if (base::StartsWithASCII(it->second.source_path, mount_path,
+                                true /*case sensitive*/)) {
         // TODO(tbarzic): Handle the case where this fails.
         UnmountPath(it->second.mount_path,
                     UNMOUNT_OPTIONS_NONE,
@@ -603,7 +603,7 @@
          it != system_path_prefixes_.end();
          ++it) {
       const std::string& prefix = *it;
-      if (StartsWithASCII(system_path, prefix, true))
+      if (base::StartsWithASCII(system_path, prefix, true))
         return prefix;
     }
     return base::EmptyString();
diff --git a/chromeos/login/auth/mock_url_fetchers.cc b/chromeos/login/auth/mock_url_fetchers.cc
index 744631f6..490f56b 100644
--- a/chromeos/login/auth/mock_url_fetchers.cc
+++ b/chromeos/login/auth/mock_url_fetchers.cc
@@ -7,7 +7,10 @@
 #include <errno.h>
 
 #include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
@@ -28,10 +31,9 @@
 }
 
 void ExpectCanceledFetcher::Start() {
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&ExpectCanceledFetcher::CompleteFetch,
-                 weak_factory_.GetWeakPtr()),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&ExpectCanceledFetcher::CompleteFetch,
+                            weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromMilliseconds(100));
 }
 
diff --git a/chromeos/login/auth/online_attempt.cc b/chromeos/login/auth/online_attempt.cc
index b78c5cd..bb955042 100644
--- a/chromeos/login/auth/online_attempt.cc
+++ b/chromeos/login/auth/online_attempt.cc
@@ -8,7 +8,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/login/auth/auth_attempt_state.h"
 #include "chromeos/login/auth/auth_attempt_state_resolver.h"
 #include "chromeos/login/auth/key.h"
@@ -27,7 +27,7 @@
 
 OnlineAttempt::OnlineAttempt(AuthAttemptState* current_attempt,
                              AuthAttemptStateResolver* callback)
-    : message_loop_(base::MessageLoopProxy::current()),
+    : task_runner_(base::ThreadTaskRunnerHandle::Get()),
       attempt_(current_attempt),
       resolver_(callback),
       try_again_(true),
@@ -45,9 +45,8 @@
 void OnlineAttempt::Initiate(net::URLRequestContextGetter* request_context) {
   client_fetcher_.reset(new GaiaAuthFetcher(
       this, GaiaConstants::kChromeOSSource, request_context));
-  message_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&OnlineAttempt::TryClientLogin, weak_factory_.GetWeakPtr()));
+  task_runner_->PostTask(FROM_HERE, base::Bind(&OnlineAttempt::TryClientLogin,
+                                               weak_factory_.GetWeakPtr()));
 }
 
 void OnlineAttempt::OnClientLoginSuccess(
@@ -109,7 +108,7 @@
 }
 
 void OnlineAttempt::TryClientLogin() {
-  message_loop_->PostDelayedTask(
+  task_runner_->PostDelayedTask(
       FROM_HERE,
       base::Bind(&OnlineAttempt::CancelClientLogin, weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromMilliseconds(kClientLoginTimeoutMs));
diff --git a/chromeos/login/auth/online_attempt.h b/chromeos/login/auth/online_attempt.h
index 1a45371..9296c03 100644
--- a/chromeos/login/auth/online_attempt.h
+++ b/chromeos/login/auth/online_attempt.h
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/login/auth/auth_status_consumer.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
@@ -19,11 +20,6 @@
 
 class GaiaAuthFetcher;
 
-namespace base {
-// TODO(skyostil): Migrate to SingleThreadTaskRunner (crbug.com/465354).
-class MessageLoopProxy;
-}
-
 namespace net {
 class URLRequestContextGetter;
 }
@@ -64,7 +60,7 @@
   bool HasPendingFetch();
   void CancelRequest();
 
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   AuthAttemptState* const attempt_;
   AuthAttemptStateResolver* const resolver_;
diff --git a/chromeos/login/auth/online_attempt_host.cc b/chromeos/login/auth/online_attempt_host.cc
index bc537fc..afcf8a7e9 100644
--- a/chromeos/login/auth/online_attempt_host.cc
+++ b/chromeos/login/auth/online_attempt_host.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/login/auth/auth_attempt_state.h"
 #include "chromeos/login/auth/online_attempt.h"
 #include "components/user_manager/user_type.h"
@@ -14,7 +14,7 @@
 namespace chromeos {
 
 OnlineAttemptHost::OnlineAttemptHost(Delegate* delegate)
-    : message_loop_(base::MessageLoopProxy::current()),
+    : task_runner_(base::ThreadTaskRunnerHandle::Get()),
       delegate_(delegate),
       weak_ptr_factory_(this) {
 }
@@ -46,10 +46,9 @@
 void OnlineAttemptHost::Resolve() {
   if (state_->online_complete()) {
     bool success = state_->online_outcome().reason() == AuthFailure::NONE;
-    message_loop_->PostTask(FROM_HERE,
-                            base::Bind(&OnlineAttemptHost::ResolveOnUIThread,
-                                       weak_ptr_factory_.GetWeakPtr(),
-                                       success));
+    task_runner_->PostTask(FROM_HERE,
+                           base::Bind(&OnlineAttemptHost::ResolveOnUIThread,
+                                      weak_ptr_factory_.GetWeakPtr(), success));
   }
 }
 
diff --git a/chromeos/login/auth/online_attempt_host.h b/chromeos/login/auth/online_attempt_host.h
index b835e5b..a5c334b 100644
--- a/chromeos/login/auth/online_attempt_host.h
+++ b/chromeos/login/auth/online_attempt_host.h
@@ -10,15 +10,11 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/login/auth/auth_attempt_state_resolver.h"
 #include "chromeos/login/auth/user_context.h"
 
-namespace base {
-// TODO(skyostil): Migrate to SingleThreadTaskRunner (crbug.com/465354).
-class MessageLoopProxy;
-}
-
 namespace net {
 class URLRequestContextGetter;
 }
@@ -61,7 +57,7 @@
   void ResolveOnUIThread(bool success);
 
  private:
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   Delegate* delegate_;
   UserContext current_attempt_user_context_;
   scoped_ptr<OnlineAttempt> online_attempt_;
diff --git a/chromeos/login/auth/stub_authenticator.cc b/chromeos/login/auth/stub_authenticator.cc
index 6613ea2..6a183a4 100644
--- a/chromeos/login/auth/stub_authenticator.cc
+++ b/chromeos/login/auth/stub_authenticator.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace chromeos {
 
@@ -21,7 +22,7 @@
                                      const UserContext& expected_user_context)
     : Authenticator(consumer),
       expected_user_context_(expected_user_context),
-      message_loop_(base::MessageLoopProxy::current()) {
+      task_runner_(base::ThreadTaskRunnerHandle::Get()) {
 }
 
 void StubAuthenticator::CompleteLogin(content::BrowserContext* context,
@@ -39,13 +40,13 @@
   // during non-online re-auth |user_context| does not have a gaia id.
   if (expected_user_context_.GetUserID() == user_context.GetUserID() &&
       *expected_user_context_.GetKey() == *user_context.GetKey()) {
-    message_loop_->PostTask(
-        FROM_HERE, base::Bind(&StubAuthenticator::OnAuthSuccess, this));
+    task_runner_->PostTask(FROM_HERE,
+                           base::Bind(&StubAuthenticator::OnAuthSuccess, this));
     return;
   }
   GoogleServiceAuthError error(
       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
-  message_loop_->PostTask(
+  task_runner_->PostTask(
       FROM_HERE, base::Bind(&StubAuthenticator::OnAuthFailure, this,
                             AuthFailure::FromNetworkAuthFailure(error)));
 }
diff --git a/chromeos/login/auth/stub_authenticator.h b/chromeos/login/auth/stub_authenticator.h
index 0fa11c4d..84d0595b 100644
--- a/chromeos/login/auth/stub_authenticator.h
+++ b/chromeos/login/auth/stub_authenticator.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/login/auth/authenticator.h"
 #include "chromeos/login/auth/user_context.h"
@@ -48,7 +48,7 @@
 
  private:
   UserContext expected_user_context_;
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(StubAuthenticator);
 };
diff --git a/chromeos/network/auto_connect_handler.cc b/chromeos/network/auto_connect_handler.cc
index 9715cd15..edb8c6d 100644
--- a/chromeos/network/auto_connect_handler.cc
+++ b/chromeos/network/auto_connect_handler.cc
@@ -8,7 +8,8 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_manager_client.h"
@@ -124,9 +125,9 @@
   }
   connect_to_best_services_after_scan_ = false;
   // Request ConnectToBestServices after processing any pending DBus calls.
-  base::MessageLoopProxy::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&AutoConnectHandler::CallShillConnectToBestServices,
-                              weak_ptr_factory_.GetWeakPtr()));
+                            weak_ptr_factory_.GetWeakPtr()));
 }
 
 void AutoConnectHandler::ResolveRequestCompleted(
diff --git a/chromeos/network/client_cert_resolver_unittest.cc b/chromeos/network/client_cert_resolver_unittest.cc
index fb04d94d..e3816d0 100644
--- a/chromeos/network/client_cert_resolver_unittest.cc
+++ b/chromeos/network/client_cert_resolver_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
@@ -63,8 +62,7 @@
     test_nsscertdb_.reset(new net::NSSCertDatabaseChromeOS(
         crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot())),
         crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot()))));
-    test_nsscertdb_->SetSlowTaskRunnerForTest(
-        message_loop_.message_loop_proxy());
+    test_nsscertdb_->SetSlowTaskRunnerForTest(message_loop_.task_runner());
 
     DBusThreadManager::Initialize();
     service_test_ =
@@ -152,7 +150,7 @@
                                 managed_config_handler_.get());
     client_cert_resolver_->AddObserver(this);
     client_cert_resolver_->SetSlowTaskRunnerForTest(
-        message_loop_.message_loop_proxy());
+        message_loop_.task_runner());
   }
 
   void SetupWifi() {
diff --git a/chromeos/network/dhcp_proxy_script_fetcher_chromeos.cc b/chromeos/network/dhcp_proxy_script_fetcher_chromeos.cc
index 41f7a4d..d0df7cf 100644
--- a/chromeos/network/dhcp_proxy_script_fetcher_chromeos.cc
+++ b/chromeos/network/dhcp_proxy_script_fetcher_chromeos.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/network/dhcp_proxy_script_fetcher_chromeos.h"
 
+#include "base/location.h"
 #include "base/task_runner_util.h"
 #include "chromeos/network/network_event_log.h"
 #include "chromeos/network/network_handler.h"
@@ -38,7 +39,7 @@
   proxy_script_fetcher_.reset(
       new net::ProxyScriptFetcherImpl(url_request_context_));
   if (NetworkHandler::IsInitialized())
-    network_handler_message_loop_ = NetworkHandler::Get()->message_loop();
+    network_handler_task_runner_ = NetworkHandler::Get()->task_runner();
 }
 
 DhcpProxyScriptFetcherChromeos::~DhcpProxyScriptFetcherChromeos() {
@@ -47,12 +48,11 @@
 int DhcpProxyScriptFetcherChromeos::Fetch(
     base::string16* utf16_text,
     const net::CompletionCallback& callback) {
-  if (!network_handler_message_loop_.get())
+  if (!network_handler_task_runner_.get())
     return net::ERR_PAC_NOT_IN_DHCP;
   CHECK(!callback.is_null());
   base::PostTaskAndReplyWithResult(
-      network_handler_message_loop_.get(),
-      FROM_HERE,
+      network_handler_task_runner_.get(), FROM_HERE,
       base::Bind(&GetPacUrlFromDefaultNetwork),
       base::Bind(&DhcpProxyScriptFetcherChromeos::ContinueFetch,
                  weak_ptr_factory_.GetWeakPtr(), utf16_text, callback));
diff --git a/chromeos/network/dhcp_proxy_script_fetcher_chromeos.h b/chromeos/network/dhcp_proxy_script_fetcher_chromeos.h
index 8c9ea97..f0d3c4f 100644
--- a/chromeos/network/dhcp_proxy_script_fetcher_chromeos.h
+++ b/chromeos/network/dhcp_proxy_script_fetcher_chromeos.h
@@ -7,11 +7,14 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "chromeos/chromeos_export.h"
 #include "net/proxy/dhcp_proxy_script_fetcher.h"
 #include "url/gurl.h"
 
+namespace base {
+class SingleThreadTaskRunner;
+}
+
 namespace net {
 class URLRequestContext;
 class ProxyScriptFetcher;
@@ -43,7 +46,7 @@
 
   net::URLRequestContext* url_request_context_;  // Weak ptr
   scoped_ptr<net::ProxyScriptFetcher> proxy_script_fetcher_;
-  scoped_refptr<base::MessageLoopProxy> network_handler_message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> network_handler_task_runner_;
 
   GURL pac_url_;
 
diff --git a/chromeos/network/host_resolver_impl_chromeos.cc b/chromeos/network/host_resolver_impl_chromeos.cc
index ebb54a2..05def37 100644
--- a/chromeos/network/host_resolver_impl_chromeos.cc
+++ b/chromeos/network/host_resolver_impl_chromeos.cc
@@ -4,8 +4,10 @@
 
 #include "chromeos/network/host_resolver_impl_chromeos.h"
 
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/sys_info.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chromeos/network/device_state.h"
 #include "chromeos/network/network_handler.h"
@@ -30,16 +32,17 @@
  public:
   static void Create(
       const base::WeakPtr<HostResolverImplChromeOS>& resolver,
-      scoped_refptr<base::MessageLoopProxy> resolver_message_loop,
+      scoped_refptr<base::SingleThreadTaskRunner> resolver_task_runner,
       NetworkStateHandler* network_state_handler) {
-    new NetworkObserver(resolver, resolver_message_loop, network_state_handler);
+    new NetworkObserver(resolver, resolver_task_runner, network_state_handler);
   }
 
-  NetworkObserver(const base::WeakPtr<HostResolverImplChromeOS>& resolver,
-                  scoped_refptr<base::MessageLoopProxy> resolver_message_loop,
-                  NetworkStateHandler* network_state_handler)
+  NetworkObserver(
+      const base::WeakPtr<HostResolverImplChromeOS>& resolver,
+      scoped_refptr<base::SingleThreadTaskRunner> resolver_task_runner,
+      NetworkStateHandler* network_state_handler)
       : resolver_(resolver),
-        resolver_message_loop_(resolver_message_loop),
+        resolver_task_runner_(resolver_task_runner),
         network_state_handler_(network_state_handler),
         weak_ptr_factory_resolver_thread_(this) {
     network_state_handler_->AddObserver(this, FROM_HERE);
@@ -96,11 +99,10 @@
 
   void CallResolverSetIpAddress(const std::string& ipv4_address,
                                 const std::string& ipv6_address) {
-    resolver_message_loop_->PostTask(
-        FROM_HERE,
-        base::Bind(&NetworkObserver::SetIpAddressOnResolverThread,
-                   weak_ptr_factory_resolver_thread_.GetWeakPtr(),
-                   ipv4_address, ipv6_address));
+    resolver_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&NetworkObserver::SetIpAddressOnResolverThread,
+                              weak_ptr_factory_resolver_thread_.GetWeakPtr(),
+                              ipv4_address, ipv6_address));
   }
 
   void SetIpAddressOnResolverThread(const std::string& ipv4_address,
@@ -110,7 +112,7 @@
   }
 
   base::WeakPtr<HostResolverImplChromeOS> resolver_;
-  scoped_refptr<base::MessageLoopProxy> resolver_message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> resolver_task_runner_;
   NetworkStateHandler* network_state_handler_;
   base::WeakPtrFactory<NetworkObserver> weak_ptr_factory_resolver_thread_;
 
@@ -120,19 +122,17 @@
 // HostResolverImplChromeOS
 
 HostResolverImplChromeOS::HostResolverImplChromeOS(
-    scoped_refptr<base::MessageLoopProxy> network_handler_message_loop,
+    scoped_refptr<base::SingleThreadTaskRunner> network_handler_task_runner,
     NetworkStateHandler* network_state_handler,
     const Options& options,
     net::NetLog* net_log)
     : HostResolverImpl(options, net_log),
-      network_handler_message_loop_(network_handler_message_loop),
+      network_handler_task_runner_(network_handler_task_runner),
       weak_ptr_factory_(this) {
-  network_handler_message_loop->PostTask(
+  network_handler_task_runner->PostTask(
       FROM_HERE,
-      base::Bind(&NetworkObserver::Create,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::MessageLoopProxy::current(),
-                 network_state_handler));
+      base::Bind(&NetworkObserver::Create, weak_ptr_factory_.GetWeakPtr(),
+                 base::ThreadTaskRunnerHandle::Get(), network_state_handler));
 }
 
 HostResolverImplChromeOS::~HostResolverImplChromeOS() {
@@ -192,23 +192,18 @@
     const Options& options,
     net::NetLog* net_log) {
   return scoped_ptr<net::HostResolver>(new HostResolverImplChromeOS(
-      NetworkHandler::Get()->message_loop(),
-      NetworkHandler::Get()->network_state_handler(),
-      options,
-      net_log));
+      NetworkHandler::Get()->task_runner(),
+      NetworkHandler::Get()->network_state_handler(), options, net_log));
 }
 
 // static
 scoped_ptr<net::HostResolver>
 HostResolverImplChromeOS::CreateHostResolverForTest(
-    scoped_refptr<base::MessageLoopProxy> network_handler_message_loop,
+    scoped_refptr<base::SingleThreadTaskRunner> network_handler_task_runner,
     NetworkStateHandler* network_state_handler) {
   Options options;
   return scoped_ptr<net::HostResolver>(new HostResolverImplChromeOS(
-      network_handler_message_loop,
-      network_state_handler,
-      options,
-      NULL));
+      network_handler_task_runner, network_state_handler, options, NULL));
 }
 
 }  // namespace chromeos
diff --git a/chromeos/network/host_resolver_impl_chromeos.h b/chromeos/network/host_resolver_impl_chromeos.h
index 726fd13..dba4398 100644
--- a/chromeos/network/host_resolver_impl_chromeos.h
+++ b/chromeos/network/host_resolver_impl_chromeos.h
@@ -11,7 +11,7 @@
 #include "net/dns/host_resolver_impl.h"
 
 namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 }
 
 namespace chromeos {
@@ -37,7 +37,7 @@
 
   // Creates a host resolver instance for testing.
   static scoped_ptr<net::HostResolver> CreateHostResolverForTest(
-      scoped_refptr<base::MessageLoopProxy> network_handler_message_loop,
+      scoped_refptr<base::SingleThreadTaskRunner> network_handler_task_runner,
       NetworkStateHandler* network_state_handler);
 
   ~HostResolverImplChromeOS() override;
@@ -55,7 +55,7 @@
   class NetworkObserver;
 
   HostResolverImplChromeOS(
-      scoped_refptr<base::MessageLoopProxy> network_handler_message_loop,
+      scoped_refptr<base::SingleThreadTaskRunner> network_handler_task_runner,
       NetworkStateHandler* network_state_handler,
       const Options& options,
       net::NetLog* net_log);
@@ -69,7 +69,7 @@
   std::string ipv4_address_;
   std::string ipv6_address_;
   base::ThreadChecker thread_checker_;
-  scoped_refptr<base::MessageLoopProxy> network_handler_message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> network_handler_task_runner_;
   base::WeakPtrFactory<HostResolverImplChromeOS> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(HostResolverImplChromeOS);
diff --git a/chromeos/network/host_resolver_impl_chromeos_unittest.cc b/chromeos/network/host_resolver_impl_chromeos_unittest.cc
index 8faee33..5ba0b0c 100644
--- a/chromeos/network/host_resolver_impl_chromeos_unittest.cc
+++ b/chromeos/network/host_resolver_impl_chromeos_unittest.cc
@@ -4,10 +4,12 @@
 
 #include "chromeos/network/host_resolver_impl_chromeos.h"
 
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_device_client.h"
 #include "chromeos/dbus/shill_ipconfig_client.h"
@@ -75,11 +77,9 @@
  protected:
   // Run from main (UI) message loop, calls Resolve on IO message loop.
   int CallResolve(net::HostResolver::RequestInfo& info) {
-    io_message_loop_.PostTask(
-        FROM_HERE,
-        base::Bind(&HostResolverImplChromeOSTest::Resolve,
-                   base::Unretained(this),
-                   info));
+    io_message_loop_.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&HostResolverImplChromeOSTest::Resolve,
+                              base::Unretained(this), info));
     io_message_loop_.RunUntilIdle();
     return result_;
   }
@@ -93,8 +93,7 @@
     net::HostResolver::Options options;
     host_resolver_ =
         chromeos::HostResolverImplChromeOS::CreateHostResolverForTest(
-            base::MessageLoopProxy::current(),
-            network_state_handler_.get());
+            base::ThreadTaskRunnerHandle::Get(), network_state_handler_.get());
   }
 
   // Run from IO message loop.
diff --git a/chromeos/network/managed_network_configuration_handler_unittest.cc b/chromeos/network/managed_network_configuration_handler_unittest.cc
index 4d965eb..c95d6b1 100644
--- a/chromeos/network/managed_network_configuration_handler_unittest.cc
+++ b/chromeos/network/managed_network_configuration_handler_unittest.cc
@@ -10,7 +10,9 @@
 #include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/mock_shill_manager_client.h"
@@ -133,10 +135,9 @@
     const std::string& userhash = profile_to_user_[profile_path.value()];
     result->SetStringWithoutPathExpansion(shill::kUserHashProperty, userhash);
 
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(base::Bind(&DereferenceAndCall, callback),
-                   base::Owned(result.release())));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(base::Bind(&DereferenceAndCall, callback),
+                              base::Owned(result.release())));
   }
 
   void GetEntry(const dbus::ObjectPath& profile_path,
@@ -151,10 +152,9 @@
     base::DictionaryValue* entry = NULL;
     entries->GetDictionaryWithoutPathExpansion(entry_path, &entry);
     ASSERT_TRUE(entry);
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(base::Bind(&DereferenceAndCall, callback),
-                   base::Owned(entry->DeepCopy())));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(base::Bind(&DereferenceAndCall, callback),
+                              base::Owned(entry->DeepCopy())));
   }
 
  protected:
@@ -172,11 +172,9 @@
 
   void GetProperties(const dbus::ObjectPath& service_path,
                      const DictionaryValueCallback& callback) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback,
-                   DBUS_METHOD_CALL_SUCCESS,
-                   base::ConstRef(service_properties_)));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(callback, DBUS_METHOD_CALL_SUCCESS,
+                              base::ConstRef(service_properties_)));
   }
 
  protected:
@@ -957,11 +955,10 @@
       const dbus::ObjectPath& profile_path,
       const ShillClientHelper::DictionaryValueCallbackWithoutStatus& callback,
       const ShillClientHelper::ErrorCallback& error_callback) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(ManagedNetworkConfigurationHandlerShutdownTest::
-                       CallbackWithEmptyDictionary,
-                   callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(ManagedNetworkConfigurationHandlerShutdownTest::
+                                  CallbackWithEmptyDictionary,
+                              callback));
   }
 
   static void CallbackWithEmptyDictionary(
diff --git a/chromeos/network/network_cert_migrator_unittest.cc b/chromeos/network/network_cert_migrator_unittest.cc
index efb308f..ff7191c 100644
--- a/chromeos/network/network_cert_migrator_unittest.cc
+++ b/chromeos/network/network_cert_migrator_unittest.cc
@@ -47,8 +47,7 @@
     test_nsscertdb_.reset(new net::NSSCertDatabaseChromeOS(
         crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot())),
         crypto::ScopedPK11Slot(PK11_ReferenceSlot(test_nssdb_.slot()))));
-    test_nsscertdb_->SetSlowTaskRunnerForTest(
-        message_loop_.message_loop_proxy());
+    test_nsscertdb_->SetSlowTaskRunnerForTest(message_loop_.task_runner());
 
     DBusThreadManager::Initialize();
     service_test_ =
diff --git a/chromeos/network/network_change_notifier_chromeos.cc b/chromeos/network/network_change_notifier_chromeos.cc
index d901263..4561091d 100644
--- a/chromeos/network/network_change_notifier_chromeos.cc
+++ b/chromeos/network/network_change_notifier_chromeos.cc
@@ -6,8 +6,10 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/network/network_change_notifier_chromeos.h"
 #include "chromeos/network/network_event_log.h"
@@ -55,7 +57,7 @@
       max_bandwidth_mbps_(
           NetworkChangeNotifier::GetMaxBandwidthForConnectionSubtype(
               SUBTYPE_NONE)),
-      message_loop_(base::MessageLoopProxy::current()),
+      task_runner_(base::ThreadTaskRunnerHandle::Get()),
       weak_ptr_factory_(this) {
   poll_callback_ = base::Bind(&NetworkChangeNotifierChromeos::PollForState,
                               weak_ptr_factory_.GetWeakPtr());
@@ -96,7 +98,7 @@
   // |this|, to allow PollForState() to modify our cached state.
   // TODO(gauravsh): Figure out why we would have missed this notification.
   if (connection_type_ == CONNECTION_NONE)
-    message_loop_->PostTask(FROM_HERE, poll_callback_);
+    task_runner_->PostTask(FROM_HERE, poll_callback_);
   return connection_type_;
 }
 
diff --git a/chromeos/network/network_change_notifier_chromeos.h b/chromeos/network/network_change_notifier_chromeos.h
index 8b322125..d7557e5 100644
--- a/chromeos/network/network_change_notifier_chromeos.h
+++ b/chromeos/network/network_change_notifier_chromeos.h
@@ -12,7 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/power_manager_client.h"
 #include "chromeos/network/network_state_handler_observer.h"
@@ -105,7 +105,7 @@
   base::Closure poll_callback_;
 
   // For setting up network refresh polling callbacks.
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   base::WeakPtrFactory<NetworkChangeNotifierChromeos> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierChromeos);
diff --git a/chromeos/network/network_change_notifier_chromeos_unittest.cc b/chromeos/network/network_change_notifier_chromeos_unittest.cc
index 993903b0..ffbe7c7 100644
--- a/chromeos/network/network_change_notifier_chromeos_unittest.cc
+++ b/chromeos/network/network_change_notifier_chromeos_unittest.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/string_split.h"
 #include "chromeos/network/network_change_notifier_factory_chromeos.h"
 #include "chromeos/network/network_state.h"
@@ -169,6 +170,7 @@
   }
 
  private:
+  base::MessageLoop message_loop_;
   NetworkState default_network_;
   NetworkChangeNotifierChromeos notifier_;
 };
diff --git a/chromeos/network/network_configuration_handler_unittest.cc b/chromeos/network/network_configuration_handler_unittest.cc
index 2b79c4c..21ff388 100644
--- a/chromeos/network/network_configuration_handler_unittest.cc
+++ b/chromeos/network/network_configuration_handler_unittest.cc
@@ -7,7 +7,9 @@
 
 #include "base/bind.h"
 #include "base/json/json_writer.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_piece.h"
 #include "base/values.h"
@@ -269,7 +271,7 @@
                      const base::Closure& callback,
                      const ShillClientHelper::ErrorCallback& error_callback) {
     // Don't run the callback immediately to emulate actual behavior.
-    message_loop_.PostTask(FROM_HERE, callback);
+    message_loop_.task_runner()->PostTask(FROM_HERE, callback);
   }
 
   bool PendingProfileEntryDeleterForTest(const std::string& service_path) {
diff --git a/chromeos/network/network_connection_handler.cc b/chromeos/network/network_connection_handler.cc
index 7fec062c..e8c4939 100644
--- a/chromeos/network/network_connection_handler.cc
+++ b/chromeos/network/network_connection_handler.cc
@@ -7,8 +7,9 @@
 #include "base/bind.h"
 #include "base/json/json_reader.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_manager_client.h"
 #include "chromeos/dbus/shill_service_client.h"
@@ -548,10 +549,9 @@
   // Post a delayed task to check to see if certificates have loaded. If they
   // haven't, and queued_connect_ has not been cleared (e.g. by a successful
   // connect request), cancel the request and notify the user.
-  base::MessageLoopProxy::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&NetworkConnectionHandler::CheckCertificatesLoaded,
-                 AsWeakPtr()),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&NetworkConnectionHandler::CheckCertificatesLoaded,
+                            AsWeakPtr()),
       base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds) - dtime);
 }
 
diff --git a/chromeos/network/network_device_handler_impl.cc b/chromeos/network/network_device_handler_impl.cc
index cb3ff2c..177fbcc3 100644
--- a/chromeos/network/network_device_handler_impl.cc
+++ b/chromeos/network/network_device_handler_impl.cc
@@ -6,8 +6,9 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -204,7 +205,7 @@
   if (!DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface())
     request_delay = base::TimeDelta::FromMilliseconds(request_delay_ms);
 
-  base::MessageLoopProxy::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, base::Bind(&CallPerformTDLSOperation, device_path, new_params,
                             callback, error_callback),
       request_delay);
@@ -232,10 +233,9 @@
     if (!DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface())
       request_delay = base::TimeDelta::FromMilliseconds(kReRequestDelayMs);
 
-    base::MessageLoopProxy::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&CallPerformTDLSOperation,
-                   device_path, retry_params, callback, error_callback),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&CallPerformTDLSOperation, device_path,
+                              retry_params, callback, error_callback),
         request_delay);
     return;
   }
diff --git a/chromeos/network/network_handler.cc b/chromeos/network/network_handler.cc
index f8f1e40c..0ce9ff8c 100644
--- a/chromeos/network/network_handler.cc
+++ b/chromeos/network/network_handler.cc
@@ -4,6 +4,7 @@
 
 #include "chromeos/network/network_handler.h"
 
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/worker_pool.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/network/auto_connect_handler.h"
@@ -26,7 +27,7 @@
 static NetworkHandler* g_network_handler = NULL;
 
 NetworkHandler::NetworkHandler()
-    : message_loop_(base::MessageLoopProxy::current()) {
+    : task_runner_(base::ThreadTaskRunnerHandle::Get()) {
   CHECK(DBusThreadManager::IsInitialized());
 
   network_state_handler_.reset(new NetworkStateHandler());
diff --git a/chromeos/network/network_handler.h b/chromeos/network/network_handler.h
index d5dc403..82d7441e 100644
--- a/chromeos/network/network_handler.h
+++ b/chromeos/network/network_handler.h
@@ -8,7 +8,7 @@
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "chromeos/chromeos_export.h"
 
 namespace chromeos {
@@ -45,9 +45,9 @@
   // Returns true if the global instance has been initialized.
   static bool IsInitialized();
 
-  // Returns the MessageLoopProxy for posting NetworkHandler calls from
-  // other threads.
-  base::MessageLoopProxy* message_loop() { return message_loop_.get(); }
+  // Returns the task runner for posting NetworkHandler calls from other
+  // threads.
+  base::SingleThreadTaskRunner* task_runner() { return task_runner_.get(); }
 
   // Do not use these accessors within this module; all dependencies should be
   // explicit so that classes can be constructed explicitly in tests without
@@ -69,7 +69,7 @@
   void Init();
 
   // The order of these determines the (inverse) destruction order.
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   scoped_ptr<NetworkStateHandler> network_state_handler_;
   scoped_ptr<NetworkDeviceHandlerImpl> network_device_handler_;
   scoped_ptr<NetworkProfileHandler> network_profile_handler_;
diff --git a/chromeos/process_proxy/process_output_watcher_unittest.cc b/chromeos/process_proxy/process_output_watcher_unittest.cc
index 5732467..7a86d6a 100644
--- a/chromeos/process_proxy/process_output_watcher_unittest.cc
+++ b/chromeos/process_proxy/process_output_watcher_unittest.cc
@@ -11,9 +11,10 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_util.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread.h"
 #include "chromeos/process_proxy/process_output_watcher.h"
@@ -107,7 +108,8 @@
     failed_ = !expectations_.CheckExpectations(output, type);
     if (failed_ || expectations_.IsDone()) {
       ASSERT_FALSE(test_case_done_callback_.is_null());
-      message_loop_.PostTask(FROM_HERE, test_case_done_callback_);
+      message_loop_.task_runner()->PostTask(FROM_HERE,
+                                            test_case_done_callback_);
       test_case_done_callback_.Reset();
     }
   }
@@ -130,12 +132,10 @@
     ASSERT_FALSE(HANDLE_EINTR(pipe(pt_pipe)));
     ASSERT_FALSE(HANDLE_EINTR(pipe(stop_pipe)));
 
-    output_watch_thread_->message_loop()->PostTask(
+    output_watch_thread_->task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&ProcessOutputWatcherTest::StartWatch,
-                   base::Unretained(this),
-                   pt_pipe[0],
-                   stop_pipe[0]));
+                   base::Unretained(this), pt_pipe[0], stop_pipe[0]));
 
     for (size_t i = 0; i < test_cases.size(); i++) {
       expectations_.SetTestCase(test_cases[i]);
diff --git a/chromeos/process_proxy/process_proxy.cc b/chromeos/process_proxy/process_proxy.cc
index 76ce5f2..4907d8b 100644
--- a/chromeos/process_proxy/process_proxy.cc
+++ b/chromeos/process_proxy/process_proxy.cc
@@ -10,10 +10,13 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/launch.h"
 #include "base/process/process.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "third_party/cros_system_api/switches/chrome_switches.h"
 
@@ -85,7 +88,7 @@
 
   callback_set_ = true;
   callback_ = callback;
-  callback_runner_ = base::MessageLoopProxy::current();
+  callback_runner_ = base::ThreadTaskRunnerHandle::Get();
 
   // This object will delete itself once watching is stopped.
   // It also takes ownership of the passed fds.
@@ -99,9 +102,9 @@
   shutdown_pipe_[PIPE_END_READ] = -1;
 
   // |watch| thread is blocked by |output_watcher| from now on.
-  watch_thread->message_loop()->PostTask(FROM_HERE,
-      base::Bind(&ProcessOutputWatcher::Start,
-                 base::Unretained(output_watcher)));
+  watch_thread->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&ProcessOutputWatcher::Start,
+                            base::Unretained(output_watcher)));
   watcher_started_ = true;
   return true;
 }
diff --git a/chromeos/process_proxy/process_proxy_unittest.cc b/chromeos/process_proxy/process_proxy_unittest.cc
index 97c74952..20221c2 100644
--- a/chromeos/process_proxy/process_proxy_unittest.cc
+++ b/chromeos/process_proxy/process_proxy_unittest.cc
@@ -7,10 +7,12 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/process/kill.h"
 #include "base/process/process.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "chromeos/process_proxy/process_proxy_registry.h"
 
@@ -76,8 +78,8 @@
     }
 
     if (!valid || TestSucceeded()) {
-      base::MessageLoop::current()->PostTask(FROM_HERE,
-                                             base::MessageLoop::QuitClosure());
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::MessageLoop::QuitClosure());
     }
   }
 
@@ -139,8 +141,8 @@
       return;
     }
     EXPECT_EQ("exit", type);
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
   }
 
   void StartRegistryTest(ProcessProxyRegistry* registry) override {
@@ -164,8 +166,8 @@
     // We may receive ^C on stdout, but we don't care about that, as long as we
     // eventually received exit event.
     if (type == "exit") {
-      base::MessageLoop::current()->PostTask(FROM_HERE,
-                                             base::MessageLoop::QuitClosure());
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::MessageLoop::QuitClosure());
     }
   }
 
@@ -206,24 +208,22 @@
       process.Terminate(0, true);
     }
 
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
   }
 
   void RunTest() {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&ProcessProxyTest::InitRegistryTest,
-                   base::Unretained(this)));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&ProcessProxyTest::InitRegistryTest,
+                              base::Unretained(this)));
 
     // Wait until all data from output watcher is received (QuitTask will be
     // fired on watcher thread).
     base::MessageLoop::current()->Run();
 
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(&ProcessProxyTest::EndRegistryTest,
-                   base::Unretained(this)));
+        base::Bind(&ProcessProxyTest::EndRegistryTest, base::Unretained(this)));
 
     // Wait until we clean up the process proxy.
     base::MessageLoop::current()->Run();
diff --git a/chromeos/settings/cros_settings_provider.cc b/chromeos/settings/cros_settings_provider.cc
index 98faf71..dceed62 100644
--- a/chromeos/settings/cros_settings_provider.cc
+++ b/chromeos/settings/cros_settings_provider.cc
@@ -27,7 +27,7 @@
   // It should not reach here from UI in the guest mode, but just in case.
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kGuestSession) &&
-      !::StartsWithASCII(path, "cros.session.", true)) {
+      !::base::StartsWithASCII(path, "cros.session.", true)) {
     LOG(ERROR) << "Ignoring the guest request to change: " << path;
     return;
   }
diff --git a/chromeos/system/version_loader.cc b/chromeos/system/version_loader.cc
index 50cdaf4..4e6272c2 100644
--- a/chromeos/system/version_loader.cc
+++ b/chromeos/system/version_loader.cc
@@ -78,7 +78,7 @@
   std::vector<std::string> lines;
   base::SplitString(contents, '\n', &lines);
   for (size_t i = 0; i < lines.size(); ++i) {
-    if (StartsWithASCII(lines[i], kFirmwarePrefix, false)) {
+    if (base::StartsWithASCII(lines[i], kFirmwarePrefix, false)) {
       std::string str = lines[i].substr(std::string(kFirmwarePrefix).size());
       size_t found = str.find_first_not_of("| ");
       if (found != std::string::npos)
diff --git a/chromeos/tpm/tpm_password_fetcher.cc b/chromeos/tpm/tpm_password_fetcher.cc
index 02c4abc..dac9c2a 100644
--- a/chromeos/tpm/tpm_password_fetcher.cc
+++ b/chromeos/tpm/tpm_password_fetcher.cc
@@ -6,7 +6,9 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 
@@ -63,7 +65,7 @@
 }
 
 void TpmPasswordFetcher::RescheduleFetch() {
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&TpmPasswordFetcher::Fetch, weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromMilliseconds(kTpmCheckIntervalMs));
diff --git a/cloud_print/service/service_state.cc b/cloud_print/service/service_state.cc
index 789d229..80dbd8ca 100644
--- a/cloud_print/service/service_state.cc
+++ b/cloud_print/service/service_state.cc
@@ -199,7 +199,7 @@
   std::vector<std::string> lines;
   Tokenize(fetcher_delegate.data(), "\r\n", &lines);
   for (size_t i = 0; i < lines.size(); ++i) {
-    if (StartsWithASCII(lines[i], kAuthStart, false))
+    if (base::StartsWithASCII(lines[i], kAuthStart, false))
       return lines[i].substr(arraysize(kAuthStart) - 1);
   }
 
diff --git a/cloud_print/service/win/cloud_print_service.cc b/cloud_print/service/win/cloud_print_service.cc
index c1b9601..b3761d3 100644
--- a/cloud_print/service/win/cloud_print_service.cc
+++ b/cloud_print/service/win/cloud_print_service.cc
@@ -147,7 +147,7 @@
         controller_(new ServiceController()) {
   }
 
-  static wchar_t* GetAppIdT() {
+  static const wchar_t* GetAppIdT() {
     return ServiceController::GetAppIdT();
   };
 
diff --git a/cloud_print/service/win/service_utils.cc b/cloud_print/service/win/service_utils.cc
index 6bced809..6932447 100644
--- a/cloud_print/service/win/service_utils.cc
+++ b/cloud_print/service/win/service_utils.cc
@@ -28,7 +28,7 @@
 
 base::string16 ReplaceLocalHostInName(const base::string16& user_name) {
   static const wchar_t kLocalDomain[] = L".\\";
-  if (StartsWith(user_name, kLocalDomain, true)) {
+  if (base::StartsWith(user_name, kLocalDomain, true)) {
     return GetLocalComputerName() +
            user_name.substr(arraysize(kLocalDomain) - 2);
   }
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 52379bf..8b26bd5c 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -289,6 +289,7 @@
     "//components/login:unit_tests",
     "//components/metrics:unit_tests",
     "//components/mime_util:unit_tests",
+    "//components/offline_pages:unit_tests",
     "//components/omnibox:unit_tests",
     "//components/packed_ct_ev_whitelist:unit_tests",
     "//components/undo:unit_tests",
diff --git a/components/autofill.gypi b/components/autofill.gypi
index cd22d67..6c4e15b 100644
--- a/components/autofill.gypi
+++ b/components/autofill.gypi
@@ -202,8 +202,6 @@
         'autofill/core/browser/webdata/autofill_profile_syncable_service.h',
         'autofill/core/browser/webdata/autofill_table.cc',
         'autofill/core/browser/webdata/autofill_table.h',
-        'autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc',
-        'autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h',
         'autofill/core/browser/webdata/autofill_wallet_syncable_service.cc',
         'autofill/core/browser/webdata/autofill_wallet_syncable_service.h',
         'autofill/core/browser/webdata/autofill_webdata.h',
diff --git a/components/autofill/content/browser/wallet/form_field_error.cc b/components/autofill/content/browser/wallet/form_field_error.cc
index 826ea37d..5d254a0 100644
--- a/components/autofill/content/browser/wallet/form_field_error.cc
+++ b/components/autofill/content/browser/wallet/form_field_error.cc
@@ -15,35 +15,35 @@
 namespace {
 
 FormFieldError::ErrorType ErrorTypeFromString(const std::string& error_type) {
-  if (LowerCaseEqualsASCII(error_type, "unknown_error"))
+  if (base::LowerCaseEqualsASCII(error_type, "unknown_error"))
     return FormFieldError::UNKNOWN_ERROR;
-  if (LowerCaseEqualsASCII(error_type, "invalid_phone_number"))
+  if (base::LowerCaseEqualsASCII(error_type, "invalid_phone_number"))
     return FormFieldError::INVALID_PHONE_NUMBER;
-  if (LowerCaseEqualsASCII(error_type, "invalid_postal_code"))
+  if (base::LowerCaseEqualsASCII(error_type, "invalid_postal_code"))
     return FormFieldError::INVALID_POSTAL_CODE;
-  if (LowerCaseEqualsASCII(error_type, "invalid_address"))
+  if (base::LowerCaseEqualsASCII(error_type, "invalid_address"))
     return FormFieldError::INVALID_ADDRESS;
-  if (LowerCaseEqualsASCII(error_type, "invalid_card_details"))
+  if (base::LowerCaseEqualsASCII(error_type, "invalid_card_details"))
     return FormFieldError::INVALID_CARD_DETAILS;
-  if (LowerCaseEqualsASCII(error_type, "invalid_city"))
+  if (base::LowerCaseEqualsASCII(error_type, "invalid_city"))
     return FormFieldError::INVALID_CITY;
-  if (LowerCaseEqualsASCII(error_type, "invalid_instrument"))
+  if (base::LowerCaseEqualsASCII(error_type, "invalid_instrument"))
     return FormFieldError::INVALID_INSTRUMENT;
-  if (LowerCaseEqualsASCII(error_type, "invalid_state"))
+  if (base::LowerCaseEqualsASCII(error_type, "invalid_state"))
     return FormFieldError::INVALID_STATE;
-  if (LowerCaseEqualsASCII(error_type, "required_field_not_set"))
+  if (base::LowerCaseEqualsASCII(error_type, "required_field_not_set"))
     return FormFieldError::REQUIRED_FIELD_NOT_SET;
   return FormFieldError::UNKNOWN_ERROR;
 }
 
 FormFieldError::Location LocationFromString(const std::string& location) {
-  if (LowerCaseEqualsASCII(location, "unknown_location"))
+  if (base::LowerCaseEqualsASCII(location, "unknown_location"))
     return FormFieldError::UNKNOWN_LOCATION;
-  if (LowerCaseEqualsASCII(location, "payment_instrument"))
+  if (base::LowerCaseEqualsASCII(location, "payment_instrument"))
     return FormFieldError::PAYMENT_INSTRUMENT;
-  if (LowerCaseEqualsASCII(location, "shipping_address"))
+  if (base::LowerCaseEqualsASCII(location, "shipping_address"))
     return FormFieldError::SHIPPING_ADDRESS;
-  if (LowerCaseEqualsASCII(location, "legal_address"))
+  if (base::LowerCaseEqualsASCII(location, "legal_address"))
     return FormFieldError::LEGAL_ADDRESS;
   return FormFieldError::UNKNOWN_LOCATION;
 }
diff --git a/components/autofill/content/browser/wallet/wallet_client.cc b/components/autofill/content/browser/wallet/wallet_client.cc
index 1a23ea0..7719a1a 100644
--- a/components/autofill/content/browser/wallet/wallet_client.cc
+++ b/components/autofill/content/browser/wallet/wallet_client.cc
@@ -66,21 +66,21 @@
 WalletClient::ErrorType StringToErrorType(const std::string& error_type) {
   std::string trimmed;
   base::TrimWhitespaceASCII(error_type, base::TRIM_ALL, &trimmed);
-  if (LowerCaseEqualsASCII(trimmed, "buyer_account_error"))
+  if (base::LowerCaseEqualsASCII(trimmed, "buyer_account_error"))
     return WalletClient::BUYER_ACCOUNT_ERROR;
-  if (LowerCaseEqualsASCII(trimmed, "unsupported_merchant"))
+  if (base::LowerCaseEqualsASCII(trimmed, "unsupported_merchant"))
     return WalletClient::UNSUPPORTED_MERCHANT;
-  if (LowerCaseEqualsASCII(trimmed, "internal_error"))
+  if (base::LowerCaseEqualsASCII(trimmed, "internal_error"))
     return WalletClient::INTERNAL_ERROR;
-  if (LowerCaseEqualsASCII(trimmed, "invalid_params"))
+  if (base::LowerCaseEqualsASCII(trimmed, "invalid_params"))
     return WalletClient::INVALID_PARAMS;
-  if (LowerCaseEqualsASCII(trimmed, "service_unavailable"))
+  if (base::LowerCaseEqualsASCII(trimmed, "service_unavailable"))
     return WalletClient::SERVICE_UNAVAILABLE;
-  if (LowerCaseEqualsASCII(trimmed, "unsupported_api_version"))
+  if (base::LowerCaseEqualsASCII(trimmed, "unsupported_api_version"))
     return WalletClient::UNSUPPORTED_API_VERSION;
-  if (LowerCaseEqualsASCII(trimmed, "unsupported_user_agent"))
+  if (base::LowerCaseEqualsASCII(trimmed, "unsupported_user_agent"))
     return WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY;
-  if (LowerCaseEqualsASCII(trimmed, "spending_limit_exceeded"))
+  if (base::LowerCaseEqualsASCII(trimmed, "spending_limit_exceeded"))
     return WalletClient::SPENDING_LIMIT_EXCEEDED;
 
   DVLOG(1) << "Unknown wallet error string: \"" << error_type << '"';
@@ -93,9 +93,9 @@
     const std::string& message_type_for_buyer) {
   std::string trimmed;
   base::TrimWhitespaceASCII(message_type_for_buyer, base::TRIM_ALL, &trimmed);
-  if (LowerCaseEqualsASCII(trimmed, "bla_country_not_supported"))
+  if (base::LowerCaseEqualsASCII(trimmed, "bla_country_not_supported"))
     return WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED;
-  if (LowerCaseEqualsASCII(trimmed, "buyer_kyc_error"))
+  if (base::LowerCaseEqualsASCII(trimmed, "buyer_kyc_error"))
     return WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS;
 
   return WalletClient::BUYER_ACCOUNT_ERROR;
@@ -649,7 +649,7 @@
         std::string trimmed;
         base::TrimWhitespaceASCII(auth_result, base::TRIM_ALL, &trimmed);
         delegate_->OnDidAuthenticateInstrument(
-            LowerCaseEqualsASCII(trimmed, "success"));
+            base::LowerCaseEqualsASCII(trimmed, "success"));
       } else {
         HandleMalformedResponse(type, scoped_request.get());
       }
diff --git a/components/autofill/content/browser/wallet/wallet_service_url.cc b/components/autofill/content/browser/wallet/wallet_service_url.cc
index 3b0c2d5..e032ed3 100644
--- a/components/autofill/content/browser/wallet/wallet_service_url.cc
+++ b/components/autofill/content/browser/wallet/wallet_service_url.cc
@@ -207,9 +207,8 @@
 bool IsSignInRelatedUrl(const GURL& url) {
   size_t unused;
   return url.GetOrigin() == GetAddAccountUrl().GetOrigin() ||
-         StartsWith(base::UTF8ToUTF16(url.GetOrigin().host()),
-                    base::ASCIIToUTF16("accounts."),
-                    false) ||
+         base::StartsWith(base::UTF8ToUTF16(url.GetOrigin().host()),
+                          base::ASCIIToUTF16("accounts."), false) ||
          IsSignInContinueUrl(url, &unused);
 }
 
diff --git a/components/autofill/content/browser/wallet/wallet_signin_helper.cc b/components/autofill/content/browser/wallet/wallet_signin_helper.cc
index f7b0fbc..fb84fba 100644
--- a/components/autofill/content/browser/wallet/wallet_signin_helper.cc
+++ b/components/autofill/content/browser/wallet/wallet_signin_helper.cc
@@ -45,8 +45,8 @@
   std::string host = wallet::GetPassiveAuthUrl(0).host();
   std::string wallet_cookie;
   for (size_t i = 0; i < cookies.size(); ++i) {
-    if (LowerCaseEqualsASCII(cookies[i].Name(), kWalletCookieName) &&
-        LowerCaseEqualsASCII(cookies[i].Domain(), host.c_str())) {
+    if (base::LowerCaseEqualsASCII(cookies[i].Name(), kWalletCookieName) &&
+        base::LowerCaseEqualsASCII(cookies[i].Domain(), host.c_str())) {
       wallet_cookie = cookies[i].Value();
       break;
     }
@@ -154,7 +154,7 @@
     return;
   }
 
-  if (!LowerCaseEqualsASCII(data, "yes")) {
+  if (!base::LowerCaseEqualsASCII(data, "yes")) {
     OnServiceError(
         GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP));
     return;
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index b6686c3c..f73e591 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -97,9 +97,8 @@
   }
   for (WebOptionElement option = options.firstItem().to<WebOptionElement>();
        !option.isNull(); option = options.nextItem().to<WebOptionElement>()) {
-    if (!StartsWith(option.value(), prefix, false) ||
-        option.value() == prefix ||
-        !element.isValidValue(option.value()))
+    if (!base::StartsWith(option.value(), prefix, false) ||
+        option.value() == prefix || !element.isValidValue(option.value()))
       continue;
 
     values->push_back(option.value());
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index c9ebc62..51a2251 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1183,7 +1183,7 @@
     // attribute was present.
     field->autocomplete_attribute = "x-max-data-length-exceeded";
   }
-  if (LowerCaseEqualsASCII(element.getAttribute(kRole), "presentation"))
+  if (base::LowerCaseEqualsASCII(element.getAttribute(kRole), "presentation"))
     field->role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION;
 
   if (!IsAutofillableElement(element))
@@ -1314,7 +1314,7 @@
   std::string lang;
   if (!html_element.isNull())
     lang = html_element.getAttribute("lang").utf8();
-  if ((lang.empty() || StartsWithASCII(lang, "en", false)) &&
+  if ((lang.empty() || base::StartsWithASCII(lang, "en", false)) &&
       !MatchesPattern(document.title(),
           base::UTF8ToUTF16("payment|checkout|address|delivery|shipping"))) {
     return false;
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index ea8944a..fd9ac7f7 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -225,7 +225,7 @@
                       bool exact_match) {
   if (exact_match)
     return username1 == username2;
-  return StartsWith(username1, username2, true);
+  return base::StartsWith(username1, username2, true);
 }
 
 // Returns |true| if the given element is editable. Otherwise, returns |false|.
@@ -288,21 +288,21 @@
   for (const auto& usernames : fill_data.other_possible_usernames) {
     for (size_t i = 0; i < usernames.second.size(); ++i) {
       if (show_all ||
-          StartsWith(usernames.second[i], current_username, false)) {
+          base::StartsWith(usernames.second[i], current_username, false)) {
         *suggestions_present = true;
         return true;
       }
     }
   }
 
-  if (show_all ||
-      StartsWith(fill_data.username_field.value, current_username, false)) {
+  if (show_all || base::StartsWith(fill_data.username_field.value,
+                                   current_username, false)) {
     *suggestions_present = true;
     return false;
   }
 
   for (const auto& login : fill_data.additional_logins) {
-    if (show_all || StartsWith(login.first, current_username, false)) {
+    if (show_all || base::StartsWith(login.first, current_username, false)) {
       *suggestions_present = true;
       return false;
     }
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
index f4dfcdf..aebdbf59 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -100,8 +100,8 @@
 // |element| is present and has the specified |value_in_lowercase|.
 bool HasAutocompleteAttributeValue(const WebInputElement& element,
                                    const char* value_in_lowercase) {
-  return LowerCaseEqualsASCII(element.getAttribute("autocomplete"),
-                              value_in_lowercase);
+  return base::LowerCaseEqualsASCII(element.getAttribute("autocomplete"),
+                                    value_in_lowercase);
 }
 
 // Helper to determine which password is the main (current) one, and which is
@@ -376,7 +376,7 @@
         nonscript_modified_values->find(username_element);
       if (username_iterator != nonscript_modified_values->end()) {
         base::string16 typed_username_value = username_iterator->second;
-        if (!StartsWith(username_value, typed_username_value, false)) {
+        if (!base::StartsWith(username_value, typed_username_value, false)) {
           // We check that |username_value| was not obtained by autofilling
           // |typed_username_value|. In case when it was, |typed_username_value|
           // is incomplete, so we should leave autofilled value.
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 5101bb8..1c6a5fa6 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -123,8 +123,6 @@
     "webdata/autofill_profile_syncable_service.h",
     "webdata/autofill_table.cc",
     "webdata/autofill_table.h",
-    "webdata/autofill_wallet_metadata_syncable_service.cc",
-    "webdata/autofill_wallet_metadata_syncable_service.h",
     "webdata/autofill_wallet_syncable_service.cc",
     "webdata/autofill_wallet_syncable_service.h",
     "webdata/autofill_webdata.h",
@@ -243,7 +241,6 @@
     "validation_unittest.cc",
     "webdata/autofill_profile_syncable_service_unittest.cc",
     "webdata/autofill_table_unittest.cc",
-    "webdata/autofill_wallet_metadata_syncable_service_unittest.cc",
     "webdata/web_data_service_unittest.cc",
   ]
 
diff --git a/components/autofill/core/browser/address.cc b/components/autofill/core/browser/address.cc
index 4b977bf..9aaa3b6b 100644
--- a/components/autofill/core/browser/address.cc
+++ b/components/autofill/core/browser/address.cc
@@ -159,7 +159,7 @@
       return false;
     }
 
-    country_code_ = StringToUpperASCII(base::UTF16ToASCII(value));
+    country_code_ = base::StringToUpperASCII(base::UTF16ToASCII(value));
     return true;
   } else if (type.html_type() == HTML_TYPE_FULL_ADDRESS) {
     // Parsing a full address is too hard.
diff --git a/components/autofill/core/browser/autofill_country.cc b/components/autofill/core/browser/autofill_country.cc
index 265c876..c62fce8 100644
--- a/components/autofill/core/browser/autofill_country.cc
+++ b/components/autofill/core/browser/autofill_country.cc
@@ -937,7 +937,8 @@
 const std::string CountryNames::GetCountryCode(const base::string16& country,
                                                const std::string& locale) {
   // First, check common country names, including 2- and 3-letter country codes.
-  std::string country_utf8 = base::UTF16ToUTF8(StringToUpperASCII(country));
+  std::string country_utf8 = base::UTF16ToUTF8(
+      base::StringToUpperASCII(country));
   std::map<std::string, std::string>::const_iterator result =
       common_names_.find(country_utf8);
   if (result != common_names_.end())
diff --git a/components/autofill/core/browser/autofill_download_manager.cc b/components/autofill/core/browser/autofill_download_manager.cc
index 87742344..efcabc73 100644
--- a/components/autofill/core/browser/autofill_download_manager.cc
+++ b/components/autofill/core/browser/autofill_download_manager.cc
@@ -272,9 +272,9 @@
       case kHttpBadGateway:
         if (!source->GetResponseHeaders()->EnumerateHeader(NULL, "server",
                                                            &server_header) ||
-            StartsWithASCII(server_header.c_str(),
-                            kAutofillQueryServerNameStartInHeader,
-                            false) != 0)
+            base::StartsWithASCII(server_header.c_str(),
+                                  kAutofillQueryServerNameStartInHeader,
+                                  false) != 0)
           break;
         // Bad gateway was received from Autofill servers. Fall through to back
         // off.
diff --git a/components/autofill/core/browser/contact_info.cc b/components/autofill/core/browser/contact_info.cc
index 10520f0..707e323 100644
--- a/components/autofill/core/browser/contact_info.cc
+++ b/components/autofill/core/browser/contact_info.cc
@@ -45,7 +45,7 @@
   base::TrimString(element, base::ASCIIToUTF16("."), &trimmed_element);
 
   for (size_t i = 0; i < set_size; ++i) {
-    if (LowerCaseEqualsASCII(trimmed_element, set[i]))
+    if (base::LowerCaseEqualsASCII(trimmed_element, set[i]))
       return true;
   }
 
diff --git a/components/autofill/core/browser/credit_card_field.cc b/components/autofill/core/browser/credit_card_field.cc
index d6b67dc..3b24ec3 100644
--- a/components/autofill/core/browser/credit_card_field.cc
+++ b/components/autofill/core/browser/credit_card_field.cc
@@ -344,7 +344,8 @@
 
 bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner) {
   if (!expiration_date_ &&
-      LowerCaseEqualsASCII(scanner->Cursor()->form_control_type, "month")) {
+      base::LowerCaseEqualsASCII(scanner->Cursor()->form_control_type,
+                                 "month")) {
     expiration_date_ = scanner->Cursor();
     expiration_month_ = nullptr;
     expiration_year_ = nullptr;
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index b0e8d0c..19e0382 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -70,7 +70,7 @@
 bool IsAutofillFieldMetadataEnabled() {
   const std::string group_name =
       base::FieldTrialList::FindFullName("AutofillFieldMetadata");
-  return StartsWithASCII(group_name, "Enabled", true);
+  return base::StartsWithASCII(group_name, "Enabled", true);
 }
 
 // Helper for |EncodeUploadRequest()| that creates a bit field corresponding to
@@ -1145,7 +1145,7 @@
     // The preceding token, if any, may be a named section.
     const std::string kSectionPrefix = "section-";
     if (!tokens.empty() &&
-        StartsWithASCII(tokens.back(), kSectionPrefix, true)) {
+        base::StartsWithASCII(tokens.back(), kSectionPrefix, true)) {
       // Prepend this section name to the suffix set in the preceding block.
       section = tokens.back().substr(kSectionPrefix.size()) + section;
       tokens.pop_back();
diff --git a/components/autofill/core/browser/options_util_unittest.cc b/components/autofill/core/browser/options_util_unittest.cc
index 11ec8cc..e2a81ef 100644
--- a/components/autofill/core/browser/options_util_unittest.cc
+++ b/components/autofill/core/browser/options_util_unittest.cc
@@ -23,6 +23,7 @@
  public:
   MOCK_CONST_METHOD0(HasSyncSetupCompleted, bool());
   MOCK_CONST_METHOD0(IsSyncActive, bool());
+  MOCK_CONST_METHOD0(IsSyncAllowed, bool());
   MOCK_CONST_METHOD0(GetActiveDataTypes, syncer::ModelTypeSet());
   MOCK_METHOD1(AddObserver, void(sync_driver::SyncServiceObserver*));
   MOCK_METHOD1(RemoveObserver, void(sync_driver::SyncServiceObserver*));
@@ -30,8 +31,8 @@
                      bool(const sync_driver::SyncServiceObserver*));
   MOCK_METHOD0(IsSyncEnabledAndLoggedIn, bool());
   MOCK_METHOD0(DisableForUser, void());
-  MOCK_METHOD0(StopAndSuppress, void());
-  MOCK_METHOD0(UnsuppressAndStart, void());
+  MOCK_METHOD0(RequestStop, void());
+  MOCK_METHOD0(RequestStart, void());
   MOCK_CONST_METHOD0(GetPreferredDataTypes, syncer::ModelTypeSet());
   MOCK_METHOD2(OnUserChoseDatatypes,
                void(bool sync_everything, syncer::ModelTypeSet chosen_types));
@@ -61,6 +62,8 @@
                                               bool is_enabled_and_logged_in) {
   scoped_ptr<SyncServiceMock> sync(new SyncServiceMock());
 
+  ON_CALL(*sync, IsSyncAllowed()).WillByDefault(Return(true));
+
   syncer::ModelTypeSet type_set;
   if (has_autofill_profile)
     type_set.Put(syncer::AUTOFILL_PROFILE);
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 82167f9..11ffafe 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -391,7 +391,7 @@
     types_seen.insert(server_field_type);
 
     if (group == CREDIT_CARD) {
-      if (LowerCaseEqualsASCII(field->form_control_type, "month")) {
+      if (base::LowerCaseEqualsASCII(field->form_control_type, "month")) {
         DCHECK_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR, server_field_type);
         local_imported_credit_card->SetInfoForMonthInputType(value);
       } else {
@@ -792,7 +792,7 @@
       continue;
     base::string16 value_canon =
         AutofillProfile::CanonicalizeProfileString(value);
-    if (StartsWith(value_canon, field_contents_canon, true)) {
+    if (base::StartsWith(value_canon, field_contents_canon, true)) {
       // Prefix match, add suggestion.
       matched_profiles.push_back(profile);
       suggestions.push_back(Suggestion(value));
@@ -866,7 +866,8 @@
            field_contents.size() >= 6)) {
         continue;
       }
-    } else if (!StartsWith(creditcard_field_value, field_contents, false)) {
+    } else if (!base::StartsWith(creditcard_field_value, field_contents,
+                                 false)) {
       continue;
     }
 
@@ -1275,7 +1276,7 @@
   std::vector<std::string> country_codes;
   AutofillCountry::GetAvailableCountries(&country_codes);
   for (size_t i = 0; i < profiles.size(); ++i) {
-    std::string country_code = StringToUpperASCII(base::UTF16ToASCII(
+    std::string country_code = base::StringToUpperASCII(base::UTF16ToASCII(
         profiles[i]->GetRawInfo(ADDRESS_HOME_COUNTRY)));
 
     if (std::find(country_codes.begin(), country_codes.end(), country_code) !=
diff --git a/components/autofill/core/browser/state_names.cc b/components/autofill/core/browser/state_names.cc
index d4975b4..de659243 100644
--- a/components/autofill/core/browser/state_names.cc
+++ b/components/autofill/core/browser/state_names.cc
@@ -80,7 +80,7 @@
 base::string16 GetAbbreviationForName(const base::string16& name) {
   for (size_t i = 0; i < arraysize(kStateData); ++i) {
     const StateData& state = kStateData[i];
-    if (LowerCaseEqualsASCII(name, state.name))
+    if (base::LowerCaseEqualsASCII(name, state.name))
       return base::ASCIIToUTF16(state.abbreviation);
   }
   return base::string16();
@@ -89,7 +89,7 @@
 base::string16 GetNameForAbbreviation(const base::string16& abbreviation) {
   for (size_t i = 0; i < arraysize(kStateData); ++i) {
     const StateData& state = kStateData[i];
-    if (LowerCaseEqualsASCII(abbreviation, state.abbreviation))
+    if (base::LowerCaseEqualsASCII(abbreviation, state.abbreviation))
       return base::ASCIIToUTF16(state.name);
   }
   return base::string16();
diff --git a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
index 578d765..dbec883 100644
--- a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
+++ b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
@@ -147,7 +147,7 @@
         response_dict->GetString("error.code", &error_code);
       }
 
-      if (LowerCaseEqualsASCII(error_code, "internal"))
+      if (base::LowerCaseEqualsASCII(error_code, "internal"))
         result = AutofillClient::TRY_AGAIN_FAILURE;
       else if (real_pan.empty() || !error_code.empty())
         result = AutofillClient::PERMANENT_FAILURE;
diff --git a/components/autofill/core/browser/webdata/autofill_change.cc b/components/autofill/core/browser/webdata/autofill_change.cc
index 2d2ff67..c02bdd84 100644
--- a/components/autofill/core/browser/webdata/autofill_change.cc
+++ b/components/autofill/core/browser/webdata/autofill_change.cc
@@ -17,11 +17,13 @@
 AutofillChange::~AutofillChange() {
 }
 
-AutofillProfileChange::AutofillProfileChange(Type type,
-                                             const std::string& key,
-                                             const AutofillProfile* profile)
-    : GenericAutofillChange<std::string>(type, key), profile_(profile) {
-  DCHECK(type == REMOVE ? !profile : profile && profile->guid() == key);
+AutofillProfileChange::AutofillProfileChange(
+  Type type, const std::string& key, const AutofillProfile* profile)
+    : GenericAutofillChange<std::string>(type, key),
+      profile_(profile) {
+  DCHECK(type == ADD ? (profile && profile->guid() == key) : true);
+  DCHECK(type == UPDATE ? (profile && profile->guid() == key) : true);
+  DCHECK(type == REMOVE ? !profile : true);
 }
 
 AutofillProfileChange::~AutofillProfileChange() {
@@ -29,23 +31,9 @@
 
 bool AutofillProfileChange::operator==(
     const AutofillProfileChange& change) const {
-  return type() == change.type() && key() == change.key() &&
-         (type() == REMOVE || *profile() == *change.profile());
-}
-
-CreditCardChange::CreditCardChange(Type type,
-                                   const std::string& key,
-                                   const CreditCard* card)
-    : GenericAutofillChange<std::string>(type, key), card_(card) {
-  DCHECK(type == REMOVE ? !card : card && card->guid() == key);
-}
-
-CreditCardChange::~CreditCardChange() {
-}
-
-bool CreditCardChange::operator==(const CreditCardChange& change) const {
-  return type() == change.type() && key() == change.key() &&
-         (type() == REMOVE || *card() == *change.card());
+  return type() == change.type() &&
+         key() == change.key() &&
+         (type() != REMOVE) ? *profile() == *change.profile() : true;
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_change.h b/components/autofill/core/browser/webdata/autofill_change.h
index 80281f5..0e85657 100644
--- a/components/autofill/core/browser/webdata/autofill_change.h
+++ b/components/autofill/core/browser/webdata/autofill_change.h
@@ -5,7 +5,6 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_CHANGE_H__
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_CHANGE_H__
 
-#include <string>
 #include <vector>
 
 #include "components/autofill/core/browser/webdata/autofill_entry.h"
@@ -13,10 +12,9 @@
 namespace autofill {
 
 class AutofillProfile;
-class CreditCard;
 
 // For classic Autofill form fields, the KeyType is AutofillKey.
-// Autofill++ types such as AutofillProfile and CreditCard simply use a string.
+// Autofill++ types such as AutofillProfile and CreditCard simply use an int.
 template <typename KeyType>
 class GenericAutofillChange {
  public:
@@ -72,25 +70,6 @@
   const AutofillProfile* profile_;
 };
 
-// Change notification details for credit card changes.
-class CreditCardChange : public GenericAutofillChange<std::string> {
- public:
-  // The |type| input specifies the change type.  The |key| input is the key,
-  // which is expected to be the GUID identifying the |card|.
-  // When |type| == ADD, |card| should be non-NULL.
-  // When |type| == UPDATE, |card| should be non-NULL.
-  // When |type| == REMOVE, |card| should be NULL.
-  CreditCardChange(Type type, const std::string& key, const CreditCard* card);
-  ~CreditCardChange() override;
-
-  const CreditCard* card() const { return card_; }
-  bool operator==(const CreditCardChange& change) const;
-
- private:
-  // Weak reference, can be NULL.
-  const CreditCard* card_;
-};
-
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_CHANGE_H__
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
deleted file mode 100644
index dae6d71..0000000
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
+++ /dev/null
@@ -1,460 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
-
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/time/time.h"
-#include "components/autofill/core/browser/autofill_data_model.h"
-#include "components/autofill/core/browser/autofill_profile.h"
-#include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill/core/browser/webdata/autofill_change.h"
-#include "components/autofill/core/browser/webdata/autofill_table.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_error_factory.h"
-#include "sync/protocol/autofill_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
-
-namespace autofill {
-
-namespace {
-
-void* UserDataKey() {
-  // Use the address of a static so that COMDAT folding won't ever fold
-  // with something else.
-  static int user_data_key = 0;
-  return reinterpret_cast<void*>(&user_data_key);
-}
-
-// Returns syncable metadata for the |local| profile or credit card.
-syncer::SyncData BuildSyncData(sync_pb::WalletMetadataSpecifics::Type type,
-                               const std::string& server_id,
-                               const AutofillDataModel& local) {
-  sync_pb::EntitySpecifics entity;
-  sync_pb::WalletMetadataSpecifics* metadata = entity.mutable_wallet_metadata();
-  metadata->set_type(type);
-  metadata->set_id(server_id);
-  metadata->set_use_count(local.use_count());
-  metadata->set_use_date(local.use_date().ToInternalValue());
-
-  std::string sync_tag;
-  switch (type) {
-    case sync_pb::WalletMetadataSpecifics::ADDRESS:
-      sync_tag = "address-" + server_id;
-      break;
-    case sync_pb::WalletMetadataSpecifics::CARD:
-      sync_tag = "card-" + server_id;
-      break;
-    case sync_pb::WalletMetadataSpecifics::UNKNOWN:
-      NOTREACHED();
-      break;
-  }
-
-  return syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity);
-}
-
-}  // namespace
-
-AutofillWalletMetadataSyncableService::
-    ~AutofillWalletMetadataSyncableService() {
-}
-
-syncer::SyncMergeResult
-AutofillWalletMetadataSyncableService::MergeDataAndStartSyncing(
-    syncer::ModelType type,
-    const syncer::SyncDataList& initial_sync_data,
-    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
-    scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!sync_processor_);
-  DCHECK(!sync_error_factory_);
-  DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
-
-  sync_processor_ = sync_processor.Pass();
-  sync_error_factory_ = sync_error_factory.Pass();
-
-  return MergeData(initial_sync_data);
-}
-
-void AutofillWalletMetadataSyncableService::StopSyncing(
-    syncer::ModelType type) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
-
-  sync_processor_.reset();
-  sync_error_factory_.reset();
-  cache_.clear();
-}
-
-syncer::SyncDataList AutofillWalletMetadataSyncableService::GetAllSyncData(
-    syncer::ModelType type) const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
-
-  syncer::SyncDataList data_list;
-  std::map<std::string, AutofillProfile*> profiles;
-  std::map<std::string, CreditCard*> cards;
-  if (GetLocalData(&profiles, &cards)) {
-    for (const auto& it : profiles) {
-      data_list.push_back(BuildSyncData(
-          sync_pb::WalletMetadataSpecifics::ADDRESS, it.first, *it.second));
-    }
-
-    for (const auto& it : cards) {
-      data_list.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
-                                        it.first, *it.second));
-    }
-  }
-
-  return data_list;
-}
-
-syncer::SyncError AutofillWalletMetadataSyncableService::ProcessSyncChanges(
-    const tracked_objects::Location& from_here,
-    const syncer::SyncChangeList& changes_from_sync) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  cache_.clear();
-
-  std::map<std::string, AutofillProfile*> profiles;
-  std::map<std::string, CreditCard*> cards;
-  GetLocalData(&profiles, &cards);
-
-  base::Callback<bool(const AutofillProfile&)> address_updater =
-      base::Bind(&AutofillWalletMetadataSyncableService::UpdateAddressStats,
-                 base::Unretained(this));
-  base::Callback<bool(const CreditCard&)> card_updater =
-      base::Bind(&AutofillWalletMetadataSyncableService::UpdateCardStats,
-                 base::Unretained(this));
-
-  syncer::SyncChangeList changes_to_sync;
-  for (const syncer::SyncChange& change : changes_from_sync) {
-    const sync_pb::WalletMetadataSpecifics& remote_metadata =
-        change.sync_data().GetSpecifics().wallet_metadata();
-    switch (change.change_type()) {
-      // Do not immediately delete data.
-      case syncer::SyncChange::ACTION_ADD:
-      // Intentional fall through.
-      case syncer::SyncChange::ACTION_UPDATE:
-        switch (remote_metadata.type()) {
-          case sync_pb::WalletMetadataSpecifics::ADDRESS:
-            MergeRemote(change.sync_data(), address_updater, &profiles,
-                        &changes_to_sync);
-            break;
-
-          case sync_pb::WalletMetadataSpecifics::CARD:
-            MergeRemote(change.sync_data(), card_updater, &cards,
-                        &changes_to_sync);
-            break;
-
-          case sync_pb::WalletMetadataSpecifics::UNKNOWN:
-            NOTREACHED();
-            break;
-        }
-        break;
-
-      // Undelete data immediately.
-      case syncer::SyncChange::ACTION_DELETE:
-        switch (remote_metadata.type()) {
-          case sync_pb::WalletMetadataSpecifics::ADDRESS: {
-            const auto& it = profiles.find(remote_metadata.id());
-            if (it != profiles.end()) {
-              cache_.push_back(
-                  BuildSyncData(sync_pb::WalletMetadataSpecifics::ADDRESS,
-                                it->first, *it->second));
-              changes_to_sync.push_back(syncer::SyncChange(
-                  FROM_HERE, syncer::SyncChange::ACTION_ADD, cache_.back()));
-              profiles.erase(it);
-            }
-            break;
-          }
-
-          case sync_pb::WalletMetadataSpecifics::CARD: {
-            const auto& it = cards.find(remote_metadata.id());
-            if (it != cards.end()) {
-              cache_.push_back(
-                  BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
-                                it->first, *it->second));
-              changes_to_sync.push_back(syncer::SyncChange(
-                  FROM_HERE, syncer::SyncChange::ACTION_ADD, cache_.back()));
-              cards.erase(it);
-            }
-            break;
-          }
-
-          case sync_pb::WalletMetadataSpecifics::UNKNOWN:
-            NOTREACHED();
-            break;
-        }
-        break;
-
-      case syncer::SyncChange::ACTION_INVALID:
-        NOTREACHED();
-        break;
-    }
-  }
-
-  // The remainder of |profiles| were not listed in |changes_from_sync|.
-  for (const auto& it : profiles) {
-    cache_.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::ADDRESS,
-                                   it.first, *it.second));
-  }
-
-  // The remainder of |cards| were not listed in |changes_from_sync|.
-  for (const auto& it : cards) {
-    cache_.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
-                                   it.first, *it.second));
-  }
-
-  syncer::SyncError status;
-  if (!changes_to_sync.empty())
-    status = SendChangesToSyncServer(changes_to_sync);
-
-  return status;
-}
-
-void AutofillWalletMetadataSyncableService::AutofillProfileChanged(
-    const AutofillProfileChange& change) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (sync_processor_ && change.profile() &&
-      change.profile()->record_type() == AutofillProfile::SERVER_PROFILE) {
-    AutofillDataModelChanged(change.profile()->server_id(), *change.profile());
-  }
-}
-
-void AutofillWalletMetadataSyncableService::CreditCardChanged(
-    const CreditCardChange& change) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (sync_processor_ && change.card() &&
-      change.card()->record_type() != CreditCard::LOCAL_CARD) {
-    AutofillDataModelChanged(change.card()->server_id(), *change.card());
-  }
-}
-
-void AutofillWalletMetadataSyncableService::AutofillMultipleChanged() {
-  // Merging data will clear the cache, so make a copy to avoid merging with
-  // empty remote data. Copying the cache is expensive, but still cheaper than
-  // GetAllSyncData().
-  if (sync_processor_)
-    MergeData(syncer::SyncDataList(cache_));
-}
-
-// static
-void AutofillWalletMetadataSyncableService::CreateForWebDataServiceAndBackend(
-    AutofillWebDataService* web_data_service,
-    AutofillWebDataBackend* webdata_backend,
-    const std::string& app_locale) {
-  web_data_service->GetDBUserData()->SetUserData(
-      UserDataKey(),
-      new AutofillWalletMetadataSyncableService(webdata_backend, app_locale));
-}
-
-// static
-AutofillWalletMetadataSyncableService*
-AutofillWalletMetadataSyncableService::FromWebDataService(
-    AutofillWebDataService* web_data_service) {
-  return static_cast<AutofillWalletMetadataSyncableService*>(
-      web_data_service->GetDBUserData()->GetUserData(UserDataKey()));
-}
-
-AutofillWalletMetadataSyncableService::AutofillWalletMetadataSyncableService(
-    AutofillWebDataBackend* webdata_backend,
-    const std::string& app_locale)
-    : webdata_backend_(webdata_backend), scoped_observer_(this) {
-  // No webdata in tests.
-  if (webdata_backend_)
-    scoped_observer_.Add(webdata_backend_);
-}
-
-bool AutofillWalletMetadataSyncableService::GetLocalData(
-    std::map<std::string, AutofillProfile*>* profiles,
-    std::map<std::string, CreditCard*>* cards) const {
-  std::vector<AutofillProfile*> profile_list;
-  bool success = AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
-                     ->GetServerProfiles(&profile_list);
-  for (AutofillProfile* profile : profile_list)
-    profiles->insert(std::make_pair(profile->server_id(), profile));
-
-  std::vector<CreditCard*> card_list;
-  success &= AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
-                 ->GetServerCreditCards(&card_list);
-  for (CreditCard* card : card_list)
-    cards->insert(std::make_pair(card->server_id(), card));
-
-  return success;
-}
-
-bool AutofillWalletMetadataSyncableService::UpdateAddressStats(
-    const AutofillProfile& profile) {
-  return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
-      ->UpdateServerAddressUsageStats(profile);
-}
-
-bool AutofillWalletMetadataSyncableService::UpdateCardStats(
-    const CreditCard& credit_card) {
-  return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
-      ->UpdateServerCardUsageStats(credit_card);
-}
-
-syncer::SyncError
-AutofillWalletMetadataSyncableService::SendChangesToSyncServer(
-    const syncer::SyncChangeList& changes_to_sync) {
-  DCHECK(sync_processor_);
-  return sync_processor_->ProcessSyncChanges(FROM_HERE, changes_to_sync);
-}
-
-syncer::SyncMergeResult AutofillWalletMetadataSyncableService::MergeData(
-    const syncer::SyncDataList& sync_data) {
-  cache_.clear();
-
-  std::map<std::string, AutofillProfile*> profiles;
-  std::map<std::string, CreditCard*> cards;
-  GetLocalData(&profiles, &cards);
-
-  syncer::SyncMergeResult result(syncer::AUTOFILL_WALLET_METADATA);
-  result.set_num_items_before_association(profiles.size() + cards.size());
-
-  base::Callback<bool(const AutofillProfile&)> address_updater =
-      base::Bind(&AutofillWalletMetadataSyncableService::UpdateAddressStats,
-                 base::Unretained(this));
-  base::Callback<bool(const CreditCard&)> card_updater =
-      base::Bind(&AutofillWalletMetadataSyncableService::UpdateCardStats,
-                 base::Unretained(this));
-
-  syncer::SyncChangeList changes_to_sync;
-  for (const syncer::SyncData& remote : sync_data) {
-    DCHECK(remote.IsValid());
-    DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, remote.GetDataType());
-    switch (remote.GetSpecifics().wallet_metadata().type()) {
-      case sync_pb::WalletMetadataSpecifics::ADDRESS:
-        if (!MergeRemote(remote, address_updater, &profiles,
-                         &changes_to_sync)) {
-          changes_to_sync.push_back(syncer::SyncChange(
-              FROM_HERE, syncer::SyncChange::ACTION_DELETE, remote));
-        }
-        break;
-
-      case sync_pb::WalletMetadataSpecifics::CARD:
-        if (!MergeRemote(remote, card_updater, &cards, &changes_to_sync)) {
-          changes_to_sync.push_back(syncer::SyncChange(
-              FROM_HERE, syncer::SyncChange::ACTION_DELETE, remote));
-        }
-        break;
-
-      case sync_pb::WalletMetadataSpecifics::UNKNOWN:
-        NOTREACHED();
-        break;
-    }
-  }
-
-  // The remainder of |profiles| were not listed in |sync_data|.
-  for (const auto& it : profiles) {
-    cache_.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::ADDRESS,
-                                   it.first, *it.second));
-    changes_to_sync.push_back(syncer::SyncChange(
-        FROM_HERE, syncer::SyncChange::ACTION_ADD, cache_.back()));
-  }
-
-  // The remainder of |cards| were not listed in |sync_data|.
-  for (const auto& it : cards) {
-    cache_.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
-                                   it.first, *it.second));
-    changes_to_sync.push_back(syncer::SyncChange(
-        FROM_HERE, syncer::SyncChange::ACTION_ADD, cache_.back()));
-  }
-
-  // Metadata is not added or deleted locally to maintain a 1:1 relationship
-  // with Wallet data.
-  result.set_num_items_after_association(result.num_items_before_association());
-  result.set_num_items_added(0);
-  result.set_num_items_deleted(0);
-
-  if (!changes_to_sync.empty())
-    result.set_error(SendChangesToSyncServer(changes_to_sync));
-
-  return result;
-}
-
-template <class DataType>
-bool AutofillWalletMetadataSyncableService::MergeRemote(
-    const syncer::SyncData& remote,
-    const base::Callback<bool(const DataType&)>& updater,
-    std::map<std::string, DataType*>* locals,
-    syncer::SyncChangeList* changes_to_sync) {
-  DCHECK(locals);
-  DCHECK(changes_to_sync);
-
-  const sync_pb::WalletMetadataSpecifics& remote_metadata =
-      remote.GetSpecifics().wallet_metadata();
-  auto it = locals->find(remote_metadata.id());
-  if (it == locals->end())
-    return false;
-
-  DataType* local_metadata = it->second;
-  locals->erase(it);
-
-  size_t remote_use_count = static_cast<size_t>(remote_metadata.use_count());
-  bool is_local_modified = false;
-  bool is_remote_outdated = false;
-  if (local_metadata->use_count() < remote_use_count) {
-    local_metadata->set_use_count(remote_use_count);
-    is_local_modified = true;
-  } else if (local_metadata->use_count() > remote_use_count) {
-    is_remote_outdated = true;
-  }
-
-  base::Time remote_use_date =
-      base::Time::FromInternalValue(remote_metadata.use_date());
-  if (local_metadata->use_date() < remote_use_date) {
-    local_metadata->set_use_date(remote_use_date);
-    is_local_modified = true;
-  } else if (local_metadata->use_date() > remote_use_date) {
-    is_remote_outdated = true;
-  }
-
-  if (is_remote_outdated) {
-    cache_.push_back(BuildSyncData(remote_metadata.type(), remote_metadata.id(),
-                                   *local_metadata));
-    changes_to_sync->push_back(syncer::SyncChange(
-        FROM_HERE, syncer::SyncChange::ACTION_UPDATE, cache_.back()));
-  } else {
-    cache_.push_back(remote);
-  }
-
-  if (is_local_modified)
-    updater.Run(*local_metadata);
-
-  return true;
-}
-
-void AutofillWalletMetadataSyncableService::AutofillDataModelChanged(
-    const std::string& server_id,
-    const AutofillDataModel& local) {
-  for (auto it = cache_.begin(); it != cache_.end(); ++it) {
-    const sync_pb::WalletMetadataSpecifics& remote =
-        it->GetSpecifics().wallet_metadata();
-    if (remote.id() == server_id) {
-      if (static_cast<size_t>(remote.use_count()) < local.use_count() &&
-          base::Time::FromInternalValue(remote.use_date()) < local.use_date()) {
-        *it = BuildSyncData(remote.type(), server_id, local);
-        SendChangesToSyncServer(syncer::SyncChangeList(
-            1, syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
-                                  *it)));
-      }
-
-      return;
-    }
-  }
-}
-
-}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
deleted file mode 100644
index 45a60ce0..0000000
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_
-
-#include <map>
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/scoped_observer.h"
-#include "base/supports_user_data.h"
-#include "base/threading/thread_checker.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
-#include "sync/api/sync_change_processor.h"
-#include "sync/api/sync_data.h"
-#include "sync/api/sync_error.h"
-#include "sync/api/sync_merge_result.h"
-#include "sync/api/syncable_service.h"
-
-namespace syncer {
-class SyncErrorFactory;
-}
-
-namespace tracked_objects {
-class Location;
-}
-
-namespace autofill {
-
-class AutofillDataModel;
-class AutofillProfile;
-class AutofillProfileChange;
-class AutofillWebDataBackend;
-class AutofillWebDataService;
-class CreditCard;
-class CreditCardChange;
-
-// Syncs usage counts and last use dates (metadata) for Wallet cards and
-// addresses (data). Creation and deletion of metadata on the sync server
-// follows the creation and deletion of the local metadata. (Local metadata has
-// 1:1 relationship with Wallet data.)
-class AutofillWalletMetadataSyncableService
-    : public base::SupportsUserData::Data,
-      public syncer::SyncableService,
-      public AutofillWebDataServiceObserverOnDBThread {
- public:
-  ~AutofillWalletMetadataSyncableService() override;
-
-  // syncer::SyncableService implementation.
-  syncer::SyncMergeResult MergeDataAndStartSyncing(
-      syncer::ModelType type,
-      const syncer::SyncDataList& initial_sync_data,
-      scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
-      scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) override;
-  void StopSyncing(syncer::ModelType type) override;
-  syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override;
-  syncer::SyncError ProcessSyncChanges(
-      const tracked_objects::Location& from_here,
-      const syncer::SyncChangeList& changes_from_sync) override;
-
-  // AutofillWebDataServiceObserverOnDBThread implementation.
-  void AutofillProfileChanged(const AutofillProfileChange& change) override;
-  void CreditCardChanged(const CreditCardChange& change) override;
-  void AutofillMultipleChanged() override;
-
-  // Creates a new AutofillWalletMetadataSyncableService and hangs it off of
-  // |web_data_service|, which takes ownership. This method should only be
-  // called on |web_data_service|'s DB thread.
-  static void CreateForWebDataServiceAndBackend(
-      AutofillWebDataService* web_data_service,
-      AutofillWebDataBackend* webdata_backend,
-      const std::string& app_locale);
-
-  // Retrieves the AutofillWalletMetadataSyncableService stored on
-  // |web_data_service|.
-  static AutofillWalletMetadataSyncableService* FromWebDataService(
-      AutofillWebDataService* web_data_service);
-
- protected:
-  AutofillWalletMetadataSyncableService(AutofillWebDataBackend* webdata_backend,
-                                        const std::string& app_locale);
-
-  // Populates the provided |profiles| and |cards| with mappings from server ID
-  // to unowned server profiles and server cards as read from disk. This data
-  // contains the usage stats. Returns true on success.
-  virtual bool GetLocalData(std::map<std::string, AutofillProfile*>* profiles,
-                            std::map<std::string, CreditCard*>* cards) const;
-
-  // Updates the stats for |profile| stored on disk. Does not trigger
-  // notifications that this profile was updated.
-  virtual bool UpdateAddressStats(const AutofillProfile& profile);
-
-  // Updates the stats for |credit_card| stored on disk. Does not trigger
-  // notifications that this credit card was updated.
-  virtual bool UpdateCardStats(const CreditCard& credit_card);
-
-  // Sends the |changes_to_sync| to the sync server.
-  virtual syncer::SyncError SendChangesToSyncServer(
-      const syncer::SyncChangeList& changes_to_sync);
-
- private:
-  // Merges local metadata with |sync_data|.
-  //
-  // Sends an "update" to the sync server if |sync_data| contains metadata that
-  // is present locally, but local metadata has higher use count and later use
-  // date.
-  //
-  // Sends a "create" to the sync server if |sync_data| does not have some local
-  // metadata.
-  //
-  // Sends a "delete" to the sync server if |sync_data| contains metadata that
-  // is not present locally.
-  syncer::SyncMergeResult MergeData(const syncer::SyncDataList& sync_data);
-
-  // Merges |remote| metadata into a collection of metadata |locals|. Returns
-  // true if the corresponding local metadata was found.
-  //
-  // Stores an "update" in |changes_to_sync| if |remote| corresponds to an item
-  // in |locals| that has higher use count and later use date.
-  template <class DataType>
-  bool MergeRemote(const syncer::SyncData& remote,
-                   const base::Callback<bool(const DataType&)>& updater,
-                   std::map<std::string, DataType*>* locals,
-                   syncer::SyncChangeList* changes_to_sync);
-
-  // Sends updates to the sync server.
-  void AutofillDataModelChanged(const std::string& server_id,
-                                const AutofillDataModel& local);
-
-  base::ThreadChecker thread_checker_;
-  AutofillWebDataBackend* webdata_backend_;  // Weak ref.
-  ScopedObserver<AutofillWebDataBackend, AutofillWalletMetadataSyncableService>
-      scoped_observer_;
-  scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
-  scoped_ptr<syncer::SyncErrorFactory> sync_error_factory_;
-
-  // Cache of sync server data maintained to avoid expensive calls to
-  // GetAllSyncData().
-  syncer::SyncDataList cache_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncableService);
-};
-
-}  // namespace autofill
-
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
deleted file mode 100644
index 3ee21e07..0000000
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
+++ /dev/null
@@ -1,771 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
-
-#include <utility>
-#include <vector>
-
-#include "base/strings/string_number_conversions.h"
-#include "base/time/time.h"
-#include "components/autofill/core/browser/autofill_profile.h"
-#include "components/autofill/core/browser/credit_card.h"
-#include "sync/api/sync_change.h"
-#include "sync/api/sync_change_processor_wrapper_for_test.h"
-#include "sync/api/sync_error_factory_mock.h"
-#include "sync/protocol/autofill_specifics.pb.h"
-#include "sync/protocol/sync.pb.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace autofill {
-namespace {
-
-using testing::DoAll;
-using testing::ElementsAre;
-using testing::Invoke;
-using testing::NiceMock;
-using testing::Return;
-using testing::UnorderedElementsAre;
-using testing::Value;
-using testing::_;
-
-ACTION_P2(GetPointersTo, profiles, cards) {
-  for (auto& profile : *profiles)
-    arg0->insert(std::make_pair(profile.server_id(), &profile));
-
-  for (auto& card : *cards)
-    arg1->insert(std::make_pair(card.server_id(), &card));
-}
-
-ACTION_P(SaveDataIn, list) {
-  for (auto it = list->begin(); it != list->end(); ++it) {
-    if (it->server_id() == arg0.server_id()) {
-      *it = arg0;
-      return;
-    }
-  }
-
-  list->push_back(arg0);
-}
-
-// A syncable service for Wallet metadata that mocks out disk IO.
-class MockService : public AutofillWalletMetadataSyncableService {
- public:
-  MockService()
-      : AutofillWalletMetadataSyncableService(nullptr, std::string()) {
-    ON_CALL(*this, GetLocalData(_, _))
-        .WillByDefault(DoAll(GetPointersTo(&server_profiles_, &server_cards_),
-                             Return(true)));
-
-    ON_CALL(*this, UpdateAddressStats(_))
-        .WillByDefault(DoAll(SaveDataIn(&server_profiles_), Return(true)));
-
-    ON_CALL(*this, UpdateCardStats(_))
-        .WillByDefault(DoAll(SaveDataIn(&server_cards_), Return(true)));
-
-    ON_CALL(*this, SendChangesToSyncServer(_))
-        .WillByDefault(
-            Invoke(this, &MockService::SendChangesToSyncServerConcrete));
-  }
-
-  ~MockService() override {}
-
-  MOCK_METHOD1(UpdateAddressStats, bool(const AutofillProfile&));
-  MOCK_METHOD1(UpdateCardStats, bool(const CreditCard&));
-  MOCK_METHOD1(SendChangesToSyncServer,
-               syncer::SyncError(const syncer::SyncChangeList&));
-
-  void ClearServerData() {
-    server_profiles_.clear();
-    server_cards_.clear();
-  }
-
- private:
-  MOCK_CONST_METHOD2(GetLocalData,
-                     bool(std::map<std::string, AutofillProfile*>*,
-                          std::map<std::string, CreditCard*>*));
-
-  syncer::SyncError SendChangesToSyncServerConcrete(
-      const syncer::SyncChangeList& changes) {
-    return AutofillWalletMetadataSyncableService::SendChangesToSyncServer(
-        changes);
-  }
-
-  syncer::SyncDataList GetAllSyncDataConcrete(syncer::ModelType type) const {
-    return AutofillWalletMetadataSyncableService::GetAllSyncData(type);
-  }
-
-  std::vector<AutofillProfile> server_profiles_;
-  std::vector<CreditCard> server_cards_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockService);
-};
-
-// Verify that nothing is sent to the sync server when there's no metadata on
-// disk.
-TEST(AutofillWalletMetadataSyncableServiceTest, NoMetadataToReturn) {
-  EXPECT_TRUE(NiceMock<MockService>()
-                  .GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA)
-                  .empty());
-}
-
-AutofillProfile BuildAddress(const std::string& server_id,
-                             int64 use_count,
-                             int64 use_date) {
-  AutofillProfile profile(AutofillProfile::SERVER_PROFILE, server_id);
-  profile.set_use_count(use_count);
-  profile.set_use_date(base::Time::FromInternalValue(use_date));
-  return profile;
-}
-
-CreditCard BuildCard(const std::string& server_id,
-                     int64 use_count,
-                     int64 use_date) {
-  CreditCard card(CreditCard::MASKED_SERVER_CARD, server_id);
-  card.set_use_count(use_count);
-  card.set_use_date(base::Time::FromInternalValue(use_date));
-  return card;
-}
-
-MATCHER_P5(SyncDataMatches,
-           sync_tag,
-           metadata_type,
-           server_id,
-           use_count,
-           use_date,
-           "") {
-  return arg.IsValid() &&
-         syncer::AUTOFILL_WALLET_METADATA == arg.GetDataType() &&
-         sync_tag == syncer::SyncDataLocal(arg).GetTag() &&
-         metadata_type == arg.GetSpecifics().wallet_metadata().type() &&
-         server_id == arg.GetSpecifics().wallet_metadata().id() &&
-         use_count == arg.GetSpecifics().wallet_metadata().use_count() &&
-         use_date == arg.GetSpecifics().wallet_metadata().use_date();
-}
-
-// Verify that all metadata from disk is sent to the sync server.
-TEST(AutofillWalletMetadataSyncableServiceTest, ReturnAllMetadata) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-
-  EXPECT_THAT(
-      local.GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA),
-      UnorderedElementsAre(
-          SyncDataMatches("address-addr",
-                          sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 1,
-                          2),
-          SyncDataMatches("card-card", sync_pb::WalletMetadataSpecifics::CARD,
-                          "card", 3, 4)));
-}
-
-void MergeMetadata(MockService* local, MockService* remote) {
-  // The wrapper for |remote| gives it a null change processor, so sending
-  // changes is not possible.
-  ON_CALL(*remote, SendChangesToSyncServer(_))
-      .WillByDefault(Return(syncer::SyncError()));
-
-  scoped_ptr<syncer::SyncErrorFactoryMock> errors(
-      new syncer::SyncErrorFactoryMock);
-  EXPECT_CALL(*errors, CreateAndUploadError(_, _)).Times(0);
-  EXPECT_FALSE(
-      local->MergeDataAndStartSyncing(
-               syncer::AUTOFILL_WALLET_METADATA,
-               remote->GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA),
-               scoped_ptr<syncer::SyncChangeProcessor>(
-                   new syncer::SyncChangeProcessorWrapperForTest(remote)),
-               errors.Pass())
-          .error()
-          .IsSet());
-}
-
-// Verify that nothing is written to disk or sent to the sync server when two
-// empty clients are syncing.
-TEST(AutofillWalletMetadataSyncableServiceTest, TwoEmptyClients) {
-  NiceMock<MockService> local;
-  NiceMock<MockService> remote;
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local, &remote);
-}
-
-MATCHER_P2(SyncChangeMatches, change_type, sync_tag, "") {
-  return arg.IsValid() && change_type == arg.change_type() &&
-         sync_tag == syncer::SyncDataLocal(arg.sync_data()).GetTag() &&
-         syncer::AUTOFILL_WALLET_METADATA == arg.sync_data().GetDataType();
-}
-
-// Verify that remote data without local counterpart is deleted during the
-// initial merge.
-TEST(AutofillWalletMetadataSyncableServiceTest, DeleteFromServerOnMerge) {
-  NiceMock<MockService> local;
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(
-      local,
-      SendChangesToSyncServer(UnorderedElementsAre(
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "address-addr"),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "card-card"))));
-
-  MergeMetadata(&local, &remote);
-}
-
-MATCHER_P6(SyncChangeAndDataMatch,
-           change_type,
-           sync_tag,
-           metadata_type,
-           server_id,
-           use_count,
-           use_date,
-           "") {
-  return Value(arg, SyncChangeMatches(change_type, sync_tag)) &&
-         Value(arg.sync_data(),
-               SyncDataMatches(sync_tag, metadata_type, server_id, use_count,
-                               use_date));
-}
-
-// Verify that local data is sent to the sync server during the initial merge,
-// if the server does not have the data already.
-TEST(AutofillWalletMetadataSyncableServiceTest, AddToServerOnMerge) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local,
-              SendChangesToSyncServer(UnorderedElementsAre(
-                  SyncChangeAndDataMatch(
-                      syncer::SyncChange::ACTION_ADD, "address-addr",
-                      sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 1, 2),
-                  SyncChangeAndDataMatch(
-                      syncer::SyncChange::ACTION_ADD, "card-card",
-                      sync_pb::WalletMetadataSpecifics::CARD, "card", 3, 4))));
-
-  MergeMetadata(&local, &remote);
-}
-
-// Verify that no data is written to disk or sent to the sync server if the
-// local and remote data are identical during the initial merge.
-TEST(AutofillWalletMetadataSyncableServiceTest, IgnoreIdenticalValuesOnMerge) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local, &remote);
-}
-
-MATCHER_P3(AutofillMetadataMatches, server_id, use_count, use_date, "") {
-  return arg.server_id() == server_id &&
-         arg.use_count() == static_cast<size_t>(use_count) &&
-         arg.use_date() == base::Time::FromInternalValue(use_date);
-}
-
-// Verify that remote data with higher values of use count and last use date is
-// saved to disk during the initial merge.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     SaveHigherValuesLocallyOnMerge) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 10, 20));
-  remote.UpdateCardStats(BuildCard("card", 30, 40));
-
-  EXPECT_CALL(local,
-              UpdateAddressStats(AutofillMetadataMatches("addr", 10, 20)));
-  EXPECT_CALL(local, UpdateCardStats(AutofillMetadataMatches("card", 30, 40)));
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local, &remote);
-}
-
-// Verify that local data with higher values of use count and last use date is
-// sent to the sync server during the initial merge.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     SendHigherValuesToServerOnMerge) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 10, 20));
-  local.UpdateCardStats(BuildCard("card", 30, 40));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(
-      local, SendChangesToSyncServer(UnorderedElementsAre(
-                 SyncChangeAndDataMatch(
-                     syncer::SyncChange::ACTION_UPDATE, "address-addr",
-                     sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 10, 20),
-                 SyncChangeAndDataMatch(
-                     syncer::SyncChange::ACTION_UPDATE, "card-card",
-                     sync_pb::WalletMetadataSpecifics::CARD, "card", 30, 40))));
-
-  MergeMetadata(&local, &remote);
-}
-
-// Verify that lower values of metadata are not sent to the sync server when
-// local metadata is updated.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     DontSendLowerValueToServerOnSingleChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  AutofillProfile address = BuildAddress("addr", 0, 0);
-  CreditCard card = BuildCard("card", 0, 0);
-
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  local.AutofillProfileChanged(AutofillProfileChange(
-      AutofillProfileChange::UPDATE, address.guid(), &address));
-  local.CreditCardChanged(
-      CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card));
-}
-
-// Verify that higher values of metadata are sent to the sync server when local
-// metadata is updated.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     SendHigherValuesToServerOnLocalSingleChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  AutofillProfile address = BuildAddress("addr", 10, 20);
-  CreditCard card = BuildCard("card", 30, 40);
-
-  EXPECT_CALL(local,
-              SendChangesToSyncServer(ElementsAre(SyncChangeAndDataMatch(
-                  syncer::SyncChange::ACTION_UPDATE, "address-addr",
-                  sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 10, 20))));
-  EXPECT_CALL(local,
-              SendChangesToSyncServer(ElementsAre(SyncChangeAndDataMatch(
-                  syncer::SyncChange::ACTION_UPDATE, "card-card",
-                  sync_pb::WalletMetadataSpecifics::CARD, "card", 30, 40))));
-
-  local.AutofillProfileChanged(AutofillProfileChange(
-      AutofillProfileChange::UPDATE, address.guid(), &address));
-  local.CreditCardChanged(
-      CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card));
-}
-
-// Verify that one-off addition of metadata is not sent to the sync
-// server. Metadata add and delete trigger multiple changes notification
-// instead.
-TEST(AutofillWalletMetadataSyncableServiceTest, DontAddToServerOnSingleChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  AutofillProfile address = BuildAddress("new-addr", 5, 6);
-  CreditCard card = BuildCard("new-card", 7, 8);
-
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  local.AutofillProfileChanged(AutofillProfileChange(
-      AutofillProfileChange::UPDATE, address.guid(), &address));
-  local.CreditCardChanged(
-      CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card));
-}
-
-// Verify that new metadata is sent to the sync server when multiple metadata
-// values change at once.
-TEST(AutofillWalletMetadataSyncableServiceTest, AddToServerOnMultiChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  // These methods do not trigger notifications or sync:
-  local.UpdateAddressStats(BuildAddress("new-addr", 5, 6));
-  local.UpdateCardStats(BuildCard("new-card", 7, 8));
-
-  EXPECT_CALL(
-      local,
-      SendChangesToSyncServer(UnorderedElementsAre(
-          SyncChangeAndDataMatch(
-              syncer::SyncChange::ACTION_ADD, "address-new-addr",
-              sync_pb::WalletMetadataSpecifics::ADDRESS, "new-addr", 5, 6),
-          SyncChangeAndDataMatch(
-              syncer::SyncChange::ACTION_ADD, "card-new-card",
-              sync_pb::WalletMetadataSpecifics::CARD, "new-card", 7, 8))));
-
-  local.AutofillMultipleChanged();
-}
-
-// Verify that higher values of existing metadata are sent to the sync server
-// when multiple metadata values change at once.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     UpdateToHigherValueOnServerOnMultiChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  // These methods do not trigger notifications or sync:
-  local.UpdateAddressStats(BuildAddress("addr", 5, 6));
-  local.UpdateCardStats(BuildCard("card", 7, 8));
-
-  EXPECT_CALL(local,
-              SendChangesToSyncServer(UnorderedElementsAre(
-                  SyncChangeAndDataMatch(
-                      syncer::SyncChange::ACTION_UPDATE, "address-addr",
-                      sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 5, 6),
-                  SyncChangeAndDataMatch(
-                      syncer::SyncChange::ACTION_UPDATE, "card-card",
-                      sync_pb::WalletMetadataSpecifics::CARD, "card", 7, 8))));
-
-  local.AutofillMultipleChanged();
-}
-
-// Verify that lower values of existing metadata are not sent to the sync server
-// when multiple metadata values change at once.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     DontUpdateToLowerValueOnServerOnMultiChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  // These methods do not trigger notifications or sync:
-  local.UpdateAddressStats(BuildAddress("addr", 0, 0));
-  local.UpdateCardStats(BuildCard("card", 0, 0));
-
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  local.AutofillMultipleChanged();
-}
-
-// Verify that erased local metadata is also erased from the sync server when
-// multiple metadata values change at once.
-TEST(AutofillWalletMetadataSyncableServiceTest, DeleteFromServerOnMultiChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  // This method dooes not trigger notifications or sync:
-  local.ClearServerData();
-
-  EXPECT_CALL(
-      local,
-      SendChangesToSyncServer(UnorderedElementsAre(
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "address-addr"),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "card-card"))));
-
-  local.AutofillMultipleChanged();
-}
-
-// Verify that empty sync change from the sync server does not trigger writing
-// to disk or sending any data to the sync server.
-TEST(AutofillWalletMetadataSyncableServiceTest, EmptySyncChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  local.ProcessSyncChanges(FROM_HERE, syncer::SyncChangeList());
-}
-
-syncer::SyncChange BuildChange(
-    syncer::SyncChange::SyncChangeType change_type,
-    const std::string& sync_tag,
-    sync_pb::WalletMetadataSpecifics::Type metadata_type,
-    const std::string& server_id,
-    int64 use_count,
-    int64 use_date) {
-  sync_pb::EntitySpecifics entity;
-  entity.mutable_wallet_metadata()->set_type(metadata_type);
-  entity.mutable_wallet_metadata()->set_id(server_id);
-  entity.mutable_wallet_metadata()->set_use_count(use_count);
-  entity.mutable_wallet_metadata()->set_use_date(use_date);
-  return syncer::SyncChange(
-      FROM_HERE, change_type,
-      syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity));
-}
-
-// Verify that new metadata from the sync server is ignored when processing
-// on-going sync changes. There should be no disk writes or messages to the sync
-// server.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     IgnoreNewMetadataFromServerOnSyncChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  syncer::SyncChangeList changes;
-  changes.push_back(
-      BuildChange(syncer::SyncChange::ACTION_ADD, "address-new-addr",
-                  sync_pb::WalletMetadataSpecifics::ADDRESS, "new-addr", 5, 6));
-  changes.push_back(BuildChange(syncer::SyncChange::ACTION_ADD, "card-new-card",
-                                sync_pb::WalletMetadataSpecifics::CARD,
-                                "new-card", 7, 8));
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  local.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that higher values of metadata from the sync server are saved to
-// disk when processing on-going sync changes.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     SaveHigherValuesFromServerOnSyncChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  syncer::SyncChangeList changes;
-  changes.push_back(
-      BuildChange(syncer::SyncChange::ACTION_UPDATE, "address-addr",
-                  sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 10, 20));
-  changes.push_back(BuildChange(syncer::SyncChange::ACTION_UPDATE, "card-card",
-                                sync_pb::WalletMetadataSpecifics::CARD, "card",
-                                30, 40));
-
-  EXPECT_CALL(local,
-              UpdateAddressStats(AutofillMetadataMatches("addr", 10, 20)));
-  EXPECT_CALL(local, UpdateCardStats(AutofillMetadataMatches("card", 30, 40)));
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  local.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that higher local values of metadata are sent to the sync server when
-// processing on-going sync changes.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     SendHigherValuesToServerOnSyncChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  syncer::SyncChangeList changes;
-  changes.push_back(
-      BuildChange(syncer::SyncChange::ACTION_UPDATE, "address-addr",
-                  sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 0, 0));
-  changes.push_back(BuildChange(syncer::SyncChange::ACTION_UPDATE, "card-card",
-                                sync_pb::WalletMetadataSpecifics::CARD, "card",
-                                0, 0));
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local,
-              SendChangesToSyncServer(UnorderedElementsAre(
-                  SyncChangeAndDataMatch(
-                      syncer::SyncChange::ACTION_UPDATE, "address-addr",
-                      sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 1, 2),
-                  SyncChangeAndDataMatch(
-                      syncer::SyncChange::ACTION_UPDATE, "card-card",
-                      sync_pb::WalletMetadataSpecifics::CARD, "card", 3, 4))));
-
-  local.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that addition of known metadata is treated the same as an update.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     TreatAdditionOfKnownMetadataAsUpdateOnSyncChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildChange(syncer::SyncChange::ACTION_ADD, "address-addr",
-                                sync_pb::WalletMetadataSpecifics::ADDRESS,
-                                "addr", 0, 0));
-  changes.push_back(BuildChange(syncer::SyncChange::ACTION_ADD, "card-card",
-                                sync_pb::WalletMetadataSpecifics::CARD, "card",
-                                0, 0));
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local,
-              SendChangesToSyncServer(UnorderedElementsAre(
-                  SyncChangeAndDataMatch(
-                      syncer::SyncChange::ACTION_UPDATE, "address-addr",
-                      sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 1, 2),
-                  SyncChangeAndDataMatch(
-                      syncer::SyncChange::ACTION_UPDATE, "card-card",
-                      sync_pb::WalletMetadataSpecifics::CARD, "card", 3, 4))));
-
-  local.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that an update of locally unknown metadata is ignored. There should be
-// no disk writes and no messages sent to the server.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     IgnoreUpdateOfUnknownMetadataOnSyncChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildChange(
-      syncer::SyncChange::ACTION_UPDATE, "address-unknown-addr",
-      sync_pb::WalletMetadataSpecifics::ADDRESS, "unknown-addr", 0, 0));
-  changes.push_back(BuildChange(
-      syncer::SyncChange::ACTION_UPDATE, "card-unknown-card",
-      sync_pb::WalletMetadataSpecifics::CARD, "unknown-card", 0, 0));
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  local.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that deletion from the sync server of locally unknown metadata is
-// ignored. There should be no disk writes and no messages sent to the server.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     IgnoreDeleteOfUnknownMetadataOnSyncChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildChange(
-      syncer::SyncChange::ACTION_DELETE, "address-unknown-addr",
-      sync_pb::WalletMetadataSpecifics::ADDRESS, "unknown-addr", 0, 0));
-  changes.push_back(BuildChange(
-      syncer::SyncChange::ACTION_DELETE, "card-unknown-card",
-      sync_pb::WalletMetadataSpecifics::CARD, "unknown-card", 0, 0));
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
-
-  local.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that deletion from the sync server of locally existing metadata will
-// trigger an undelete message sent to the server.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     UndeleteExistingMetadataOnSyncChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  local.UpdateCardStats(BuildCard("card", 3, 4));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
-  remote.UpdateCardStats(BuildCard("card", 3, 4));
-  MergeMetadata(&local, &remote);
-  syncer::SyncChangeList changes;
-  changes.push_back(
-      BuildChange(syncer::SyncChange::ACTION_DELETE, "address-addr",
-                  sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 0, 0));
-  changes.push_back(BuildChange(syncer::SyncChange::ACTION_DELETE, "card-card",
-                                sync_pb::WalletMetadataSpecifics::CARD, "card",
-                                0, 0));
-
-  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local,
-              SendChangesToSyncServer(UnorderedElementsAre(
-                  SyncChangeAndDataMatch(
-                      syncer::SyncChange::ACTION_ADD, "address-addr",
-                      sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 1, 2),
-                  SyncChangeAndDataMatch(
-                      syncer::SyncChange::ACTION_ADD, "card-card",
-                      sync_pb::WalletMetadataSpecifics::CARD, "card", 3, 4))));
-
-  local.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that processing sync changes maintains the local cache of sync server
-// data, which is used to avoid calling the expensive GetAllSyncData() function.
-TEST(AutofillWalletMetadataSyncableServiceTest,
-     CacheIsUpToDateAfterSyncChange) {
-  NiceMock<MockService> local;
-  local.UpdateAddressStats(BuildAddress("addr1", 1, 2));
-  local.UpdateAddressStats(BuildAddress("addr2", 3, 4));
-  local.UpdateCardStats(BuildCard("card1", 5, 6));
-  local.UpdateCardStats(BuildCard("card2", 7, 8));
-  NiceMock<MockService> remote;
-  remote.UpdateAddressStats(BuildAddress("addr1", 1, 2));
-  remote.UpdateAddressStats(BuildAddress("addr2", 3, 4));
-  remote.UpdateCardStats(BuildCard("card1", 5, 6));
-  remote.UpdateCardStats(BuildCard("card2", 7, 8));
-  MergeMetadata(&local, &remote);
-  syncer::SyncChangeList changes;
-  changes.push_back(
-      BuildChange(syncer::SyncChange::ACTION_UPDATE, "address-addr1",
-                  sync_pb::WalletMetadataSpecifics::ADDRESS, "addr1", 10, 20));
-  changes.push_back(BuildChange(syncer::SyncChange::ACTION_UPDATE, "card-card1",
-                                sync_pb::WalletMetadataSpecifics::CARD, "card1",
-                                50, 60));
-  local.ProcessSyncChanges(FROM_HERE, changes);
-  // This method dooes not trigger notifications or sync:
-  local.ClearServerData();
-
-  EXPECT_CALL(
-      local,
-      SendChangesToSyncServer(UnorderedElementsAre(
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "address-addr1"),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "address-addr2"),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "card-card1"),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "card-card2"))));
-
-  local.AutofillMultipleChanged();
-}
-
-}  // namespace
-}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend.h b/components/autofill/core/browser/webdata/autofill_webdata_backend.h
index 8b06ffb..2f46301 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_backend.h
+++ b/components/autofill/core/browser/webdata/autofill_webdata_backend.h
@@ -31,10 +31,10 @@
   // Remove expired elements from the database and commit if needed.
   virtual void RemoveExpiredFormElements() = 0;
 
-  // Notifies listeners on both DB and UI threads that multiple changes have
-  // been made to to Autofill records of the database.
-  // NOTE: This method is intended to be called from the DB thread. The UI
-  // thread notifications are asynchronous.
+  // Notifies listeners on the UI thread that multiple changes have been made to
+  // to Autofill records of the database.
+  // NOTE: This method is intended to be called from the DB thread. It
+  // asynchronously notifies listeners on the UI thread.
   virtual void NotifyOfMultipleAutofillChanges() = 0;
 };
 
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
index 187f3e6..ec48b80 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
+++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
@@ -67,12 +67,6 @@
 
 void AutofillWebDataBackendImpl::NotifyOfMultipleAutofillChanges() {
   DCHECK(db_thread_->BelongsToCurrentThread());
-
-  // DB thread notification.
-  FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
-                    AutofillMultipleChanged());
-
-  // UI thread notification.
   ui_thread_->PostTask(FROM_HERE, on_changed_callback_);
 }
 
@@ -284,10 +278,6 @@
     return WebDatabase::COMMIT_NOT_NEEDED;
   }
 
-  FOR_EACH_OBSERVER(
-      AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
-      CreditCardChanged(CreditCardChange(CreditCardChange::ADD,
-                                         credit_card.guid(), &credit_card)));
   return WebDatabase::COMMIT_NEEDED;
 }
 
@@ -307,11 +297,6 @@
     NOTREACHED();
     return WebDatabase::COMMIT_NOT_NEEDED;
   }
-
-  FOR_EACH_OBSERVER(
-      AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
-      CreditCardChanged(CreditCardChange(CreditCardChange::UPDATE,
-                                         credit_card.guid(), &credit_card)));
   return WebDatabase::COMMIT_NEEDED;
 }
 
@@ -322,10 +307,6 @@
     NOTREACHED();
     return WebDatabase::COMMIT_NOT_NEEDED;
   }
-
-  FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
-                    CreditCardChanged(CreditCardChange(CreditCardChange::REMOVE,
-                                                       guid, nullptr)));
   return WebDatabase::COMMIT_NEEDED;
 }
 
@@ -380,31 +361,20 @@
     const CreditCard& card,
     WebDatabase* db) {
   DCHECK(db_thread_->BelongsToCurrentThread());
-  if (!AutofillTable::FromWebDatabase(db)->UpdateServerCardUsageStats(card))
-    return WebDatabase::COMMIT_NOT_NEEDED;
-
-  FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
-                    CreditCardChanged(CreditCardChange(CreditCardChange::UPDATE,
-                                                       card.guid(), &card)));
-
-  return WebDatabase::COMMIT_NEEDED;
+  if (AutofillTable::FromWebDatabase(db)->UpdateServerCardUsageStats(card))
+    return WebDatabase::COMMIT_NEEDED;
+  return WebDatabase::COMMIT_NOT_NEEDED;
 }
 
 WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressUsageStats(
     const AutofillProfile& profile,
     WebDatabase* db) {
   DCHECK(db_thread_->BelongsToCurrentThread());
-  if (!AutofillTable::FromWebDatabase(db)->UpdateServerAddressUsageStats(
+  if (AutofillTable::FromWebDatabase(db)->UpdateServerAddressUsageStats(
           profile)) {
-    return WebDatabase::COMMIT_NOT_NEEDED;
+    return WebDatabase::COMMIT_NEEDED;
   }
-
-  FOR_EACH_OBSERVER(
-      AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
-      AutofillProfileChanged(AutofillProfileChange(
-          AutofillProfileChange::UPDATE, profile.guid(), &profile)));
-
-  return WebDatabase::COMMIT_NEEDED;
+  return WebDatabase::COMMIT_NOT_NEEDED;
 }
 
 WebDatabase::State AutofillWebDataBackendImpl::ClearAllServerData(
@@ -430,17 +400,12 @@
           delete_end,
           &profile_guids,
           &credit_card_guids)) {
-    for (const std::string& guid : profile_guids) {
+    for (std::vector<std::string>::iterator iter = profile_guids.begin();
+         iter != profile_guids.end(); ++iter) {
+      AutofillProfileChange change(AutofillProfileChange::REMOVE, *iter, NULL);
       FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
                         db_observer_list_,
-                        AutofillProfileChanged(AutofillProfileChange(
-                            AutofillProfileChange::REMOVE, guid, nullptr)));
-    }
-    for (const std::string& guid : credit_card_guids) {
-      FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
-                        db_observer_list_,
-                        CreditCardChanged(CreditCardChange(
-                            CreditCardChange::REMOVE, guid, nullptr)));
+                        AutofillProfileChanged(change));
     }
     // Note: It is the caller's responsibility to post notifications for any
     // changes, e.g. by calling the Refresh() method of PersonalDataManager.
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h b/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
index e8bf79ca..f4333e5 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
+++ b/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
@@ -18,14 +18,6 @@
   // in the WebDatabase.
   virtual void AutofillProfileChanged(const AutofillProfileChange& change) {}
 
-  // Called on DB thread when a CreditCard has been added/removed/updated in the
-  // WebDatabase.
-  virtual void CreditCardChanged(const CreditCardChange& change) {}
-
-  // Called on DB thread when multiple Autofill entries have been modified by
-  // Sync.
-  virtual void AutofillMultipleChanged() {}
-
  protected:
   virtual ~AutofillWebDataServiceObserverOnDBThread() {}
 };
diff --git a/components/bookmarks.gypi b/components/bookmarks.gypi
index 5b6b73f5..0ac445b 100644
--- a/components/bookmarks.gypi
+++ b/components/bookmarks.gypi
@@ -59,6 +59,8 @@
         'bookmarks/browser/bookmark_utils.h',
         'bookmarks/browser/scoped_group_bookmark_actions.cc',
         'bookmarks/browser/scoped_group_bookmark_actions.h',
+        'bookmarks/browser/startup_task_runner_service.cc',
+        'bookmarks/browser/startup_task_runner_service.h',
       ],
       'conditions': [
         ['OS == "android"', {
diff --git a/components/bookmarks/browser/BUILD.gn b/components/bookmarks/browser/BUILD.gn
index 091b20a..8d1719d 100644
--- a/components/bookmarks/browser/BUILD.gn
+++ b/components/bookmarks/browser/BUILD.gn
@@ -35,6 +35,8 @@
     "bookmark_utils.h",
     "scoped_group_bookmark_actions.cc",
     "scoped_group_bookmark_actions.h",
+    "startup_task_runner_service.cc",
+    "startup_task_runner_service.h",
   ]
 
   deps = [
diff --git a/components/bookmarks/browser/bookmark_storage.cc b/components/bookmarks/browser/bookmark_storage.cc
index 2612f9c3..74d6417 100644
--- a/components/bookmarks/browser/bookmark_storage.cc
+++ b/components/bookmarks/browser/bookmark_storage.cc
@@ -16,7 +16,6 @@
 #include "components/bookmarks/browser/bookmark_index.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/common/bookmark_constants.h"
-#include "components/startup_metric_utils/startup_metric_utils.h"
 
 using base::TimeTicks;
 
@@ -51,8 +50,6 @@
                   const base::WeakPtr<BookmarkStorage>& storage,
                   scoped_ptr<BookmarkLoadDetails> details,
                   base::SequencedTaskRunner* task_runner) {
-  startup_metric_utils::ScopedSlowStartupUMA
-      scoped_timer("Startup.SlowStartupBookmarksLoad");
   bool load_index = false;
   bool bookmark_file_exists = base::PathExists(path);
   if (bookmark_file_exists) {
diff --git a/components/bookmarks/browser/bookmark_utils.cc b/components/bookmarks/browser/bookmark_utils.cc
index 28690f27..e9f32d4 100644
--- a/components/bookmarks/browser/bookmark_utils.cc
+++ b/components/bookmarks/browser/bookmark_utils.cc
@@ -262,7 +262,7 @@
   for (int i = 0; i < parent->child_count(); i++) {
     const BookmarkNode* node = parent->GetChild(i);
     if (node->is_url() && (url == node->url()) &&
-        StartsWith(node->GetTitle(), *title, false)) {
+        base::StartsWith(node->GetTitle(), *title, false)) {
       titles.insert(node->GetTitle());
     }
   }
diff --git a/chrome/browser/profiles/startup_task_runner_service.cc b/components/bookmarks/browser/startup_task_runner_service.cc
similarity index 60%
rename from chrome/browser/profiles/startup_task_runner_service.cc
rename to components/bookmarks/browser/startup_task_runner_service.cc
index d28bdd7..7ec9cd2 100644
--- a/chrome/browser/profiles/startup_task_runner_service.cc
+++ b/components/bookmarks/browser/startup_task_runner_service.cc
@@ -2,14 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/profiles/startup_task_runner_service.h"
+#include "components/bookmarks/browser/startup_task_runner_service.h"
 
 #include "base/deferred_sequenced_task_runner.h"
 #include "base/logging.h"
-#include "chrome/browser/profiles/profile.h"
+#include "base/sequenced_task_runner.h"
 
-StartupTaskRunnerService::StartupTaskRunnerService(Profile* profile)
-    : profile_(profile) {
+StartupTaskRunnerService::StartupTaskRunnerService(
+    const scoped_refptr<base::SequencedTaskRunner>& io_task_runner)
+    : io_task_runner_(io_task_runner) {
+  DCHECK(io_task_runner_);
 }
 
 StartupTaskRunnerService::~StartupTaskRunnerService() {
@@ -18,9 +20,9 @@
 scoped_refptr<base::DeferredSequencedTaskRunner>
     StartupTaskRunnerService::GetBookmarkTaskRunner() {
   DCHECK(CalledOnValidThread());
-  if (!bookmark_task_runner_.get()) {
+  if (!bookmark_task_runner_) {
     bookmark_task_runner_ =
-        new base::DeferredSequencedTaskRunner(profile_->GetIOTaskRunner());
+        new base::DeferredSequencedTaskRunner(io_task_runner_);
   }
   return bookmark_task_runner_;
 }
diff --git a/chrome/browser/profiles/startup_task_runner_service.h b/components/bookmarks/browser/startup_task_runner_service.h
similarity index 76%
rename from chrome/browser/profiles/startup_task_runner_service.h
rename to components/bookmarks/browser/startup_task_runner_service.h
index d8e6b22..f99935f 100644
--- a/chrome/browser/profiles/startup_task_runner_service.h
+++ b/components/bookmarks/browser/startup_task_runner_service.h
@@ -2,25 +2,26 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_H_
-#define CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_H_
+#ifndef COMPONENTS_BOOKMARKS_BROWSER_STARTUP_TASK_RUNNER_SERVICE_H_
+#define COMPONENTS_BOOKMARKS_BROWSER_STARTUP_TASK_RUNNER_SERVICE_H_
 
 #include "base/basictypes.h"
+#include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/non_thread_safe.h"
 #include "components/keyed_service/core/keyed_service.h"
 
-class Profile;
-
 namespace base {
 class DeferredSequencedTaskRunner;
+class SequencedTaskRunner;
 }  // namespace base
 
 // This service manages the startup task runners.
 class StartupTaskRunnerService : public base::NonThreadSafe,
                                  public KeyedService {
  public:
-  explicit StartupTaskRunnerService(Profile* profile);
+  explicit StartupTaskRunnerService(
+      const scoped_refptr<base::SequencedTaskRunner>& io_task_runner);
   ~StartupTaskRunnerService() override;
 
   // Returns sequenced task runner where all bookmarks I/O operations are
@@ -36,10 +37,10 @@
   void StartDeferredTaskRunners();
 
  private:
-  Profile* profile_;
+  scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
   scoped_refptr<base::DeferredSequencedTaskRunner> bookmark_task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(StartupTaskRunnerService);
 };
 
-#endif  // CHROME_BROWSER_PROFILES_STARTUP_TASK_RUNNER_SERVICE_H_
+#endif  // COMPONENTS_BOOKMARKS_BROWSER_STARTUP_TASK_RUNNER_SERVICE_H_
diff --git a/components/browser_watcher/exit_code_watcher_win_unittest.cc b/components/browser_watcher/exit_code_watcher_win_unittest.cc
index f9d495a3..10ba2fd4 100644
--- a/components/browser_watcher/exit_code_watcher_win_unittest.cc
+++ b/components/browser_watcher/exit_code_watcher_win_unittest.cc
@@ -98,9 +98,8 @@
                           KEY_QUERY_VALUE);
 
     // The value name should encode the process id at the start.
-    EXPECT_TRUE(StartsWith(it.Name(),
-                           base::StringPrintf(L"%d-", proc_id),
-                           false));
+    EXPECT_TRUE(base::StartsWith(it.Name(), base::StringPrintf(L"%d-", proc_id),
+                                 false));
     DWORD value = 0;
     ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(it.Name(), &value));
     ASSERT_EQ(exit_code, value);
diff --git a/components/clipboard/BUILD.gn b/components/clipboard/BUILD.gn
index 336db09..74a391d5 100644
--- a/components/clipboard/BUILD.gn
+++ b/components/clipboard/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application.gni")
 
 source_set("lib") {
   sources = [
diff --git a/components/clipboard/public/interfaces/BUILD.gn b/components/clipboard/public/interfaces/BUILD.gn
index 6ee9bb7..7bca33b 100644
--- a/components/clipboard/public/interfaces/BUILD.gn
+++ b/components/clipboard/public/interfaces/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index b97f071f..87cfdfe 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -58,7 +58,6 @@
       'autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc',
       'autofill/core/browser/validation_unittest.cc',
       'autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc',
-      'autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc',
       'autofill/core/browser/webdata/autofill_table_unittest.cc',
       'autofill/core/browser/webdata/web_data_service_unittest.cc',
       'autofill/core/common/autofill_regexes_unittest.cc',
@@ -331,12 +330,16 @@
     'network_time_unittest_sources': [
       'network_time/network_time_tracker_unittest.cc',
     ],
+    'offline_page_unittest_sources': [
+      'offline_pages/offline_page_model_unittest.cc',
+    ],
     'omnibox_unittest_sources': [
       'omnibox/answers_cache_unittest.cc',
       'omnibox/autocomplete_input_unittest.cc',
       'omnibox/autocomplete_match_unittest.cc',
       'omnibox/autocomplete_result_unittest.cc',
       'omnibox/base_search_provider_unittest.cc',
+      'omnibox/in_memory_url_index_types_unittest.cc',
       'omnibox/keyword_provider_unittest.cc',
       'omnibox/omnibox_field_trial_unittest.cc',
       'omnibox/suggestion_answer_unittest.cc',
@@ -695,6 +698,7 @@
         '<@(metrics_unittest_sources)',
         '<@(mime_util_unittest_sources)',
         '<@(network_time_unittest_sources)',
+        '<@(offline_page_unittest_sources)',
         '<@(omnibox_unittest_sources)',
         '<@(os_crypt_unittest_sources)',
         '<@(packed_ct_ev_whitelist_unittest_sources)',
@@ -797,6 +801,7 @@
         'components.gyp:metrics_profiler',
         'components.gyp:metrics_test_support',
         'components.gyp:network_time',
+        'components.gyp:offline_pages',
         'components.gyp:omnibox',
         'components.gyp:omnibox_test_support',
         'components.gyp:os_crypt',
diff --git a/components/components_unittests.isolate b/components/components_unittests.isolate
index 3c1f393..ccdaf16 100644
--- a/components/components_unittests.isolate
+++ b/components/components_unittests.isolate
@@ -54,7 +54,6 @@
     ['OS=="linux"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
         ],
       },
@@ -62,7 +61,6 @@
     ['OS=="mac"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
           '<(PRODUCT_DIR)/osmesa.so',
         ],
       },
@@ -71,7 +69,6 @@
       'variables': {
         'files': [
           '../chrome/test/data/policy/',
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/osmesa.dll',
         ],
       },
@@ -87,7 +84,6 @@
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/components_unittests.dSYM/',
-          '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
           '<(PRODUCT_DIR)/osmesa.so.dSYM/',
         ],
       },
diff --git a/components/content_settings/core/common/content_settings_pattern_parser.cc b/components/content_settings/core/common/content_settings_pattern_parser.cc
index 8494bfd4..ae7dcc3 100644
--- a/components/content_settings/core/common/content_settings_pattern_parser.cc
+++ b/components/content_settings/core/common/content_settings_pattern_parser.cc
@@ -130,7 +130,7 @@
                                            host_component.len);
     if (host == kHostWildcard) {
       builder->WithDomainWildcard();
-    } else if (StartsWithASCII(host, kDomainWildcard, true)) {
+    } else if (base::StartsWithASCII(host, kDomainWildcard, true)) {
       host = host.substr(kDomainWildcardLength);
       builder->WithDomainWildcard();
       builder->WithHost(host);
diff --git a/components/cronet/android/test/native_test_server.cc b/components/cronet/android/test/native_test_server.cc
index 9003b64..022b1c5 100644
--- a/components/cronet/android/test/native_test_server.cc
+++ b/components/cronet/android/test/native_test_server.cc
@@ -102,7 +102,7 @@
     return response.Pass();
   }
 
-  if (StartsWithASCII(request.relative_url, kEchoHeaderPath, true)) {
+  if (base::StartsWithASCII(request.relative_url, kEchoHeaderPath, true)) {
     GURL url = g_test_server->GetURL(request.relative_url);
     auto it = request.headers.find(url.query());
     if (it != request.headers.end()) {
@@ -141,7 +141,7 @@
   DCHECK(get_data_dir);
   dir_path = dir_path.Append(FILE_PATH_LITERAL("test"));
 
-  if (StartsWithASCII(request.relative_url, kSdchPath, true)) {
+  if (base::StartsWithASCII(request.relative_url, kSdchPath, true)) {
     base::FilePath file_path = dir_path.Append("sdch/index");
     scoped_ptr<CustomHttpResponse> response =
         ConstructResponseBasedOnFile(file_path).Pass();
@@ -162,7 +162,7 @@
     return response.Pass();
   }
 
-  if (StartsWithASCII(request.relative_url, kSdchTestPath, true)) {
+  if (base::StartsWithASCII(request.relative_url, kSdchTestPath, true)) {
     auto avail_dictionary_header = request.headers.find("Avail-Dictionary");
     if (avail_dictionary_header != request.headers.end()) {
       base::FilePath file_path = dir_path.Append(
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc
index 77f07dad..cca2197 100644
--- a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc
+++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc
@@ -128,9 +128,9 @@
     bool is_data_reduction_proxy = false;
 
     if (tests[i].lofi_on_through_switch) {
-      base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-      command_line->AppendSwitch(
-          data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kDataReductionProxyLoFi,
+          switches::kDataReductionProxyLoFiValueAlwaysOn);
     }
 
     EXPECT_CALL(*config(), IsDataReductionProxy(testing::_, nullptr))
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
index 6db84f1..238130d 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
@@ -737,10 +737,10 @@
   int user_visible_savings_percent =
       user_visible_savings_bytes * 100 / original_content_length;
   UMA_HISTOGRAM_PERCENTAGE(
-      "Net.DailyUserVisibleSavingsPercent_DataRedictionProxyEnabled",
+      "Net.DailyUserVisibleSavingsPercent_DataReductionProxyEnabled",
       user_visible_savings_percent);
   UMA_HISTOGRAM_COUNTS(
-      "Net.DailyUserVisibleSavingsSize_DataRedictionProxyEnabled",
+      "Net.DailyUserVisibleSavingsSize_DataReductionProxyEnabled",
       user_visible_savings_bytes >> 10);
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
index 6beee3cf..2ffcf3a8 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -21,6 +21,7 @@
 #include "components/variations/variations_associated_data.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
+#include "net/base/network_change_notifier.h"
 #include "net/base/network_quality.h"
 #include "net/base/network_quality_estimator.h"
 #include "net/proxy/proxy_server.h"
@@ -196,12 +197,17 @@
       net_log_(net_log),
       configurator_(configurator),
       event_creator_(event_creator),
-      auto_lofi_minimum_rtt_(base::TimeDelta()),
-      auto_lofi_maximum_kbps_(0),
-      auto_lofi_hysteresis_(base::TimeDelta()),
+      auto_lofi_minimum_rtt_(base::TimeDelta::Max()),
+      auto_lofi_maximum_kbps_(UINT64_MAX),
+      auto_lofi_hysteresis_(base::TimeDelta::Max()),
+      network_quality_last_updated_(base::TimeTicks()),
+      network_prohibitively_slow_(false),
+      connection_type_(net::NetworkChangeNotifier::GetConnectionType()),
       lofi_status_(LOFI_STATUS_TEMPORARILY_OFF) {
   DCHECK(configurator);
   DCHECK(event_creator);
+  if (DataReductionProxyParams::IsLoFiDisabledViaFlags())
+    SetLoFiModeOff();
   // Constructed on the UI thread, but should be checked on the IO thread.
   thread_checker_.DetachFromThread();
 }
@@ -370,19 +376,46 @@
 }
 
 bool DataReductionProxyConfig::IsNetworkQualityProhibitivelySlow(
-    const net::NetworkQualityEstimator* network_quality_estimator) const {
+    const net::NetworkQualityEstimator* network_quality_estimator) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (!network_quality_estimator)
     return false;
 
+  // True iff network type changed since the last call to
+  // IsNetworkQualityProhibitivelySlow(). This call happens only on main frame
+  // requests.
+  bool network_type_changed = false;
+  if (net::NetworkChangeNotifier::GetConnectionType() != connection_type_) {
+    connection_type_ = net::NetworkChangeNotifier::GetConnectionType();
+    network_type_changed = true;
+  }
+  // Return the cached entry if the last update was within the hysteresis
+  // duration and if the connection type has not changed.
+  if (!network_type_changed && !network_quality_last_updated_.is_null() &&
+      base::TimeTicks::Now() - network_quality_last_updated_ <=
+          auto_lofi_hysteresis_) {
+    return network_prohibitively_slow_;
+  }
+
+  network_quality_last_updated_ = base::TimeTicks::Now();
+
   net::NetworkQuality network_quality =
       network_quality_estimator->GetEstimate();
   // TODO(tbansal): Set |network_prohibitively_slow| based on medians
   // provided by NetworkQualityEstimator API and field trial parameters.
-  // Also, ensure that state of network is not changed more than once within
-  // the hysteresis period.
-  return false;
+
+  // Network is prohibitvely slow if either the downlink bandwidth is too low
+  // or the RTT is too high.
+  if ((network_quality.peak_throughput_kbps > 0 &&
+       network_quality.peak_throughput_kbps <= auto_lofi_maximum_kbps_) ||
+      (network_quality.fastest_rtt > base::TimeDelta() &&
+       network_quality.fastest_rtt >= auto_lofi_minimum_rtt_)) {
+    network_prohibitively_slow_ = true;
+  } else {
+    network_prohibitively_slow_ = false;
+  }
+  return network_prohibitively_slow_;
 }
 
 bool DataReductionProxyConfig::IsIncludedInLoFiEnabledFieldTrial() const {
@@ -722,6 +755,11 @@
                                                      fetcher_callback);
 }
 
+void DataReductionProxyConfig::SetLoFiModeOff() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  lofi_status_ = LOFI_STATUS_OFF;
+}
+
 void DataReductionProxyConfig::UpdateLoFiStatusOnMainFrameRequest(
     bool user_temporarily_disabled_lofi,
     const net::NetworkQualityEstimator* network_quality_estimator) {
@@ -756,11 +794,21 @@
     }
   }
 
-  if (DataReductionProxyParams::IsLoFiEnabledThroughSwitch()) {
+  if (DataReductionProxyParams::IsLoFiAlwaysOnViaFlags()) {
     lofi_status_ = LOFI_STATUS_ACTIVE_FROM_FLAGS;
     return;
   }
 
+  if (DataReductionProxyParams::IsLoFiCellularOnlyViaFlags()) {
+    if (net::NetworkChangeNotifier::IsConnectionCellular(
+            net::NetworkChangeNotifier::GetConnectionType())) {
+      lofi_status_ = LOFI_STATUS_ACTIVE_FROM_FLAGS;
+      return;
+    }
+    lofi_status_ = LOFI_STATUS_TEMPORARILY_OFF;
+    return;
+  }
+
   if (IsIncludedInLoFiControlFieldTrial()) {
     lofi_status_ = IsNetworkQualityProhibitivelySlow(network_quality_estimator)
                        ? LOFI_STATUS_ACTIVE_CONTROL
@@ -806,7 +854,7 @@
   const std::string vpn_interface_name_prefix = "tun";
   for (size_t i = 0; i < network_interfaces.size(); ++i) {
     std::string interface_name = network_interfaces[i].name;
-    if (LowerCaseEqualsASCII(
+    if (base::LowerCaseEqualsASCII(
             interface_name.begin(),
             interface_name.begin() + vpn_interface_name_prefix.size(),
             vpn_interface_name_prefix.c_str())) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
index 074f913..3c85e41a 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -234,6 +234,9 @@
   // Should be called on all URL requests (main frame and non main frame).
   bool ShouldUseLoFiHeaderForRequests() const;
 
+  // Sets |lofi_status_| to LOFI_STATUS_OFF.
+  void SetLoFiModeOff();
+
   // Updates |lofi_status_| based on the arguments provided and the current
   // value of |lofi_status_|.
   // |network_quality_estimator| may be NULL.
@@ -277,8 +280,7 @@
                            TestMaybeDisableIfVPNTrialDisabled);
   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest,
                            TestMaybeDisableIfVPNTrialEnabled);
-  FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest,
-                           PopulateAutoLoFiParams);
+  FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest, AutoLoFiParams);
 
   // NetworkChangeNotifier::IPAddressObserver:
   void OnIPAddressChanged() override;
@@ -340,7 +342,7 @@
   // |network_quality_estimator| may be NULL.
   // Virtualized for unit testing.
   virtual bool IsNetworkQualityProhibitivelySlow(
-      const net::NetworkQualityEstimator* network_quality_estimator) const;
+      const net::NetworkQualityEstimator* network_quality_estimator);
 
   // Returns true only if Lo-Fi "q=low" header should be added to the Chrome
   // Proxy header based on the value of |lofi_status|.
@@ -389,6 +391,17 @@
   // duration shorter than |auto_lofi_hysteresis_|.
   base::TimeDelta auto_lofi_hysteresis_;
 
+  // Time when the network quality was last updated.
+  base::TimeTicks network_quality_last_updated_;
+
+  // True iff the network was determined to be prohibitively slow when the
+  // network quality was last updated (most recent main frame request).
+  bool network_prohibitively_slow_;
+
+  // Set to the connection type reported by NetworkChangeNotifier when the
+  // network quality was last updated (most recent main frame request).
+  net::NetworkChangeNotifier::ConnectionType connection_type_;
+
   // Current Lo-Fi status.
   // The value changes only on main frame load.
   LoFiStatus lofi_status_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
index 51d50f28..97f4f2b4 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -9,7 +9,6 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/command_line.h"
 #include "base/json/json_writer.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -51,9 +50,6 @@
 const char kUMAConfigServiceFetchLatency[] =
     "DataReductionProxy.ConfigService.FetchLatency";
 
-// Default URL for retrieving the Data Reduction Proxy configuration.
-const char kClientConfigURL[] = "";
-
 // Used in all Data Reduction Proxy URLs to specify API Key.
 const char kApiKeyName[] = "key";
 
@@ -118,23 +114,6 @@
   return kDefaultBackoffPolicy;
 }
 
-// static
-GURL DataReductionProxyConfigServiceClient::GetConfigServiceURL(
-    const base::CommandLine& command_line) {
-  if (!command_line.HasSwitch(switches::kDataReductionProxyConfigURL))
-    return GURL(kClientConfigURL);
-
-  std::string value(
-      command_line.GetSwitchValueASCII(switches::kDataReductionProxyConfigURL));
-  GURL result(value);
-  if (result.is_valid())
-    return result;
-
-  LOG(WARNING) << "The following client config URL specified at the "
-               << "command-line is invalid: " << value;
-  return GURL(kClientConfigURL);
-}
-
 DataReductionProxyConfigServiceClient::DataReductionProxyConfigServiceClient(
     scoped_ptr<DataReductionProxyParams> params,
     const net::BackoffEntry::Policy& backoff_policy,
@@ -152,8 +131,8 @@
       net_log_(net_log),
       config_storer_(config_storer),
       backoff_entry_(&backoff_policy),
-      config_service_url_(AddApiKeyToUrl(
-          GetConfigServiceURL(*base::CommandLine::ForCurrentProcess()))),
+      config_service_url_(
+          AddApiKeyToUrl(DataReductionProxyParams::GetConfigServiceURL())),
       use_local_config_(!config_service_url_.is_valid()),
       remote_config_applied_(false),
       url_request_context_getter_(nullptr),
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
index 62612276..8e0441c 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h
@@ -20,10 +20,6 @@
 #include "net/url_request/url_fetcher_delegate.h"
 #include "url/gurl.h"
 
-namespace base {
-class CommandLine;
-}
-
 namespace net {
 class HostPortPair;
 class HttpResponseHeaders;
@@ -55,10 +51,6 @@
     : public net::NetworkChangeNotifier::IPAddressObserver,
       public net::URLFetcherDelegate {
  public:
-  // Returns the URL from which the Data Reduction Proxy configuration should
-  // be retrieved.
-  static GURL GetConfigServiceURL(const base::CommandLine& command_line);
-
   // The caller must ensure that all parameters remain alive for the lifetime of
   // the |DataReductionProxyConfigClient|, with the exception of |params|
   // which this instance will own.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
index e9fc3d1f..0e952d7d 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -4,11 +4,13 @@
 
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.h"
 
+#include <map>
 #include <string>
 #include <vector>
 
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/metrics/field_trial.h"
 #include "base/time/tick_clock.h"
 #include "base/values.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
@@ -20,6 +22,7 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
 #include "components/data_reduction_proxy/proto/client_config.pb.h"
+#include "components/variations/variations_associated_data.h"
 #include "net/http/http_response_headers.h"
 #include "net/proxy/proxy_server.h"
 #include "net/socket/socket_test_util.h"
@@ -68,6 +71,9 @@
 const char kSerializedFallback[] = "serialized.net:80";
 const char kSerializedSessionKey[] = "SerializedSessionKey";
 
+const char kConfigServiceFieldTrial[] = "DataReductionProxyConfigService";
+const char kConfigServiceURLParam[] = "url";
+
 }  // namespace
 
 namespace data_reduction_proxy {
@@ -326,26 +332,81 @@
 
 TEST_F(DataReductionProxyConfigServiceClientTest, GetConfigServiceURL) {
   const struct {
+    std::string trial_group_value;
+    std::string trial_url_param;
+  } variations[] = {
+      {
+       "Enabled", "http://enabled.config-service/",
+      },
+      {
+       "Disabled", "http://disabled.config-service/",
+      },
+      {
+       "EnabledOther", "http://other.config-service/",
+      },
+  };
+
+  variations::testing::ClearAllVariationParams();
+  for (const auto& variation : variations) {
+    std::map<std::string, std::string> variation_params;
+    variation_params[kConfigServiceURLParam] = variation.trial_url_param;
+    ASSERT_TRUE(variations::AssociateVariationParams(
+        kConfigServiceFieldTrial, variation.trial_group_value,
+        variation_params));
+  }
+
+  const struct {
+    std::string test_case;
     std::string flag_value;
+    std::string trial_group_value;
     GURL expected;
   } tests[] = {
       {
-       "", GURL(),
+       "Nothing set", "", "", GURL(),
       },
       {
-       "http://configservice.chrome-test.com",
-       GURL("http://configservice.chrome-test.com"),
+       "Only command line set",
+       "http://commandline.config-service/",
+       "",
+       GURL("http://commandline.config-service/"),
+      },
+      {
+       "Enabled group", "", "Enabled", GURL("http://enabled.config-service/"),
+      },
+      {
+       "Disabled group",
+       "",
+       "Disabled",
+       GURL("http://disabled.config-service/"),
+      },
+      {
+       "Alternate enabled group",
+       "",
+       "EnabledOther",
+       GURL("http://other.config-service/"),
+      },
+      {
+       "Command line precedence",
+       "http://commandline.config-service/",
+       "Enabled",
+       GURL("http://commandline.config-service/"),
       },
   };
 
   for (const auto& test : tests) {
     // Reset all flags.
     base::CommandLine::ForCurrentProcess()->InitFromArgv(0, NULL);
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kDataReductionProxyConfigURL, test.flag_value);
-    EXPECT_EQ(test.expected,
-              DataReductionProxyConfigServiceClient::GetConfigServiceURL(
-                  *base::CommandLine::ForCurrentProcess()));
+    if (!test.flag_value.empty()) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kDataReductionProxyConfigURL, test.flag_value);
+    }
+    base::FieldTrialList field_trial_list(nullptr);
+    if (!test.trial_group_value.empty()) {
+      base::FieldTrialList::CreateFieldTrial(kConfigServiceFieldTrial,
+                                             test.trial_group_value);
+    }
+    EXPECT_EQ(test.expected, DataReductionProxyParams::GetConfigServiceURL())
+        << test.test_case;
   }
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
index e5714e4..5c6ed938 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
@@ -52,7 +52,7 @@
 }
 
 bool TestDataReductionProxyConfig::IsNetworkQualityProhibitivelySlow(
-    const net::NetworkQualityEstimator* network_quality_estimator) const {
+    const net::NetworkQualityEstimator* network_quality_estimator) {
   return network_quality_prohibitively_slow_;
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
index d31ed9a..efb90708 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
@@ -80,8 +80,7 @@
   void SetNetworkProhibitivelySlow(bool network_quality_prohibitively_slow);
 
   bool IsNetworkQualityProhibitivelySlow(
-      const net::NetworkQualityEstimator* network_quality_estimator)
-      const override;
+      const net::NetworkQualityEstimator* network_quality_estimator) override;
 
   net::NetworkInterfaceList* interfaces() {
     return network_interfaces_.get();
@@ -133,7 +132,7 @@
   MOCK_METHOD2(SecureProxyCheck,
                void(const GURL& secure_proxy_check_url,
                     FetcherResponseCallback fetcher_callback));
-  MOCK_CONST_METHOD1(
+  MOCK_METHOD1(
       IsNetworkQualityProhibitivelySlow,
       bool(const net::NetworkQualityEstimator* network_quality_estimator));
   MOCK_CONST_METHOD0(IsIncludedInLoFiEnabledFieldTrial, bool());
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index b1e63166..b7c7cd13 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
+#include "base/strings/safe_sprintf.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
@@ -19,6 +20,8 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
 #include "components/variations/variations_associated_data.h"
+#include "net/base/network_quality.h"
+#include "net/base/network_quality_estimator.h"
 #include "net/http/http_status_code.h"
 #include "net/log/test_net_log.h"
 #include "net/proxy/proxy_server.h"
@@ -1155,8 +1158,9 @@
   for (size_t i = 0; i < arraysize(tests); ++i) {
     config()->ResetLoFiStatusForTest();
     if (tests[i].lofi_switch_enabled) {
-      base::CommandLine::ForCurrentProcess()->AppendSwitch(
-          data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kDataReductionProxyLoFi,
+          switches::kDataReductionProxyLoFiValueAlwaysOn);
     }
 
     EXPECT_CALL(*config(), IsIncludedInLoFiEnabledFieldTrial())
@@ -1189,8 +1193,9 @@
   for (size_t i = 0; i < arraysize(tests); ++i) {
     config()->ResetLoFiStatusForTest();
     if (tests[i].lofi_switch_enabled) {
-      base::CommandLine::ForCurrentProcess()->AppendSwitch(
-          data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kDataReductionProxyLoFi,
+          switches::kDataReductionProxyLoFiValueAlwaysOn);
     } else {
       EXPECT_CALL(*config(), IsIncludedInLoFiEnabledFieldTrial())
           .WillRepeatedly(testing::Return(true));
@@ -1213,30 +1218,95 @@
   }
 }
 
-TEST_F(DataReductionProxyConfigTest, PopulateAutoLoFiParams) {
+// Overrides net::NetworkQualityEstimator::GetEstimate() for testing purposes.
+class TestNetworkQualityEstimator : public net::NetworkQualityEstimator {
+ public:
+  TestNetworkQualityEstimator() : rtt_(base::TimeDelta()), kbps_(0) {}
+
+  ~TestNetworkQualityEstimator() override {}
+
+  net::NetworkQuality GetEstimate() const override {
+    return net::NetworkQuality(rtt_, 0.0, kbps_, 0.0);
+  }
+
+  void SetRtt(base::TimeDelta rtt) { rtt_ = rtt; }
+
+  void SetKbps(uint64_t kbps) { kbps_ = kbps; }
+
+ private:
+  base::TimeDelta rtt_;
+  uint64_t kbps_;
+};
+
+TEST_F(DataReductionProxyConfigTest, AutoLoFiParams) {
+  DataReductionProxyConfig config(nullptr, nullptr, configurator(),
+                                  event_creator());
   variations::testing::ClearAllVariationParams();
   std::map<std::string, std::string> variation_params;
-  variation_params["rtt_msec"] = "120";
+
+  int rtt_msec = 120;
+  char rtt[20];
+  base::strings::SafeSPrintf(rtt, "%d", rtt_msec);
+  variation_params["rtt_msec"] = rtt;
+
   variation_params["kbps"] = "240";
-  variation_params["hysteresis_period_seconds"] = "360";
+
+  int hysteresis_sec = 360;
+  char hysteresis[20];
+  base::strings::SafeSPrintf(hysteresis, "%d", hysteresis_sec);
+  variation_params["hysteresis_period_seconds"] = hysteresis;
+
   variation_params["spurious_field"] = "480";
 
   ASSERT_TRUE(variations::AssociateVariationParams(
       DataReductionProxyParams::GetLoFiFieldTrialName(), "Enabled",
       variation_params));
-  EXPECT_CALL(*config(), IsIncludedInLoFiEnabledFieldTrial())
-      .WillRepeatedly(testing::Return(true));
 
   base::FieldTrialList field_trial_list(nullptr);
   base::FieldTrialList::CreateFieldTrial(
       DataReductionProxyParams::GetLoFiFieldTrialName(), "Enabled");
 
-  config()->PopulateAutoLoFiParams();
+  config.PopulateAutoLoFiParams();
 
-  EXPECT_EQ(config()->auto_lofi_minimum_rtt_,
-            base::TimeDelta::FromMilliseconds(120));
-  EXPECT_EQ(config()->auto_lofi_maximum_kbps_, 240U);
-  EXPECT_EQ(config()->auto_lofi_hysteresis_, base::TimeDelta::FromSeconds(360));
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(rtt_msec),
+            config.auto_lofi_minimum_rtt_);
+  EXPECT_EQ(240U, config.auto_lofi_maximum_kbps_);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(hysteresis_sec),
+            config.auto_lofi_hysteresis_);
+
+  TestNetworkQualityEstimator test_network_quality_estimator;
+
+  // RTT is higher than threshold. Network is slow.
+  test_network_quality_estimator.SetRtt(
+      base::TimeDelta::FromMilliseconds(rtt_msec + 1));
+  EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
+      &test_network_quality_estimator));
+
+  // Network quality improved. RTT is lower than the threshold. However,
+  // network should still be marked as slow because of hysteresis.
+  test_network_quality_estimator.SetRtt(
+      base::TimeDelta::FromMilliseconds(rtt_msec - 1));
+  EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
+      &test_network_quality_estimator));
+
+  // Change the last update time to be older than the hysteresis duration.
+  // Checking network quality afterwards should show that network is no longer
+  // slow.
+  config.network_quality_last_updated_ =
+      base::TimeTicks::Now() - base::TimeDelta::FromSeconds(hysteresis_sec + 1);
+  EXPECT_FALSE(config.IsNetworkQualityProhibitivelySlow(
+      &test_network_quality_estimator));
+
+  // Changing the RTT has no effect because of hysteresis.
+  test_network_quality_estimator.SetRtt(
+      base::TimeDelta::FromMilliseconds(rtt_msec + 1));
+  EXPECT_FALSE(config.IsNetworkQualityProhibitivelySlow(
+      &test_network_quality_estimator));
+
+  // Change in connection type changes the network quality despite hysteresis.
+  config.connection_type_ = net::NetworkChangeNotifier::CONNECTION_WIFI;
+  EXPECT_TRUE(config.IsNetworkQualityProhibitivelySlow(
+      &test_network_quality_estimator));
 }
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
index fbacf8f..9f190a72 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
@@ -476,6 +476,48 @@
   EXPECT_EQ(std::vector<GURL>(1, GURL("http://foo.com")), request->url_chain());
 }
 
+TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectChainToHttps) {
+  // First, a redirect is successfully received through the Data Reduction
+  // Proxy. HSTS is forced for play.google.com and prebaked into Chrome, so
+  // http://play.google.com will automatically be redirected to
+  // https://play.google.com. See net/http/transport_security_state_static.json.
+  MockRead first_redirect_reads[] = {
+      MockRead(
+          "HTTP/1.1 302 Found\r\n"
+          "Location: http://play.google.com\r\n"
+          "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n"),
+      MockRead(""),
+      MockRead(net::SYNCHRONOUS, net::OK),
+  };
+  net::StaticSocketDataProvider first_redirect_socket(
+      first_redirect_reads, arraysize(first_redirect_reads), nullptr, 0);
+  mock_socket_factory()->AddSocketDataProvider(&first_redirect_socket);
+
+  // Receive the response for https://play.google.com.
+  MockRead https_response_reads[] = {
+      MockRead("HTTP/1.1 200 OK\r\n\r\n"),
+      MockRead(kBody.c_str()),
+      MockRead(net::SYNCHRONOUS, net::OK),
+  };
+  net::StaticSocketDataProvider https_response_socket(
+      https_response_reads, arraysize(https_response_reads), nullptr, 0);
+  mock_socket_factory()->AddSocketDataProvider(&https_response_socket);
+  net::SSLSocketDataProvider https_response_ssl_socket(net::SYNCHRONOUS,
+                                                       net::OK);
+  mock_socket_factory()->AddSSLSocketDataProvider(&https_response_ssl_socket);
+
+  scoped_ptr<net::URLRequest> request =
+      CreateAndExecuteRequest(GURL("http://music.google.com"));
+  EXPECT_FALSE(delegate().request_failed());
+  EXPECT_EQ(kBody, delegate().data_received());
+
+  std::vector<GURL> expected_url_chain;
+  expected_url_chain.push_back(GURL("http://music.google.com"));
+  expected_url_chain.push_back(GURL("http://play.google.com"));
+  expected_url_chain.push_back(GURL("https://play.google.com"));
+  EXPECT_EQ(expected_url_chain, request->url_chain());
+}
+
 }  // namespace
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
index 0c21098..f9b68cc 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -265,6 +265,10 @@
     config_client_->ApplySerializedConfig(serialized_config);
 }
 
+void DataReductionProxyIOData::SetLoFiModeOff() {
+  config_->SetLoFiModeOff();
+}
+
 void DataReductionProxyIOData::UpdateContentLengths(
     int64 received_content_length,
     int64 original_content_length,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
index d63529f8..6bfdee87 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
@@ -88,6 +88,9 @@
   // Applies a serialized Data Reduction Proxy configuration.
   void SetDataReductionProxyConfiguration(const std::string& serialized_config);
 
+  // Sets Lo-Fi mode off in |config_|.
+  void SetLoFiModeOff();
+
   // Bridge methods to safely call to the UI thread objects.
   void UpdateContentLengths(int64 received_content_length,
                             int64 original_content_length,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index 164f082..89bb199e5 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -175,15 +175,14 @@
     const net::ProxyInfo& proxy_info,
     net::HttpRequestHeaders* headers) {
   DCHECK(data_reduction_proxy_config_);
-  DCHECK(request);
 
   // TODO(bengr): Investigate a better approach to update the network
   // quality so that state of Lo-Fi is stored per page.
   net::NetworkQualityEstimator* network_quality_estimator = nullptr;
-  if (request->context())
+  if (request && request->context())
     network_quality_estimator = request->context()->network_quality_estimator();
 
-  if (request->load_flags() & net::LOAD_MAIN_FRAME) {
+  if (request && ((request->load_flags() & net::LOAD_MAIN_FRAME) != 0)) {
     data_reduction_proxy_config_->UpdateLoFiStatusOnMainFrameRequest(
         ((request->load_flags() & net::LOAD_BYPASS_CACHE) != 0),
         network_quality_estimator);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index c016af2..c6a60a0 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -226,8 +226,9 @@
 
   for (size_t i = 0; i < arraysize(tests); ++i) {
     if (tests[i].lofi_switch_enabled) {
-      base::CommandLine::ForCurrentProcess()->AppendSwitch(
-          data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kDataReductionProxyLoFi,
+          switches::kDataReductionProxyLoFiValueAlwaysOn);
     }
     config()->SetIncludedInLoFiEnabledFieldTrial(tests[i].auto_lofi_enabled);
     config()->SetNetworkProhibitivelySlow(tests[i].auto_lofi_enabled);
@@ -449,8 +450,9 @@
     config()->SetNetworkProhibitivelySlow(tests[i].auto_lofi_enabled);
 
     if (tests[i].lofi_enabled_through_switch) {
-      base::CommandLine::ForCurrentProcess()->AppendSwitch(
-          data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kDataReductionProxyLoFi,
+          switches::kDataReductionProxyLoFiValueAlwaysOn);
     }
 
     config()->UpdateLoFiStatusOnMainFrameRequest(false, nullptr);
@@ -627,4 +629,24 @@
   EXPECT_FALSE(other_proxy_info.is_direct());
 }
 
+// Notify network delegate with a NULL request.
+TEST_F(DataReductionProxyNetworkDelegateTest, NullRequest) {
+  net::HttpRequestHeaders headers;
+  net::ProxyInfo data_reduction_proxy_info;
+  std::string data_reduction_proxy;
+  base::TrimString(params()->DefaultOrigin(), "/", &data_reduction_proxy);
+  data_reduction_proxy_info.UsePacString(
+      "PROXY " +
+      net::ProxyServer::FromURI(params()->DefaultOrigin(),
+                                net::ProxyServer::SCHEME_HTTP)
+          .host_port_pair()
+          .ToString() +
+      "; DIRECT");
+  EXPECT_FALSE(data_reduction_proxy_info.is_empty());
+
+  data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders(
+      nullptr, data_reduction_proxy_info, &headers);
+  EXPECT_TRUE(headers.HasHeader(kChromeProxyHeader));
+}
+
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
index 5c2acf2..d7210455 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
@@ -59,6 +59,9 @@
       prefs::kDailyOriginalContentLengthViaDataReductionProxy);
   registry->RegisterListPref(prefs::kDailyContentLengthViaDataReductionProxy);
   registry->RegisterInt64Pref(prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
+  registry->RegisterIntegerPref(prefs::kLoFiImplicitOptOutEpoch, 0);
+  registry->RegisterIntegerPref(prefs::kLoFiLoadImagesPerSession, 0);
+  registry->RegisterIntegerPref(prefs::kLoFiConsecutiveSessionDisables, 0);
   registry->RegisterInt64Pref(prefs::kSimulatedConfigRetrieveTime, 0L);
   registry->RegisterStringPref(prefs::kDataReductionProxyConfig, std::string());
 }
@@ -107,6 +110,9 @@
       prefs::kDailyContentLengthViaDataReductionProxy);
   registry->RegisterInt64Pref(
       prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
+  registry->RegisterIntegerPref(prefs::kLoFiImplicitOptOutEpoch, 0);
+  registry->RegisterIntegerPref(prefs::kLoFiLoadImagesPerSession, 0);
+  registry->RegisterIntegerPref(prefs::kLoFiConsecutiveSessionDisables, 0);
   registry->RegisterInt64Pref(prefs::kSimulatedConfigRetrieveTime, 0L);
   registry->RegisterStringPref(prefs::kDataReductionProxyConfig, std::string());
 }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
index 6ddc62a..37698c3 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
@@ -28,7 +28,7 @@
 #include "net/proxy/proxy_server.h"
 #include "net/url_request/url_request.h"
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_IOS)
 #include "google_apis/google_api_keys.h"
 #endif
 
@@ -344,9 +344,9 @@
       *base::CommandLine::ForCurrentProcess();
   std::string key =
     command_line.GetSwitchValueASCII(switches::kDataReductionProxyKey);
-// Android and iOS get the default key from a preprocessor constant. All other
+// iOS gets the default key from a preprocessor constant. All other
 // platforms get the key from google_apis
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_IOS)
 #if defined(SPDY_PROXY_AUTH_VALUE)
   if (key.empty())
     key = SPDY_PROXY_AUTH_VALUE;
@@ -355,7 +355,7 @@
   if (key.empty()) {
     key = google_apis::GetSpdyProxyAuthValue();
   }
-#endif  // defined(OS_ANDROID) || defined(OS_IOS)
+#endif  // defined(OS_IOS)
   return key;
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
index 4b26de7..a6b2f69 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
@@ -293,8 +293,9 @@
 
   test_context_->config()->ResetLoFiStatusForTest();
   // Add the LoFi command line switch.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kDataReductionProxyLoFi,
+      switches::kDataReductionProxyLoFiValueAlwaysOn);
 
   SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(),
                         kClientStr, std::string(), std::string(), "low",
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
index 8490a55c..5778286 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
@@ -13,6 +13,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service_observer.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 
 namespace data_reduction_proxy {
@@ -57,6 +58,8 @@
               io_data_, config_value));
     }
   }
+
+  InitializeLoFiPrefs();
 }
 
 void DataReductionProxyService::Shutdown() {
@@ -125,6 +128,65 @@
   settings_->SetLoFiModeActiveOnMainFrame(lo_fi_mode_active);
 }
 
+void DataReductionProxyService::SetLoFiModeOff() {
+  DCHECK(CalledOnValidThread());
+  if (io_task_runner_->BelongsToCurrentThread()) {
+    io_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&DataReductionProxyIOData::SetLoFiModeOff, io_data_));
+    return;
+  }
+  io_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&DataReductionProxyIOData::SetLoFiModeOff, io_data_));
+}
+
+void DataReductionProxyService::InitializeLoFiPrefs() {
+  DCHECK(CalledOnValidThread());
+  if (prefs_) {
+    int lo_fi_user_requests_for_images_per_session =
+        DataReductionProxyParams::GetFieldTrialParameterAsInteger(
+            DataReductionProxyParams::GetLoFiFieldTrialName(),
+            "load_images_requests_per_session", 3, 0);
+
+    int lo_fi_implicit_opt_out_epoch =
+        DataReductionProxyParams::GetFieldTrialParameterAsInteger(
+            DataReductionProxyParams::GetLoFiFieldTrialName(),
+            "implicit_opt_out_epoch", 0, 0);
+
+    int lo_fi_consecutive_session_disables =
+        DataReductionProxyParams::GetFieldTrialParameterAsInteger(
+            DataReductionProxyParams::GetLoFiFieldTrialName(),
+            "consecutive_session_disables", 3, 0);
+
+    if (prefs_->GetInteger(prefs::kLoFiImplicitOptOutEpoch) <
+        lo_fi_implicit_opt_out_epoch) {
+      // We have a new implicit opt out epoch, reset the consecutive session
+      // disables count so that Lo-Fi can be enabled again.
+      prefs_->SetInteger(prefs::kLoFiConsecutiveSessionDisables, 0);
+      prefs_->SetInteger(prefs::kLoFiImplicitOptOutEpoch,
+                         lo_fi_implicit_opt_out_epoch);
+      settings_->RecordLoFiImplicitOptOutAction(
+          LO_FI_OPT_OUT_ACTION_NEXT_EPOCH);
+    } else if (!DataReductionProxyParams::IsLoFiAlwaysOnViaFlags() &&
+               (prefs_->GetInteger(prefs::kLoFiConsecutiveSessionDisables) >=
+                lo_fi_consecutive_session_disables)) {
+      // If Lo-Fi isn't always on and and the number of
+      // |consecutive_session_disables| has been met, turn Lo-Fi off for this
+      // session.
+      SetLoFiModeOff();
+    } else if (prefs_->GetInteger(prefs::kLoFiLoadImagesPerSession) <
+               lo_fi_user_requests_for_images_per_session) {
+      // If the last session didn't have
+      // |lo_fi_user_requests_for_images_per_session| and the number of
+      // |consecutive_session_disables| hasn't been met, reset the consecutive
+      // sessions count.
+      prefs_->SetInteger(prefs::kLoFiConsecutiveSessionDisables, 0);
+    }
+    prefs_->SetInteger(prefs::kLoFiLoadImagesPerSession, 0);
+  }
+}
+
 void DataReductionProxyService::SetInt64Pref(const std::string& pref_path,
                                              int64 value) {
   if (prefs_)
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
index 9ef540e..b4eff3b 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_SERVICE_H_
 #define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_SERVICE_H_
 
+#include <string>
+
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -95,6 +97,12 @@
   // DataReductionProxySettings.
   void SetLoFiModeActiveOnMainFrame(bool lo_fi_mode_active);
 
+  // Sets Lo-Fi mode off on the IO thread.
+  void SetLoFiModeOff();
+
+  // Initializes the Lo-Fi implicit opt out prefs.
+  void InitializeLoFiPrefs();
+
   // Stores an int64 value in |prefs_|.
   void SetInt64Pref(const std::string& pref_path, int64 value);
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
index a53b660..67f9ad4 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
@@ -23,6 +23,10 @@
 const char kUMAProxyStartupStateHistogram[] =
     "DataReductionProxy.StartupState";
 
+// Key of the UMA DataReductionProxy.LoFi.ImplicitOptOutAction histogram.
+const char kUMALoFiImplicitOptOutAction[] =
+    "DataReductionProxy.LoFi.ImplicitOptOutAction";
+
 }  // namespace
 
 namespace data_reduction_proxy {
@@ -40,6 +44,14 @@
       lo_fi_show_image_requested_(false),
       prefs_(NULL),
       config_(nullptr) {
+  lo_fi_user_requests_for_images_per_session_ =
+      DataReductionProxyParams::GetFieldTrialParameterAsInteger(
+          DataReductionProxyParams::GetLoFiFieldTrialName(),
+          "load_images_requests_per_session", 3, 0);
+  lo_fi_consecutive_session_disables_ =
+      DataReductionProxyParams::GetFieldTrialParameterAsInteger(
+          DataReductionProxyParams::GetLoFiFieldTrialName(),
+          "consecutive_session_disables", 3, 0);
 }
 
 DataReductionProxySettings::~DataReductionProxySettings() {
@@ -191,6 +203,26 @@
   lo_fi_show_image_requested_ = true;
 }
 
+void DataReductionProxySettings::IncrementLoFiUserRequestsForImages() {
+  if (!prefs_ || DataReductionProxyParams::IsLoFiAlwaysOnViaFlags())
+    return;
+  prefs_->SetInteger(prefs::kLoFiLoadImagesPerSession,
+                     prefs_->GetInteger(prefs::kLoFiLoadImagesPerSession) + 1);
+  if (prefs_->GetInteger(prefs::kLoFiLoadImagesPerSession) >=
+      lo_fi_user_requests_for_images_per_session_) {
+    data_reduction_proxy_service_->SetLoFiModeOff();
+    prefs_->SetInteger(
+        prefs::kLoFiConsecutiveSessionDisables,
+        prefs_->GetInteger(prefs::kLoFiConsecutiveSessionDisables) + 1);
+    RecordLoFiImplicitOptOutAction(LO_FI_OPT_OUT_ACTION_DISABLED_FOR_SESSION);
+    if (prefs_->GetInteger(prefs::kLoFiConsecutiveSessionDisables) >=
+        lo_fi_consecutive_session_disables_) {
+      RecordLoFiImplicitOptOutAction(
+          LO_FI_OPT_OUT_ACTION_DISABLED_UNTIL_NEXT_EPOCH);
+    }
+  }
+}
+
 void DataReductionProxySettings::RegisterDataReductionProxyFieldTrial() {
   register_synthetic_field_trial_.Run(
       "SyntheticDataReductionProxySetting",
@@ -288,6 +320,12 @@
                             PROXY_STARTUP_STATE_COUNT);
 }
 
+void DataReductionProxySettings::RecordLoFiImplicitOptOutAction(
+    LoFiImplicitOptOutAction action) {
+  UMA_HISTOGRAM_ENUMERATION(kUMALoFiImplicitOptOutAction, action,
+                            LO_FI_OPT_OUT_ACTION_INDEX_BOUNDARY);
+}
+
 ContentLengthList
 DataReductionProxySettings::GetDailyContentLengths(const char* pref_name) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
index 8e65315f..24590ff8 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -44,6 +44,17 @@
   PROXY_STARTUP_STATE_COUNT,
 };
 
+// Values of the UMA DataReductionProxy.LoFi.ImplicitOptOutAction histogram.
+// This enum must remain synchronized with
+// DataReductionProxyLoFiImplicitOptOutAction in
+// metrics/histograms/histograms.xml.
+enum LoFiImplicitOptOutAction {
+  LO_FI_OPT_OUT_ACTION_DISABLED_FOR_SESSION = 0,
+  LO_FI_OPT_OUT_ACTION_DISABLED_UNTIL_NEXT_EPOCH,
+  LO_FI_OPT_OUT_ACTION_NEXT_EPOCH,
+  LO_FI_OPT_OUT_ACTION_INDEX_BOUNDARY,
+};
+
 // Central point for configuring the data reduction proxy.
 // This object lives on the UI thread and all of its methods are expected to
 // be called from there.
@@ -115,6 +126,15 @@
   // context menu request has been made since the last main frame request.
   void SetLoFiShowImageRequested();
 
+  // Counts the number of requests to reload the page with images from the Lo-Fi
+  // snackbar. If the user requests the page with images a certain number of
+  // times, then Lo-Fi is disabled for the remainder of the session.
+  void IncrementLoFiUserRequestsForImages();
+
+  // Records UMA for Lo-Fi implicit opt out actions.
+  void RecordLoFiImplicitOptOutAction(
+      data_reduction_proxy::LoFiImplicitOptOutAction action);
+
   // Returns the time in microseconds that the last update was made to the
   // daily original and received content lengths.
   int64 GetDataReductionLastUpdateTime();
@@ -217,6 +237,12 @@
                            TestInitDataReductionProxyOff);
   FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
                            CheckInitMetricsWhenNotAllowed);
+  FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+                           TestLoFiImplicitOptOutClicksPerSession);
+  FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+                           TestLoFiImplicitOptOutConsecutiveSessions);
+  FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
+                           TestLoFiImplicitOptOutHistograms);
 
   // Override of DataReductionProxyService::Observer.
   void OnServiceInitialized() override;
@@ -265,6 +291,16 @@
   // last main frame request.
   bool lo_fi_show_image_requested_;
 
+  // The number of requests to reload the page with images from the Lo-Fi
+  // snackbar until Lo-Fi is disabled for the remainder of the
+  // session.
+  int lo_fi_user_requests_for_images_per_session_;
+
+  // The number of consecutive sessions where Lo-Fi was disabled for
+  // Lo-Fi to be disabled until the next implicit opt out epoch, which may be in
+  // a later session, or never.
+  int lo_fi_consecutive_session_disables_;
+
   BooleanPrefMember spdy_proxy_auth_enabled_;
   BooleanPrefMember data_reduction_proxy_alternative_enabled_;
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
index 8c9d34e..60686d2 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/md5.h"
 #include "base/metrics/field_trial.h"
+#include "base/test/histogram_tester.h"
 #include "base/test/mock_entropy_provider.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
@@ -336,6 +337,159 @@
   CheckDataReductionProxyLoFiSyntheticTrial(false);
 }
 
+TEST_F(DataReductionProxySettingsTest, TestLoFiImplicitOptOutClicksPerSession) {
+  test_context_->config()->ResetLoFiStatusForTest();
+  EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
+                   prefs::kLoFiLoadImagesPerSession));
+  EXPECT_EQ(LoFiStatus::LOFI_STATUS_TEMPORARILY_OFF,
+            test_context_->config()->GetLoFiStatus());
+
+  // Click "Show images" |lo_fi_user_requests_for_images_per_session_| times.
+  for (int i = 1; i <= settings_->lo_fi_user_requests_for_images_per_session_;
+       ++i) {
+    settings_->IncrementLoFiUserRequestsForImages();
+    EXPECT_EQ(i, test_context_->pref_service()->GetInteger(
+                     prefs::kLoFiLoadImagesPerSession));
+  }
+
+  test_context_->RunUntilIdle();
+  EXPECT_EQ(1, test_context_->pref_service()->GetInteger(
+                   prefs::kLoFiConsecutiveSessionDisables));
+  EXPECT_EQ(LoFiStatus::LOFI_STATUS_OFF,
+            test_context_->config()->GetLoFiStatus());
+
+  // Reset the opt out pref values and config Lo-Fi status as if we're starting
+  // a new session.
+  test_context_->config()->ResetLoFiStatusForTest();
+  settings_->data_reduction_proxy_service_->InitializeLoFiPrefs();
+  EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
+                   prefs::kLoFiLoadImagesPerSession));
+  EXPECT_EQ(LoFiStatus::LOFI_STATUS_TEMPORARILY_OFF,
+            test_context_->config()->GetLoFiStatus());
+
+  // Have a session that doesn't have
+  // |lo_fi_user_requests_for_images_per_session_| so
+  // kLoFiConsecutiveSessionDisables resets.
+  for (int i = 1;
+       i <= settings_->lo_fi_user_requests_for_images_per_session_ - 1; ++i) {
+    settings_->IncrementLoFiUserRequestsForImages();
+    EXPECT_EQ(i, test_context_->pref_service()->GetInteger(
+                     prefs::kLoFiLoadImagesPerSession));
+  }
+
+  test_context_->RunUntilIdle();
+  // Still should have only one consecutive session disable and Lo-Fi status
+  // shouldn't have been set to off.
+  EXPECT_EQ(1, test_context_->pref_service()->GetInteger(
+                   prefs::kLoFiConsecutiveSessionDisables));
+  EXPECT_EQ(LoFiStatus::LOFI_STATUS_TEMPORARILY_OFF,
+            test_context_->config()->GetLoFiStatus());
+
+  // Start a new session. The consecutive session count should now be reset to
+  // zero.
+  test_context_->config()->ResetLoFiStatusForTest();
+  settings_->data_reduction_proxy_service_->InitializeLoFiPrefs();
+  EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
+                   prefs::kLoFiConsecutiveSessionDisables));
+}
+
+TEST_F(DataReductionProxySettingsTest,
+       TestLoFiImplicitOptOutConsecutiveSessions) {
+  test_context_->config()->ResetLoFiStatusForTest();
+  EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
+                   prefs::kLoFiLoadImagesPerSession));
+  EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
+                   prefs::kLoFiConsecutiveSessionDisables));
+  EXPECT_EQ(LoFiStatus::LOFI_STATUS_TEMPORARILY_OFF,
+            test_context_->config()->GetLoFiStatus());
+
+  // Disable Lo-Fi for |lo_fi_consecutive_session_disables_|.
+  for (int i = 1; i <= settings_->lo_fi_consecutive_session_disables_; ++i) {
+    // Start a new session.
+    test_context_->config()->ResetLoFiStatusForTest();
+    settings_->data_reduction_proxy_service_->InitializeLoFiPrefs();
+    EXPECT_EQ(LoFiStatus::LOFI_STATUS_TEMPORARILY_OFF,
+              test_context_->config()->GetLoFiStatus());
+
+    // Click "Show images" |lo_fi_user_requests_for_images_per_session_| times
+    // for each session.
+    for (int j = 1; j <= settings_->lo_fi_user_requests_for_images_per_session_;
+         ++j) {
+      settings_->IncrementLoFiUserRequestsForImages();
+      EXPECT_EQ(j, test_context_->pref_service()->GetInteger(
+                       prefs::kLoFiLoadImagesPerSession));
+    }
+
+    test_context_->RunUntilIdle();
+    EXPECT_EQ(i, test_context_->pref_service()->GetInteger(
+                     prefs::kLoFiConsecutiveSessionDisables));
+    EXPECT_EQ(LoFiStatus::LOFI_STATUS_OFF,
+              test_context_->config()->GetLoFiStatus());
+  }
+
+  // Start a new session. Lo-Fi should be set off.
+  test_context_->config()->ResetLoFiStatusForTest();
+  settings_->data_reduction_proxy_service_->InitializeLoFiPrefs();
+  test_context_->RunUntilIdle();
+  EXPECT_EQ(3, test_context_->pref_service()->GetInteger(
+                   prefs::kLoFiConsecutiveSessionDisables));
+  EXPECT_EQ(LoFiStatus::LOFI_STATUS_OFF,
+            test_context_->config()->GetLoFiStatus());
+
+  // Set the implicit opt out epoch to -1 so that the default value of zero will
+  // be an increase and the opt out status will be reset.
+  test_context_->pref_service()->SetInteger(prefs::kLoFiImplicitOptOutEpoch,
+                                            -1);
+
+  // Start a new session. Lo-Fi should be set on again.
+  test_context_->config()->ResetLoFiStatusForTest();
+  settings_->data_reduction_proxy_service_->InitializeLoFiPrefs();
+  test_context_->RunUntilIdle();
+  EXPECT_EQ(0, test_context_->pref_service()->GetInteger(
+                   prefs::kLoFiConsecutiveSessionDisables));
+  EXPECT_EQ(LoFiStatus::LOFI_STATUS_TEMPORARILY_OFF,
+            test_context_->config()->GetLoFiStatus());
+}
+
+TEST_F(DataReductionProxySettingsTest, TestLoFiImplicitOptOutHistograms) {
+  const char kUMALoFiImplicitOptOutAction[] =
+      "DataReductionProxy.LoFi.ImplicitOptOutAction";
+  base::HistogramTester histogram_tester;
+
+  // Disable Lo-Fi for |lo_fi_consecutive_session_disables_|.
+  for (int i = 1; i <= settings_->lo_fi_consecutive_session_disables_; ++i) {
+    // Start a new session.
+    test_context_->config()->ResetLoFiStatusForTest();
+    settings_->data_reduction_proxy_service_->InitializeLoFiPrefs();
+
+    // Click "Show images" |lo_fi_show_images_clicks_per_session_| times for
+    // each session.
+    for (int j = 1; j <= settings_->lo_fi_user_requests_for_images_per_session_;
+         ++j) {
+      settings_->IncrementLoFiUserRequestsForImages();
+    }
+
+    test_context_->RunUntilIdle();
+    histogram_tester.ExpectBucketCount(
+        kUMALoFiImplicitOptOutAction, LO_FI_OPT_OUT_ACTION_DISABLED_FOR_SESSION,
+        i);
+  }
+
+  histogram_tester.ExpectBucketCount(
+      kUMALoFiImplicitOptOutAction,
+      LO_FI_OPT_OUT_ACTION_DISABLED_UNTIL_NEXT_EPOCH, 1);
+
+  // Set the implicit opt out epoch to -1 so that the default value of zero
+  // will be an increase and implicit opt out will be reset.
+  test_context_->pref_service()->SetInteger(prefs::kLoFiImplicitOptOutEpoch,
+                                            -1);
+  test_context_->config()->ResetLoFiStatusForTest();
+  settings_->data_reduction_proxy_service_->InitializeLoFiPrefs();
+  test_context_->RunUntilIdle();
+  histogram_tester.ExpectBucketCount(kUMALoFiImplicitOptOutAction,
+                                     LO_FI_OPT_OUT_ACTION_NEXT_EPOCH, 1);
+}
+
 TEST_F(DataReductionProxySettingsTest, TestGetDailyContentLengths) {
   ContentLengthList result =
       settings_->GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
index 35c93f51..b423275 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -74,9 +74,8 @@
 
   while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
     if (value.size() > prefix.size()) {
-      if (LowerCaseEqualsASCII(value.begin(),
-                               value.begin() + prefix.size(),
-                               prefix.c_str())) {
+      if (base::LowerCaseEqualsASCII(
+              value.begin(), value.begin() + prefix.size(), prefix.c_str())) {
         if (action_value)
           *action_value = value.substr(prefix.size());
         return true;
@@ -99,9 +98,8 @@
 
   while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
     if (value.size() > prefix.size()) {
-      if (LowerCaseEqualsASCII(value.begin(),
-                               value.begin() + prefix.size(),
-                               prefix.c_str())) {
+      if (base::LowerCaseEqualsASCII(
+              value.begin(), value.begin() + prefix.size(), prefix.c_str())) {
         int64 seconds;
         if (!base::StringToInt64(
                 StringPiece(value.begin() + prefix.size(), value.end()),
@@ -305,10 +303,10 @@
   void* iter = NULL;
   while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
     if (value.size() > chrome_proxy_fingerprint_prefix.size()) {
-      if (LowerCaseEqualsASCII(
-          value.begin(),
-          value.begin() + chrome_proxy_fingerprint_prefix.size(),
-          chrome_proxy_fingerprint_prefix.c_str())) {
+      if (base::LowerCaseEqualsASCII(
+              value.begin(),
+              value.begin() + chrome_proxy_fingerprint_prefix.size(),
+              chrome_proxy_fingerprint_prefix.c_str())) {
         continue;
       }
     }
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index 612ed38..4f269a3 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -10,10 +10,12 @@
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/field_trial.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/values.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_client_config_parser.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
+#include "components/variations/variations_associated_data.h"
 #include "net/base/host_port_pair.h"
 #include "net/proxy/proxy_server.h"
 #include "url/url_constants.h"
@@ -47,6 +49,12 @@
 
 const char kLoFiFieldTrial[] = "DataReductionProxyLoFi";
 
+const char kConfigServiceFieldTrial[] = "DataReductionProxyConfigService";
+const char kConfigServiceURLParam[] = "url";
+
+// Default URL for retrieving the Data Reduction Proxy configuration.
+const char kClientConfigURL[] = "";
+
 const char kConfigScheme[] = "scheme";
 const char kConfigHost[] = "host";
 const char kConfigPort[] = "port";
@@ -111,9 +119,30 @@
 }
 
 // static
-bool DataReductionProxyParams::IsLoFiEnabledThroughSwitch() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+bool DataReductionProxyParams::IsLoFiAlwaysOnViaFlags() {
+  const std::string& lo_fi_value =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          data_reduction_proxy::switches::kDataReductionProxyLoFi);
+  return lo_fi_value ==
+         data_reduction_proxy::switches::kDataReductionProxyLoFiValueAlwaysOn;
+}
+
+// static
+bool DataReductionProxyParams::IsLoFiCellularOnlyViaFlags() {
+  const std::string& lo_fi_value =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          data_reduction_proxy::switches::kDataReductionProxyLoFi);
+  return lo_fi_value == data_reduction_proxy::switches::
+                            kDataReductionProxyLoFiValueCellularOnly;
+}
+
+// static
+bool DataReductionProxyParams::IsLoFiDisabledViaFlags() {
+  const std::string& lo_fi_value =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          data_reduction_proxy::switches::kDataReductionProxyLoFi);
+  return lo_fi_value ==
+         data_reduction_proxy::switches::kDataReductionProxyLoFiValueDisabled;
 }
 
 //static
@@ -149,8 +178,39 @@
 
 // static
 bool DataReductionProxyParams::IsConfigClientEnabled() {
+  std::string group_value =
+      base::FieldTrialList::FindFullName(kConfigServiceFieldTrial);
+  base::StringPiece group = group_value;
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      data_reduction_proxy::switches::kEnableDataReductionProxyConfigClient);
+             data_reduction_proxy::switches::
+                 kEnableDataReductionProxyConfigClient) ||
+         group.starts_with(kEnabled);
+}
+
+// static
+GURL DataReductionProxyParams::GetConfigServiceURL() {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  std::string url;
+  if (command_line->HasSwitch(switches::kDataReductionProxyConfigURL)) {
+    url = command_line->GetSwitchValueASCII(
+        switches::kDataReductionProxyConfigURL);
+  }
+
+  if (url.empty()) {
+    url = variations::GetVariationParamValue(kConfigServiceFieldTrial,
+                                             kConfigServiceURLParam);
+  }
+
+  if (url.empty())
+    return GURL(kClientConfigURL);
+
+  GURL result(url);
+  if (result.is_valid())
+    return result;
+
+  LOG(WARNING) << "The following client config URL specified at the "
+               << "command-line or variation is invalid: " << url;
+  return GURL(kClientConfigURL);
 }
 
 // static
@@ -173,6 +233,24 @@
   return true;
 }
 
+// static
+int DataReductionProxyParams::GetFieldTrialParameterAsInteger(
+    const std::string& group,
+    const std::string& param_name,
+    int default_value,
+    int min_value) {
+  DCHECK(default_value >= min_value);
+  std::string param_value =
+      variations::GetVariationParamValue(group, param_name);
+  int value;
+  if (param_value.empty() || !base::StringToInt(param_value, &value) ||
+      value < min_value) {
+    return default_value;
+  }
+
+  return value;
+}
+
 void DataReductionProxyParams::EnableQuic(bool enable) {
   quic_enabled_ = enable;
   DCHECK(!quic_enabled_ || IsIncludedInQuicFieldTrial());
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
index 111abe04..9ae7ef4 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -97,8 +97,16 @@
       const char* build_fingerprint);
 
   // Returns true if this client has the command line switch to enable Lo-Fi
+  // mode always on.
+  static bool IsLoFiAlwaysOnViaFlags();
+
+  // Returns true if this client has the command line switch to enable Lo-Fi
+  // mode only on cellular connections.
+  static bool IsLoFiCellularOnlyViaFlags();
+
+  // Returns true if this client has the command line switch to disable Lo-Fi
   // mode.
-  static bool IsLoFiEnabledThroughSwitch();
+  static bool IsLoFiDisabledViaFlags();
 
   // Returns true if this client has the command line switch to show
   // interstitials for data reduction proxy bypasses.
@@ -124,6 +132,10 @@
   // Returns true if the Data Reduction Proxy config client should be used.
   static bool IsConfigClientEnabled();
 
+  // If the Data Reduction Proxy config client is being used, the URL for the
+  // Data Reduction Proxy config service.
+  static GURL GetConfigServiceURL();
+
   // Returns true if the Data Reduction Proxy is forced to be enabled from the
   // command line.
   static bool ShouldForceEnableDataReductionProxy();
@@ -132,6 +144,14 @@
   // secure proxy check fails.
   static bool ShouldUseSecureProxyByDefault();
 
+  // Retrieves the int stored in |param_name| from the field trial group
+  // |group|. If the value is not present, cannot be parsed, or is less than
+  // |min_value|, returns |default_value|.
+  static int GetFieldTrialParameterAsInteger(const std::string& group,
+                                             const std::string& param_name,
+                                             int default_value,
+                                             int min_value);
+
   // Constructs configuration parameters. If |kAllowed|, then the standard
   // data reduction proxy configuration is allowed to be used. If
   // |kfallbackAllowed| a fallback proxy can be used if the primary proxy is
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
index 467e3be7..1de54cf 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 
 #include <map>
+#include <string>
 #include <vector>
 
 #include "base/command_line.h"
@@ -16,6 +17,10 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+const char kConfigServiceFieldTrial[] = "DataReductionProxyConfigService";
+}
+
 namespace data_reduction_proxy {
 class DataReductionProxyParamsTest : public testing::Test {
  public:
@@ -576,6 +581,53 @@
       "google/hammerhead/hammerhead:5.0/LRX210/1570415:user/release-keys"));
 }
 
+TEST_F(DataReductionProxyParamsTest, IsClientConfigEnabled) {
+  const struct {
+    std::string test_case;
+    bool command_line_set;
+    std::string trial_group_value;
+    bool expected;
+  } tests[] = {
+      {
+       "Nothing set", false, "", false,
+      },
+      {
+       "Command line set", true, "", true,
+      },
+      {
+       "Enabled in experiment", false, "Enabled", true,
+      },
+      {
+       "Alternate enabled in experiment", false, "EnabledOther", true,
+      },
+      {
+       "Disabled in experiment", false, "Disabled", false,
+      },
+      {
+       "Command line set, enabled in experiment", true, "Enabled", true,
+      },
+      {
+       "Command line set, disabled in experiment", true, "Disabled", true,
+      },
+  };
+
+  for (const auto& test : tests) {
+    // Reset all flags.
+    base::CommandLine::ForCurrentProcess()->InitFromArgv(0, NULL);
+    if (test.command_line_set) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kEnableDataReductionProxyConfigClient, "");
+    }
+    base::FieldTrialList field_trial_list(nullptr);
+    if (!test.trial_group_value.empty()) {
+      base::FieldTrialList::CreateFieldTrial(kConfigServiceFieldTrial,
+                                             test.trial_group_value);
+    }
+    EXPECT_EQ(test.expected, DataReductionProxyParams::IsConfigClientEnabled())
+        << test.test_case;
+  }
+}
+
 TEST_F(DataReductionProxyParamsTest, SecureProxyCheckDefault) {
   struct {
     bool command_line_set;
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
index 5164895c..3eed0e8 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
@@ -91,6 +91,22 @@
 // received over the network.
 const char kHttpOriginalContentLength[] = "http_original_content_length";
 
+// An integer pref that contains the Lo-Fi epoch for the implicit opt-out rules.
+// Any time this value is incremented via Finch,
+// kLoFiConsecutiveSessionDisables is reset to zero.
+const char kLoFiImplicitOptOutEpoch[] =
+    "data_reduction_lo_fi.implicit_opt_out_epoch";
+
+// An integer pref that contains the number of times that "Load images" has been
+// requested on the Lo-Fi snackbar for the current session.
+const char kLoFiLoadImagesPerSession[] =
+    "data_reduction_lo_fi.load_images_requests_per_session";
+
+// An integer pref that contains the number of consecutive sessions that LoFi
+// has been disabled.
+const char kLoFiConsecutiveSessionDisables[] =
+    "data_reduction_lo_fi.consecutive_session_disables";
+
 // Pref to store the retrieval time of the last simulated Data Reduction Proxy
 // configuration. This is part of an experiment to see how many bytes are lost
 // if the Data Reduction Proxy is not used due to configuration being expired
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
index 72116b54..9a53e72 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
@@ -29,6 +29,9 @@
 extern const char kDataReductionProxyWasEnabledBefore[];
 extern const char kHttpOriginalContentLength[];
 extern const char kHttpReceivedContentLength[];
+extern const char kLoFiImplicitOptOutEpoch[];
+extern const char kLoFiLoadImagesPerSession[];
+extern const char kLoFiConsecutiveSessionDisables[];
 extern const char kSimulatedConfigRetrieveTime[];
 extern const char kStatisticsPrefsMigrated[];
 extern const char kUpdateDailyReceivedContentLengths[];
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
index fabc575e..a62fadf 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
@@ -49,6 +49,13 @@
 // The origin of the data reduction SSL proxy.
 const char kDataReductionSSLProxy[] = "data-reduction-ssl-proxy";
 
+// The mode for Data Reduction Proxy Lo-Fi. The various modes are always-on,
+// cellular-only, and disabled.
+const char kDataReductionProxyLoFi[] = "data-reduction-proxy-lo-fi";
+const char kDataReductionProxyLoFiValueAlwaysOn[] = "always-on";
+const char kDataReductionProxyLoFiValueCellularOnly[] = "cellular-only";
+const char kDataReductionProxyLoFiValueDisabled[] = "disabled";
+
 // Disables the origin of the data reduction proxy dev.
 const char kDisableDataReductionProxyDev[] =
     "disable-spdy-proxy-dev-auth-origin";
@@ -67,10 +74,6 @@
 // Enable the alternative data reduction proxy.
 const char kEnableDataReductionProxyAlt[] = "enable-data-reduction-proxy-alt";
 
-// Enable Data Reduction Proxy Lo-Fi mode.
-const char kEnableDataReductionProxyLoFi[] =
-    "enable-data-reduction-proxy-lo-fi";
-
 // Enable the data reduction proxy bypass warning.
 const char kEnableDataReductionProxyBypassWarning[] =
     "enable-data-reduction-proxy-bypass-warning";
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
index 27fe7c1..8be863d 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
@@ -22,12 +22,15 @@
 extern const char kDataReductionProxyStartSecureDisabled[];
 extern const char kDataReductionProxyWarmupURL[];
 extern const char kDataReductionSSLProxy[];
+extern const char kDataReductionProxyLoFi[];
+extern const char kDataReductionProxyLoFiValueAlwaysOn[];
+extern const char kDataReductionProxyLoFiValueCellularOnly[];
+extern const char kDataReductionProxyLoFiValueDisabled[];
 extern const char kDisableDataReductionProxyDev[];
 extern const char kEnableDataReductionProxyDev[];
 extern const char kEnableDataReductionProxyCarrierTest[];
 extern const char kEnableDataReductionProxy[];
 extern const char kEnableDataReductionProxyAlt[];
-extern const char kEnableDataReductionProxyLoFi[];
 extern const char kEnableDataReductionProxyBypassWarning[];
 extern const char kClearDataReductionProxyDataSavings[];
 extern const char kEnableDataReductionProxyConfigClient[];
diff --git a/components/devtools_service/BUILD.gn b/components/devtools_service/BUILD.gn
index 1dc5c46..a08eadb 100644
--- a/components/devtools_service/BUILD.gn
+++ b/components/devtools_service/BUILD.gn
@@ -2,10 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application.gni")
 
 source_set("lib") {
   sources = [
+    "devtools_agent_host.cc",
+    "devtools_agent_host.h",
     "devtools_http_server.cc",
     "devtools_http_server.h",
     "devtools_registry_impl.cc",
@@ -21,6 +23,7 @@
     "//components/devtools_service/public/interfaces",
     "//mojo/application/public/cpp",
     "//mojo/common",
+    "//mojo/services/network/public/cpp",
     "//mojo/services/network/public/interfaces",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//url",
diff --git a/components/devtools_service/devtools_agent_host.cc b/components/devtools_service/devtools_agent_host.cc
new file mode 100644
index 0000000..d31811a
--- /dev/null
+++ b/components/devtools_service/devtools_agent_host.cc
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/devtools_service/devtools_agent_host.h"
+
+#include "base/guid.h"
+#include "base/logging.h"
+
+namespace devtools_service {
+
+DevToolsAgentHost::DevToolsAgentHost(DevToolsAgentPtr agent)
+    : id_(base::GenerateGUID()),
+      agent_(agent.Pass()),
+      binding_(this),
+      delegate_(nullptr) {
+  agent_.set_error_handler(this);
+}
+
+DevToolsAgentHost::~DevToolsAgentHost() {
+  if (delegate_)
+    delegate_->OnAgentHostClosed(this);
+}
+
+void DevToolsAgentHost::SetDelegate(Delegate* delegate) {
+  delegate_ = delegate;
+  if (delegate_) {
+    if (binding_.is_bound())
+      return;
+
+    DevToolsAgentClientPtr client;
+    binding_.Bind(&client);
+    agent_->SetClient(client.Pass(), id_);
+  } else {
+    if (!binding_.is_bound())
+      return;
+
+    binding_.Close();
+  }
+}
+
+void DevToolsAgentHost::SendProtocolMessageToAgent(const std::string& message) {
+  agent_->DispatchProtocolMessage(message);
+}
+
+void DevToolsAgentHost::DispatchProtocolMessage(const mojo::String& message) {
+  delegate_->DispatchProtocolMessage(this, message);
+}
+
+void DevToolsAgentHost::OnConnectionError() {
+  agent_connection_error_handler_.Run();
+}
+
+}  // namespace devtools_service
diff --git a/components/devtools_service/devtools_agent_host.h b/components/devtools_service/devtools_agent_host.h
new file mode 100644
index 0000000..7b5e759
--- /dev/null
+++ b/components/devtools_service/devtools_agent_host.h
@@ -0,0 +1,73 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_AGENT_HOST_H_
+#define COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_AGENT_HOST_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "components/devtools_service/public/interfaces/devtools_service.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/callback.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
+
+namespace devtools_service {
+
+// DevToolsAgentHost represents a DevTools agent at the service side.
+class DevToolsAgentHost : public DevToolsAgentClient,
+                          public mojo::ErrorHandler {
+ public:
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    virtual void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
+                                         const std::string& message) = 0;
+
+    // Notifies the delegate that |agent_host| is going away.
+    virtual void OnAgentHostClosed(DevToolsAgentHost* agent_host) = 0;
+  };
+
+  explicit DevToolsAgentHost(DevToolsAgentPtr agent);
+
+  ~DevToolsAgentHost() override;
+
+  void set_agent_connection_error_handler(const mojo::Closure& handler) {
+    agent_connection_error_handler_ = handler;
+  }
+
+  std::string id() const { return id_; }
+
+  // Doesn't take ownership of |delegate|. If |delegate| dies before this
+  // object, a new delegate or nullptr must be set so that this object doesn't
+  // hold an invalid pointer.
+  void SetDelegate(Delegate* delegate);
+
+  bool IsAttached() const { return !!delegate_; }
+
+  void SendProtocolMessageToAgent(const std::string& message);
+
+ private:
+  // DevToolsAgentClient implementation.
+  void DispatchProtocolMessage(const mojo::String& message) override;
+
+  // mojo::ErrorHandler implementation.
+  void OnConnectionError() override;
+
+  const std::string id_;
+
+  DevToolsAgentPtr agent_;
+  mojo::Closure agent_connection_error_handler_;
+
+  mojo::Binding<DevToolsAgentClient> binding_;
+
+  Delegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevToolsAgentHost);
+};
+
+}  // namespace devtools_service
+
+#endif  // COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_AGENT_HOST_H_
diff --git a/components/devtools_service/devtools_http_server.cc b/components/devtools_service/devtools_http_server.cc
index 7199f2b..ef17bcd 100644
--- a/components/devtools_service/devtools_http_server.cc
+++ b/components/devtools_service/devtools_http_server.cc
@@ -4,17 +4,282 @@
 
 #include "components/devtools_service/devtools_http_server.h"
 
+#include <string.h>
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "components/devtools_service/devtools_agent_host.h"
+#include "components/devtools_service/devtools_registry_impl.h"
 #include "components/devtools_service/devtools_service.h"
 #include "mojo/application/public/cpp/application_impl.h"
-#include "mojo/services/network/public/interfaces/http_message.mojom.h"
+#include "mojo/services/network/public/cpp/web_socket_read_queue.h"
+#include "mojo/services/network/public/cpp/web_socket_write_queue.h"
 #include "mojo/services/network/public/interfaces/net_address.mojom.h"
 #include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "mojo/services/network/public/interfaces/web_socket.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
 
 namespace devtools_service {
 
+namespace {
+
+const char kPageUrlPrefix[] = "/devtools/page/";
+const char kBrowserUrlPrefix[] = "/devtools/browser";
+const char kJsonRequestUrlPrefix[] = "/json";
+
+const char kActivateCommand[] = "activate";
+const char kCloseCommand[] = "close";
+const char kListCommand[] = "list";
+const char kNewCommand[] = "new";
+const char kVersionCommand[] = "version";
+
+const char kTargetIdField[] = "id";
+const char kTargetTypeField[] = "type";
+const char kTargetTitleField[] = "title";
+const char kTargetDescriptionField[] = "description";
+const char kTargetUrlField[] = "url";
+const char kTargetWebSocketDebuggerUrlField[] = "webSocketDebuggerUrl";
+const char kTargetDevtoolsFrontendUrlField[] = "devtoolsFrontendUrl";
+
+bool ParseJsonPath(const std::string& path,
+                   std::string* command,
+                   std::string* target_id) {
+  // Fall back to list in case of empty query.
+  if (path.empty()) {
+    *command = kListCommand;
+    return true;
+  }
+
+  if (path.find("/") != 0) {
+    // Malformed command.
+    return false;
+  }
+  *command = path.substr(1);
+
+  size_t separator_pos = command->find("/");
+  if (separator_pos != std::string::npos) {
+    *target_id = command->substr(separator_pos + 1);
+    *command = command->substr(0, separator_pos);
+  }
+  return true;
+}
+
+mojo::HttpResponsePtr MakeResponse(uint32_t status_code,
+                                   const std::string& content_type,
+                                   const std::string& body) {
+  mojo::HttpResponsePtr response(mojo::HttpResponse::New());
+  response->headers.resize(2);
+  response->headers[0] = mojo::HttpHeader::New();
+  response->headers[0]->name = "Content-Length";
+  response->headers[0]->value =
+      base::StringPrintf("%lu", static_cast<unsigned long>(body.size()));
+  response->headers[1] = mojo::HttpHeader::New();
+  response->headers[1]->name = "Content-Type";
+  response->headers[1]->value = content_type;
+
+  if (!body.empty()) {
+    uint32_t num_bytes = static_cast<uint32_t>(body.size());
+    MojoCreateDataPipeOptions options;
+    options.struct_size = sizeof(MojoCreateDataPipeOptions);
+    options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
+    options.element_num_bytes = 1;
+    options.capacity_num_bytes = num_bytes;
+    mojo::DataPipe data_pipe(options);
+    response->body = data_pipe.consumer_handle.Pass();
+    MojoResult result =
+        WriteDataRaw(data_pipe.producer_handle.get(), body.data(), &num_bytes,
+                     MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
+    CHECK_EQ(MOJO_RESULT_OK, result);
+  }
+  return response.Pass();
+}
+
+mojo::HttpResponsePtr MakeJsonResponse(uint32_t status_code,
+                                       base::Value* value,
+                                       const std::string& message) {
+  // Serialize value and message.
+  std::string json_value;
+  if (value) {
+    base::JSONWriter::WriteWithOptions(
+        *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_value);
+  }
+
+  return MakeResponse(status_code, "application/json; charset=UTF-8",
+                      json_value + message);
+}
+
+class WebSocketRelayer : public DevToolsAgentHost::Delegate,
+                         public mojo::WebSocketClient,
+                         public mojo::ErrorHandler {
+ public:
+  // Creates a WebSocketRelayer instance and sets it as the delegate of
+  // |agent_host|.
+  //
+  // The object destroys itself when either of the following happens:
+  // - |agent_host| is dead and the object finishes all pending sends (if any)
+  //   to the Web socket; or
+  // - the underlying pipe of |web_socket| is closed and the object finishes all
+  //   pending receives (if any) from the Web socket.
+  static mojo::WebSocketClientPtr SetUp(
+      DevToolsAgentHost* agent_host,
+      mojo::WebSocketPtr web_socket,
+      mojo::ScopedDataPipeProducerHandle send_stream) {
+    DCHECK(agent_host);
+    DCHECK(web_socket);
+    DCHECK(send_stream.is_valid());
+
+    mojo::WebSocketClientPtr web_socket_client;
+    new WebSocketRelayer(agent_host, web_socket.Pass(), send_stream.Pass(),
+                         &web_socket_client);
+    return web_socket_client.Pass();
+  }
+
+ private:
+  WebSocketRelayer(DevToolsAgentHost* agent_host,
+                   mojo::WebSocketPtr web_socket,
+                   mojo::ScopedDataPipeProducerHandle send_stream,
+                   mojo::WebSocketClientPtr* web_socket_client)
+      : agent_host_(agent_host),
+        binding_(this, web_socket_client),
+        web_socket_(web_socket.Pass()),
+        send_stream_(send_stream.Pass()),
+        write_send_stream_(new mojo::WebSocketWriteQueue(send_stream_.get())),
+        pending_send_count_(0),
+        pending_receive_count_(0) {
+    web_socket_.set_error_handler(this);
+    agent_host->SetDelegate(this);
+  }
+
+  ~WebSocketRelayer() override {
+    if (agent_host_)
+      agent_host_->SetDelegate(nullptr);
+  }
+
+  // DevToolsAgentHost::Delegate implementation.
+  void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
+                               const std::string& message) override {
+    if (!web_socket_)
+      return;
+
+    // TODO(yzshen): It shouldn't be an issue to pass an empty message. However,
+    // WebSocket{Read,Write}Queue doesn't handle that correctly.
+    if (message.empty())
+      return;
+
+    pending_send_count_++;
+    uint32_t size = static_cast<uint32_t>(message.size());
+    write_send_stream_->Write(
+        &message[0], size,
+        base::Bind(&WebSocketRelayer::OnFinishedWritingSendStream,
+                   base::Unretained(this), size));
+  }
+
+  void OnAgentHostClosed(DevToolsAgentHost* agent_host) override {
+    DispatchProtocolMessage(agent_host_,
+                            "{ \"method\": \"Inspector.detached\", "
+                            "\"params\": { \"reason\": \"target_closed\" } }");
+
+    // No need to call SetDelegate(nullptr) on |agent_host_| because it is going
+    // away.
+    agent_host_ = nullptr;
+
+    if (ShouldSelfDestruct())
+      delete this;
+  }
+
+  // WebSocketClient implementation.
+  void DidConnect(const mojo::String& selected_subprotocol,
+                  const mojo::String& extensions,
+                  mojo::ScopedDataPipeConsumerHandle receive_stream) override {
+    receive_stream_ = receive_stream.Pass();
+    read_receive_stream_.reset(
+        new mojo::WebSocketReadQueue(receive_stream_.get()));
+  }
+
+  void DidReceiveData(bool fin,
+                      mojo::WebSocket::MessageType type,
+                      uint32_t num_bytes) override {
+    if (!agent_host_)
+      return;
+
+    // TODO(yzshen): It shouldn't be an issue to pass an empty message. However,
+    // WebSocket{Read,Write}Queue doesn't handle that correctly.
+    if (num_bytes == 0)
+      return;
+
+    pending_receive_count_++;
+    read_receive_stream_->Read(
+        num_bytes, base::Bind(&WebSocketRelayer::OnFinishedReadingReceiveStream,
+                              base::Unretained(this), num_bytes));
+  }
+
+  void DidReceiveFlowControl(int64_t quota) override {}
+
+  void DidFail(const mojo::String& message) override {}
+
+  void DidClose(bool was_clean,
+                uint16_t code,
+                const mojo::String& reason) override {}
+
+  // mojo::ErrorHandler implementation.
+  void OnConnectionError() override {
+    web_socket_ = nullptr;
+    binding_.Close();
+
+    if (ShouldSelfDestruct())
+      delete this;
+  }
+
+  void OnFinishedWritingSendStream(uint32_t num_bytes, const char* buffer) {
+    DCHECK_GT(pending_send_count_, 0u);
+    pending_send_count_--;
+
+    if (web_socket_ && buffer)
+      web_socket_->Send(true, mojo::WebSocket::MESSAGE_TYPE_TEXT, num_bytes);
+
+    if (ShouldSelfDestruct())
+      delete this;
+  }
+
+  void OnFinishedReadingReceiveStream(uint32_t num_bytes, const char* data) {
+    DCHECK_GT(pending_receive_count_, 0u);
+    pending_receive_count_--;
+
+    if (agent_host_ && data)
+      agent_host_->SendProtocolMessageToAgent(std::string(data, num_bytes));
+
+    if (ShouldSelfDestruct())
+      delete this;
+  }
+
+  bool ShouldSelfDestruct() const {
+    return (!agent_host_ && pending_send_count_ == 0) ||
+           (!web_socket_ && pending_receive_count_ == 0);
+  }
+
+  DevToolsAgentHost* agent_host_;
+  mojo::Binding<WebSocketClient> binding_;
+  mojo::WebSocketPtr web_socket_;
+
+  mojo::ScopedDataPipeProducerHandle send_stream_;
+  scoped_ptr<mojo::WebSocketWriteQueue> write_send_stream_;
+  size_t pending_send_count_;
+
+  mojo::ScopedDataPipeConsumerHandle receive_stream_;
+  scoped_ptr<mojo::WebSocketReadQueue> read_receive_stream_;
+  size_t pending_receive_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebSocketRelayer);
+};
+
+}  // namespace
+
 class DevToolsHttpServer::HttpConnectionDelegateImpl
     : public mojo::HttpConnectionDelegate,
       public mojo::ErrorHandler {
@@ -61,7 +326,7 @@
 
 DevToolsHttpServer::DevToolsHttpServer(DevToolsService* service,
                                        uint16_t remote_debugging_port)
-    : service_(service) {
+    : service_(service), remote_debugging_port_(remote_debugging_port) {
   VLOG(1) << "Remote debugging HTTP server is started on port "
           << remote_debugging_port << ".";
   mojo::NetworkServicePtr network_service;
@@ -104,30 +369,13 @@
     const OnReceivedRequestCallback& callback) {
   DCHECK(connections_.find(connection) != connections_.end());
 
-  // TODO(yzshen): Implement it.
-  static const char kNotImplemented[] = "Not implemented yet!";
-  mojo::HttpResponsePtr response(mojo::HttpResponse::New());
-  response->headers.resize(2);
-  response->headers[0] = mojo::HttpHeader::New();
-  response->headers[0]->name = "Content-Length";
-  response->headers[0]->value = base::StringPrintf(
-      "%lu", static_cast<unsigned long>(sizeof(kNotImplemented)));
-  response->headers[1] = mojo::HttpHeader::New();
-  response->headers[1]->name = "Content-Type";
-  response->headers[1]->value = "text/html";
-
-  uint32_t num_bytes = sizeof(kNotImplemented);
-  MojoCreateDataPipeOptions options;
-  options.struct_size = sizeof(MojoCreateDataPipeOptions);
-  options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
-  options.element_num_bytes = 1;
-  options.capacity_num_bytes = num_bytes;
-  mojo::DataPipe data_pipe(options);
-  response->body = data_pipe.consumer_handle.Pass();
-  WriteDataRaw(data_pipe.producer_handle.get(), kNotImplemented, &num_bytes,
-               MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
-
-  callback.Run(response.Pass());
+  if (request->url.get().find(kJsonRequestUrlPrefix) == 0) {
+    callback.Run(ProcessJsonRequest(request.Pass()));
+  } else {
+    // TODO(yzshen): Implement it.
+    NOTIMPLEMENTED();
+    callback.Run(MakeResponse(404, "text/html", "Not implemented yet!"));
+  }
 }
 
 void DevToolsHttpServer::OnReceivedWebSocketRequest(
@@ -136,8 +384,36 @@
     const OnReceivedWebSocketRequestCallback& callback) {
   DCHECK(connections_.find(connection) != connections_.end());
 
-  // TODO(yzshen): Implement it.
-  NOTIMPLEMENTED();
+  std::string path = request->url;
+  size_t browser_pos = path.find(kBrowserUrlPrefix);
+  if (browser_pos == 0) {
+    // TODO(yzshen): Implement it.
+    NOTIMPLEMENTED();
+    callback.Run(nullptr, mojo::ScopedDataPipeConsumerHandle(), nullptr);
+    return;
+  }
+
+  size_t pos = path.find(kPageUrlPrefix);
+  if (pos != 0) {
+    callback.Run(nullptr, mojo::ScopedDataPipeConsumerHandle(), nullptr);
+    return;
+  }
+
+  std::string target_id = path.substr(strlen(kPageUrlPrefix));
+  DevToolsAgentHost* agent = service_->registry()->GetAgentById(target_id);
+  if (!agent || agent->IsAttached()) {
+    callback.Run(nullptr, mojo::ScopedDataPipeConsumerHandle(), nullptr);
+    return;
+  }
+
+  mojo::WebSocketPtr web_socket;
+  mojo::InterfaceRequest<mojo::WebSocket> web_socket_request =
+      mojo::GetProxy(&web_socket);
+  mojo::DataPipe data_pipe;
+  mojo::WebSocketClientPtr web_socket_client = WebSocketRelayer::SetUp(
+      agent, web_socket.Pass(), data_pipe.producer_handle.Pass());
+  callback.Run(web_socket_request.Pass(), data_pipe.consumer_handle.Pass(),
+               web_socket_client.Pass());
 }
 
 void DevToolsHttpServer::OnConnectionClosed(
@@ -148,4 +424,58 @@
   connections_.erase(connection);
 }
 
+mojo::HttpResponsePtr DevToolsHttpServer::ProcessJsonRequest(
+    mojo::HttpRequestPtr request) {
+  // Trim "/json".
+  std::string path = request->url.get().substr(strlen(kJsonRequestUrlPrefix));
+
+  // Trim query.
+  size_t query_pos = path.find("?");
+  if (query_pos != std::string::npos)
+    path = path.substr(0, query_pos);
+
+  // Trim fragment.
+  size_t fragment_pos = path.find("#");
+  if (fragment_pos != std::string::npos)
+    path = path.substr(0, fragment_pos);
+
+  std::string command;
+  std::string target_id;
+  if (!ParseJsonPath(path, &command, &target_id))
+    return MakeJsonResponse(404, nullptr,
+                            "Malformed query: " + request->url.get());
+
+  if (command == kVersionCommand || command == kNewCommand ||
+      command == kActivateCommand || command == kCloseCommand) {
+    NOTIMPLEMENTED();
+    return MakeJsonResponse(404, nullptr,
+                            "Not implemented yet: " + request->url.get());
+  }
+
+  if (command == kListCommand) {
+    base::ListValue list_value;
+    for (DevToolsRegistryImpl::Iterator iter(service_->registry());
+         !iter.IsAtEnd(); iter.Advance()) {
+      scoped_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue());
+
+      // TODO(yzshen): Add more information.
+      dict_value->SetString(kTargetDescriptionField, std::string());
+      dict_value->SetString(kTargetDevtoolsFrontendUrlField, std::string());
+      dict_value->SetString(kTargetIdField, iter.value()->id());
+      dict_value->SetString(kTargetTitleField, std::string());
+      dict_value->SetString(kTargetTypeField, "page");
+      dict_value->SetString(kTargetUrlField, std::string());
+      dict_value->SetString(
+          kTargetWebSocketDebuggerUrlField,
+          base::StringPrintf("ws://127.0.0.1:%u%s%s",
+                             static_cast<unsigned>(remote_debugging_port_),
+                             kPageUrlPrefix, iter.value()->id().c_str()));
+      list_value.Append(dict_value.Pass());
+    }
+    return MakeJsonResponse(200, &list_value, std::string());
+  }
+
+  return MakeJsonResponse(404, nullptr, "Unknown command: " + command);
+}
+
 }  // namespace devtools_service
diff --git a/components/devtools_service/devtools_http_server.h b/components/devtools_service/devtools_http_server.h
index 6a9a1a9b..a4f4eed 100644
--- a/components/devtools_service/devtools_http_server.h
+++ b/components/devtools_service/devtools_http_server.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "mojo/services/network/public/interfaces/http_connection.mojom.h"
+#include "mojo/services/network/public/interfaces/http_message.mojom.h"
 #include "mojo/services/network/public/interfaces/http_server.mojom.h"
 
 namespace devtools_service {
@@ -30,25 +31,27 @@
       mojo::HttpConnectionPtr connection,
       mojo::InterfaceRequest<mojo::HttpConnectionDelegate> delegate) override;
 
-  // The following methods are called by HttpConnectionDelegateImpl.
+  // The following three methods are called by HttpConnectionDelegateImpl.
   using OnReceivedRequestCallback =
       mojo::HttpConnectionDelegate::OnReceivedRequestCallback;
   void OnReceivedRequest(HttpConnectionDelegateImpl* connection,
                          mojo::HttpRequestPtr request,
                          const OnReceivedRequestCallback& callback);
-
   using OnReceivedWebSocketRequestCallback =
       mojo::HttpConnectionDelegate::OnReceivedWebSocketRequestCallback;
   void OnReceivedWebSocketRequest(
       HttpConnectionDelegateImpl* connection,
       mojo::HttpRequestPtr request,
       const OnReceivedWebSocketRequestCallback& callback);
-
   void OnConnectionClosed(HttpConnectionDelegateImpl* connection);
 
+  mojo::HttpResponsePtr ProcessJsonRequest(mojo::HttpRequestPtr request);
+
   // Not owned by this object.
   DevToolsService* const service_;
 
+  const uint16_t remote_debugging_port_;
+
   scoped_ptr<mojo::Binding<mojo::HttpServerDelegate>>
       http_server_delegate_binding_;
 
diff --git a/components/devtools_service/devtools_registry_impl.cc b/components/devtools_service/devtools_registry_impl.cc
index 130f20f..3fc7e0d 100644
--- a/components/devtools_service/devtools_registry_impl.cc
+++ b/components/devtools_service/devtools_registry_impl.cc
@@ -5,9 +5,17 @@
 #include "components/devtools_service/devtools_registry_impl.h"
 
 #include "base/logging.h"
+#include "components/devtools_service/devtools_agent_host.h"
 
 namespace devtools_service {
 
+DevToolsRegistryImpl::Iterator::Iterator(DevToolsRegistryImpl* registry)
+    : registry_(registry), iter_(registry->agents_.begin()) {
+}
+
+DevToolsRegistryImpl::Iterator::~Iterator() {
+}
+
 DevToolsRegistryImpl::DevToolsRegistryImpl(DevToolsService* service)
     : service_(service) {
 }
@@ -20,9 +28,26 @@
   bindings_.AddBinding(this, request.Pass());
 }
 
+DevToolsAgentHost* DevToolsRegistryImpl::GetAgentById(const std::string& id) {
+  auto iter = agents_.find(id);
+  if (iter == agents_.end())
+    return nullptr;
+
+  return iter->second.get();
+}
+
 void DevToolsRegistryImpl::RegisterAgent(DevToolsAgentPtr agent) {
-  // TODO(yzshen): Implement it.
-  NOTIMPLEMENTED();
+  linked_ptr<DevToolsAgentHost> agent_host(new DevToolsAgentHost(agent.Pass()));
+  std::string id = agent_host->id();
+  agent_host->set_agent_connection_error_handler(
+      [this, id]() { OnAgentConnectionError(id); });
+
+  agents_[agent_host->id()] = agent_host;
+}
+
+void DevToolsRegistryImpl::OnAgentConnectionError(const std::string& id) {
+  DCHECK(agents_.find(id) != agents_.end());
+  agents_.erase(id);
 }
 
 }  // namespace devtools_service
diff --git a/components/devtools_service/devtools_registry_impl.h b/components/devtools_service/devtools_registry_impl.h
index c12c0de..431f39a 100644
--- a/components/devtools_service/devtools_registry_impl.h
+++ b/components/devtools_service/devtools_registry_impl.h
@@ -5,30 +5,57 @@
 #ifndef COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_REGISTRY_IMPL_H_
 #define COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_REGISTRY_IMPL_H_
 
+#include <map>
+#include <string>
+
 #include "base/macros.h"
+#include "base/memory/linked_ptr.h"
 #include "components/devtools_service/public/interfaces/devtools_service.mojom.h"
 #include "mojo/common/weak_binding_set.h"
 
 namespace devtools_service {
 
+class DevToolsAgentHost;
 class DevToolsService;
 
 class DevToolsRegistryImpl : public DevToolsRegistry {
  public:
+  class Iterator {
+   public:
+    // |registry| must outlive this object.
+    explicit Iterator(DevToolsRegistryImpl* registry);
+    ~Iterator();
+
+    bool IsAtEnd() const { return iter_ == registry_->agents_.end(); }
+    void Advance() { ++iter_; }
+
+    DevToolsAgentHost* value() { return iter_->second.get(); }
+
+   private:
+    DevToolsRegistryImpl* const registry_;
+    std::map<std::string, linked_ptr<DevToolsAgentHost>>::const_iterator iter_;
+  };
+
   // |service| must outlive this object.
   explicit DevToolsRegistryImpl(DevToolsService* service);
   ~DevToolsRegistryImpl() override;
 
   void BindToRegistryRequest(mojo::InterfaceRequest<DevToolsRegistry> request);
 
+  DevToolsAgentHost* GetAgentById(const std::string& id);
+
  private:
   // DevToolsRegistry implementation.
   void RegisterAgent(DevToolsAgentPtr agent) override;
 
+  void OnAgentConnectionError(const std::string& id);
+
   DevToolsService* const service_;
 
   mojo::WeakBindingSet<DevToolsRegistry> bindings_;
 
+  std::map<std::string, linked_ptr<DevToolsAgentHost>> agents_;
+
   DISALLOW_COPY_AND_ASSIGN(DevToolsRegistryImpl);
 };
 
diff --git a/components/devtools_service/public/cpp/BUILD.gn b/components/devtools_service/public/cpp/BUILD.gn
new file mode 100644
index 0000000..2f8933b
--- /dev/null
+++ b/components/devtools_service/public/cpp/BUILD.gn
@@ -0,0 +1,10 @@
+# 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.
+
+source_set("cpp") {
+  sources = [
+    "switches.cc",
+    "switches.h",
+  ]
+}
diff --git a/components/devtools_service/public/cpp/switches.cc b/components/devtools_service/public/cpp/switches.cc
new file mode 100644
index 0000000..0a1d8ea4
--- /dev/null
+++ b/components/devtools_service/public/cpp/switches.cc
@@ -0,0 +1,12 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/devtools_service/public/cpp/switches.h"
+
+namespace devtools_service {
+
+// Enables remote debug over HTTP on the specified port.
+const char kRemoteDebuggingPort[] = "remote-debugging-port";
+
+}  // namespace devtools_service
diff --git a/components/devtools_service/public/cpp/switches.h b/components/devtools_service/public/cpp/switches.h
new file mode 100644
index 0000000..65c48e9a
--- /dev/null
+++ b/components/devtools_service/public/cpp/switches.h
@@ -0,0 +1,16 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DEVTOOLS_SERVICE_PUBLIC_CPP_SWITCHES_H_
+#define COMPONENTS_DEVTOOLS_SERVICE_PUBLIC_CPP_SWITCHES_H_
+
+namespace devtools_service {
+
+// All switches in alphabetical order. The switches should be documented
+// alongside the definition of their values in the .cc file.
+extern const char kRemoteDebuggingPort[];
+
+}  // namespace devtools_service
+
+#endif  // COMPONENTS_DEVTOOLS_SERVICE_PUBLIC_CPP_SWITCHES_H_
diff --git a/components/devtools_service/public/interfaces/BUILD.gn b/components/devtools_service/public/interfaces/BUILD.gn
index db42b1a..3b54773 100644
--- a/components/devtools_service/public/interfaces/BUILD.gn
+++ b/components/devtools_service/public/interfaces/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
diff --git a/components/devtools_service/public/interfaces/devtools_service.mojom b/components/devtools_service/public/interfaces/devtools_service.mojom
index 5f7b454..80a2ad8 100644
--- a/components/devtools_service/public/interfaces/devtools_service.mojom
+++ b/components/devtools_service/public/interfaces/devtools_service.mojom
@@ -30,7 +30,7 @@
   // DispatchProtocolMessage() calls. If a client doesn't want to receive
   // messages anymore, it could simply close the underlying message pipe of
   // |client|.
-  SetClient(DevToolsAgentClient client);
+  SetClient(DevToolsAgentClient client, string client_id);
 
   // Sends a command (in remote debugging protocol JSON format) to the agent.
   DispatchProtocolMessage(string message);
diff --git a/components/dom_distiller/content/distiller_page_web_contents.cc b/components/dom_distiller/content/distiller_page_web_contents.cc
index cfa408c..327a79f 100644
--- a/components/dom_distiller/content/distiller_page_web_contents.cc
+++ b/components/dom_distiller/content/distiller_page_web_contents.cc
@@ -6,6 +6,7 @@
 
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/dom_distiller/content/web_contents_main_frame_observer.h"
 #include "components/dom_distiller/core/distiller_page.h"
@@ -59,7 +60,8 @@
     : state_(IDLE),
       source_page_handle_(nullptr),
       browser_context_(browser_context),
-      render_view_size_(render_view_size) {
+      render_view_size_(render_view_size),
+      weak_factory_(this) {
   if (optional_web_contents_handle) {
     source_page_handle_ = optional_web_contents_handle.Pass();
     if (render_view_size.IsEmpty())
@@ -164,7 +166,7 @@
     DCHECK(state_ == LOADING_PAGE || state_ == EXECUTING_JAVASCRIPT);
     state_ = PAGELOAD_FAILED;
     scoped_ptr<base::Value> empty = base::Value::CreateNullValue();
-    OnWebContentsDistillationDone(GURL(), empty.get());
+    OnWebContentsDistillationDone(GURL(), base::TimeTicks(), empty.get());
   }
 }
 
@@ -182,16 +184,25 @@
   frame->ExecuteJavaScript(
       base::UTF8ToUTF16(script_),
       base::Bind(&DistillerPageWebContents::OnWebContentsDistillationDone,
-                 base::Unretained(this),
-                 source_page_handle_->web_contents()->GetLastCommittedURL()));
+                 weak_factory_.GetWeakPtr(),
+                 source_page_handle_->web_contents()->GetLastCommittedURL(),
+                 base::TimeTicks::Now()));
 }
 
 void DistillerPageWebContents::OnWebContentsDistillationDone(
     const GURL& page_url,
+    const base::TimeTicks& javascript_start,
     const base::Value* value) {
   DCHECK(state_ == IDLE || state_ == LOADING_PAGE ||  // TODO(nyquist): 493795.
          state_ == PAGELOAD_FAILED || state_ == EXECUTING_JAVASCRIPT);
   state_ = IDLE;
+
+  if (!javascript_start.is_null()) {
+    base::TimeDelta javascript_time = base::TimeTicks::Now() - javascript_start;
+    UMA_HISTOGRAM_TIMES("DomDistiller.Time.RunJavaScript", javascript_time);
+    DVLOG(1) << "DomDistiller.Time.RunJavaScript = " << javascript_time;
+  }
+
   DistillerPage::OnDistillationDone(page_url, value);
 }
 
diff --git a/components/dom_distiller/content/distiller_page_web_contents.h b/components/dom_distiller/content/distiller_page_web_contents.h
index 82abe8d..3a7db655 100644
--- a/components/dom_distiller/content/distiller_page_web_contents.h
+++ b/components/dom_distiller/content/distiller_page_web_contents.h
@@ -100,6 +100,7 @@
 
   // Called when the distillation is done or if the page load failed.
   void OnWebContentsDistillationDone(const GURL& page_url,
+                                     const base::TimeTicks& javascript_start,
                                      const base::Value* value);
 
   // The current state of the |DistillerPage|, initially |IDLE|.
@@ -112,6 +113,7 @@
 
   content::BrowserContext* browser_context_;
   gfx::Size render_view_size_;
+  base::WeakPtrFactory<DistillerPageWebContents> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(DistillerPageWebContents);
 };
 
diff --git a/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc b/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc
index aa01a86..201d972fe 100644
--- a/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc
+++ b/components/dom_distiller/content/distiller_page_web_contents_browsertest.cc
@@ -366,6 +366,49 @@
   EXPECT_EQ("Test Page Title", distiller_result_->title());
 }
 
+IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
+                       PageDestroyedBeforeFinishDistillation) {
+
+  content::WebContents* current_web_contents = shell()->web_contents();
+
+  dom_distiller::WebContentsMainFrameObserver::CreateForWebContents(
+      current_web_contents);
+
+  base::RunLoop url_loaded_runner;
+  WebContentsMainFrameHelper main_frame_loaded(current_web_contents,
+                                               url_loaded_runner.QuitClosure(),
+                                               true);
+  current_web_contents->GetController().LoadURL(
+      embedded_test_server()->GetURL(kSimpleArticlePath),
+      content::Referrer(),
+      ui::PAGE_TRANSITION_TYPED,
+      std::string());
+  url_loaded_runner.Run();
+
+  scoped_ptr<SourcePageHandleWebContents> source_page_handle(
+      new SourcePageHandleWebContents(current_web_contents, false));
+
+  TestDistillerPageWebContents* distiller_page(
+      new TestDistillerPageWebContents(
+          current_web_contents->GetBrowserContext(),
+          current_web_contents->GetContainerBounds().size(),
+          source_page_handle.Pass(),
+          false));
+  distiller_page_ = distiller_page;
+
+  base::RunLoop run_loop;
+  DistillPage(run_loop.QuitClosure(), kSimpleArticlePath);
+
+  // It can not crash the loop when returning the result.
+  delete distiller_page_;
+
+  // Make sure the test ends when it does not crash.
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(2));
+
+  run_loop.Run();
+}
+
 IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, MarkupInfo) {
   DistillerPageWebContents distiller_page(
       shell()->web_contents()->GetBrowserContext(),
diff --git a/components/dom_distiller/core/css/distilledpage.css b/components/dom_distiller/core/css/distilledpage.css
index 9ce71eb..e1b42ff0 100644
--- a/components/dom_distiller/core/css/distilledpage.css
+++ b/components/dom_distiller/core/css/distilledpage.css
@@ -81,6 +81,7 @@
 body {
   height: 100%;
   line-height: 1.4;
+  margin: 0px auto;
   text-rendering: optimizeLegibility;
   transition-property: color, background-color;
   transition-duration: 0.5s;
@@ -156,23 +157,32 @@
 
 /* Margins for Show Original link. */
 
-#showOriginal {
-  margin: auto 1.296rem 1.296rem 5%;
+#closeReaderView {
+  background-color: #FFFFFF;
+  border-top: 1px solid #E0E0E0;
+  color: #4285F4;
+  flex: 0 0 auto;
+  font-family: 'Roboto-Medium', 'Open Sans', sans-serif;
+  font-weight: 700;
+  line-height: 14px;
+  margin-top: 24px;
+  padding: 24px 16px;
+  font-size: 14px;
+  text-align: right;
+  text-decoration: none;
+  text-transform: uppercase;
+  width: 100%;
 }
 
 #content {
   margin: 0.2rem 2.2%;
 }
 
-/* Main margins. */
-
-body {
-  max-width: 800px;
-  margin: 0px auto 0px auto;
-}
-
 #mainContent {
-  margin: auto 0px;
+  flex: 1 1 auto;
+  margin: 0px auto;
+  max-width: 800px;
+  width: 100%;
 }
 
 #articleHeader {
@@ -323,9 +333,10 @@
 
 /* Footer feedback form. */
 #contentWrap {
+  display: flex;
+  flex-flow: column;
   min-height: 100%;
   overflow: auto;
-  padding-bottom: 120px;
   position: relative;
   z-index: 1;
 }
diff --git a/components/dom_distiller/core/css/distilledpage_ios.css b/components/dom_distiller/core/css/distilledpage_ios.css
new file mode 100644
index 0000000..7bf3128e
--- /dev/null
+++ b/components/dom_distiller/core/css/distilledpage_ios.css
@@ -0,0 +1,19 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+/* The following are iOS specific rules for rendering on WebKit instead of
+ * Blink. */
+
+#mainContent {
+  -webkit-flex: 1 1 auto;
+}
+
+#closeReaderView {
+  -webkit-flex: 0 0 auto;
+}
+
+#contentWrap {
+  -webkit-flex-flow: column;
+  display: -webkit-flex;
+}
diff --git a/components/dom_distiller/core/html/dom_distiller_viewer.html b/components/dom_distiller/core/html/dom_distiller_viewer.html
index 455277c..2fd8419 100644
--- a/components/dom_distiller/core/html/dom_distiller_viewer.html
+++ b/components/dom_distiller/core/html/dom_distiller_viewer.html
@@ -28,63 +28,61 @@
         </header>
         <div id="content"><noscript>$5</noscript></div>
       </article>
-    </div>
-    <div id="loadingIndicator" class="visible">
-      <div id="loader">
-        <div class="circle initial">
-          <span class="mask">
-            <span class="mover"></span>
-          </span>
-        </div>
+      <div id="loadingIndicator" class="visible">
+        <div id="loader">
+          <div class="circle initial">
+            <span class="mask">
+              <span class="mover"></span>
+            </span>
+          </div>
 
-        <div class="circle red">
-          <span class="mask first">
-            <span class="base"></span>
-            <span class="mover"></span>
-          </span>
-          <span class="mask second">
-            <span class="base"></span>
-            <span class="mover"></span>
-          </span>
-        </div>
+          <div class="circle red">
+            <span class="mask first">
+              <span class="base"></span>
+              <span class="mover"></span>
+            </span>
+            <span class="mask second">
+              <span class="base"></span>
+              <span class="mover"></span>
+            </span>
+          </div>
 
-        <div class="circle yellow">
-          <span class="mask first">
-            <span class="base"></span>
-            <span class="mover"></span>
-          </span>
-          <span class="mask second">
-            <span class="base"></span>
-            <span class="mover"></span>
-          </span>
-        </div>
+          <div class="circle yellow">
+            <span class="mask first">
+              <span class="base"></span>
+              <span class="mover"></span>
+            </span>
+            <span class="mask second">
+              <span class="base"></span>
+              <span class="mover"></span>
+            </span>
+          </div>
 
-        <div class="circle green">
-          <span class="mask first">
-            <span class="base"></span>
-            <span class="mover"></span>
-          </span>
-          <span class="mask second">
-            <span class="base"></span>
-            <span class="mover"></span>
-          </span>
-        </div>
+          <div class="circle green">
+            <span class="mask first">
+              <span class="base"></span>
+              <span class="mover"></span>
+            </span>
+            <span class="mask second">
+              <span class="base"></span>
+              <span class="mover"></span>
+            </span>
+          </div>
 
-        <div class="circle blue">
-          <span class="mask first">
-            <span class="base"></span>
-            <span class="mover"></span>
-          </span>
-          <span class="mask second">
-            <span class="base"></span>
-            <span class="mover"></span>
-          </span>
+          <div class="circle blue">
+            <span class="mask first">
+              <span class="base"></span>
+              <span class="mover"></span>
+            </span>
+            <span class="mask second">
+              <span class="base"></span>
+              <span class="mover"></span>
+            </span>
+          </div>
         </div>
       </div>
     </div>
-    <div id="showOriginal">
-      <a href="$6">$7</a>
-    </div>
+    <a href="$6" id="closeReaderView">$7</a>
   </div>
   <div id="feedbackContainer" class="footerFeedback">
     <div class="feedbackContent">
diff --git a/components/dom_distiller/core/javascript/dom_distiller_viewer.js b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
index 75292a2..bf114cf 100644
--- a/components/dom_distiller/core/javascript/dom_distiller_viewer.js
+++ b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// This variable will be changed by iOS scripts.
+var distiller_on_ios = false;
+
 function addToPage(html) {
   var div = document.createElement('div');
   div.innerHTML = html;
@@ -120,10 +123,15 @@
  * @param noText The i18n text for the feedback answer 'NO'.
  */
 function showFeedbackForm(questionText, yesText, noText) {
+  // If the distiller is running on iOS, do not show the feedback form. This
+  // variable is set in distiller_viewer.cc before this function is run.
+  if (distiller_on_ios) return;
+
   document.getElementById('feedbackYes').innerText = yesText;
   document.getElementById('feedbackNo').innerText = noText;
   document.getElementById('feedbackQuestion').innerText = questionText;
 
+  document.getElementById('contentWrap').style.paddingBottom = '120px';
   document.getElementById('feedbackContainer').style.display = 'block';
 }
 
@@ -143,12 +151,13 @@
 }
 
 // Add a listener to the "View Original" link to report opt-outs.
-document.getElementById('showOriginal').addEventListener('click', function(e) {
-  var img = document.createElement('img');
-  img.src = "/vieworiginal";
-  img.style.display = "none";
-  document.body.appendChild(img);
-}, true);
+document.getElementById('closeReaderView').addEventListener('click',
+    function(e) {
+      var img = document.createElement('img');
+      img.src = "/vieworiginal";
+      img.style.display = "none";
+      document.body.appendChild(img);
+    }, true);
 
 document.getElementById('feedbackYes').addEventListener('click', function(e) {
   sendFeedback(true);
diff --git a/components/dom_distiller/core/viewer.cc b/components/dom_distiller/core/viewer.cc
index 60ea7f1..e61734f 100644
--- a/components/dom_distiller/core/viewer.cc
+++ b/components/dom_distiller/core/viewer.cc
@@ -117,7 +117,7 @@
 #if defined(OS_IOS)
   // On iOS the content is inlined as there is no API to detect those requests
   // and return the local data once a page is loaded.
-  css << "<style>" << viewer::GetCss() << "</style>";
+  css << "<style>" << viewer::GetCss() << viewer::GetIOSCss() << "</style>";
   script << "<script>\n" << viewer::GetJavaScript() << "\n</script>";
 #else
   css << "<link rel=\"stylesheet\" href=\"/" << kViewerCssPath << "\">";
@@ -139,7 +139,8 @@
 
   substitutions.push_back(original_url);                                  // $6
   substitutions.push_back(
-      l10n_util::GetStringUTF8(IDS_DOM_DISTILLER_VIEWER_VIEW_ORIGINAL));  // $7
+      l10n_util::GetStringUTF8(
+          IDS_DOM_DISTILLER_VIEWER_CLOSE_READER_VIEW));                   // $7
 
   substitutions.push_back(script.str());                                  // $8
 
@@ -245,6 +246,11 @@
           IDR_DISTILLER_CSS).as_string();
 }
 
+const std::string GetIOSCss() {
+  return ResourceBundle::GetSharedInstance().GetRawDataResource(
+          IDR_DISTILLER_IOS_CSS).as_string();
+}
+
 const std::string GetJavaScript() {
   return ResourceBundle::GetSharedInstance()
       .GetRawDataResource(IDR_DOM_DISTILLER_VIEWER_JS)
@@ -259,7 +265,7 @@
   std::string entry_id =
       url_utils::GetValueForKeyInUrlPathQuery(path, kEntryIdKey);
   bool has_valid_entry_id = !entry_id.empty();
-  entry_id = StringToUpperASCII(entry_id);
+  entry_id = base::StringToUpperASCII(entry_id);
 
   std::string requested_url_str =
       url_utils::GetValueForKeyInUrlPathQuery(path, kUrlKey);
diff --git a/components/dom_distiller/core/viewer.h b/components/dom_distiller/core/viewer.h
index 61b0e40..9b05daa 100644
--- a/components/dom_distiller/core/viewer.h
+++ b/components/dom_distiller/core/viewer.h
@@ -69,6 +69,9 @@
 // Returns the default CSS to be used for a viewer.
 const std::string GetCss();
 
+// Returns the iOS specific CSS to be used for the distiller viewer.
+const std::string GetIOSCss();
+
 // Returns the default JS to be used for a viewer.
 const std::string GetJavaScript();
 
diff --git a/components/dom_distiller_strings.grdp b/components/dom_distiller_strings.grdp
index f268587..d6fed096 100644
--- a/components/dom_distiller_strings.grdp
+++ b/components/dom_distiller_strings.grdp
@@ -25,6 +25,9 @@
   <message name="IDS_DOM_DISTILLER_WEBUI_FETCHING_ENTRIES" desc="The text to show while fetching the list of entries on the DOM Distiller debug page.">
     Fetching entries...
   </message>
+  <message name="IDS_DOM_DISTILLER_VIEWER_CLOSE_READER_VIEW" desc="The text to show on a button at the bottom of the page to close reader view.">
+    Close reader view
+  </message>
   <message name="IDS_DOM_DISTILLER_VIEWER_FAILED_TO_FIND_ARTICLE_TITLE" desc="The text to show in place of a reading list article title if the article is not found.">
     Failed to find article.
   </message>
@@ -40,9 +43,6 @@
   <message name="IDS_DOM_DISTILLER_VIEWER_NO_DATA_CONTENT" desc="The text to show in place of reading list article content if there is no data found.">
     No data found.
   </message>
-  <message name="IDS_DOM_DISTILLER_VIEWER_VIEW_ORIGINAL" desc="The text to show on a link of an article to view the original page.">
-    View Original
-  </message>
   <message name="IDS_DOM_DISTILLER_VIEWER_LOADING_STRING" desc="The text to show indicating that the viewer is still loading more content from the article.">
     Loading...
   </message>
diff --git a/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc b/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc
index c7c29f9..15e9dfe 100644
--- a/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc
+++ b/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc
@@ -369,7 +369,7 @@
 TEST_F(EnhancedBookmarkModelTest, TestRemoteId) {
   const BookmarkNode* node = AddBookmark();
   // Verify that the remote id starts with the correct prefix.
-  EXPECT_TRUE(StartsWithASCII(model_->GetRemoteId(node), "ebc_", true));
+  EXPECT_TRUE(base::StartsWithASCII(model_->GetRemoteId(node), "ebc_", true));
 
   // Getting the remote id for nodes that don't have them should return the
   // empty string.
diff --git a/components/error_page/renderer/net_error_helper_core.cc b/components/error_page/renderer/net_error_helper_core.cc
index dfcd68f..a35c254 100644
--- a/components/error_page/renderer/net_error_helper_core.cc
+++ b/components/error_page/renderer/net_error_helper_core.cc
@@ -334,6 +334,8 @@
                               accept_languages));
       suggest->SetString("originalUrlForDisplay", original_url_for_display);
       suggest->SetInteger("trackingId", tracking_id);
+      suggest->SetInteger("type", static_cast<int>(correction_index));
+
       params->override_suggestions->Append(suggest);
       break;
     }
diff --git a/components/favicon/content/content_favicon_driver_unittest.cc b/components/favicon/content/content_favicon_driver_unittest.cc
index 30f9e5e..4851945 100644
--- a/components/favicon/content/content_favicon_driver_unittest.cc
+++ b/components/favicon/content/content_favicon_driver_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/favicon/content/content_favicon_driver.h"
 
 #include "base/memory/scoped_ptr.h"
+#include "components/favicon/core/favicon_client.h"
 #include "components/favicon/core/favicon_handler.h"
 #include "components/favicon/core/favicon_service.h"
 #include "content/public/test/test_renderer_host.h"
diff --git a/components/favicon/core/favicon_client.h b/components/favicon/core/favicon_client.h
index faeea185..71dce4e 100644
--- a/components/favicon/core/favicon_client.h
+++ b/components/favicon/core/favicon_client.h
@@ -10,7 +10,6 @@
 #include "base/macros.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "components/favicon_base/favicon_callback.h"
-#include "components/keyed_service/core/keyed_service.h"
 
 class GURL;
 
@@ -18,8 +17,11 @@
 
 // This class abstracts operations that depend on the embedder's environment,
 // e.g. Chrome.
-class FaviconClient : public KeyedService {
+class FaviconClient {
  public:
+  FaviconClient() {}
+  virtual ~FaviconClient() {}
+
   // Returns true if the specified URL is a native application page URL.
   // If this returns true the favicon for the page must be fetched using
   // GetFaviconForNativeApplicationURL().
@@ -35,10 +37,6 @@
       const favicon_base::FaviconResultsCallback& callback,
       base::CancelableTaskTracker* tracker) = 0;
 
- protected:
-  FaviconClient() {}
-  ~FaviconClient() override {}
-
  private:
   DISALLOW_COPY_AND_ASSIGN(FaviconClient);
 };
diff --git a/components/favicon/core/favicon_driver_impl.cc b/components/favicon/core/favicon_driver_impl.cc
index c95bf3aa..9007569 100644
--- a/components/favicon/core/favicon_driver_impl.cc
+++ b/components/favicon/core/favicon_driver_impl.cc
@@ -30,7 +30,7 @@
   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableIconNtp))
     return true;
 
-  return StartsWithASCII(group_name, "Enabled", true);
+  return base::StartsWithASCII(group_name, "Enabled", true);
 }
 
 #if defined(OS_ANDROID) || defined(OS_IOS)
diff --git a/components/favicon/core/favicon_service.cc b/components/favicon/core/favicon_service.cc
index 31c70412..769c3e2 100644
--- a/components/favicon/core/favicon_service.cc
+++ b/components/favicon/core/favicon_service.cc
@@ -48,9 +48,10 @@
 
 }  // namespace
 
-FaviconService::FaviconService(FaviconClient* favicon_client,
+FaviconService::FaviconService(scoped_ptr<FaviconClient> favicon_client,
                                history::HistoryService* history_service)
-    : history_service_(history_service), favicon_client_(favicon_client) {
+    : favicon_client_(favicon_client.Pass()),
+      history_service_(history_service) {
 }
 
 FaviconService::~FaviconService() {
diff --git a/components/favicon/core/favicon_service.h b/components/favicon/core/favicon_service.h
index f8ebea4..747da38 100644
--- a/components/favicon/core/favicon_service.h
+++ b/components/favicon/core/favicon_service.h
@@ -32,7 +32,7 @@
 class FaviconService : public KeyedService {
  public:
   // The FaviconClient must outlive the constructed FaviconService.
-  FaviconService(FaviconClient* favicon_client,
+  FaviconService(scoped_ptr<FaviconClient> favicon_client,
                  history::HistoryService* history_service);
 
   ~FaviconService() override;
@@ -241,8 +241,8 @@
           favicon_bitmap_results);
 
   base::hash_set<MissingFaviconURLHash> missing_favicon_urls_;
+  scoped_ptr<FaviconClient> favicon_client_;
   history::HistoryService* history_service_;
-  FaviconClient* favicon_client_;
 
   DISALLOW_COPY_AND_ASSIGN(FaviconService);
 };
diff --git a/components/favicon/core/large_icon_service_unittest.cc b/components/favicon/core/large_icon_service_unittest.cc
index df7fcbd0..acc088c 100644
--- a/components/favicon/core/large_icon_service_unittest.cc
+++ b/components/favicon/core/large_icon_service_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "components/favicon/core/favicon_client.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/favicon_base/fallback_icon_style.h"
 #include "components/favicon_base/favicon_types.h"
diff --git a/components/feedback/feedback_data_unittest.cc b/components/feedback/feedback_data_unittest.cc
index 141c174..e10bc2f 100644
--- a/components/feedback/feedback_data_unittest.cc
+++ b/components/feedback/feedback_data_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <set>
 
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
@@ -38,13 +39,11 @@
   MOCK_METHOD1(DispatchReport, void(const std::string&));
 };
 
-MockUploader *g_uploader;
-
-KeyedService* CreateFeedbackUploaderService(content::BrowserContext* context) {
-  if (!g_uploader)
-    g_uploader = new MockUploader(context);
-  EXPECT_CALL(*g_uploader, DispatchReport(testing::_)).Times(1);
-  return g_uploader;
+scoped_ptr<KeyedService> CreateFeedbackUploaderService(
+    content::BrowserContext* context) {
+  scoped_ptr<MockUploader> uploader(new MockUploader(context));
+  EXPECT_CALL(*uploader, DispatchReport(testing::_)).Times(1);
+  return uploader.Pass();
 }
 
 scoped_ptr<std::string> MakeScoped(const char* str) {
@@ -108,8 +107,6 @@
   Send();
   RunMessageLoop();
   EXPECT_TRUE(data_->IsDataComplete());
-  delete g_uploader;
-  g_uploader = NULL;
 }
 
 }  // namespace feedback
diff --git a/components/feedback/feedback_uploader_unittest.cc b/components/feedback/feedback_uploader_unittest.cc
index 4985129..bd744854c 100644
--- a/components/feedback/feedback_uploader_unittest.cc
+++ b/components/feedback/feedback_uploader_unittest.cc
@@ -7,6 +7,7 @@
 #include <set>
 
 #include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
@@ -30,8 +31,9 @@
 const base::TimeDelta kRetryDelayForTest =
     base::TimeDelta::FromMilliseconds(100);
 
-KeyedService* CreateFeedbackUploaderService(content::BrowserContext* context) {
-  return new feedback::FeedbackUploaderChrome(context);
+scoped_ptr<KeyedService> CreateFeedbackUploaderService(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(new feedback::FeedbackUploaderChrome(context));
 }
 
 }  // namespace
diff --git a/components/filesystem/BUILD.gn b/components/filesystem/BUILD.gn
index 26e9d06..7579c0c 100644
--- a/components/filesystem/BUILD.gn
+++ b/components/filesystem/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application.gni")
 
 source_set("lib") {
   sources = [
diff --git a/components/filesystem/public/interfaces/BUILD.gn b/components/filesystem/public/interfaces/BUILD.gn
index a5128c3..139ef49 100644
--- a/components/filesystem/public/interfaces/BUILD.gn
+++ b/components/filesystem/public/interfaces/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
diff --git a/components/gcm_driver/registration_info.cc b/components/gcm_driver/registration_info.cc
index 31f412d4..5bae2fd 100644
--- a/components/gcm_driver/registration_info.cc
+++ b/components/gcm_driver/registration_info.cc
@@ -21,7 +21,8 @@
     std::string* registration_id) {
   scoped_ptr<RegistrationInfo> registration;
 
-  if (StartsWithASCII(serialzied_key, kInsanceIDSerializationPrefix, true))
+  if (base::StartsWithASCII(serialzied_key, kInsanceIDSerializationPrefix,
+                            true))
     registration.reset(new InstanceIDTokenInfo);
   else
     registration.reset(new GCMRegistrationInfo);
@@ -182,7 +183,8 @@
   if (serialized_key.empty() || serialized_value.empty())
     return false;
 
-  if (!StartsWithASCII(serialized_key, kInsanceIDSerializationPrefix, true))
+  if (!base::StartsWithASCII(serialized_key, kInsanceIDSerializationPrefix,
+                             true))
     return false;
 
   std::vector<std::string> fields;
diff --git a/components/google/core/browser/google_url_tracker.cc b/components/google/core/browser/google_url_tracker.cc
index 0b834308..770c9af 100644
--- a/components/google/core/browser/google_url_tracker.cc
+++ b/components/google/core/browser/google_url_tracker.cc
@@ -97,7 +97,7 @@
   std::string url_str;
   source->GetResponseAsString(&url_str);
   base::TrimWhitespace(url_str, base::TRIM_ALL, &url_str);
-  if (!StartsWithASCII(url_str, ".google.", false))
+  if (!base::StartsWithASCII(url_str, ".google.", false))
     return;
   GURL url("https://www" + url_str);
   if (!url.is_valid() || (url.path().length() > 1) || url.has_query() ||
diff --git a/components/google/core/browser/google_util.cc b/components/google/core/browser/google_util.cc
index dfe5d04..4d7d9d7 100644
--- a/components/google/core/browser/google_util.cc
+++ b/components/google/core/browser/google_util.cc
@@ -54,12 +54,12 @@
     return false;
   // Removes the tld and the preceding dot.
   std::string host_minus_tld(host, 0, host.length() - tld_length - 1);
-  if (LowerCaseEqualsASCII(host_minus_tld, domain_in_lower_case.c_str()))
+  if (base::LowerCaseEqualsASCII(host_minus_tld, domain_in_lower_case.c_str()))
     return true;
   if (subdomain_permission == google_util::ALLOW_SUBDOMAIN)
     return EndsWith(host_minus_tld, "." + domain_in_lower_case, false);
-  return LowerCaseEqualsASCII(host_minus_tld,
-                              ("www." + domain_in_lower_case).c_str());
+  return base::LowerCaseEqualsASCII(host_minus_tld,
+                                    ("www." + domain_in_lower_case).c_str());
 }
 
 // True if |url| is a valid URL with HTTP or HTTPS scheme. If |port_permission|
@@ -162,7 +162,8 @@
 bool StartsWithCommandLineGoogleBaseURL(const GURL& url) {
   GURL base_url(CommandLineGoogleBaseURL());
   return base_url.is_valid() &&
-      StartsWithASCII(url.possibly_invalid_spec(), base_url.spec(), true);
+         base::StartsWithASCII(url.possibly_invalid_spec(), base_url.spec(),
+                               true);
 }
 
 bool IsGoogleHostname(const std::string& host,
@@ -188,7 +189,7 @@
 
   // Make sure the path is a known home page path.
   std::string path(url.path());
-  return IsPathHomePageBase(path) || StartsWithASCII(path, "/ig", false);
+  return IsPathHomePageBase(path) || base::StartsWithASCII(path, "/ig", false);
 }
 
 bool IsGoogleSearchUrl(const GURL& url) {
diff --git a/components/gpu/public/interfaces/BUILD.gn b/components/gpu/public/interfaces/BUILD.gn
index 151272b..a5f246d 100644
--- a/components/gpu/public/interfaces/BUILD.gn
+++ b/components/gpu/public/interfaces/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc
index 201e0810..0f272a3 100644
--- a/components/guest_view/browser/guest_view_base.cc
+++ b/components/guest_view/browser/guest_view_base.cc
@@ -110,15 +110,17 @@
       return;
 
     destroyed_ = true;
-    guest_->EmbedderWillBeDestroyed();
+    GuestViewManager::FromBrowserContext(web_contents()->GetBrowserContext())
+        ->EmbedderWillBeDestroyed(
+            web_contents()->GetRenderProcessHost()->GetID());
     guest_->Destroy();
   }
 
   DISALLOW_COPY_AND_ASSIGN(OwnerContentsObserver);
 };
 
-// This observer ensures that the GuestViewBase destroys itself when its
-// embedder goes away.
+// This observer ensures that the GuestViewBase destroys itself if its opener
+// WebContents goes away before the GuestViewBase is attached.
 class GuestViewBase::OpenerLifetimeObserver : public WebContentsObserver {
  public:
   OpenerLifetimeObserver(GuestViewBase* guest)
@@ -318,6 +320,11 @@
 }
 
 // static
+void GuestViewBase::CleanUp(int embedder_process_id, int view_instance_id) {
+  // TODO(paulmeyer): Add in any general GuestView cleanup work here.
+}
+
+// static
 GuestViewBase* GuestViewBase::FromWebContents(const WebContents* web_contents) {
   WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer();
   auto it = guest_map->find(web_contents);
diff --git a/components/guest_view/browser/guest_view_base.h b/components/guest_view/browser/guest_view_base.h
index 2f167e15..cba69a12 100644
--- a/components/guest_view/browser/guest_view_base.h
+++ b/components/guest_view/browser/guest_view_base.h
@@ -60,6 +60,13 @@
     return nullptr;
   }
 
+  // Cleans up state when this GuestView is being destroyed.
+  // Note that this cannot be done in the destructor since a GuestView could
+  // potentially be created and destroyed in JavaScript before getting a
+  // GuestViewBase instance. This method can be hidden by a CleanUp() method in
+  // a derived class, in which case the derived method should call this one.
+  static void CleanUp(int embedder_process_id, int view_instance_id);
+
   static GuestViewBase* FromWebContents(
       const content::WebContents* web_contents);
 
@@ -92,12 +99,6 @@
   // completed loading.
   virtual void GuestViewDidStopLoading() {}
 
-  // This method is called before the embedder is destroyed.
-  // |owner_web_contents_| should still be valid during this call. This
-  // allows the derived class to perform some cleanup related to the embedder
-  // web contents.
-  virtual void EmbedderWillBeDestroyed() {}
-
   // This method is called when the embedder's zoom changes.
   virtual void EmbedderZoomChanged(double old_zoom_level,
                                    double new_zoom_level) {}
diff --git a/components/guest_view/browser/guest_view_manager.cc b/components/guest_view/browser/guest_view_manager.cc
index 04cc2205..7aad57f6 100644
--- a/components/guest_view/browser/guest_view_manager.cc
+++ b/components/guest_view/browser/guest_view_manager.cc
@@ -245,6 +245,40 @@
   }
 }
 
+void GuestViewManager::ViewCreated(int embedder_process_id,
+                                   int view_instance_id,
+                                   const std::string& view_type) {
+  if (guest_view_registry_.empty())
+    RegisterGuestViewTypes();
+  auto view_it = guest_view_registry_.find(view_type);
+  CHECK(view_it != guest_view_registry_.end())
+      << "Invalid GuestView created of type \"" << view_type << "\"";
+
+  // Register the cleanup callback for when this view is destroyed.
+  RegisterViewDestructionCallback(embedder_process_id,
+                                  view_instance_id,
+                                  base::Bind(view_it->second.cleanup_function,
+                                             embedder_process_id,
+                                             view_instance_id));
+}
+
+void GuestViewManager::ViewGarbageCollected(int embedder_process_id,
+                                            int view_instance_id) {
+  // Find and call any callbacks associated with the view that has been garbage
+  // collected.
+  auto embedder_it = view_destruction_callback_map_.find(embedder_process_id);
+  if (embedder_it == view_destruction_callback_map_.end())
+    return;
+  CallbacksForEachViewID& callbacks_for_embedder = embedder_it->second;
+  auto view_it = callbacks_for_embedder.find(view_instance_id);
+  if (view_it == callbacks_for_embedder.end())
+    return;
+  Callbacks& callbacks_for_view = view_it->second;
+  for (auto& callback : callbacks_for_view)
+    callback.Run();
+  callbacks_for_embedder.erase(view_it);
+}
+
 GuestViewBase* GuestViewManager::CreateGuestInternal(
     content::WebContents* owner_web_contents,
     const std::string& view_type) {
@@ -257,13 +291,21 @@
     return nullptr;
   }
 
-  return it->second.Run(owner_web_contents);
+  return it->second.create_function.Run(owner_web_contents);
 }
 
 void GuestViewManager::RegisterGuestViewTypes() {
   delegate_->RegisterAdditionalGuestViewTypes();
 }
 
+void GuestViewManager::RegisterViewDestructionCallback(
+    int embedder_process_id,
+    int view_instance_id,
+    const base::Closure& callback) {
+  view_destruction_callback_map_[embedder_process_id][view_instance_id]
+      .push_back(callback);
+}
+
 bool GuestViewManager::IsGuestAvailableToContext(GuestViewBase* guest) {
   return delegate_->IsGuestAvailableToContext(guest);
 }
@@ -277,6 +319,22 @@
   delegate_->DispatchEvent(event_name, args.Pass(), guest, instance_id);
 }
 
+void GuestViewManager::EmbedderWillBeDestroyed(int embedder_process_id) {
+  // Find and call any callbacks associated with the embedder that is being
+  // destroyed.
+  auto embedder_it = view_destruction_callback_map_.find(embedder_process_id);
+  if (embedder_it == view_destruction_callback_map_.end())
+    return;
+  CallbacksForEachViewID& callbacks_for_embedder = embedder_it->second;
+  for (auto& view_pair : callbacks_for_embedder) {
+    Callbacks& callbacks_for_view = view_pair.second;
+    for (auto& callback : callbacks_for_view) {
+      callback.Run();
+    }
+  }
+  view_destruction_callback_map_.erase(embedder_it);
+}
+
 content::WebContents* GuestViewManager::GetGuestByInstanceID(
     int guest_instance_id) {
   auto it = guest_web_contents_by_instance_id_.find(guest_instance_id);
@@ -370,7 +428,14 @@
 bool GuestViewManager::ElementInstanceKey::operator==(
     const GuestViewManager::ElementInstanceKey& other) const {
   return (embedder_process_id == other.embedder_process_id) &&
-    (element_instance_id == other.element_instance_id);
+         (element_instance_id == other.element_instance_id);
 }
 
+GuestViewManager::GuestViewData::GuestViewData(
+    const GuestViewCreateFunction& create_function,
+    const GuestViewCleanUpFunction& cleanup_function)
+    : create_function(create_function), cleanup_function(cleanup_function) {}
+
+GuestViewManager::GuestViewData::~GuestViewData() {}
+
 }  // namespace guest_view
diff --git a/components/guest_view/browser/guest_view_manager.h b/components/guest_view/browser/guest_view_manager.h
index 034f7565..d2f3c2b 100644
--- a/components/guest_view/browser/guest_view_manager.h
+++ b/components/guest_view/browser/guest_view_manager.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MANAGER_H_
 
 #include <map>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/gtest_prod_util.h"
@@ -89,9 +90,19 @@
     // registered here.
     if (guest_view_registry_.count(T::Type))
       return;
-    guest_view_registry_[T::Type] = base::Bind(&T::Create);
+    auto registry_entry = std::make_pair(
+        T::Type,
+        GuestViewData(base::Bind(&T::Create), base::Bind(&T::CleanUp)));
+    guest_view_registry_.insert(registry_entry);
   }
 
+  // Registers a callback to be called when the view identified by
+  // |embedder_process_id| and |view_instance_id| is destroyed.
+  // Note that multiple callbacks can be registered for one view.
+  void RegisterViewDestructionCallback(int embedder_process_id,
+                                       int view_instance_id,
+                                       const base::Closure& callback);
+
   using WebContentsCreatedCallback =
       base::Callback<void(content::WebContents*)>;
   void CreateGuest(const std::string& view_type,
@@ -121,12 +132,20 @@
   friend class GuestViewEvent;
   friend class GuestViewMessageFilter;
 
-  // Can be overriden in tests.
+  // These methods are virtual so that they can be overriden in tests.
+
   virtual void AddGuest(int guest_instance_id,
                         content::WebContents* guest_web_contents);
   virtual void RemoveGuest(int guest_instance_id);
+
+  // Called when a GuestView has been created in JavaScript.
+  virtual void ViewCreated(int embedder_process_id,
+                           int view_instance_id,
+                           const std::string& view_type);
+
+  // Called when a GuestView has been garbage collected in JavaScript.
   virtual void ViewGarbageCollected(int embedder_process_id,
-                                    int view_instance_id) {}
+                                    int view_instance_id);
 
   // Creates a guest of the provided |view_type|.
   GuestViewBase* CreateGuestInternal(content::WebContents* owner_web_contents,
@@ -146,6 +165,10 @@
                      GuestViewBase* guest,
                      int instance_id);
 
+  // This method is called when the embedder with ID |embedder_process_id| is
+  // about to be destroyed.
+  void EmbedderWillBeDestroyed(int embedder_process_id);
+
   content::WebContents* GetGuestByInstanceID(int guest_instance_id);
 
   bool CanEmbedderAccessInstanceIDMaybeKill(
@@ -190,11 +213,18 @@
   using GuestInstanceIDReverseMap = std::map<int, ElementInstanceKey>;
   GuestInstanceIDReverseMap reverse_instance_id_map_;
 
-  using GuestCreationCallback =
+  using GuestViewCreateFunction =
       base::Callback<GuestViewBase*(content::WebContents*)>;
-  using GuestViewCreationMap =
-      std::map<std::string, GuestViewManager::GuestCreationCallback>;
-  GuestViewCreationMap guest_view_registry_;
+  using GuestViewCleanUpFunction = base::Callback<void(int, int)>;
+  struct GuestViewData {
+    GuestViewData(const GuestViewCreateFunction& create_function,
+                  const GuestViewCleanUpFunction& cleanup_function);
+    ~GuestViewData();
+    const GuestViewCreateFunction create_function;
+    const GuestViewCleanUpFunction cleanup_function;
+  };
+  using GuestViewMethodMap = std::map<std::string, GuestViewData>;
+  GuestViewMethodMap guest_view_registry_;
 
   int current_instance_id_;
 
@@ -211,6 +241,13 @@
 
   scoped_ptr<GuestViewManagerDelegate> delegate_;
 
+  // |view_destruction_callback_map_| maps from embedder process ID to view ID
+  // to a vector of callback functions to be called when that view is destroyed.
+  using Callbacks = std::vector<base::Closure> ;
+  using CallbacksForEachViewID = std::map<int, Callbacks> ;
+  using CallbacksForEachEmbedderID = std::map<int, CallbacksForEachViewID> ;
+  CallbacksForEachEmbedderID view_destruction_callback_map_;
+
   DISALLOW_COPY_AND_ASSIGN(GuestViewManager);
 };
 
diff --git a/components/guest_view/browser/guest_view_message_filter.cc b/components/guest_view/browser/guest_view_message_filter.cc
index de7dbec..13835a0f 100644
--- a/components/guest_view/browser/guest_view_message_filter.cc
+++ b/components/guest_view/browser/guest_view_message_filter.cc
@@ -74,6 +74,7 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(GuestViewMessageFilter, message)
     IPC_MESSAGE_HANDLER(GuestViewHostMsg_AttachGuest, OnAttachGuest)
+    IPC_MESSAGE_HANDLER(GuestViewHostMsg_ViewCreated, OnViewCreated)
     IPC_MESSAGE_HANDLER(GuestViewHostMsg_ViewGarbageCollected,
                         OnViewGarbageCollected)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -81,6 +82,13 @@
   return handled;
 }
 
+void GuestViewMessageFilter::OnViewCreated(int view_instance_id,
+                                           const std::string& view_type) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  GetOrCreateGuestViewManager()->ViewCreated(render_process_id_,
+                                             view_instance_id, view_type);
+}
+
 void GuestViewMessageFilter::OnViewGarbageCollected(int view_instance_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   GetOrCreateGuestViewManager()->ViewGarbageCollected(render_process_id_,
diff --git a/components/guest_view/browser/guest_view_message_filter.h b/components/guest_view/browser/guest_view_message_filter.h
index 50b94e83..163945b 100644
--- a/components/guest_view/browser/guest_view_message_filter.h
+++ b/components/guest_view/browser/guest_view_message_filter.h
@@ -53,9 +53,6 @@
   void OnDestruct() const override;
   bool OnMessageReceived(const IPC::Message& message) override;
 
-  // Message handlers on the UI thread.
-  void OnViewGarbageCollected(int view_instance_id);
-
   const int render_process_id_;
 
   // Should only be accessed on the UI thread.
@@ -72,6 +69,8 @@
   void OnAttachGuest(int element_instance_id,
                      int guest_instance_id,
                      const base::DictionaryValue& attach_params);
+  void OnViewCreated(int view_instance_id, const std::string& view_type);
+  void OnViewGarbageCollected(int view_instance_id);
 
   DISALLOW_COPY_AND_ASSIGN(GuestViewMessageFilter);
 };
diff --git a/components/guest_view/browser/test_guest_view_manager.cc b/components/guest_view/browser/test_guest_view_manager.cc
index 584d0fcf..4f04d65 100644
--- a/components/guest_view/browser/test_guest_view_manager.cc
+++ b/components/guest_view/browser/test_guest_view_manager.cc
@@ -91,6 +91,7 @@
 
 void TestGuestViewManager::ViewGarbageCollected(int embedder_process_id,
                                                 int view_instance_id) {
+  GuestViewManager::ViewGarbageCollected(embedder_process_id, view_instance_id);
   ++num_views_garbage_collected_;
   if (gc_message_loop_runner_.get())
     gc_message_loop_runner_->Quit();
diff --git a/components/guest_view/browser/test_guest_view_manager.h b/components/guest_view/browser/test_guest_view_manager.h
index 2463fb6..d312d98 100644
--- a/components/guest_view/browser/test_guest_view_manager.h
+++ b/components/guest_view/browser/test_guest_view_manager.h
@@ -36,11 +36,15 @@
   size_t GetNumRemovedInstanceIDs() const;
 
   using GuestViewCreateFunction =
-      base::Callback<GuestViewBase*(content::WebContents*)>;;
+      base::Callback<GuestViewBase*(content::WebContents*)>;
 
   template <typename T>
-  void RegisterTestGuestViewType(GuestViewCreateFunction create_function) {
-    guest_view_registry_[T::Type] = create_function;
+  void RegisterTestGuestViewType(
+      const GuestViewCreateFunction& create_function) {
+    auto registry_entry = std::make_pair(
+        T::Type,
+        GuestViewData(create_function, base::Bind(&T::CleanUp)));
+    guest_view_registry_.insert(registry_entry);
   }
 
   // Returns the number of guests that have been created since the creation of
diff --git a/components/guest_view/common/guest_view_messages.h b/components/guest_view/common/guest_view_messages.h
index fb68ed4..bc0061d 100644
--- a/components/guest_view/common/guest_view_messages.h
+++ b/components/guest_view/common/guest_view_messages.h
@@ -35,6 +35,12 @@
                      base::DictionaryValue /* attach_params */)
 
 // Sent by the renderer when a GuestView (identified by |view_instance_id|) has
+// been created in JavaScript.
+IPC_MESSAGE_CONTROL2(GuestViewHostMsg_ViewCreated,
+                     int /* view_instance_id */,
+                     std::string /* view_type */)
+
+// Sent by the renderer when a GuestView (identified by |view_instance_id|) has
 // been garbage collected in JavaScript.
 IPC_MESSAGE_CONTROL1(GuestViewHostMsg_ViewGarbageCollected,
                      int /* view_instance_id */)
diff --git a/components/guest_view/renderer/guest_view_container.cc b/components/guest_view/renderer/guest_view_container.cc
index 1c13456b5..8a3c437 100644
--- a/components/guest_view/renderer/guest_view_container.cc
+++ b/components/guest_view/renderer/guest_view_container.cc
@@ -49,12 +49,43 @@
 GuestViewContainer::GuestViewContainer(content::RenderFrame* render_frame)
     : element_instance_id_(guest_view::kInstanceIDNone),
       render_frame_(render_frame),
-      ready_(false) {
+      ready_(false),
+      in_destruction_(false) {
   render_frame_lifetime_observer_.reset(
       new RenderFrameLifetimeObserver(this, render_frame_));
 }
 
 GuestViewContainer::~GuestViewContainer() {
+  // Note: Cleanups should be done in GuestViewContainer::Destroy(), not here.
+}
+
+// static.
+GuestViewContainer* GuestViewContainer::FromID(int element_instance_id) {
+  GuestViewContainerMap* guest_view_containers =
+      g_guest_view_container_map.Pointer();
+  auto it = guest_view_containers->find(element_instance_id);
+  return it == guest_view_containers->end() ? nullptr : it->second;
+}
+
+// Right now a GuestViewContainer can be destroyed in one of the following
+// ways:
+//
+// 1. If GuestViewContainer is driven by content/, the element (browser plugin)
+//   can destroy GuestViewContainer when the element is destroyed.
+// 2. If GuestViewContainer is managed outside of content/, then the
+//   <webview> element's GC will destroy it.
+// 3. If GuestViewContainer's embedder frame is destroyed, we'd also destroy
+//   GuestViewContainer.
+void GuestViewContainer::Destroy(bool embedder_frame_destroyed) {
+  if (in_destruction_)
+    return;
+
+  in_destruction_ = true;
+
+  // Give our derived class an opportunity to perform some cleanup prior to
+  // destruction.
+  OnDestroy(embedder_frame_destroyed);
+
   if (element_instance_id() != guest_view::kInstanceIDNone)
     g_guest_view_container_map.Get().erase(element_instance_id());
 
@@ -67,19 +98,14 @@
     // Call the JavaScript callbacks with no arguments which implies an error.
     pending_request->ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
   }
-}
 
-// static.
-GuestViewContainer* GuestViewContainer::FromID(int element_instance_id) {
-  GuestViewContainerMap* guest_view_containers =
-      g_guest_view_container_map.Pointer();
-  auto it = guest_view_containers->find(element_instance_id);
-  return it == guest_view_containers->end() ? nullptr : it->second;
+  delete this;
 }
 
 void GuestViewContainer::RenderFrameDestroyed() {
   OnRenderFrameDestroyed();
   render_frame_ = nullptr;
+  Destroy(true /* embedder_frame_destroyed */);
 }
 
 void GuestViewContainer::IssueRequest(linked_ptr<GuestViewRequest> request) {
@@ -146,4 +172,8 @@
       std::make_pair(element_instance_id, this));
 }
 
+void GuestViewContainer::DidDestroyElement() {
+  Destroy(false);
+}
+
 }  // namespace guest_view
diff --git a/components/guest_view/renderer/guest_view_container.h b/components/guest_view/renderer/guest_view_container.h
index 50b05cb..8232961 100644
--- a/components/guest_view/renderer/guest_view_container.h
+++ b/components/guest_view/renderer/guest_view_container.h
@@ -17,7 +17,6 @@
 class GuestViewContainer : public content::BrowserPluginDelegate {
  public:
   explicit GuestViewContainer(content::RenderFrame* render_frame);
-  ~GuestViewContainer() override;
 
   static GuestViewContainer* FromID(int element_instance_id);
 
@@ -33,6 +32,11 @@
   // container.
   bool OnMessageReceived(const IPC::Message& message);
 
+  // Destroys this GuestViewContainer after performing necessary cleanup.
+  // |embedder_frame_destroyed| is true if this destruction is due to the
+  // embedding frame of the container being destroyed.
+  void Destroy(bool embedder_frame_destroyed);
+
   // Called when the embedding RenderFrame is destroyed.
   virtual void OnRenderFrameDestroyed() {}
 
@@ -43,6 +47,14 @@
   // Called to perform actions when a GuestViewContainer gets a geometry.
   virtual void OnReady() {}
 
+  // Called to perform actions when a GuestViewContainer is about to be
+  // destroyed.
+  // Note that this should be called exactly once.
+  virtual void OnDestroy(bool embedder_frame_destroyed) {}
+
+ protected:
+  ~GuestViewContainer() override;
+
  private:
   class RenderFrameLifetimeObserver;
   friend class RenderFrameLifetimeObserver;
@@ -58,12 +70,14 @@
   // BrowserPluginDelegate implementation.
   void Ready() final;
   void SetElementInstanceID(int element_instance_id) final;
+  void DidDestroyElement() final;
 
   int element_instance_id_;
   content::RenderFrame* render_frame_;
   scoped_ptr<RenderFrameLifetimeObserver> render_frame_lifetime_observer_;
 
   bool ready_;
+  bool in_destruction_;
 
   std::deque<linked_ptr<GuestViewRequest> > pending_requests_;
   linked_ptr<GuestViewRequest> pending_response_;
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 97adc072e4..d04c038d 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -412,6 +412,13 @@
   }
 }
 
+TopHostsList HistoryBackend::TopHosts(int num_hosts) const {
+  if (!db_)
+    return TopHostsList();
+
+  return db_->TopHosts(num_hosts);
+}
+
 void HistoryBackend::AddPage(const HistoryAddPageArgs& request) {
   if (!db_)
     return;
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h
index 0903cbbd..76d4b50b 100644
--- a/components/history/core/browser/history_backend.h
+++ b/components/history/core/browser/history_backend.h
@@ -198,6 +198,11 @@
 
   void ClearCachedDataForContextID(ContextID context_id);
 
+  // Computes the |num_hosts| most-visited hostnames in the past 30 days. See
+  // history_service.h for details. Returns an empty list if db_ is not
+  // initialized.
+  TopHostsList TopHosts(int num_hosts) const;
+
   // Navigation ----------------------------------------------------------------
 
   // |request.time| must be unique with high probability.
@@ -507,6 +512,12 @@
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest,
                            UpdateFaviconMappingsAndFetchNoDB);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, QueryFilteredURLs);
+  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, TopHosts);
+  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, TopHosts_ElidePortAndScheme);
+  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, TopHosts_ElideWWW);
+  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, TopHosts_OnlyLast30Days);
+  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, TopHosts_MaxNumHosts);
+  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, TopHosts_IgnoreUnusualURLs);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, UpdateVisitDuration);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, ExpireHistoryForTimes);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, DeleteFTSIndexDatabases);
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc
index eaf5e9c..5b8c01e 100644
--- a/components/history/core/browser/history_backend_unittest.cc
+++ b/components/history/core/browser/history_backend_unittest.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -50,6 +51,8 @@
 
 namespace {
 
+using ::testing::ElementsAre;
+
 const int kTinyEdgeSize = 10;
 const int kSmallEdgeSize = 16;
 const int kLargeEdgeSize = 32;
@@ -2883,6 +2886,104 @@
   EXPECT_EQ(1U, filtered_list[1].extended_info.total_visits);
 }
 
+TEST_F(HistoryBackendTest, TopHosts) {
+  std::vector<GURL> urls;
+  urls.push_back(GURL("http://cnn.com/us"));
+  urls.push_back(GURL("http://cnn.com/intl"));
+  urls.push_back(GURL("http://dogtopia.com/"));
+  for (const auto& url : urls) {
+    backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
+                           history::SOURCE_BROWSED);
+  }
+
+  EXPECT_THAT(backend_->TopHosts(3),
+              ElementsAre(std::make_pair("cnn.com", 2),
+                          std::make_pair("dogtopia.com", 1)));
+}
+
+TEST_F(HistoryBackendTest, TopHosts_ElidePortAndScheme) {
+  std::vector<GURL> urls;
+  urls.push_back(GURL("http://cnn.com/us"));
+  urls.push_back(GURL("https://cnn.com/intl"));
+  urls.push_back(GURL("http://cnn.com:567/sports"));
+  for (const auto& url : urls) {
+    backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
+                           history::SOURCE_BROWSED);
+  }
+
+  EXPECT_THAT(backend_->TopHosts(3), ElementsAre(std::make_pair("cnn.com", 3)));
+}
+
+TEST_F(HistoryBackendTest, TopHosts_ElideWWW) {
+  std::vector<GURL> urls;
+  urls.push_back(GURL("http://www.cnn.com/us"));
+  urls.push_back(GURL("http://cnn.com/intl"));
+  urls.push_back(GURL("http://www.dogtopia.com/"));
+  for (const auto& url : urls) {
+    backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
+                           history::SOURCE_BROWSED);
+  }
+
+  EXPECT_THAT(backend_->TopHosts(3),
+              ElementsAre(std::make_pair("cnn.com", 2),
+                          std::make_pair("dogtopia.com", 1)));
+}
+
+TEST_F(HistoryBackendTest, TopHosts_OnlyLast30Days) {
+  std::vector<GURL> urls;
+  urls.push_back(GURL("http://cnn.com/us"));
+  urls.push_back(GURL("http://cnn.com/intl"));
+  urls.push_back(GURL("http://dogtopia.com/"));
+  for (const auto& url : urls) {
+    backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
+                           history::SOURCE_BROWSED);
+  }
+  backend_->AddPageVisit(GURL("http://www.oracle.com/"),
+                         base::Time::Now() - base::TimeDelta::FromDays(31), 0,
+                         ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED);
+
+  EXPECT_THAT(backend_->TopHosts(3),
+              ElementsAre(std::make_pair("cnn.com", 2),
+                          std::make_pair("dogtopia.com", 1)));
+}
+
+TEST_F(HistoryBackendTest, TopHosts_MaxNumHosts) {
+  std::vector<GURL> urls;
+  urls.push_back(GURL("http://cnn.com/us"));
+  urls.push_back(GURL("http://cnn.com/intl"));
+  urls.push_back(GURL("http://cnn.com/sports"));
+  urls.push_back(GURL("http://dogtopia.com/"));
+  urls.push_back(GURL("http://dogtopia.com/webcam"));
+  urls.push_back(GURL("http://www.gardenweb.com/"));
+  for (const auto& url : urls) {
+    backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
+                           history::SOURCE_BROWSED);
+  }
+
+  EXPECT_THAT(backend_->TopHosts(2),
+              ElementsAre(std::make_pair("cnn.com", 3),
+                          std::make_pair("dogtopia.com", 2)));
+}
+
+TEST_F(HistoryBackendTest, TopHosts_IgnoreUnusualURLs) {
+  std::vector<GURL> urls;
+  urls.push_back(GURL("http://cnn.com/us"));
+  urls.push_back(GURL("ftp://cnn.com/intl"));
+  urls.push_back(GURL("https://cnn.com/sports"));
+  urls.push_back(
+      GURL("chrome-extension://nghiiepjnjgjeolabmjjceablnkpkjde/options.html"));
+  urls.push_back(GURL("file:///home/foobar/tmp/baz.html"));
+  urls.push_back(GURL("data:text/plain,Hello%20world%21"));
+  urls.push_back(GURL("chrome://memory"));
+  urls.push_back(GURL("about:mammon"));
+  for (const auto& url : urls) {
+    backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
+                           history::SOURCE_BROWSED);
+  }
+
+  EXPECT_THAT(backend_->TopHosts(5), ElementsAre(std::make_pair("cnn.com", 3)));
+}
+
 TEST_F(HistoryBackendTest, UpdateVisitDuration) {
   // This unit test will test adding and deleting visit details information.
   ASSERT_TRUE(backend_.get());
diff --git a/components/history/core/browser/history_database.cc b/components/history/core/browser/history_database.cc
index 3de4523..888a30a 100644
--- a/components/history/core/browser/history_database.cc
+++ b/components/history/core/browser/history_database.cc
@@ -7,13 +7,18 @@
 #include <algorithm>
 #include <set>
 #include <string>
+#include <utility>
+#include <vector>
 
 #include "base/command_line.h"
+#include "base/containers/hash_tables.h"
 #include "base/files/file_util.h"
 #include "base/metrics/histogram.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/rand_util.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
+#include "sql/statement.h"
 #include "sql/transaction.h"
 
 #if defined(OS_MACOSX) && !defined(OS_IOS)
@@ -30,6 +35,7 @@
 const int kCurrentVersionNumber = 29;
 const int kCompatibleVersionNumber = 16;
 const char kEarlyExpirationThresholdKey[] = "early_expiration_threshold";
+const int kMaxHostsInMemory = 10000;
 
 }  // namespace
 
@@ -186,6 +192,53 @@
   }
 }
 
+TopHostsList HistoryDatabase::TopHosts(int num_hosts) {
+  base::Time one_month_ago =
+      std::max(base::Time::Now() - base::TimeDelta::FromDays(30), base::Time());
+
+  sql::Statement url_sql(db_.GetUniqueStatement(
+      "SELECT url, visit_count FROM urls WHERE last_visit_time > ?"));
+  url_sql.BindInt64(0, one_month_ago.ToInternalValue());
+
+  // Collect a map from host to visit count.
+  base::hash_map<std::string, int> host_count;
+  while (url_sql.Step()) {
+    GURL url(url_sql.ColumnString(0));
+    if (!(url.is_valid() && (url.SchemeIsHTTPOrHTTPS() || url.SchemeIs("ftp"))))
+      continue;
+
+    int64 visit_count = url_sql.ColumnInt64(1);
+    std::string host = url.host();
+    if (base::StartsWithASCII(host, "www.", true))
+      host.assign(host, 4, std::string::npos);
+    host_count[host] += visit_count;
+
+    // kMaxHostsInMemory is well above typical values for
+    // History.MonthlyHostCount, but here to guard against unbounded memory
+    // growth in the event of an atypical history.
+    if (host_count.size() >= kMaxHostsInMemory)
+      break;
+  }
+
+  // Collect the top 100 hosts by visit count, into the range
+  // [top_hosts.begin(), middle).
+  typedef std::vector<std::pair<int, std::string>> IntermediateList;
+  IntermediateList top_hosts;
+  for (const auto& it : host_count)
+    top_hosts.push_back(std::make_pair(-it.second, it.first));
+  IntermediateList::size_type middle_index = std::min(
+      base::saturated_cast<IntermediateList::size_type, int>(num_hosts),
+      top_hosts.size());
+  auto middle = std::min(top_hosts.end(), top_hosts.begin() + middle_index);
+  std::partial_sort(top_hosts.begin(), middle, top_hosts.end());
+
+  TopHostsList hosts;
+  for (IntermediateList::const_iterator it = top_hosts.begin(); it != middle;
+       ++it)
+    hosts.push_back(std::make_pair(it->second, -it->first));
+  return hosts;
+}
+
 void HistoryDatabase::BeginExclusiveMode() {
   // We can't use set_exclusive_locking() since that only has an effect before
   // the DB is opened.
diff --git a/components/history/core/browser/history_database.h b/components/history/core/browser/history_database.h
index 3abdead..f688843 100644
--- a/components/history/core/browser/history_database.h
+++ b/components/history/core/browser/history_database.h
@@ -10,6 +10,7 @@
 #include "base/gtest_prod_util.h"
 #include "build/build_config.h"
 #include "components/history/core/browser/download_database.h"
+#include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/url_database.h"
 #include "components/history/core/browser/visit_database.h"
 #include "components/history/core/browser/visitsegment_database.h"
@@ -84,6 +85,10 @@
   // called once and only upon successful Init.
   void ComputeDatabaseMetrics(const base::FilePath& filename);
 
+  // Computes the |num_hosts| most-visited hostnames in the past 30 days. See
+  // history_service.h for details.
+  TopHostsList TopHosts(int num_hosts);
+
   // Call to set the mode on the database to exclusive. The default locking mode
   // is "normal" but we want to run in exclusive mode for slightly better
   // performance since we know nobody else is using the database. This is
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index cbec585..25a19d20 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -355,6 +355,16 @@
                  history_backend_.get(), base::MessageLoop::current(), task));
 }
 
+void HistoryService::TopHosts(int num_hosts,
+                              const TopHostsCallback& callback) const {
+  DCHECK(thread_) << "History service being called after cleanup";
+  DCHECK(thread_checker_.CalledOnValidThread());
+  PostTaskAndReplyWithResult(
+      thread_->message_loop_proxy().get(), FROM_HERE,
+      base::Bind(&HistoryBackend::TopHosts, history_backend_.get(), num_hosts),
+      callback);
+}
+
 void HistoryService::AddPage(const GURL& url,
                              Time time,
                              ContextID context_id,
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index f45d926..947ad23 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -26,6 +26,7 @@
 #include "components/favicon_base/favicon_callback.h"
 #include "components/favicon_base/favicon_usage_data.h"
 #include "components/history/core/browser/delete_directive_handler.h"
+#include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/keyword_id.h"
 #include "components/history/core/browser/typed_url_syncable_service.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -82,6 +83,9 @@
   // Miscellaneous commonly-used types.
   typedef std::vector<PageUsageData*> PageUsageDataList;
 
+  // Callback for value asynchronously returned by TopHosts().
+  typedef base::Callback<void(const TopHostsList&)> TopHostsCallback;
+
   // Must call Init after construction. The empty constructor provided only for
   // unit tests. When using the full constructor, |history_client| may only be
   // null during testing, while |visit_delegate| may be null if the embedder use
@@ -148,6 +152,20 @@
   // KeyedService:
   void Shutdown() override;
 
+  // Computes the |num_hosts| most-visited hostnames in the past 30 days and
+  // returns a list of those hosts paired with their visit counts. The following
+  // caveats apply:
+  // 1. Hostnames are stripped of their 'www.' prefix. Visits to foo.com and
+  //    www.foo.com are summed into the resultant foo.com entry.
+  // 2. Ports and schemes are ignored. Visits to http://foo.com/ and
+  //    https://foo.com:567/ are summed into the resultant foo.com entry.
+  // 3. If the history is abnormally large and diverse, the function will give
+  //    up early and return an approximate list.
+  // 4. Only http://, https://, and ftp:// URLs are counted.
+  //
+  // Note: Virtual needed for mocking.
+  virtual void TopHosts(int num_hosts, const TopHostsCallback& callback) const;
+
   // Navigation ----------------------------------------------------------------
 
   // Adds the given canonical URL to history with the given time as the visit
diff --git a/components/history/core/browser/history_types.h b/components/history/core/browser/history_types.h
index a49ee300..3eadbca 100644
--- a/components/history/core/browser/history_types.h
+++ b/components/history/core/browser/history_types.h
@@ -9,6 +9,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -448,6 +449,9 @@
   DISALLOW_COPY_AND_ASSIGN(MostVisitedThumbnails);
 };
 
+// Map from host to visit count, sorted by visit count descending.
+typedef std::vector<std::pair<std::string, int>> TopHostsList;
+
 // Favicons -------------------------------------------------------------------
 
 // Used for the mapping between the page and icon.
diff --git a/components/history/core/browser/visitsegment_database.cc b/components/history/core/browser/visitsegment_database.cc
index 7beabd0..891c1b5 100644
--- a/components/history/core/browser/visitsegment_database.cc
+++ b/components/history/core/browser/visitsegment_database.cc
@@ -108,7 +108,7 @@
   const char* host_c = host.c_str();
   // Remove www. to avoid some dups.
   if (static_cast<int>(host.size()) > kWWWDotLen &&
-      LowerCaseEqualsASCII(host_c, host_c + kWWWDotLen, kWWWDot)) {
+      base::LowerCaseEqualsASCII(host_c, host_c + kWWWDotLen, kWWWDot)) {
     r.SetHost(host.c_str(),
               url::Component(kWWWDotLen,
                              static_cast<int>(host.size()) - kWWWDotLen));
diff --git a/components/html_viewer/BUILD.gn b/components/html_viewer/BUILD.gn
index 2d79209..a6b31350 100644
--- a/components/html_viewer/BUILD.gn
+++ b/components/html_viewer/BUILD.gn
@@ -4,9 +4,8 @@
 
 import("//build/module_args/v8.gni")
 import("//mojo/mojo_application_package.gni")
+import("//mojo/public/mojo_application.gni")
 import("//testing/test.gni")
-import("//third_party/mojo/src/mojo/public/mojo.gni")
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
 import("//tools/grit/grit_rule.gni")
 import("//tools/grit/repack.gni")
 
@@ -69,6 +68,8 @@
     "blink_resource_constants.h",
     "blink_url_request_type_converters.cc",
     "blink_url_request_type_converters.h",
+    "devtools_agent_impl.cc",
+    "devtools_agent_impl.h",
     "discardable_memory_allocator.cc",
     "discardable_memory_allocator.h",
     "frame_tree_manager.cc",
@@ -114,6 +115,8 @@
     "//cc/blink",
     "//cc/surfaces",
     "//components/clipboard/public/interfaces",
+    "//components/devtools_service/public/cpp",
+    "//components/devtools_service/public/interfaces",
     "//components/mime_util",
     "//components/resource_provider/public/cpp",
     "//components/resource_provider/public/interfaces",
diff --git a/components/html_viewer/DEPS b/components/html_viewer/DEPS
index 159ccb1..6e2d9a9 100644
--- a/components/html_viewer/DEPS
+++ b/components/html_viewer/DEPS
@@ -4,6 +4,7 @@
   "+blink/public/resources",
   "+cc",
   "+components/clipboard",
+  "+components/devtools_service/public",
   "+components/gpu",
   "+components/mime_util",
   "+components/resource_provider/public",
diff --git a/components/html_viewer/blink_url_request_type_converters.cc b/components/html_viewer/blink_url_request_type_converters.cc
index 9e6a40d..339db95c 100644
--- a/components/html_viewer/blink_url_request_type_converters.cc
+++ b/components/html_viewer/blink_url_request_type_converters.cc
@@ -23,7 +23,7 @@
     const std::string& name_latin1 = name.latin1();
     const std::string& value_latin1 = value.latin1();
 
-    if (LowerCaseEqualsASCII(name_latin1, "accept"))
+    if (base::LowerCaseEqualsASCII(name_latin1, "accept"))
       has_accept_header_ = true;
 
     HttpHeaderPtr header = HttpHeader::New();
diff --git a/components/html_viewer/devtools_agent_impl.cc b/components/html_viewer/devtools_agent_impl.cc
new file mode 100644
index 0000000..d7534288
--- /dev/null
+++ b/components/html_viewer/devtools_agent_impl.cc
@@ -0,0 +1,107 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/html_viewer/devtools_agent_impl.h"
+
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "mojo/application/public/cpp/connect.h"
+#include "mojo/application/public/interfaces/shell.mojom.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/WebKit/public/web/WebDevToolsAgent.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+
+namespace html_viewer {
+
+DevToolsAgentImpl::DevToolsAgentImpl(blink::WebLocalFrame* frame,
+                                     mojo::Shell* shell)
+    : frame_(frame), binding_(this) {
+  DCHECK(frame);
+  DCHECK(shell);
+
+  mojo::ServiceProviderPtr devtools_service_provider;
+  mojo::URLRequestPtr request(mojo::URLRequest::New());
+  request->url = "mojo:devtools_service";
+  shell->ConnectToApplication(
+      request.Pass(), mojo::GetProxy(&devtools_service_provider), nullptr);
+  devtools_service::DevToolsRegistryPtr devtools_registry;
+  mojo::ConnectToService(devtools_service_provider.get(), &devtools_registry);
+
+  devtools_service::DevToolsAgentPtr agent;
+  binding_.Bind(&agent);
+  devtools_registry->RegisterAgent(agent.Pass());
+
+  frame_->setDevToolsAgentClient(this);
+}
+
+DevToolsAgentImpl::~DevToolsAgentImpl() {
+  if (client_)
+    frame_->devToolsAgent()->detach();
+}
+
+void DevToolsAgentImpl::SetClient(
+    devtools_service::DevToolsAgentClientPtr client,
+    const mojo::String& client_id) {
+  if (client_)
+    frame_->devToolsAgent()->detach();
+
+  client_ = client.Pass();
+  client_.set_error_handler(this);
+
+  frame_->devToolsAgent()->attach(blink::WebString::fromUTF8(client_id));
+}
+
+void DevToolsAgentImpl::DispatchProtocolMessage(const mojo::String& message) {
+  // TODO(yzshen): (1) Eventually the handling code for Page.navigate (and some
+  // other commands) should live with the code managing tabs and navigation.
+  // We will need a DevToolsAgent implementation there as well, which handles
+  // some of the commands and relays messages between the DevTools service and
+  // the HTML viewer.
+  // (2) Consider refactoring and reusing the existing DevTools protocol parsing
+  // code.
+  do {
+    scoped_ptr<base::Value> value = base::JSONReader::Read(message.get());
+    base::DictionaryValue* command = nullptr;
+    if (!value || !value->GetAsDictionary(&command))
+      break;
+
+    std::string method;
+    if (!command->GetString("method", &method) || method != "Page.navigate")
+      break;
+
+    std::string url_string;
+    if (!command->GetString("params.url", &url_string))
+      break;
+
+    GURL url(url_string);
+    if (!url.is_valid())
+      break;
+
+    frame_->loadRequest(blink::WebURLRequest(url));
+
+    // The command should fall through to be handled by frame_->devToolsAgent().
+  } while (false);
+
+  frame_->devToolsAgent()->dispatchOnInspectorBackend(
+      blink::WebString::fromUTF8(message));
+}
+
+void DevToolsAgentImpl::sendProtocolMessage(int call_id,
+                                            const blink::WebString& response,
+                                            const blink::WebString& state) {
+  if (client_)
+    client_->DispatchProtocolMessage(response.utf8());
+}
+
+void DevToolsAgentImpl::OnConnectionError() {
+  client_.reset();
+  frame_->devToolsAgent()->detach();
+}
+
+}  // namespace html_viewer
diff --git a/components/html_viewer/devtools_agent_impl.h b/components/html_viewer/devtools_agent_impl.h
new file mode 100644
index 0000000..53074ce
--- /dev/null
+++ b/components/html_viewer/devtools_agent_impl.h
@@ -0,0 +1,56 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_HTML_VIEWER_DEVTOOLS_AGENT_IMPL_H_
+#define COMPONENTS_HTML_VIEWER_DEVTOOLS_AGENT_IMPL_H_
+
+#include "base/macros.h"
+#include "components/devtools_service/public/interfaces/devtools_service.mojom.h"
+#include "third_party/WebKit/public/web/WebDevToolsAgentClient.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
+
+namespace blink {
+class WebLocalFrame;
+}
+
+namespace mojo {
+class Shell;
+}
+
+namespace html_viewer {
+
+class DevToolsAgentImpl : public devtools_service::DevToolsAgent,
+                          public blink::WebDevToolsAgentClient,
+                          public mojo::ErrorHandler {
+ public:
+  // |frame| must outlive this object.
+  DevToolsAgentImpl(blink::WebLocalFrame* frame, mojo::Shell* shell);
+  ~DevToolsAgentImpl() override;
+
+  blink::WebLocalFrame* frame() const { return frame_; }
+
+ private:
+  // devtools_service::DevToolsAgent implementation.
+  void SetClient(devtools_service::DevToolsAgentClientPtr client,
+                 const mojo::String& client_id) override;
+  void DispatchProtocolMessage(const mojo::String& message) override;
+
+  // blink::WebDevToolsAgentClient implementation.
+  void sendProtocolMessage(int call_id,
+                           const blink::WebString& response,
+                           const blink::WebString& state);
+
+  // mojo::ErrorHandler implementation.
+  void OnConnectionError() override;
+
+  blink::WebLocalFrame* const frame_;
+  mojo::Binding<DevToolsAgent> binding_;
+  devtools_service::DevToolsAgentClientPtr client_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevToolsAgentImpl);
+};
+
+}  // namespace html_viewer
+
+#endif  // COMPONENTS_HTML_VIEWER_DEVTOOLS_AGENT_IMPL_H_
diff --git a/components/html_viewer/html_document.cc b/components/html_viewer/html_document.cc
index 62ef9cb..462313f 100644
--- a/components/html_viewer/html_document.cc
+++ b/components/html_viewer/html_document.cc
@@ -12,8 +12,10 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/thread_task_runner_handle.h"
+#include "components/devtools_service/public/cpp/switches.h"
 #include "components/html_viewer/blink_input_events_type_converters.h"
 #include "components/html_viewer/blink_url_request_type_converters.h"
+#include "components/html_viewer/devtools_agent_impl.h"
 #include "components/html_viewer/media_factory.h"
 #include "components/html_viewer/setup.h"
 #include "components/html_viewer/web_layer_tree_view_impl.h"
@@ -67,6 +69,11 @@
   return base::CommandLine::ForCurrentProcess()->HasSwitch(kOOPIF);
 }
 
+bool EnableRemoteDebugging() {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      devtools_service::kRemoteDebuggingPort);
+}
+
 // WebRemoteFrameClient implementation used for OOPIFs.
 // TODO(sky): this needs to talk to browser by way of an interface.
 class RemoteFrameClientImpl : public blink::WebRemoteFrameClient {
@@ -151,14 +158,14 @@
           html_document_app->app_lifetime_helper()->CreateAppRefCount()),
       html_document_app_(html_document_app),
       response_(response.Pass()),
+      navigator_host_(connection->GetServiceProvider()),
       web_view_(nullptr),
       root_(nullptr),
       view_manager_client_factory_(html_document_app->shell(), this),
       setup_(setup),
       frame_tree_manager_binding_(&frame_tree_manager_) {
-  embedder_exported_services_.AddService(
+  connection->AddService(
       static_cast<mojo::InterfaceFactory<mandoline::FrameTreeClient>*>(this));
-
   connection->AddService(
       static_cast<InterfaceFactory<mojo::AxProvider>*>(this));
   connection->AddService(&view_manager_client_factory_);
@@ -177,17 +184,10 @@
     root_->RemoveObserver(this);
 }
 
-void HTMLDocument::OnEmbed(
-    View* root,
-    mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services) {
+void HTMLDocument::OnEmbed(View* root) {
   DCHECK(!setup_->is_headless());
   root_ = root;
   root_->AddObserver(this);
-  embedder_service_provider_ = exposed_services.Pass();
-  navigator_host_.set_service_provider(embedder_service_provider_.get());
-
-  embedder_exported_services_.Bind(services.Pass());
 
   InitSetupAndLoadIfNecessary();
 }
@@ -221,8 +221,19 @@
   touch_handler_.reset(new TouchHandler(web_view_));
   web_layer_tree_view_impl_->set_widget(web_view_);
   ConfigureSettings(web_view_->settings());
-  web_view_->setMainFrame(
-      blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, this));
+
+  blink::WebLocalFrame* main_frame =
+      blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, this);
+  web_view_->setMainFrame(main_frame);
+
+  // TODO(yzshen): http://crbug.com/498986 Creating DevToolsAgentImpl instances
+  // causes html_viewer_apptests flakiness currently. Before we fix that we
+  // cannot enable remote debugging (which is required by Telemetry tests) on
+  // the bots.
+  if (EnableRemoteDebugging()) {
+    devtools_agent_.reset(
+        new DevToolsAgentImpl(main_frame, html_document_app_->shell()));
+  }
 
   GURL url(response->url);
 
@@ -333,9 +344,17 @@
 }
 
 void HTMLDocument::frameDetached(blink::WebFrame* frame) {
+  frameDetached(frame, DetachType::Remove);
+}
+
+void HTMLDocument::frameDetached(blink::WebFrame* frame, DetachType type) {
+  DCHECK(type == DetachType::Remove);
   if (frame->parent())
     frame->parent()->removeChild(frame);
 
+  if (devtools_agent_ && frame == devtools_agent_->frame())
+    devtools_agent_.reset();
+
   // |frame| is invalid after here.
   frame->close();
 }
@@ -352,7 +371,7 @@
   if (info.frame->parent() && EnableOOPIFs()) {
     mojo::View* view = frame_to_view_[info.frame].view;
     mojo::URLRequestPtr url_request = mojo::URLRequest::From(info.urlRequest);
-    view->Embed(url_request.Pass(), nullptr, nullptr);
+    view->EmbedAllowingReembed(url_request.Pass());
     // TODO(sky): I tried swapping the frame types here, but that resulted in
     // the view never getting sized. Figure out why.
     // TODO(sky): there are timing conditions here, and we should only do this
diff --git a/components/html_viewer/html_document.h b/components/html_viewer/html_document.h
index 2ddaf04..19cc3ec5 100644
--- a/components/html_viewer/html_document.h
+++ b/components/html_viewer/html_document.h
@@ -42,6 +42,7 @@
 namespace html_viewer {
 
 class AxProviderImpl;
+class DevToolsAgentImpl;
 class Setup;
 class WebLayerTreeViewImpl;
 
@@ -97,6 +98,7 @@
       const blink::WebString& frameName,
       blink::WebSandboxFlags sandboxFlags);
   virtual void frameDetached(blink::WebFrame* frame);
+  virtual void frameDetached(blink::WebFrame* frame, DetachType type);
   virtual blink::WebCookieJar* cookieJar(blink::WebLocalFrame* frame);
   virtual blink::WebNavigationPolicy decidePolicyForNavigation(
       const NavigationPolicyInfo& info);
@@ -112,9 +114,7 @@
   virtual blink::WebEncryptedMediaClient* encryptedMediaClient();
 
   // ViewManagerDelegate methods:
-  void OnEmbed(mojo::View* root,
-               mojo::InterfaceRequest<mojo::ServiceProvider> services,
-               mojo::ServiceProviderPtr exposed_services) override;
+  void OnEmbed(mojo::View* root) override;
   void OnViewManagerDestroyed(mojo::ViewManager* view_manager) override;
 
   // ViewObserver methods:
@@ -146,8 +146,6 @@
   scoped_ptr<mojo::AppRefCount> app_refcount_;
   mojo::ApplicationImpl* html_document_app_;
   mojo::URLResponsePtr response_;
-  mojo::ServiceProviderPtr embedder_service_provider_;
-  mojo::ServiceProviderImpl embedder_exported_services_;
   mojo::LazyInterfacePtr<mojo::NavigatorHost> navigator_host_;
   blink::WebView* web_view_;
   mojo::View* root_;
@@ -171,6 +169,8 @@
   FrameTreeManager frame_tree_manager_;
   mojo::Binding<mandoline::FrameTreeClient> frame_tree_manager_binding_;
 
+  scoped_ptr<DevToolsAgentImpl> devtools_agent_;
+
   DISALLOW_COPY_AND_ASSIGN(HTMLDocument);
 };
 
diff --git a/components/html_viewer/html_viewer.cc b/components/html_viewer/html_viewer.cc
index c891987..3219a9b 100644
--- a/components/html_viewer/html_viewer.cc
+++ b/components/html_viewer/html_viewer.cc
@@ -162,13 +162,6 @@
   }
 
   bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
-    // If we're not being connected to from the view manager assume we're being
-    // run in tests, or a headless environment, in which case we'll never get a
-    // ui and there is no point in waiting for it.
-    if (connection->GetRemoteApplicationURL() != "mojo://view_manager/" &&
-        !setup_->did_init()) {
-      setup_->InitHeadless();
-    }
     connection->AddService(this);
     return true;
   }
diff --git a/components/html_viewer/media_factory.cc b/components/html_viewer/media_factory.cc
index 101015a8..75a78a17a 100644
--- a/components/html_viewer/media_factory.cc
+++ b/components/html_viewer/media_factory.cc
@@ -88,11 +88,7 @@
                                       ->HasSwitch(kEnableMojoMediaRenderer)),
       compositor_task_runner_(compositor_task_runner),
       shell_(shell) {
-  if (!media::IsMediaLibraryInitialized()) {
-    base::FilePath module_dir;
-    CHECK(PathService::Get(base::DIR_EXE, &module_dir));
-    CHECK(media::InitializeMediaLibrary(module_dir));
-  }
+  media::InitializeMediaLibrary();
 }
 
 MediaFactory::~MediaFactory() {
@@ -160,6 +156,10 @@
 }
 
 media::MediaPermission* MediaFactory::GetMediaPermission() {
+  // TODO(xhwang): Replace DefaultMediaPermission with something real when
+  // permissions are supported in html_viewer.
+  NOTIMPLEMENTED();
+
   if (!media_permission_)
     media_permission_.reset(new media::DefaultMediaPermission(true));
   return media_permission_.get();
diff --git a/components/html_viewer/setup.cc b/components/html_viewer/setup.cc
index 76a6614..3da3601 100644
--- a/components/html_viewer/setup.cc
+++ b/components/html_viewer/setup.cc
@@ -75,7 +75,7 @@
       discardable_memory_allocator_(kDesiredMaxMemory),
       compositor_thread_("compositor thread") {
   if (is_headless_)
-    InitHeadless();
+    InitIfNecessary(gfx::Size(1024, 1024), 1.f);
 }
 
 Setup::~Setup() {
@@ -85,12 +85,6 @@
   }
 }
 
-void Setup::InitHeadless() {
-  DCHECK(!did_init_);
-  is_headless_ = true;
-  InitIfNecessary(gfx::Size(1024, 1024), 1.f);
-}
-
 void Setup::InitIfNecessary(const gfx::Size& screen_size_in_pixels,
                             float device_pixel_ratio) {
   if (did_init_)
@@ -136,6 +130,10 @@
   // Display process ID, thread ID and timestamp in logs.
   logging::SetLogItems(true, true, true, false);
 
+  // TODO(fsamuel): Slimming paint currently crashes mandoline. Investigate.
+  // See http://crbug.com/499353.
+  blink::WebRuntimeFeatures::enableSlimmingPaint(false);
+
   if (command_line->HasSwitch(kDisableEncryptedMedia))
     blink::WebRuntimeFeatures::enableEncryptedMedia(false);
 
diff --git a/components/html_viewer/setup.h b/components/html_viewer/setup.h
index ed32554..305ef14 100644
--- a/components/html_viewer/setup.h
+++ b/components/html_viewer/setup.h
@@ -39,10 +39,6 @@
   explicit Setup(mojo::ApplicationImpl* app);
   ~Setup();
 
-  // Use to explicitly create headless regardless of command line switches.
-  // This must be invoked before InitIfNecessary().
-  void InitHeadless();
-
   // Inits with the specified screen size and device pixel ratio.
   // NOTE: we wait to complete setup until the device pixel ratio is available
   // as ResourceBundle uses the device pixel ratio during initialization.
@@ -72,7 +68,7 @@
 
   resource_provider::ResourceLoader resource_loader_;
 
-  bool is_headless_;
+  const bool is_headless_;
 
   // True once we've completed init.
   bool did_init_;
diff --git a/components/html_viewer/web_mime_registry_impl.cc b/components/html_viewer/web_mime_registry_impl.cc
index 7954aba7..a050693 100644
--- a/components/html_viewer/web_mime_registry_impl.cc
+++ b/components/html_viewer/web_mime_registry_impl.cc
@@ -44,7 +44,7 @@
     const blink::WebString& mime_type) {
   std::string ascii_mime_type = ToASCIIOrEmpty(mime_type);
   return (mime_util::IsSupportedImageMimeType(ascii_mime_type) ||
-          (StartsWithASCII(ascii_mime_type, "image/", true) &&
+          (base::StartsWithASCII(ascii_mime_type, "image/", true) &&
            mime_util::IsSupportedNonImageMimeType(ascii_mime_type)))
              ? WebMimeRegistry::IsSupported
              : WebMimeRegistry::IsNotSupported;
diff --git a/components/html_viewer/web_url_loader_impl.cc b/components/html_viewer/web_url_loader_impl.cc
index ebaece9a..48d291f 100644
--- a/components/html_viewer/web_url_loader_impl.cc
+++ b/components/html_viewer/web_url_loader_impl.cc
@@ -30,10 +30,10 @@
   if (status_line.is_null())
     return blink::WebURLResponse::HTTP_0_9;
 
-  if (StartsWithASCII(status_line, "HTTP/1.0", true))
+  if (base::StartsWithASCII(status_line, "HTTP/1.0", true))
     return blink::WebURLResponse::HTTP_1_0;
 
-  if (StartsWithASCII(status_line, "HTTP/1.1", true))
+  if (base::StartsWithASCII(status_line, "HTTP/1.1", true))
     return blink::WebURLResponse::HTTP_1_1;
 
   return blink::WebURLResponse::Unknown;
diff --git a/components/infobars/core/infobar_delegate.cc b/components/infobars/core/infobar_delegate.cc
index 37fbdf7..d9f76551 100644
--- a/components/infobars/core/infobar_delegate.cc
+++ b/components/infobars/core/infobar_delegate.cc
@@ -68,6 +68,10 @@
   return nullptr;
 }
 
+PermissionInfobarDelegate* InfoBarDelegate::AsPermissionInfobarDelegate() {
+  return nullptr;
+}
+
 PopupBlockedInfoBarDelegate* InfoBarDelegate::AsPopupBlockedInfoBarDelegate() {
   return nullptr;
 }
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index ec6cd82..4c1e2341 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -14,6 +14,7 @@
 class InsecureContentInfoBarDelegate;
 class MediaStreamInfoBarDelegate;
 class NativeAppInfoBarDelegate;
+class PermissionInfobarDelegate;
 class PopupBlockedInfoBarDelegate;
 class RegisterProtocolHandlerInfoBarDelegate;
 class ScreenCaptureInfoBarDelegate;
@@ -114,6 +115,7 @@
   virtual InsecureContentInfoBarDelegate* AsInsecureContentInfoBarDelegate();
   virtual MediaStreamInfoBarDelegate* AsMediaStreamInfoBarDelegate();
   virtual NativeAppInfoBarDelegate* AsNativeAppInfoBarDelegate();
+  virtual PermissionInfobarDelegate* AsPermissionInfobarDelegate();
   virtual PopupBlockedInfoBarDelegate* AsPopupBlockedInfoBarDelegate();
   virtual RegisterProtocolHandlerInfoBarDelegate*
       AsRegisterProtocolHandlerInfoBarDelegate();
diff --git a/components/invalidation.gypi b/components/invalidation.gypi
index 8378c2c..35fc77a 100644
--- a/components/invalidation.gypi
+++ b/components/invalidation.gypi
@@ -177,6 +177,7 @@
           'target_name': 'invalidation_java',
           'type': 'none',
           'dependencies': [
+            'invalidation_proto_java',
             '../base/base.gyp:base',
             '../sync/sync.gyp:sync_java',
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_javalib',
@@ -187,6 +188,14 @@
           'includes': [ '../build/java.gypi' ],
         },
         {
+          'target_name': 'invalidation_proto_java',
+          'type': 'none',
+          'sources': [
+            'invalidation/android/proto/serialized_invalidation.proto',
+          ],
+          'includes': [ '../build/protoc_java.gypi' ],
+        },
+        {
           'target_name': 'invalidation_javatests',
           'type': 'none',
           'dependencies': [
@@ -199,6 +208,23 @@
           'includes': [ '../build/java.gypi' ],
         },
         {
+          'target_name': 'invalidation_junit_tests',
+          'type': 'none',
+          'dependencies': [
+            'invalidation_java',
+            '../base/base.gyp:base_java',
+            '../base/base.gyp:base_java_test_support',
+            '../testing/android/junit/junit_test.gyp:junit_test_support',
+          ],
+          'variables': {
+            'main_class': 'org.chromium.testing.local.JunitTestMain',
+            'src_paths': [
+              'invalidation/android/junit/'
+            ],
+          },
+          'includes': [ '../build/host_jar.gypi' ],
+        },
+        {
           'target_name': 'invalidation_jni_headers',
           'type': 'none',
           'sources': [
diff --git a/components/invalidation/BUILD.gn b/components/invalidation/BUILD.gn
index e361dae..7fa7b87 100644
--- a/components/invalidation/BUILD.gn
+++ b/components/invalidation/BUILD.gn
@@ -170,14 +170,22 @@
 if (is_android) {
   android_library("java") {
     deps = [
+      ":proto_java",
       "//base:base_java",
       "//sync/android:sync_java",
+      "//third_party/android_protobuf:protobuf_nano_javalib",
       "//third_party/cacheinvalidation:cacheinvalidation_javalib",
       "//third_party/cacheinvalidation:cacheinvalidation_proto_java",
       "//third_party/jsr-305:jsr_305_javalib",
     ]
     DEPRECATED_java_in_dir = "android/java/src"
   }
+  proto_java_library("proto_java") {
+    proto_path = "android/proto"
+    sources = [
+      "$proto_path/serialized_invalidation.proto",
+    ]
+  }
   android_library("javatests") {
     deps = [
       ":java",
@@ -189,6 +197,14 @@
     ]
     DEPRECATED_java_in_dir = "android/javatests/src"
   }
+  junit_binary("junit_tests") {
+    java_files = [ "android/junit/src/org/chromium/components/invalidation/PendingInvalidationTest.java" ]
+    deps = [
+      ":java",
+      "//base:base_java",
+      "//base:base_java_test_support",
+    ]
+  }
   generate_jni("jni_headers") {
     sources = [
       "android/java/src/org/chromium/components/invalidation/InvalidationService.java",
diff --git a/components/invalidation/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java b/components/invalidation/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java
index ced6f51..0b7fec42f 100644
--- a/components/invalidation/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java
+++ b/components/invalidation/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java
@@ -116,13 +116,13 @@
 
     @Override
     public void invalidateUnknownVersion(ObjectId objectId, byte[] ackHandle) {
-        requestSync(objectId, null, null);
+        requestSync(objectId, 0L, null);
         acknowledge(ackHandle);
     }
 
     @Override
     public void invalidateAll(byte[] ackHandle) {
-        requestSync(null, null, null);
+        requestSync(null, 0L, null);
         acknowledge(ackHandle);
     }
 
@@ -426,23 +426,15 @@
      * @param version the version of the object that changed, if known.
      * @param payload the payload of the change, if known.
      */
-    private void requestSync(@Nullable ObjectId objectId, @Nullable Long version,
-            @Nullable String payload) {
-        // Construct the bundle to supply to the native sync code.
-        Bundle bundle = new Bundle();
-        if (objectId == null && version == null && payload == null) {
-            // Use an empty bundle in this case for compatibility with the v1 implementation.
-        } else {
-            if (objectId != null) {
-                bundle.putInt("objectSource", objectId.getSource());
-                bundle.putString("objectId", new String(objectId.getName()));
-            }
-            // We use "0" as the version if we have an unknown-version invalidation. This is OK
-            // because the native sync code special-cases zero and always syncs for invalidations at
-            // that version (Tango defines a special UNKNOWN_VERSION constant with this value).
-            bundle.putLong("version", (version == null) ? 0 : version);
-            bundle.putString("payload", (payload == null) ? "" : payload);
+    private void requestSync(@Nullable ObjectId objectId, long version, @Nullable String payload) {
+        int objectSource = 0;
+        String objectName = null;
+        if (objectId != null) {
+            objectName = new String(objectId.getName());
+            objectSource = objectId.getSource();
         }
+        Bundle bundle =
+                PendingInvalidation.createBundle(objectName, objectSource, version, payload);
         Account account = ChromeSigninController.get(this).getSignedInUser();
         String contractAuthority = AndroidSyncSettings.getContractAuthority(this);
         requestSyncFromContentResolver(bundle, account, contractAuthority);
diff --git a/components/invalidation/android/java/src/org/chromium/components/invalidation/InvalidationService.java b/components/invalidation/android/java/src/org/chromium/components/invalidation/InvalidationService.java
index e8bf6757..96963ad 100644
--- a/components/invalidation/android/java/src/org/chromium/components/invalidation/InvalidationService.java
+++ b/components/invalidation/android/java/src/org/chromium/components/invalidation/InvalidationService.java
@@ -8,6 +8,8 @@
 import android.content.Context;
 import android.content.Intent;
 
+import com.google.protos.ipc.invalidation.Types;
+
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
 import org.chromium.base.ThreadUtils;
@@ -35,16 +37,15 @@
         mNativeInvalidationServiceAndroid = nativeInvalidationServiceAndroid;
     }
 
-    public void requestSyncFromNativeChrome(
+    public void notifyInvalidationToNativeChrome(
             int objectSource, String objectId, long version, String payload) {
         ThreadUtils.assertOnUiThread();
-        nativeRequestSync(
+        nativeInvalidate(
                 mNativeInvalidationServiceAndroid, objectSource, objectId, version, payload);
     }
 
     public void requestSyncFromNativeChromeForAllTypes() {
-        ThreadUtils.assertOnUiThread();
-        nativeRequestSyncForAllTypes(mNativeInvalidationServiceAndroid);
+        notifyInvalidationToNativeChrome(Types.ObjectSource.CHROME_SYNC, null, 0L, null);
     }
 
     @CalledByNative
@@ -66,9 +67,8 @@
     public void setRegisteredObjectIds(int[] objectSources, String[] objectNames) {
         InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
         Account account = invalidationPreferences.getSavedSyncedAccount();
-        Intent registerIntent =
-                InvalidationIntentProtocol.createRegisterIntent(
-                        account, objectSources, objectNames);
+        Intent registerIntent = InvalidationIntentProtocol.createRegisterIntent(
+                account, objectSources, objectNames);
         registerIntent.setClass(mContext, InvalidationClientService.class);
         mContext.startService(registerIntent);
     }
@@ -85,7 +85,6 @@
         return InvalidationClientNameProvider.get().getInvalidatorClientName();
     }
 
-    private native void nativeRequestSync(long nativeInvalidationServiceAndroid,
-            int objectSource, String objectId, long version, String payload);
-    private native void nativeRequestSyncForAllTypes(long nativeInvalidationServiceAndroid);
+    private native void nativeInvalidate(long nativeInvalidationServiceAndroid, int objectSource,
+            String objectId, long version, String payload);
 }
diff --git a/components/invalidation/android/java/src/org/chromium/components/invalidation/PendingInvalidation.java b/components/invalidation/android/java/src/org/chromium/components/invalidation/PendingInvalidation.java
new file mode 100644
index 0000000..10f1293
--- /dev/null
+++ b/components/invalidation/android/java/src/org/chromium/components/invalidation/PendingInvalidation.java
@@ -0,0 +1,136 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.invalidation;
+
+import android.os.Bundle;
+import android.util.Base64;
+
+import com.google.protobuf.nano.MessageNano;
+
+import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.components.invalidation.SerializedInvalidation.Invalidation;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import javax.annotation.Nullable;
+
+/**
+ * A container class that stores the received invalidations.
+ * It plays the role of abstracting conversions to and from other storage types like String
+ * (storing in prefStore) and Bundle (ContentProvider).
+ */
+public class PendingInvalidation {
+    private static final String TAG = Log.makeTag("invalidation");
+
+    private static final String INVALIDATION_OBJECT_SOURCE_KEY = "objectSource";
+    private static final String INVALIDATION_OBJECT_ID_KEY = "objectId";
+    private static final String INVALIDATION_VERSION_KEY = "version";
+    private static final String INVALIDATION_PAYLOAD_KEY = "payload";
+
+    public final String mObjectId;
+    public final int mObjectSource;
+    public final long mVersion;
+    public final String mPayload;
+
+    /**
+     * A constructor used in tests only.
+     */
+    @VisibleForTesting
+    public PendingInvalidation(String id, int source, long version, String payload) {
+        mObjectId = id;
+        mObjectSource = source;
+        mVersion = version;
+        mPayload = payload;
+    }
+
+    /**
+     * Parse a PendingInvalidation from a bundle.
+     */
+    public PendingInvalidation(Bundle bundle) {
+        // bundle.get* methods helpfully give compatible fallback values so we don't handle that.
+        mObjectId = bundle.getString(INVALIDATION_OBJECT_ID_KEY);
+        mObjectSource = bundle.getInt(INVALIDATION_OBJECT_SOURCE_KEY);
+        mVersion = bundle.getLong(INVALIDATION_VERSION_KEY);
+        mPayload = bundle.getString(INVALIDATION_PAYLOAD_KEY);
+    }
+
+    /**
+     * Encode an invalidation into a bundle.
+     */
+    public static Bundle createBundle(String id, int source, long version, String payload) {
+        Bundle bundle = new Bundle();
+        bundle.putString(INVALIDATION_OBJECT_ID_KEY, id);
+        bundle.putInt(INVALIDATION_OBJECT_SOURCE_KEY, source);
+        bundle.putLong(INVALIDATION_VERSION_KEY, version);
+        bundle.putString(INVALIDATION_PAYLOAD_KEY, payload);
+        return bundle;
+    }
+
+    /**
+     * Encode an invalidation into a String.
+     * The invalidation is first encoded as {@link SerializedInvalidation.Invalidation}, which is
+     * further encoded into a String of Base64 encoding.
+     * Do not call for mObjectSource == 0, which is an invalidation for all types and is handled
+     * specially.
+     */
+    public String encodeToString() {
+        assert mObjectSource != 0;
+        Invalidation invalidation = new Invalidation();
+        invalidation.objectSource = mObjectSource;
+        invalidation.objectId = mObjectId;
+        invalidation.version = mVersion;
+        invalidation.payload = mPayload;
+        return Base64.encodeToString(MessageNano.toByteArray(invalidation), Base64.DEFAULT);
+    }
+
+    /**
+     * Decode the invalidation encoded as a String into a Bundle.
+     * Return value is {@code null} if the string could not be parsed or is an invalidation for all.
+     */
+    @Nullable
+    public static Bundle decodeToBundle(String encoded) {
+        assert encoded != null;
+        byte[] decoded = Base64.decode(encoded, Base64.DEFAULT);
+        Invalidation invalidation;
+        try {
+            invalidation = MessageNano.mergeFrom(new Invalidation(), decoded);
+        } catch (IOException e) {
+            Log.e(TAG, "Could not parse the serialized invalidations.", e);
+            return null;
+        }
+        assert invalidation != null;
+        if (invalidation.objectSource == null || invalidation.objectSource == 0) return null;
+        return createBundle(invalidation.objectId, invalidation.objectSource,
+                invalidation.version != null ? invalidation.version : 0L, invalidation.payload);
+    }
+
+    @VisibleForTesting
+    @Override
+    public boolean equals(Object other) {
+        if (other == null) return false;
+        if (other == this) return true;
+        if (!(other instanceof PendingInvalidation)) return false;
+        PendingInvalidation otherInvalidation = (PendingInvalidation) other;
+        if (mObjectSource != otherInvalidation.mObjectSource) return false;
+        if (mObjectSource == 0) return true;
+        if (!mObjectId.equals(otherInvalidation.mObjectId)) return false;
+        if (!mPayload.equals(otherInvalidation.mPayload)) return false;
+        return mVersion == otherInvalidation.mVersion;
+    }
+
+    @Override
+    public int hashCode() {
+        return mObjectId == null ? mObjectSource : mObjectSource ^ mObjectId.hashCode()
+                        ^ Long.valueOf(mVersion).hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return String.format(Locale.US, "objectSrc:%d,objectId:%s,version:%d,payload:%s",
+                mObjectSource, mObjectId, mVersion, mPayload);
+    }
+}
diff --git a/components/invalidation/android/javatests/src/org/chromium/components/invalidation/InvalidationClientServiceTest.java b/components/invalidation/android/javatests/src/org/chromium/components/invalidation/InvalidationClientServiceTest.java
index d30c873..a4fd8e3 100644
--- a/components/invalidation/android/javatests/src/org/chromium/components/invalidation/InvalidationClientServiceTest.java
+++ b/components/invalidation/android/javatests/src/org/chromium/components/invalidation/InvalidationClientServiceTest.java
@@ -7,7 +7,6 @@
 import android.accounts.Account;
 import android.content.ComponentName;
 import android.content.Intent;
-import android.os.Bundle;
 import android.test.ServiceTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -364,21 +363,23 @@
          */
         // Call invalidate.
         int version = 4747;
-        ObjectId objectId = ObjectId.newInstance(55, "BOOKMARK".getBytes());
+        int objectSource = 55;
+        String objectName = "BOOKMARK";
+        ObjectId objectId = ObjectId.newInstance(objectSource, objectName.getBytes());
         final String payload = "testInvalidate-" + hasPayload;
-        Invalidation invalidation = hasPayload ?
-                Invalidation.newInstance(objectId, version, payload.getBytes()) :
-                Invalidation.newInstance(objectId, version);
+        Invalidation invalidation = hasPayload
+                ? Invalidation.newInstance(objectId, version, payload.getBytes())
+                : Invalidation.newInstance(objectId, version);
         byte[] ackHandle = ("testInvalidate-" + hasPayload).getBytes();
         getService().invalidate(invalidation, ackHandle);
 
         // Validate bundle.
         assertEquals(1, getService().mRequestedSyncs.size());
-        Bundle syncBundle = getService().mRequestedSyncs.get(0);
-        assertEquals(55, syncBundle.getInt("objectSource"));
-        assertEquals("BOOKMARK", syncBundle.getString("objectId"));
-        assertEquals(version, syncBundle.getLong("version"));
-        assertEquals(hasPayload ? payload : "", syncBundle.getString("payload"));
+        PendingInvalidation request = new PendingInvalidation(getService().mRequestedSyncs.get(0));
+        assertEquals(objectSource, request.mObjectSource);
+        assertEquals(objectName, request.mObjectId);
+        assertEquals(version, request.mVersion);
+        assertEquals(hasPayload ? payload : null, request.mPayload);
 
         // Ensure acknowledged.
         assertSingleAcknowledgement(ackHandle);
@@ -391,17 +392,19 @@
          * Test plan: call invalidateUnknownVersion(). Verify the produced bundle has the correct
          * fields.
          */
-        ObjectId objectId = ObjectId.newInstance(55, "BOOKMARK".getBytes());
+        int objectSource = 55;
+        String objectName = "BOOKMARK";
+        ObjectId objectId = ObjectId.newInstance(objectSource, objectName.getBytes());
         byte[] ackHandle = "testInvalidateUV".getBytes();
         getService().invalidateUnknownVersion(objectId, ackHandle);
 
         // Validate bundle.
         assertEquals(1, getService().mRequestedSyncs.size());
-        Bundle syncBundle = getService().mRequestedSyncs.get(0);
-        assertEquals(55, syncBundle.getInt("objectSource"));
-        assertEquals("BOOKMARK", syncBundle.getString("objectId"));
-        assertEquals(0, syncBundle.getLong("version"));
-        assertEquals("", syncBundle.getString("payload"));
+        PendingInvalidation request = new PendingInvalidation(getService().mRequestedSyncs.get(0));
+        assertEquals(objectSource, request.mObjectSource);
+        assertEquals(objectName, request.mObjectId);
+        assertEquals(0, request.mVersion);
+        assertEquals(null, request.mPayload);
 
         // Ensure acknowledged.
         assertSingleAcknowledgement(ackHandle);
@@ -418,8 +421,8 @@
 
         // Validate bundle.
         assertEquals(1, getService().mRequestedSyncs.size());
-        Bundle syncBundle = getService().mRequestedSyncs.get(0);
-        assertEquals(0, syncBundle.keySet().size());
+        PendingInvalidation request = new PendingInvalidation(getService().mRequestedSyncs.get(0));
+        assertEquals(0, request.mObjectSource);
 
         // Ensure acknowledged.
         assertSingleAcknowledgement(ackHandle);
@@ -589,9 +592,9 @@
             expectedRegisteredIds.addAll(expectedObjectIds);
         }
 
-        return actualSyncTypes.equals(expectedSyncTypes) &&
-                actualObjectIds.equals(expectedObjectIds) &&
-                getService().mCurrentRegistrations.equals(expectedRegisteredIds);
+        return actualSyncTypes.equals(expectedSyncTypes)
+                && actualObjectIds.equals(expectedObjectIds)
+                && getService().mCurrentRegistrations.equals(expectedRegisteredIds);
     }
 
     @SmallTest
diff --git a/components/invalidation/android/junit/src/org/chromium/components/invalidation/PendingInvalidationTest.java b/components/invalidation/android/junit/src/org/chromium/components/invalidation/PendingInvalidationTest.java
new file mode 100644
index 0000000..a1104fb
--- /dev/null
+++ b/components/invalidation/android/junit/src/org/chromium/components/invalidation/PendingInvalidationTest.java
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.invalidation;
+
+import android.os.Bundle;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * Tests for {@link PendingInvalidation}.
+ */
+@RunWith(BlockJUnit4ClassRunner.class)
+public class PendingInvalidationTest {
+    private static String sObjecId = "ObjectId";
+    private static int sObjectSource = 4;
+    private static long sVersion = 5;
+    private static String sPayload = "Payload";
+
+    @Test
+    public void testParseFromBundle() {
+        PendingInvalidation invalidation =
+                new PendingInvalidation(sObjecId, sObjectSource, sVersion, sPayload);
+        Bundle bundle =
+                PendingInvalidation.createBundle(sObjecId, sObjectSource, sVersion, sPayload);
+        PendingInvalidation parsedInvalidation = new PendingInvalidation(bundle);
+        assertEquals(sObjecId, parsedInvalidation.mObjectId);
+        assertEquals(sObjectSource, parsedInvalidation.mObjectSource);
+        assertEquals(sVersion, parsedInvalidation.mVersion);
+        assertEquals(sPayload, parsedInvalidation.mPayload);
+        assertEquals(invalidation, parsedInvalidation);
+    }
+
+    @Test
+    public void testParseToAndFromProtocolBuffer() {
+        PendingInvalidation invalidation =
+                new PendingInvalidation(sObjecId, sObjectSource, sVersion, sPayload);
+        Bundle bundle = PendingInvalidation.decodeToBundle(invalidation.encodeToString());
+        PendingInvalidation parsedInvalidation = new PendingInvalidation(bundle);
+        assertEquals(sObjecId, parsedInvalidation.mObjectId);
+        assertEquals(sObjectSource, parsedInvalidation.mObjectSource);
+        assertEquals(sVersion, parsedInvalidation.mVersion);
+        assertEquals(sPayload, parsedInvalidation.mPayload);
+        assertEquals(invalidation, parsedInvalidation);
+    }
+}
diff --git a/components/invalidation/android/proto/serialized_invalidation.proto b/components/invalidation/android/proto/serialized_invalidation.proto
new file mode 100644
index 0000000..c191f7e
--- /dev/null
+++ b/components/invalidation/android/proto/serialized_invalidation.proto
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Protocol buffer definition for saving pending invalidations that are
+// received when Chrome is unable to process them (i.e. it is backgrounded).
+//
+syntax = "proto2";
+package org.chromium.components.invalidation;
+option optimize_for = LITE_RUNTIME;
+
+message Invalidation {
+  // Next ID to use: 5
+  optional string object_id = 1;
+  optional int32 object_source = 2;
+  optional int64 version = 3;
+  optional string payload = 4;
+}
diff --git a/components/invalidation/gcm_network_channel_unittest.cc b/components/invalidation/gcm_network_channel_unittest.cc
index 34ab7fab..83ac630 100644
--- a/components/invalidation/gcm_network_channel_unittest.cc
+++ b/components/invalidation/gcm_network_channel_unittest.cc
@@ -232,7 +232,7 @@
   net::FakeURLFetcher::AddExtraRequestHeader(header_line);
   std::string header_name("echo-token: ");
   std::string echo_token;
-  if (StartsWithASCII(header_line, header_name, false)) {
+  if (base::StartsWithASCII(header_line, header_name, false)) {
     echo_token = header_line;
     ReplaceFirstSubstringAfterOffset(
         &echo_token, 0, header_name, std::string());
diff --git a/components/invalidation/invalidation_service_android.cc b/components/invalidation/invalidation_service_android.cc
index adab880..b91f8e8 100644
--- a/components/invalidation/invalidation_service_android.cc
+++ b/components/invalidation/invalidation_service_android.cc
@@ -119,55 +119,48 @@
   invalidator_registrar_.UpdateInvalidatorState(invalidator_state_);
 }
 
-void InvalidationServiceAndroid::RequestSync(JNIEnv* env,
-                                             jobject obj,
-                                             jint object_source,
-                                             jstring java_object_id,
-                                             jlong version,
-                                             jstring java_state) {
-  invalidation::ObjectId object_id(object_source,
-      ConvertJavaStringToUTF8(env, java_object_id));
-
-  syncer::ObjectIdInvalidationMap object_ids_with_states;
-
-  if (version == ipc::invalidation::Constants::UNKNOWN) {
-    object_ids_with_states.Insert(
-        syncer::Invalidation::InitUnknownVersion(object_id));
-  } else {
-    ObjectIdVersionMap::iterator it =
-        max_invalidation_versions_.find(object_id);
-    if ((it != max_invalidation_versions_.end()) &&
-        (version <= it->second)) {
-      DVLOG(1) << "Dropping redundant invalidation with version " << version;
-      return;
+void InvalidationServiceAndroid::Invalidate(JNIEnv* env,
+                                            jobject obj,
+                                            jint object_source,
+                                            jstring java_object_id,
+                                            jlong version,
+                                            jstring java_payload) {
+  syncer::ObjectIdInvalidationMap object_invalidation_map;
+  if (!java_object_id) {
+    syncer::ObjectIdSet sync_ids;
+    if (object_source == 0) {
+      sync_ids = invalidator_registrar_.GetAllRegisteredIds();
+    } else {
+      for (const auto& id : invalidator_registrar_.GetAllRegisteredIds()) {
+        if (id.source() == object_source)
+          sync_ids.insert(id);
+      }
     }
-    max_invalidation_versions_[object_id] = version;
-    object_ids_with_states.Insert(
-        syncer::Invalidation::Init(object_id, version,
-                                   ConvertJavaStringToUTF8(env, java_state)));
+    object_invalidation_map =
+        syncer::ObjectIdInvalidationMap::InvalidateAll(sync_ids);
+  } else {
+    invalidation::ObjectId object_id(
+        object_source, ConvertJavaStringToUTF8(env, java_object_id));
+
+    if (version == ipc::invalidation::Constants::UNKNOWN) {
+      object_invalidation_map.Insert(
+          syncer::Invalidation::InitUnknownVersion(object_id));
+    } else {
+      ObjectIdVersionMap::iterator it =
+          max_invalidation_versions_.find(object_id);
+      if ((it != max_invalidation_versions_.end()) && (version <= it->second)) {
+        DVLOG(1) << "Dropping redundant invalidation with version " << version;
+        return;
+      }
+      max_invalidation_versions_[object_id] = version;
+      object_invalidation_map.Insert(syncer::Invalidation::Init(
+          object_id, version, ConvertJavaStringToUTF8(env, java_payload)));
+    }
   }
 
-  DispatchInvalidations(object_ids_with_states);
-}
-
-void InvalidationServiceAndroid::RequestSyncForAllTypes(JNIEnv* env,
-                                                        jobject obj) {
-  syncer::ObjectIdInvalidationMap object_ids_with_states;
-  DispatchInvalidations(object_ids_with_states);
-}
-
-void InvalidationServiceAndroid::DispatchInvalidations(
-    syncer::ObjectIdInvalidationMap& object_invalidation_map) {
-  // An empty map implies that we should invalidate all.
-  const syncer::ObjectIdInvalidationMap& effective_invalidation_map =
-      object_invalidation_map.Empty() ?
-      syncer::ObjectIdInvalidationMap::InvalidateAll(
-          invalidator_registrar_.GetAllRegisteredIds()) :
-      object_invalidation_map;
-
   invalidator_registrar_.DispatchInvalidationsToHandlers(
-      effective_invalidation_map);
-  logger_.OnInvalidation(effective_invalidation_map);
+      object_invalidation_map);
+  logger_.OnInvalidation(object_invalidation_map);
 }
 
 // static
diff --git a/components/invalidation/invalidation_service_android.h b/components/invalidation/invalidation_service_android.h
index 19ba4b2..d3f697cf 100644
--- a/components/invalidation/invalidation_service_android.h
+++ b/components/invalidation/invalidation_service_android.h
@@ -50,14 +50,12 @@
       base::Callback<void(const base::DictionaryValue&)> caller) const override;
   IdentityProvider* GetIdentityProvider() override;
 
-  void RequestSync(JNIEnv* env,
-                   jobject obj,
-                   jint object_source,
-                   jstring object_id,
-                   jlong version,
-                   jstring state);
-
-  void RequestSyncForAllTypes(JNIEnv* env, jobject obj);
+  void Invalidate(JNIEnv* env,
+                  jobject obj,
+                  jint object_source,
+                  jstring object_id,
+                  jlong version,
+                  jstring state);
 
   // The InvalidationServiceAndroid always reports that it is enabled.
   // This is used only by unit tests.
@@ -89,9 +87,6 @@
   // and invalidations.
   InvalidationLogger logger_;
 
-  void DispatchInvalidations(
-      syncer::ObjectIdInvalidationMap& object_invalidation_map);
-
   DISALLOW_COPY_AND_ASSIGN(InvalidationServiceAndroid);
 };
 
diff --git a/components/keyed_service/content/browser_context_keyed_service_factory.cc b/components/keyed_service/content/browser_context_keyed_service_factory.cc
index d7edb8e..db69459a 100644
--- a/components/keyed_service/content/browser_context_keyed_service_factory.cc
+++ b/components/keyed_service/content/browser_context_keyed_service_factory.cc
@@ -85,10 +85,13 @@
   KeyedServiceFactory::ContextDestroyed(context);
 }
 
-KeyedService* BrowserContextKeyedServiceFactory::BuildServiceInstanceFor(
+scoped_ptr<KeyedService>
+BrowserContextKeyedServiceFactory::BuildServiceInstanceFor(
     base::SupportsUserData* context) const {
-  return BuildServiceInstanceFor(
-      static_cast<content::BrowserContext*>(context));
+  // TODO(isherman): The wrapped BuildServiceInstanceFor() should return a
+  // scoped_ptr as well.
+  return make_scoped_ptr(
+      BuildServiceInstanceFor(static_cast<content::BrowserContext*>(context)));
 }
 
 bool BrowserContextKeyedServiceFactory::IsOffTheRecord(
diff --git a/components/keyed_service/content/browser_context_keyed_service_factory.h b/components/keyed_service/content/browser_context_keyed_service_factory.h
index 24c3467..5543bbd 100644
--- a/components/keyed_service/content/browser_context_keyed_service_factory.h
+++ b/components/keyed_service/content/browser_context_keyed_service_factory.h
@@ -40,7 +40,7 @@
   // A function that supplies the instance of a KeyedService for a given
   // BrowserContext. This is used primarily for testing, where we want to feed
   // a specific mock into the BCKSF system.
-  typedef KeyedService* (*TestingFactoryFunction)(
+  typedef scoped_ptr<KeyedService>(*TestingFactoryFunction)(
       content::BrowserContext* context);
 
   // Associates |factory| with |context| so that |factory| is used to create
@@ -130,7 +130,7 @@
       user_prefs::PrefRegistrySyncable* registry) {}
 
   // KeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  scoped_ptr<KeyedService> BuildServiceInstanceFor(
       base::SupportsUserData* context) const final;
   bool IsOffTheRecord(base::SupportsUserData* context) const final;
 
diff --git a/components/keyed_service/core/keyed_service_factory.cc b/components/keyed_service/core/keyed_service_factory.cc
index 1417bab..efc61f9 100644
--- a/components/keyed_service/core/keyed_service_factory.cc
+++ b/components/keyed_service/core/keyed_service_factory.cc
@@ -77,7 +77,7 @@
   // Create new object.
   // Check to see if we have a per-context testing factory that we should use
   // instead of default behavior.
-  KeyedService* service = nullptr;
+  scoped_ptr<KeyedService> service;
   const auto& jt = testing_factories_.find(context);
   if (jt != testing_factories_.end()) {
     if (jt->second) {
@@ -89,14 +89,14 @@
     service = BuildServiceInstanceFor(context);
   }
 
-  Associate(context, service);
-  return service;
+  Associate(context, service.Pass());
+  return mapping_[context];
 }
 
 void KeyedServiceFactory::Associate(base::SupportsUserData* context,
-                                    KeyedService* service) {
+                                    scoped_ptr<KeyedService> service) {
   DCHECK(!ContainsKey(mapping_, context));
-  mapping_.insert(std::make_pair(context, service));
+  mapping_.insert(std::make_pair(context, service.release()));
 }
 
 void KeyedServiceFactory::Disassociate(base::SupportsUserData* context) {
diff --git a/components/keyed_service/core/keyed_service_factory.h b/components/keyed_service/core/keyed_service_factory.h
index 9cc965bd..e2ef4b8b 100644
--- a/components/keyed_service/core/keyed_service_factory.h
+++ b/components/keyed_service/core/keyed_service_factory.h
@@ -10,6 +10,7 @@
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
 #include "components/keyed_service/core/keyed_service_base_factory.h"
 #include "components/keyed_service/core/keyed_service_export.h"
 
@@ -32,7 +33,7 @@
   // A function that supplies the instance of a KeyedService for a given
   // |context|. This is used primarily for testing, where we want to feed
   // a specific mock into the KeyedServiceFactory system.
-  typedef KeyedService* (*TestingFactoryFunction)(
+  typedef scoped_ptr<KeyedService>(*TestingFactoryFunction)(
       base::SupportsUserData* context);
 
   // Associates |factory| with |context| so that |factory| is used to create
@@ -56,13 +57,14 @@
                                      bool create);
 
   // Maps |context| to |service| with debug checks to prevent duplication.
-  void Associate(base::SupportsUserData* context, KeyedService* service);
+  void Associate(base::SupportsUserData* context,
+                 scoped_ptr<KeyedService> service);
 
   // Removes the mapping from |context| to a service.
   void Disassociate(base::SupportsUserData* context);
 
   // Returns a new KeyedService that will be associated with |context|.
-  virtual KeyedService* BuildServiceInstanceFor(
+  virtual scoped_ptr<KeyedService> BuildServiceInstanceFor(
       base::SupportsUserData* context) const = 0;
 
   // Returns whether the |context| is off-the-record or not.
diff --git a/components/keyed_service/ios/browser_state_keyed_service_factory.cc b/components/keyed_service/ios/browser_state_keyed_service_factory.cc
index c5279912..7c75278 100644
--- a/components/keyed_service/ios/browser_state_keyed_service_factory.cc
+++ b/components/keyed_service/ios/browser_state_keyed_service_factory.cc
@@ -74,9 +74,13 @@
   KeyedServiceFactory::ContextDestroyed(context);
 }
 
-KeyedService* BrowserStateKeyedServiceFactory::BuildServiceInstanceFor(
+scoped_ptr<KeyedService>
+BrowserStateKeyedServiceFactory::BuildServiceInstanceFor(
     base::SupportsUserData* context) const {
-  return BuildServiceInstanceFor(static_cast<web::BrowserState*>(context));
+  // TODO(isherman): The wrapped BuildServiceInstanceFor() should return a
+  // scoped_ptr as well.
+  return make_scoped_ptr(
+      BuildServiceInstanceFor(static_cast<web::BrowserState*>(context)));
 }
 
 bool BrowserStateKeyedServiceFactory::IsOffTheRecord(
diff --git a/components/keyed_service/ios/browser_state_keyed_service_factory.h b/components/keyed_service/ios/browser_state_keyed_service_factory.h
index 7341aa19..69f28fd 100644
--- a/components/keyed_service/ios/browser_state_keyed_service_factory.h
+++ b/components/keyed_service/ios/browser_state_keyed_service_factory.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
 #include "components/keyed_service/core/keyed_service_export.h"
 #include "components/keyed_service/core/keyed_service_factory.h"
 
@@ -30,7 +31,8 @@
   // A function that supplies the instance of a KeyedService for a given
   // BrowserState. This is used primarily for testing, where we want to feed
   // a specific mock into the BSKSF system.
-  typedef KeyedService* (*TestingFactoryFunction)(web::BrowserState* context);
+  typedef scoped_ptr<KeyedService>(*TestingFactoryFunction)(
+      web::BrowserState* context);
 
   // Associates |factory| with |context| so that |factory| is used to create
   // the KeyedService when requested.  |factory| can be NULL to signal that
@@ -114,7 +116,7 @@
       user_prefs::PrefRegistrySyncable* registry) {}
 
   // KeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
+  scoped_ptr<KeyedService> BuildServiceInstanceFor(
       base::SupportsUserData* context) const final;
   bool IsOffTheRecord(base::SupportsUserData* context) const final;
 
diff --git a/components/metrics/proto/omnibox_event.proto b/components/metrics/proto/omnibox_event.proto
index b3e6656..bf13d4c 100644
--- a/components/metrics/proto/omnibox_event.proto
+++ b/components/metrics/proto/omnibox_event.proto
@@ -39,9 +39,10 @@
   // This corresponds the index of the |suggestion| below.
   optional int32 selected_index = 5;
 
-  // Whether or not the top match was hidden in the omnibox suggestions
-  // dropdown.
-  optional bool is_top_result_hidden_in_dropdown = 14;
+  // DEPRECATED. Whether or not the top match was hidden in the omnibox
+  // suggestions dropdown.
+  optional bool DEPRECATED_is_top_result_hidden_in_dropdown = 14
+      [deprecated = true];
 
   // Whether the omnibox popup is open.  It can be closed if, for instance,
   // the user clicks in the omnibox and hits return to reload the same page.
diff --git a/components/metrics/serialization/serialization_utils.cc b/components/metrics/serialization/serialization_utils.cc
index 11f45a6..940729d 100644
--- a/components/metrics/serialization/serialization_utils.cc
+++ b/components/metrics/serialization/serialization_utils.cc
@@ -97,15 +97,15 @@
   const std::string& name = parts[0];
   const std::string& value = parts[1];
 
-  if (LowerCaseEqualsASCII(name, "crash")) {
+  if (base::LowerCaseEqualsASCII(name, "crash")) {
     return MetricSample::CrashSample(value);
-  } else if (LowerCaseEqualsASCII(name, "histogram")) {
+  } else if (base::LowerCaseEqualsASCII(name, "histogram")) {
     return MetricSample::ParseHistogram(value);
-  } else if (LowerCaseEqualsASCII(name, "linearhistogram")) {
+  } else if (base::LowerCaseEqualsASCII(name, "linearhistogram")) {
     return MetricSample::ParseLinearHistogram(value);
-  } else if (LowerCaseEqualsASCII(name, "sparsehistogram")) {
+  } else if (base::LowerCaseEqualsASCII(name, "sparsehistogram")) {
     return MetricSample::ParseSparseHistogram(value);
-  } else if (LowerCaseEqualsASCII(name, "useraction")) {
+  } else if (base::LowerCaseEqualsASCII(name, "useraction")) {
     return MetricSample::UserActionSample(value);
   } else {
     DLOG(ERROR) << "invalid event type: " << name << ", value: " << value;
diff --git a/components/mime_util/mime_util.cc b/components/mime_util/mime_util.cc
index 5e5d004..3841fbb 100644
--- a/components/mime_util/mime_util.cc
+++ b/components/mime_util/mime_util.cc
@@ -161,9 +161,10 @@
 #if !defined(OS_IOS)
          media::IsSupportedMediaMimeType(mime_type) ||
 #endif
-         (StartsWithASCII(mime_type, "text/", false /* case insensitive */) &&
+         (base::StartsWithASCII(mime_type, "text/",
+                                false /* case insensitive */) &&
           !IsUnsupportedTextMimeType(mime_type)) ||
-         (StartsWithASCII(mime_type, "application/", false) &&
+         (base::StartsWithASCII(mime_type, "application/", false) &&
           net::MatchesMimeType("application/*+json", mime_type));
 }
 
@@ -178,7 +179,7 @@
 }
 
 bool MimeUtil::IsSupportedMimeType(const std::string& mime_type) const {
-  return (StartsWithASCII(mime_type, "image/", false) &&
+  return (base::StartsWithASCII(mime_type, "image/", false) &&
           IsSupportedImageMimeType(mime_type)) ||
          IsSupportedNonImageMimeType(mime_type);
 }
diff --git a/components/nacl.gyp b/components/nacl.gyp
index cc733fd..d4f23c7 100644
--- a/components/nacl.gyp
+++ b/components/nacl.gyp
@@ -451,6 +451,22 @@
         },
       ],
     }],
+    ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
+      'targets': [
+        {
+          'target_name': 'nacl_helper_nonsfi_unittests',
+          'type': '<(gtest_target_type)',
+          'sources': [
+            'nacl/loader/nonsfi/nacl_helper_nonsfi_unittests.cc',
+          ],
+          'dependencies': [
+            '../base/base.gyp:base',
+            '../base/base.gyp:test_launcher_nacl_nonsfi',
+            'nacl_nonsfi.gyp:nacl_helper_nonsfi_unittests_main',
+          ],
+        },
+      ],
+    }],
   ],
   'targets': [
     {
diff --git a/components/nacl/loader/nacl_listener.cc b/components/nacl/loader/nacl_listener.cc
index c7352f2..defd931 100644
--- a/components/nacl/loader/nacl_listener.cc
+++ b/components/nacl/loader/nacl_listener.cc
@@ -328,8 +328,7 @@
 #if defined(OS_LINUX) || defined(OS_MACOSX)
   int urandom_fd = dup(base::GetUrandomFD());
   if (urandom_fd < 0) {
-    LOG(ERROR) << "Failed to dup() the urandom FD";
-    return;
+    LOG(FATAL) << "Failed to dup() the urandom FD";
   }
   NaClChromeMainSetUrandomFd(urandom_fd);
 #endif
@@ -344,8 +343,7 @@
 
   nap = NaClAppCreate();
   if (nap == NULL) {
-    LOG(ERROR) << "NaClAppCreate() failed";
-    return;
+    LOG(FATAL) << "NaClAppCreate() failed";
   }
 
   IPC::ChannelHandle browser_handle;
@@ -383,12 +381,11 @@
           ppapi_renderer_handle,
           trusted_listener_->TakeClientChannelHandle(),
           manifest_service_handle)))
-    LOG(ERROR) << "Failed to send IPC channel handle to NaClProcessHost.";
+    LOG(FATAL) << "Failed to send IPC channel handle to NaClProcessHost.";
 
   struct NaClChromeMainArgs* args = NaClChromeMainArgsCreate();
   if (args == NULL) {
-    LOG(ERROR) << "NaClChromeMainArgsCreate() failed";
-    return;
+    LOG(FATAL) << "NaClChromeMainArgsCreate() failed";
   }
 
 #if defined(OS_LINUX) || defined(OS_MACOSX)
@@ -409,8 +406,7 @@
   args->irt_fd = _open_osfhandle(reinterpret_cast<intptr_t>(irt_handle),
                                  _O_RDONLY | _O_BINARY);
   if (args->irt_fd < 0) {
-    LOG(ERROR) << "_open_osfhandle() failed";
-    return;
+    LOG(FATAL) << "_open_osfhandle() failed";
   }
 #else
   args->irt_fd = irt_handle;
diff --git a/components/nacl/loader/nacl_trusted_listener.cc b/components/nacl/loader/nacl_trusted_listener.cc
index 4c67a09..76d0cee 100644
--- a/components/nacl/loader/nacl_trusted_listener.cc
+++ b/components/nacl/loader/nacl_trusted_listener.cc
@@ -5,6 +5,32 @@
 #include "components/nacl/loader/nacl_trusted_listener.h"
 
 #include "base/single_thread_task_runner.h"
+#include "ipc/message_filter.h"
+#include "native_client/src/public/chrome_main.h"
+
+namespace {
+
+// The OnChannelError() event must be processed in a MessageFilter so it can
+// be handled on the IO thread.  The main thread used by NaClListener is busy
+// in NaClChromeMainAppStart(), so it can't be used for servicing messages.
+class EOFMessageFilter : public IPC::MessageFilter {
+ public:
+  void OnChannelError() override {
+    // The renderer process dropped its connection to this process (the NaCl
+    // loader process), either because the <embed> element was removed
+    // (perhaps implicitly if the tab was closed) or because the renderer
+    // crashed.  The NaCl loader process should therefore exit.
+    //
+    // For SFI NaCl, trusted code does this exit voluntarily, but untrusted
+    // code cannot disable it.  However, for Non-SFI NaCl, the following exit
+    // call could be disabled by untrusted code.
+    NaClExit(0);
+  }
+ private:
+  ~EOFMessageFilter() override {}
+};
+
+}
 
 NaClTrustedListener::NaClTrustedListener(
     const IPC::ChannelHandle& handle,
@@ -17,6 +43,7 @@
                                       ipc_task_runner,
                                       true,  /* create_channel_now */
                                       shutdown_event).Pass();
+  channel_->AddFilter(new EOFMessageFilter());
 }
 
 NaClTrustedListener::~NaClTrustedListener() {
@@ -35,10 +62,6 @@
   return false;
 }
 
-void NaClTrustedListener::OnChannelError() {
-  channel_->Close();
-}
-
 bool NaClTrustedListener::Send(IPC::Message* msg) {
   return channel_->Send(msg);
 }
diff --git a/components/nacl/loader/nacl_trusted_listener.h b/components/nacl/loader/nacl_trusted_listener.h
index a430e49..6b6fdb1 100644
--- a/components/nacl/loader/nacl_trusted_listener.h
+++ b/components/nacl/loader/nacl_trusted_listener.h
@@ -25,7 +25,6 @@
 
   // Listener implementation.
   bool OnMessageReceived(const IPC::Message& message) override;
-  void OnChannelError() override;
 
   bool Send(IPC::Message* msg);
 
diff --git a/components/nacl/loader/nonsfi/nacl_helper_nonsfi_unittests.cc b/components/nacl/loader/nonsfi/nacl_helper_nonsfi_unittests.cc
new file mode 100644
index 0000000..dbca0a6
--- /dev/null
+++ b/components/nacl/loader/nonsfi/nacl_helper_nonsfi_unittests.cc
@@ -0,0 +1,13 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/test/launcher/test_launcher_nacl_nonsfi.h"
+
+int main(int argc, char* argv[]) {
+  base::AtExitManager at_exit;
+  base::CommandLine::Init(argc, argv);
+  return base::TestLauncherNonSfiMain("nacl_helper_nonsfi_unittests_main");
+}
diff --git a/components/nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc b/components/nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc
index acfc1270..4338fb6 100644
--- a/components/nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc
+++ b/components/nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc
@@ -488,14 +488,6 @@
 BPF_TEST_C(NaClNonSfiSandboxTest,
            StartingAndJoiningThreadWorks,
            nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
-#if defined(OS_NACL_NONSFI)
-  // base::Thread internally uses LazyInstance, which registers a callback to
-  // AtExitManager. However, in PNaCl toolchain build, it is not instantiated
-  // by the test runner, unlike host toolchain build (nacl_loader_unittests).
-  // Hence, declare it here so that the LazyInstance will work properly.
-  base::AtExitManager at_exit;
-#endif
-
   base::Thread thread("sandbox_tests");
   BPF_ASSERT(thread.Start());
   // |thread|'s destructor will join the thread.
diff --git a/components/nacl/loader/nonsfi/run_all_unittests.cc b/components/nacl/loader/nonsfi/run_all_unittests.cc
new file mode 100644
index 0000000..7abc2573
--- /dev/null
+++ b/components/nacl/loader/nonsfi/run_all_unittests.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int RunAllTestsImpl() {
+  return RUN_ALL_TESTS();
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  base::AtExitManager at_exit;
+  testing::InitGoogleTest(&argc, argv);
+  return base::LaunchUnitTests(argc, argv, base::Bind(&RunAllTestsImpl));
+}
diff --git a/components/nacl/renderer/plugin/service_runtime.cc b/components/nacl/renderer/plugin/service_runtime.cc
index d60fa8f..fd01c3b 100644
--- a/components/nacl/renderer/plugin/service_runtime.cc
+++ b/components/nacl/renderer/plugin/service_runtime.cc
@@ -42,7 +42,6 @@
       main_service_runtime_(main_service_runtime),
       uses_nonsfi_mode_(uses_nonsfi_mode),
       bootstrap_channel_(NACL_INVALID_HANDLE) {
-  NaClSrpcChannelInitialize(&command_channel_);
 }
 
 bool ServiceRuntime::SetupCommandChannel() {
@@ -58,10 +57,17 @@
     return true;
   }
 
-  if (!subprocess_->SetupCommand(&command_channel_)) {
+  if (!subprocess_->ConnectBootstrapSocket()) {
     ErrorInfo error_info;
     error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_CMD_CHANNEL,
-                         "ServiceRuntime: command channel creation failed");
+                         "ServiceRuntime: ConnectBootstrapSocket() failed");
+    ReportLoadError(error_info);
+    return false;
+  }
+  if (!subprocess_->RetrieveSockAddr()) {
+    ErrorInfo error_info;
+    error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_CMD_CHANNEL,
+                         "ServiceRuntime: RetrieveSockAddr() failed");
     ReportLoadError(error_info);
     return false;
   }
@@ -138,8 +144,6 @@
 
   // Note that this does waitpid() to get rid of any zombie subprocess.
   subprocess_.reset(NULL);
-
-  NaClSrpcDtor(&command_channel_);
 }
 
 ServiceRuntime::~ServiceRuntime() {
diff --git a/components/nacl/renderer/plugin/service_runtime.h b/components/nacl/renderer/plugin/service_runtime.h
index b280e67..5d1bda6 100644
--- a/components/nacl/renderer/plugin/service_runtime.h
+++ b/components/nacl/renderer/plugin/service_runtime.h
@@ -76,7 +76,6 @@
 
   void ReportLoadError(const ErrorInfo& error_info);
 
-  NaClSrpcChannel command_channel_;
   Plugin* plugin_;
   PP_Instance pp_instance_;
   bool main_service_runtime_;
diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc
index fea1b3d..f407aa4 100644
--- a/components/nacl/renderer/ppb_nacl_private_impl.cc
+++ b/components/nacl/renderer/ppb_nacl_private_impl.cc
@@ -610,7 +610,7 @@
   // generated from ManifestResolveKey or PnaclResources::ReadResourceInfo.
   // So, it's safe to just use string parsing operations here instead of
   // URL-parsing ones.
-  DCHECK(StartsWithASCII(url, kPNaClTranslatorBaseUrl, true));
+  DCHECK(base::StartsWithASCII(url, kPNaClTranslatorBaseUrl, true));
   std::string r = url.substr(std::string(kPNaClTranslatorBaseUrl).length());
 
   // Use white-listed-chars.
diff --git a/components/nacl_helper_nonsfi_unittests.isolate b/components/nacl_helper_nonsfi_unittests.isolate
index 8de0893..b7973b9 100644
--- a/components/nacl_helper_nonsfi_unittests.isolate
+++ b/components/nacl_helper_nonsfi_unittests.isolate
@@ -10,6 +10,7 @@
         ],
         'files': [
           '<(PRODUCT_DIR)/nacl_helper_nonsfi_unittests',
+          '<(PRODUCT_DIR)/nacl_helper_nonsfi_unittests_main',
         ],
         'read_only': 1,
       },
diff --git a/components/nacl_nonsfi.gyp b/components/nacl_nonsfi.gyp
index aeead0d..8ae540fd 100644
--- a/components/nacl_nonsfi.gyp
+++ b/components/nacl_nonsfi.gyp
@@ -178,16 +178,17 @@
     ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
       'targets': [
         {
-          'target_name': 'nacl_helper_nonsfi_unittests',
+          'target_name': 'nacl_helper_nonsfi_unittests_main',
           'type': 'none',
           'variables': {
             'nacl_untrusted_build': 1,
-            'nexe_target': 'nacl_helper_nonsfi_unittests',
-            # Rename the output binary file to nacl_helper_nonsfi_unittests
-            # and put it directly under out/{Debug,Release}/, so that this is
-            # in the standard location, for running on the buildbots.
-            'out_newlib32_nonsfi': '<(PRODUCT_DIR)/nacl_helper_nonsfi_unittests',
-            'out_newlib_arm_nonsfi': '<(PRODUCT_DIR)/nacl_helper_nonsfi_unitttests',
+            'nexe_target': 'nacl_helper_nonsfi_unittests_main',
+            # Rename the output binary file to
+            # nacl_helper_nonsfi_unittests_main and put it directly under
+            # out/{Debug,Release}/, so that this is in the standard location,
+            # for running on the buildbots.
+            'out_newlib32_nonsfi': '<(PRODUCT_DIR)/nacl_helper_nonsfi_unittests_main',
+            'out_newlib_arm_nonsfi': '<(PRODUCT_DIR)/nacl_helper_nonsfi_unittests_main',
 
             'build_glibc': 0,
             'build_newlib': 0,
@@ -198,6 +199,7 @@
             'sources': [
               'nacl/loader/nonsfi/nonsfi_sandbox_sigsys_unittest.cc',
               'nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc',
+              'nacl/loader/nonsfi/run_all_unittests.cc',
             ],
 
             'link_flags': [
@@ -205,12 +207,12 @@
               '-lcontent_common_nacl_nonsfi',
               '-levent_nacl_nonsfi',
               '-lgio',
-              '-lgtest_main_nacl',
               '-lgtest_nacl',
               '-lnacl_helper_nonsfi_sandbox',
               '-lplatform',
               '-lsandbox_linux_nacl_nonsfi',
               '-lsandbox_linux_test_utils_nacl_nonsfi',
+              '-ltest_support_base_nacl_nonsfi',
             ],
 
             'conditions': [
@@ -220,12 +222,12 @@
                   '>(tc_lib_dir_nonsfi_helper32)/libcontent_common_nacl_nonsfi.a',
                   '>(tc_lib_dir_nonsfi_helper32)/libevent_nacl_nonsfi.a',
                   '>(tc_lib_dir_nonsfi_helper32)/libgio.a',
-                  '>(tc_lib_dir_nonsfi_helper32)/libgtest_main_nacl.a',
                   '>(tc_lib_dir_nonsfi_helper32)/libgtest_nacl.a',
                   '>(tc_lib_dir_nonsfi_helper32)/libnacl_helper_nonsfi_sandbox.a',
                   '>(tc_lib_dir_nonsfi_helper32)/libplatform.a',
                   '>(tc_lib_dir_nonsfi_helper32)/libsandbox_linux_nacl_nonsfi.a',
                   '>(tc_lib_dir_nonsfi_helper32)/libsandbox_linux_test_utils_nacl_nonsfi.a',
+                  '>(tc_lib_dir_nonsfi_helper32)/libtest_support_base_nacl_nonsfi.a',
                 ],
               }],
               ['target_arch=="arm"', {
@@ -234,12 +236,12 @@
                   '>(tc_lib_dir_nonsfi_helper_arm)/libcontent_common_nacl_nonsfi.a',
                   '>(tc_lib_dir_nonsfi_helper_arm)/libevent_nacl_nonsfi.a',
                   '>(tc_lib_dir_nonsfi_helper_arm)/libgio.a',
-                  '>(tc_lib_dir_nonsfi_helper_arm)/libgtest_main_nacl.a',
                   '>(tc_lib_dir_nonsfi_helper_arm)/libgtest_nacl.a',
                   '>(tc_lib_dir_nonsfi_helper_arm)/libnacl_helper_nonsfi_sandbox.a',
                   '>(tc_lib_dir_nonsfi_helper_arm)/libplatform.a',
                   '>(tc_lib_dir_nonsfi_helper_arm)/libsandbox_linux_nacl_nonsfi.a',
                   '>(tc_lib_dir_nonsfi_helper_arm)/libsandbox_linux_test_utils_nacl_nonsfi.a',
+                  '>(tc_lib_dir_nonsfi_helper_arm)/libtest_support_base_nacl_nonsfi.a',
                 ],
               }],
             ],
@@ -247,12 +249,12 @@
 
           'dependencies': [
             '../base/base_nacl.gyp:base_nacl_nonsfi',
+            '../base/base_nacl.gyp:test_support_base_nacl_nonsfi',
             '../content/content_nacl_nonsfi.gyp:content_common_nacl_nonsfi',
             '../native_client/src/nonsfi/irt/irt.gyp:nacl_sys_private',
             '../native_client/src/untrusted/nacl/nacl.gyp:nacl_lib_newlib',
             '../sandbox/linux/sandbox_linux_nacl_nonsfi.gyp:sandbox_linux_nacl_nonsfi',
             '../sandbox/linux/sandbox_linux_nacl_nonsfi.gyp:sandbox_linux_test_utils_nacl_nonsfi',
-            '../testing/gtest_nacl.gyp:gtest_main_nacl',
             '../testing/gtest_nacl.gyp:gtest_nacl',
             'nacl_helper_nonsfi_sandbox',
           ],
@@ -266,7 +268,8 @@
           'target_name': 'nacl_helper_nonsfi_unittests_run',
           'type': 'none',
           'dependencies': [
-            'nacl_helper_nonsfi_unittests',
+            'nacl.gyp:nacl_helper_nonsfi_unittests',
+            'nacl_helper_nonsfi_unittests_main',
           ],
           'includes': [
             '../build/isolate.gypi',
diff --git a/components/navigation_metrics/navigation_metrics.cc b/components/navigation_metrics/navigation_metrics.cc
index 214c75fc..ffebe68 100644
--- a/components/navigation_metrics/navigation_metrics.cc
+++ b/components/navigation_metrics/navigation_metrics.cc
@@ -9,6 +9,8 @@
 
 namespace {
 
+// This enum is used in building the histogram. So, this is append only,
+// any new scheme should be added at the end, before SCHEME_MAX
 enum Scheme {
   SCHEME_UNKNOWN,
   SCHEME_HTTP,
@@ -19,6 +21,7 @@
   SCHEME_JAVASCRIPT,
   SCHEME_ABOUT,
   SCHEME_CHROME,
+  SCHEME_BLOB,
   SCHEME_MAX,
 };
 
@@ -32,6 +35,7 @@
   url::kJavaScriptScheme,
   url::kAboutScheme,
   "chrome",
+  url::kBlobScheme,
   "max",
 };
 
diff --git a/components/network_hints.gypi b/components/network_hints.gypi
index 4edde6a..418d79e 100644
--- a/components/network_hints.gypi
+++ b/components/network_hints.gypi
@@ -13,6 +13,7 @@
       ],
       'dependencies': [
         '../base/base.gyp:base',
+        '../ui/accessibility/accessibility.gyp:accessibility',
       ],
       'sources': [
         'network_hints/common/network_hints_common.cc',
diff --git a/components/network_hints/common/BUILD.gn b/components/network_hints/common/BUILD.gn
index 1e06117..97e4374 100644
--- a/components/network_hints/common/BUILD.gn
+++ b/components/network_hints/common/BUILD.gn
@@ -15,5 +15,6 @@
 
   deps = [
     "//base",
+    "//ui/accessibility",
   ]
 }
diff --git a/components/offline_pages.gypi b/components/offline_pages.gypi
index 4afb2fc1..3f217ed 100644
--- a/components/offline_pages.gypi
+++ b/components/offline_pages.gypi
@@ -22,6 +22,8 @@
         'offline_pages/offline_page_item.h',
         'offline_pages/offline_page_model.cc',
         'offline_pages/offline_page_model.h',
+        'offline_pages/offline_page_metadata_store.cc',
+        'offline_pages/offline_page_metadata_store.h',
       ],
     },
   ],
diff --git a/components/offline_pages/BUILD.gn b/components/offline_pages/BUILD.gn
index 17c32e9..e4de8cc 100644
--- a/components/offline_pages/BUILD.gn
+++ b/components/offline_pages/BUILD.gn
@@ -2,11 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# GYP: //components/offline_pages.gypi:offline_pages'
+# GYP: //components/offline_pages.gypi:offline_pages
 static_library("offline_pages") {
   sources = [
     "offline_page_item.cc",
     "offline_page_item.h",
+    "offline_page_metadata_store.cc",
+    "offline_page_metadata_store.h",
     "offline_page_model.cc",
     "offline_page_model.h",
   ]
@@ -18,3 +20,15 @@
     "//url",
   ]
 }
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "offline_page_model_unittest.cc",
+  ]
+
+  deps = [
+    ":offline_pages",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/offline_pages/offline_page_metadata_store.cc b/components/offline_pages/offline_page_metadata_store.cc
new file mode 100644
index 0000000..e5cf058
--- /dev/null
+++ b/components/offline_pages/offline_page_metadata_store.cc
@@ -0,0 +1,15 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/offline_page_metadata_store.h"
+
+namespace offline_pages {
+
+OfflinePageMetadataStore::OfflinePageMetadataStore() {
+}
+
+OfflinePageMetadataStore::~OfflinePageMetadataStore() {
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/offline_page_metadata_store.h b/components/offline_pages/offline_page_metadata_store.h
new file mode 100644
index 0000000..6d5cc07
--- /dev/null
+++ b/components/offline_pages/offline_page_metadata_store.h
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_METADATA_STORE_H_
+#define COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_METADATA_STORE_H_
+
+#include <vector>
+
+#include "base/callback.h"
+
+class GURL;
+
+namespace offline_pages {
+
+struct OfflinePageItem;
+
+// OfflinePageMetadataStore keeps metadata for the offline pages.
+// Ability to create multiple instances of the store as well as behavior of
+// asynchronous operations when the object is being destroyed, before such
+// operation finishes will depend on implementation. It should be possbile to
+// issue multiple asynchronous operations in parallel.
+class OfflinePageMetadataStore {
+ public:
+  typedef base::Callback<void(bool, const std::vector<OfflinePageItem>&)>
+      LoadCallback;
+  typedef base::Callback<void(bool)> UpdateCallback;
+
+  OfflinePageMetadataStore();
+  virtual ~OfflinePageMetadataStore();
+
+  // Get all of the offline pages from the store.
+  virtual void Load(const LoadCallback& callback) = 0;
+
+  // Asynchronously adds offline page metadata to the store for a given URL.
+  // Result of the update is passed in callback.
+  virtual void AddOfflinePage(const OfflinePageItem& offline_page,
+                              const UpdateCallback& callback) = 0;
+
+  // Asynchronously removes offline page metadata from the store.
+  // Result of the update is passed in callback.
+  virtual void RemoveOfflinePage(const GURL& page_url,
+                                 const UpdateCallback& callback) = 0;
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_METADATA_STORE_H_
diff --git a/components/offline_pages/offline_page_model.cc b/components/offline_pages/offline_page_model.cc
index afb51c9a..5fd54d0 100644
--- a/components/offline_pages/offline_page_model.cc
+++ b/components/offline_pages/offline_page_model.cc
@@ -6,11 +6,13 @@
 
 #include "base/logging.h"
 #include "components/offline_pages/offline_page_item.h"
+#include "components/offline_pages/offline_page_metadata_store.h"
 #include "url/gurl.h"
 
 namespace offline_pages {
 
-OfflinePageModel::OfflinePageModel() {
+OfflinePageModel::OfflinePageModel(scoped_ptr<OfflinePageMetadataStore> store)
+    : store_(store.Pass()) {
 }
 
 OfflinePageModel::~OfflinePageModel() {
@@ -29,4 +31,8 @@
   return std::vector<OfflinePageItem>();
 }
 
+OfflinePageMetadataStore* OfflinePageModel::GetStoreForTesting() {
+  return store_.get();
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/offline_page_model.h b/components/offline_pages/offline_page_model.h
index 7e57a14c..d32ace1 100644
--- a/components/offline_pages/offline_page_model.h
+++ b/components/offline_pages/offline_page_model.h
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 class GURL;
@@ -15,12 +16,13 @@
 namespace offline_pages {
 
 struct OfflinePageItem;
+class OfflinePageMetadataStore;
 
 // Serivce for saving pages offline, storing the offline copy and metadata, and
 // retrieving them upon request.
 class OfflinePageModel : public KeyedService {
  public:
-  OfflinePageModel();
+  explicit OfflinePageModel(scoped_ptr<OfflinePageMetadataStore> store);
   ~OfflinePageModel() override;
 
   // KeyedService:
@@ -32,7 +34,13 @@
   // Gets a set of all offline pages metadata.
   std::vector<OfflinePageItem> GetAllOfflinePages();
 
+  // Methods for testing only:
+  OfflinePageMetadataStore* GetStoreForTesting();
+
  private:
+  // Persistent store for offline page metadata.
+  scoped_ptr<OfflinePageMetadataStore> store_;
+
   DISALLOW_COPY_AND_ASSIGN(OfflinePageModel);
 };
 
diff --git a/components/offline_pages/offline_page_model_unittest.cc b/components/offline_pages/offline_page_model_unittest.cc
new file mode 100644
index 0000000..b6119ef63
--- /dev/null
+++ b/components/offline_pages/offline_page_model_unittest.cc
@@ -0,0 +1,68 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/offline_page_model.h"
+
+#include "components/offline_pages/offline_page_metadata_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace offline_pages {
+
+namespace {
+
+class OfflinePageTestStore : public OfflinePageMetadataStore {
+ public:
+  ~OfflinePageTestStore() override;
+
+  // OfflinePageMetadataStore overrides:
+  void Load(const LoadCallback& callback) override;
+  void AddOfflinePage(const OfflinePageItem& offline_page,
+                      const UpdateCallback& callback) override;
+  void RemoveOfflinePage(const GURL& page_url,
+                         const UpdateCallback& callback) override;
+};
+
+OfflinePageTestStore::~OfflinePageTestStore() {
+}
+
+void OfflinePageTestStore::Load(const LoadCallback& callback) {
+}
+
+void OfflinePageTestStore::AddOfflinePage(const OfflinePageItem& offline_page,
+                                          const UpdateCallback& callback) {
+}
+
+void OfflinePageTestStore::RemoveOfflinePage(const GURL& page_url,
+                                             const UpdateCallback& callback) {
+}
+
+class OfflinePageModelTest : public testing::Test {
+ public:
+  OfflinePageModelTest();
+  ~OfflinePageModelTest() override;
+
+  scoped_ptr<OfflinePageMetadataStore> BuildStore();
+};
+
+OfflinePageModelTest::OfflinePageModelTest() {
+}
+
+OfflinePageModelTest::~OfflinePageModelTest() {
+}
+
+scoped_ptr<OfflinePageMetadataStore> OfflinePageModelTest::BuildStore() {
+  return scoped_ptr<OfflinePageMetadataStore>(new OfflinePageTestStore());
+}
+
+TEST_F(OfflinePageModelTest, Initialize) {
+  scoped_ptr<OfflinePageMetadataStore> store = BuildStore();
+  OfflinePageMetadataStore* store_ptr = store.get();
+  OfflinePageModel model(store.Pass());
+  EXPECT_EQ(store_ptr, model.GetStoreForTesting());
+}
+
+}  // namespace
+
+}  // namespace offline_pages
diff --git a/components/omnibox.gypi b/components/omnibox.gypi
index 2680cf0..e4eb50a 100644
--- a/components/omnibox.gypi
+++ b/components/omnibox.gypi
@@ -48,6 +48,8 @@
         'omnibox/autocomplete_scheme_classifier.h',
         'omnibox/base_search_provider.cc',
         'omnibox/base_search_provider.h',
+        'omnibox/in_memory_url_index_types.cc',
+        'omnibox/in_memory_url_index_types.h',
         'omnibox/keyword_extensions_delegate.cc',
         'omnibox/keyword_extensions_delegate.h',
         'omnibox/keyword_provider.cc',
diff --git a/components/omnibox/BUILD.gn b/components/omnibox/BUILD.gn
index 08ff27d..6c43f57 100644
--- a/components/omnibox/BUILD.gn
+++ b/components/omnibox/BUILD.gn
@@ -19,6 +19,8 @@
     "autocomplete_scheme_classifier.h",
     "base_search_provider.cc",
     "base_search_provider.h",
+    "in_memory_url_index_types.cc",
+    "in_memory_url_index_types.h",
     "keyword_extensions_delegate.cc",
     "keyword_extensions_delegate.h",
     "keyword_provider.cc",
@@ -78,6 +80,7 @@
     "autocomplete_match_unittest.cc",
     "autocomplete_result_unittest.cc",
     "base_search_provider_unittest.cc",
+    "in_memory_url_index_types_unittest.cc",
     "keyword_provider_unittest.cc",
     "omnibox_field_trial_unittest.cc",
     "suggestion_answer_unittest.cc",
diff --git a/components/omnibox/answers_cache.cc b/components/omnibox/answers_cache.cc
index 00d8c3f..35cf5a3 100644
--- a/components/omnibox/answers_cache.cc
+++ b/components/omnibox/answers_cache.cc
@@ -23,7 +23,7 @@
   base::string16 collapsed_query = base::CollapseWhitespace(query, false);
   for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) {
     // If the query text starts with trimmed input, this is valid prefetch data.
-    if (StartsWith(it->full_query_text, collapsed_query, false)) {
+    if (base::StartsWith(it->full_query_text, collapsed_query, false)) {
       // Move the touched item to the front of the list.
       cache_.splice(cache_.begin(), cache_, it);
       return cache_.front();
diff --git a/components/omnibox/autocomplete_input.cc b/components/omnibox/autocomplete_input.cc
index 30af0d2..a078f8cf 100644
--- a/components/omnibox/autocomplete_input.cc
+++ b/components/omnibox/autocomplete_input.cc
@@ -169,7 +169,7 @@
   if (!canonicalized_url->is_valid())
     return metrics::OmniboxInputType::QUERY;
 
-  if (LowerCaseEqualsASCII(parsed_scheme_utf8, url::kFileScheme)) {
+  if (base::LowerCaseEqualsASCII(parsed_scheme_utf8, url::kFileScheme)) {
     // A user might or might not type a scheme when entering a file URL.  In
     // either case, |parsed_scheme_utf8| will tell us that this is a file URL,
     // but |parts->scheme| might be empty, e.g. if the user typed "C:\foo".
@@ -183,8 +183,8 @@
   // (e.g. "ftp" or "view-source") but I'll wait to spend the effort on that
   // until I run into some cases that really need it.
   if (parts->scheme.is_nonempty() &&
-      !LowerCaseEqualsASCII(parsed_scheme_utf8, url::kHttpScheme) &&
-      !LowerCaseEqualsASCII(parsed_scheme_utf8, url::kHttpsScheme)) {
+      !base::LowerCaseEqualsASCII(parsed_scheme_utf8, url::kHttpScheme) &&
+      !base::LowerCaseEqualsASCII(parsed_scheme_utf8, url::kHttpsScheme)) {
     metrics::OmniboxInputType::Type type =
         scheme_classifier.GetInputTypeForScheme(parsed_scheme_utf8);
     if (type != metrics::OmniboxInputType::INVALID)
@@ -435,7 +435,7 @@
   int after_scheme_and_colon = parts.scheme.end() + 1;
   // For the view-source scheme, we should emphasize the scheme and host of the
   // URL qualified by the view-source prefix.
-  if (LowerCaseEqualsASCII(scheme_str, kViewSourceScheme) &&
+  if (base::LowerCaseEqualsASCII(scheme_str, kViewSourceScheme) &&
       (static_cast<int>(text.length()) > after_scheme_and_colon)) {
     // Obtain the URL prefixed by view-source and parse it.
     base::string16 real_url(text.substr(after_scheme_and_colon));
@@ -457,7 +457,7 @@
         host->reset();
       }
     }
-  } else if (LowerCaseEqualsASCII(scheme_str, url::kFileSystemScheme) &&
+  } else if (base::LowerCaseEqualsASCII(scheme_str, url::kFileSystemScheme) &&
              parts.inner_parsed() && parts.inner_parsed()->scheme.is_valid()) {
     *host = parts.inner_parsed()->host;
   }
diff --git a/components/omnibox/autocomplete_result.cc b/components/omnibox/autocomplete_result.cc
index f2d171f7..7ae331e2 100644
--- a/components/omnibox/autocomplete_result.cc
+++ b/components/omnibox/autocomplete_result.cc
@@ -294,11 +294,6 @@
   return &matches_[index];
 }
 
-bool AutocompleteResult::ShouldHideTopMatch() const {
-  return chrome::ShouldHideTopVerbatimMatch() &&
-      TopMatchIsStandaloneVerbatimMatch();
-}
-
 bool AutocompleteResult::TopMatchIsStandaloneVerbatimMatch() const {
   if (empty() || !match_at(0).IsVerbatimType())
     return false;
diff --git a/components/omnibox/autocomplete_result.h b/components/omnibox/autocomplete_result.h
index 6d8d746..1ffc40c 100644
--- a/components/omnibox/autocomplete_result.h
+++ b/components/omnibox/autocomplete_result.h
@@ -102,31 +102,6 @@
 
   // Returns true if the top match is a verbatim search or URL match (see
   // IsVerbatimType() in autocomplete_match.h), and the next match is not also
-  // some kind of verbatim match.  In this case, the top match will be hidden,
-  // and nothing in the dropdown will appear selected by default; hitting enter
-  // will navigate to the (hidden) default match, while pressing the down arrow
-  // key will select the first visible match, which is actually the second match
-  // in the result set.
-  //
-  // Hiding the top match in these cases is possible because users should
-  // already know what will happen on hitting enter from the omnibox text
-  // itself, without needing to see the same text appear again, selected, just
-  // below their typing.  Instead, by hiding the verbatim match, there is one
-  // less line to skip over in order to visually scan downwards to see other
-  // suggested matches.  This makes it more likely that users will see and
-  // select useful non-verbatim matches.  (Note that hiding the verbatim match
-  // this way is similar to how most other browsers' address bars behave.)
-  //
-  // We avoid hiding when the top two matches are both verbatim in order to
-  // avoid potential confusion if a user were to see the second match just below
-  // their typing and assume it would be the default action.
-  //
-  // Note that if the top match should be hidden and it is the only match,
-  // the dropdown should be closed.
-  bool ShouldHideTopMatch() const;
-
-  // Returns true if the top match is a verbatim search or URL match (see
-  // IsVerbatimType() in autocomplete_match.h), and the next match is not also
   // some kind of verbatim match.
   bool TopMatchIsStandaloneVerbatimMatch() const;
 
diff --git a/components/omnibox/autocomplete_result_unittest.cc b/components/omnibox/autocomplete_result_unittest.cc
index 4cc1385f..d72aa4c 100644
--- a/components/omnibox/autocomplete_result_unittest.cc
+++ b/components/omnibox/autocomplete_result_unittest.cc
@@ -647,80 +647,6 @@
   }
 }
 
-TEST_F(AutocompleteResultTest, ShouldHideTopMatch) {
-  base::FieldTrialList::CreateFieldTrial("InstantExtended",
-                                         "Group1 hide_verbatim:1");
-  ACMatches matches;
-
-  // Case 1: Top match is a verbatim match.
-  PopulateAutocompleteMatchesFromTestData(kVerbatimMatches, 1, &matches);
-  AutocompleteResult result;
-  result.AppendMatches(AutocompleteInput(), matches);
-  EXPECT_TRUE(result.ShouldHideTopMatch());
-  matches.clear();
-  result.Reset();
-
-  // Case 2: If the verbatim first match is followed by another verbatim match,
-  // don't hide the top verbatim match.
-  PopulateAutocompleteMatchesFromTestData(kVerbatimMatches,
-                                          arraysize(kVerbatimMatches),
-                                          &matches);
-  result.AppendMatches(AutocompleteInput(), matches);
-  EXPECT_FALSE(result.ShouldHideTopMatch());
-  matches.clear();
-  result.Reset();
-
-  // Case 3: Top match is not a verbatim match. Do not hide the top match.
-  PopulateAutocompleteMatchesFromTestData(kNonVerbatimMatches, 1, &matches);
-  PopulateAutocompleteMatchesFromTestData(kVerbatimMatches,
-                                          arraysize(kVerbatimMatches),
-                                          &matches);
-  result.AppendMatches(AutocompleteInput(), matches);
-  EXPECT_FALSE(result.ShouldHideTopMatch());
-}
-
-TEST_F(AutocompleteResultTest, ShouldHideTopMatchAfterCopy) {
-  base::FieldTrialList::CreateFieldTrial("InstantExtended",
-                                         "Group1 hide_verbatim:1");
-  ACMatches matches;
-
-  // Case 1: Top match is a verbatim match followed by only copied matches.
-  PopulateAutocompleteMatchesFromTestData(kVerbatimMatches,
-                                          arraysize(kVerbatimMatches),
-                                          &matches);
-  for (size_t i = 1; i < arraysize(kVerbatimMatches); ++i)
-    matches[i].from_previous = true;
-  AutocompleteResult result;
-  result.AppendMatches(AutocompleteInput(), matches);
-  EXPECT_TRUE(result.ShouldHideTopMatch());
-  result.Reset();
-
-  // Case 2: The copied matches are then followed by a non-verbatim match.
-  PopulateAutocompleteMatchesFromTestData(kNonVerbatimMatches, 1, &matches);
-  result.AppendMatches(AutocompleteInput(), matches);
-  EXPECT_TRUE(result.ShouldHideTopMatch());
-  result.Reset();
-
-  // Case 3: The copied matches are instead followed by a verbatim match.
-  matches.back().from_previous = true;
-  PopulateAutocompleteMatchesFromTestData(kVerbatimMatches, 1, &matches);
-  result.AppendMatches(AutocompleteInput(), matches);
-  EXPECT_FALSE(result.ShouldHideTopMatch());
-}
-
-TEST_F(AutocompleteResultTest, DoNotHideTopMatch_FieldTrialFlagDisabled) {
-  // This test config is identical to ShouldHideTopMatch test ("Case 1") except
-  // that the "hide_verbatim" flag is disabled in the field trials.
-  base::FieldTrialList::CreateFieldTrial("InstantExtended",
-                                         "Group1 hide_verbatim:0");
-  ACMatches matches;
-  PopulateAutocompleteMatchesFromTestData(kVerbatimMatches, 1, &matches);
-  AutocompleteResult result;
-  result.AppendMatches(AutocompleteInput(), matches);
-  // Field trial flag "hide_verbatim" is disabled. Do not hide top match.
-  EXPECT_FALSE(result.ShouldHideTopMatch());
-}
-
 TEST_F(AutocompleteResultTest, TopMatchIsStandaloneVerbatimMatch) {
   ACMatches matches;
   AutocompleteResult result;
@@ -750,11 +676,4 @@
   EXPECT_TRUE(result.TopMatchIsStandaloneVerbatimMatch());
   result.Reset();
   matches.clear();
-
-  // Case 5: Multiple verbatim matches found in AutocompleteResult.
-  PopulateAutocompleteMatchesFromTestData(kVerbatimMatches,
-                                          arraysize(kVerbatimMatches),
-                                          &matches);
-  result.AppendMatches(AutocompleteInput(), matches);
-  EXPECT_FALSE(result.ShouldHideTopMatch());
 }
diff --git a/components/omnibox/base_search_provider.cc b/components/omnibox/base_search_provider.cc
index bb2db75..dbbedd4c 100644
--- a/components/omnibox/base_search_provider.cc
+++ b/components/omnibox/base_search_provider.cc
@@ -244,7 +244,7 @@
   if (!input.prevent_inline_autocomplete() &&
       !suggestion.received_after_last_keystroke() &&
       (!in_keyword_mode || suggestion.from_keyword_provider()) &&
-      StartsWith(suggestion.suggestion(), input.text(), false)) {
+      base::StartsWith(suggestion.suggestion(), input.text(), false)) {
     match.inline_autocompletion =
         suggestion.suggestion().substr(input.text().length());
     match.allowed_to_be_default_match = true;
diff --git a/chrome/browser/autocomplete/in_memory_url_index_types.cc b/components/omnibox/in_memory_url_index_types.cc
similarity index 98%
rename from chrome/browser/autocomplete/in_memory_url_index_types.cc
rename to components/omnibox/in_memory_url_index_types.cc
index e0f8b82..a2e000f 100644
--- a/chrome/browser/autocomplete/in_memory_url_index_types.cc
+++ b/components/omnibox/in_memory_url_index_types.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/autocomplete/in_memory_url_index_types.h"
+#include "components/omnibox/in_memory_url_index_types.h"
 
 #include <algorithm>
 #include <functional>
diff --git a/chrome/browser/autocomplete/in_memory_url_index_types.h b/components/omnibox/in_memory_url_index_types.h
similarity index 96%
rename from chrome/browser/autocomplete/in_memory_url_index_types.h
rename to components/omnibox/in_memory_url_index_types.h
index b8e96e4..f9e16ee 100644
--- a/chrome/browser/autocomplete/in_memory_url_index_types.h
+++ b/components/omnibox/in_memory_url_index_types.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_AUTOCOMPLETE_IN_MEMORY_URL_INDEX_TYPES_H_
-#define CHROME_BROWSER_AUTOCOMPLETE_IN_MEMORY_URL_INDEX_TYPES_H_
+#ifndef COMPONENTS_OMNIBOX_IN_MEMORY_URL_INDEX_TYPES_H_
+#define COMPONENTS_OMNIBOX_IN_MEMORY_URL_INDEX_TYPES_H_
 
 #include <map>
 #include <set>
@@ -168,4 +168,4 @@
 };
 typedef std::map<HistoryID, RowWordStarts> WordStartsMap;
 
-#endif  // CHROME_BROWSER_AUTOCOMPLETE_IN_MEMORY_URL_INDEX_TYPES_H_
+#endif  // COMPONENTS_OMNIBOX_IN_MEMORY_URL_INDEX_TYPES_H_
diff --git a/chrome/browser/autocomplete/in_memory_url_index_types_unittest.cc b/components/omnibox/in_memory_url_index_types_unittest.cc
similarity index 98%
rename from chrome/browser/autocomplete/in_memory_url_index_types_unittest.cc
rename to components/omnibox/in_memory_url_index_types_unittest.cc
index f00705b..1bc4301 100644
--- a/chrome/browser/autocomplete/in_memory_url_index_types_unittest.cc
+++ b/components/omnibox/in_memory_url_index_types_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/autocomplete/in_memory_url_index_types.h"
+#include "components/omnibox/in_memory_url_index_types.h"
 
 #include <algorithm>
 
diff --git a/components/omnibox/search_provider.cc b/components/omnibox/search_provider.cc
index 670debf..e97e7f0 100644
--- a/components/omnibox/search_provider.cc
+++ b/components/omnibox/search_provider.cc
@@ -732,9 +732,9 @@
   // and happens to currently be invalid -- in which case we again want to run
   // our checks below.  Other QUERY cases are less likely to be URLs and thus we
   // assume we're OK.
-  if (!LowerCaseEqualsASCII(input_.scheme(), url::kHttpScheme) &&
-      !LowerCaseEqualsASCII(input_.scheme(), url::kHttpsScheme) &&
-      !LowerCaseEqualsASCII(input_.scheme(), url::kFtpScheme))
+  if (!base::LowerCaseEqualsASCII(input_.scheme(), url::kHttpScheme) &&
+      !base::LowerCaseEqualsASCII(input_.scheme(), url::kHttpsScheme) &&
+      !base::LowerCaseEqualsASCII(input_.scheme(), url::kFtpScheme))
     return (input_.type() != metrics::OmniboxInputType::QUERY);
 
   // Don't send URLs with usernames, queries or refs.  Some of these are
@@ -756,7 +756,7 @@
   // Don't send anything for https except the hostname.  Hostnames are OK
   // because they are visible when the TCP connection is established, but the
   // specific path may reveal private information.
-  if (LowerCaseEqualsASCII(input_.scheme(), url::kHttpsScheme) &&
+  if (base::LowerCaseEqualsASCII(input_.scheme(), url::kHttpsScheme) &&
       parts.path.is_nonempty())
     return true;
 
diff --git a/components/omnibox/search_suggestion_parser.cc b/components/omnibox/search_suggestion_parser.cc
index 26d1933e..ecf580df 100644
--- a/components/omnibox/search_suggestion_parser.cc
+++ b/components/omnibox/search_suggestion_parser.cc
@@ -148,7 +148,7 @@
         suggestion_.length() - match_contents_.length();
     // Ensure the query starts with the input text, and ends with the match
     // contents, and the input text has an overlap with contents.
-    if (StartsWith(suggestion_, input_text, true) &&
+    if (base::StartsWith(suggestion_, input_text, true) &&
         EndsWith(suggestion_, match_contents_, true) &&
         (input_text.length() > contents_index)) {
       lookup_text = input_text.substr(contents_index);
diff --git a/components/omnibox/suggestion_answer.cc b/components/omnibox/suggestion_answer.cc
index aec952e..db6c85a 100644
--- a/components/omnibox/suggestion_answer.cc
+++ b/components/omnibox/suggestion_answer.cc
@@ -106,11 +106,11 @@
     // "//host/path", which is web-speak for "use the enclosing page's scheme",
     // but not a valid path of an URL.  The GWS frontend commonly (always?)
     // redirects to HTTPS so we just default to that here.
-    image_line->image_url_ = GURL(
-        StartsWith(url_string, base::ASCIIToUTF16("//"), false) ?
-            (base::ASCIIToUTF16(url::kHttpsScheme) + base::ASCIIToUTF16(":") +
-                url_string) :
-            url_string);
+    image_line->image_url_ =
+        GURL(base::StartsWith(url_string, base::ASCIIToUTF16("//"), false)
+                 ? (base::ASCIIToUTF16(url::kHttpsScheme) +
+                    base::ASCIIToUTF16(":") + url_string)
+                 : url_string);
 
     if (!image_line->image_url_.is_valid())
       return false;
diff --git a/components/omnibox/url_prefix.cc b/components/omnibox/url_prefix.cc
index be5a5ef..b1fdcdb 100644
--- a/components/omnibox/url_prefix.cc
+++ b/components/omnibox/url_prefix.cc
@@ -71,7 +71,7 @@
 bool URLPrefix::PrefixMatch(const URLPrefix& prefix,
                             const base::string16& text,
                             const base::string16& prefix_suffix) {
-  return StartsWith(text, prefix.prefix + prefix_suffix, false);
+  return base::StartsWith(text, prefix.prefix + prefix_suffix, false);
 }
 
 // static
diff --git a/components/pairing/bluetooth_controller_pairing_controller.cc b/components/pairing/bluetooth_controller_pairing_controller.cc
index 476b205..b843354e 100644
--- a/components/pairing/bluetooth_controller_pairing_controller.cc
+++ b/components/pairing/bluetooth_controller_pairing_controller.cc
@@ -70,8 +70,8 @@
     device::BluetoothDevice* device) {
   DCHECK_EQ(current_stage_, STAGE_DEVICES_DISCOVERY);
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (StartsWith(device->GetName(), base::ASCIIToUTF16(kDeviceNamePrefix),
-                 false)) {
+  if (base::StartsWith(device->GetName(), base::ASCIIToUTF16(kDeviceNamePrefix),
+                       false)) {
     discovered_devices_.insert(device->GetAddress());
     FOR_EACH_OBSERVER(ControllerPairingController::Observer, observers_,
                       DiscoveredDevicesListChanged());
diff --git a/components/password_manager/core/browser/affiliation_utils.cc b/components/password_manager/core/browser/affiliation_utils.cc
index 6fbf02c..98c9099 100644
--- a/components/password_manager/core/browser/affiliation_utils.cc
+++ b/components/password_manager/core/browser/affiliation_utils.cc
@@ -18,7 +18,6 @@
 #include "net/base/escape.h"
 #include "url/third_party/mozilla/url_parse.h"
 #include "url/url_canon_stdstring.h"
-#include "url/url_util.h"
 
 namespace password_manager {
 
@@ -183,11 +182,11 @@
   url::ParseStandardURL(input_uri.c_str(), input_uri.size(), &input_parsed);
 
   base::StringPiece scheme = ComponentString(input_uri, input_parsed.scheme);
-  if (url::LowerCaseEqualsASCII(scheme.begin(), scheme.end(),
-                                url::kHttpsScheme)) {
+  if (base::LowerCaseEqualsASCII(scheme.begin(), scheme.end(),
+                                 url::kHttpsScheme)) {
     return CanonicalizeWebFacetURI(input_uri, input_parsed, canonical_uri);
-  } else if (url::LowerCaseEqualsASCII(scheme.begin(), scheme.end(),
-                                       kAndroidAppScheme)) {
+  } else if (base::LowerCaseEqualsASCII(scheme.begin(), scheme.end(),
+                                        kAndroidAppScheme)) {
     return CanonicalizeAndroidFacetURI(input_uri, input_parsed, canonical_uri);
   }
   return false;
@@ -303,7 +302,7 @@
     return false;
   if (command_line.HasSwitch(switches::kEnableAffiliationBasedMatching))
     return true;
-  return StartsWithASCII(group_name, "Enabled", /*case_sensitive=*/false);
+  return base::StartsWithASCII(group_name, "Enabled", /*case_sensitive=*/false);
 }
 
 bool IsPropagatingPasswordChangesToWebCredentialsEnabled(
@@ -318,7 +317,7 @@
     return false;
   if (command_line.HasSwitch(switches::kEnableAffiliationBasedMatching))
     return true;
-  return LowerCaseEqualsASCII(update_enabled, "enabled");
+  return base::LowerCaseEqualsASCII(update_enabled, "enabled");
 }
 
 bool IsAffiliationRequestsForDummyFacetsEnabled(
@@ -329,7 +328,7 @@
     return false;
   if (command_line.HasSwitch(switches::kEnableAffiliationBasedMatching))
     return true;
-  return LowerCaseEqualsASCII(synthesizing_enabled, "enabled");
+  return base::LowerCaseEqualsASCII(synthesizing_enabled, "enabled");
 }
 
 bool IsValidAndroidFacetURI(const std::string& url) {
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index d585a47..a9b6644 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -64,8 +64,8 @@
                     const base::string16& current_username,
                     std::vector<autofill::Suggestion>* suggestions,
                     bool show_all) {
-  if (show_all ||
-      StartsWith(fill_data.username_field.value, current_username, false)) {
+  if (show_all || base::StartsWith(fill_data.username_field.value,
+                                   current_username, false)) {
     autofill::Suggestion suggestion(
         ReplaceEmptyUsername(fill_data.username_field.value));
     suggestion.label = GetHumanReadableRealm(fill_data.preferred_realm);
@@ -74,7 +74,7 @@
   }
 
   for (const auto& login : fill_data.additional_logins) {
-    if (show_all || StartsWith(login.first, current_username, false)) {
+    if (show_all || base::StartsWith(login.first, current_username, false)) {
       autofill::Suggestion suggestion(ReplaceEmptyUsername(login.first));
       suggestion.label = GetHumanReadableRealm(login.second.realm);
       suggestion.frontend_id = autofill::POPUP_ITEM_ID_PASSWORD_ENTRY;
@@ -85,7 +85,7 @@
   for (const auto& usernames : fill_data.other_possible_usernames) {
     for (size_t i = 0; i < usernames.second.size(); ++i) {
       if (show_all ||
-          StartsWith(usernames.second[i], current_username, false)) {
+          base::StartsWith(usernames.second[i], current_username, false)) {
         autofill::Suggestion suggestion(
             ReplaceEmptyUsername(usernames.second[i]));
         suggestion.label = GetHumanReadableRealm(usernames.first.realm);
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index da366f2..9995a218 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -168,7 +168,7 @@
     origins_match =
         observed_form_.origin.host() == form.origin.host() &&
         observed_form_.origin.port() == form.origin.port() &&
-        StartsWithASCII(new_path, old_path, /*case_sensitive=*/true);
+        base::StartsWithASCII(new_path, old_path, /*case_sensitive=*/true);
   }
 
   if (!origins_match)
@@ -392,7 +392,7 @@
       // instead of explicitly handling empty path matches.
       bool is_credential_protected =
           observed_form_.scheme == PasswordForm::SCHEME_HTML &&
-          StartsWithASCII("/", login->origin.path(), true) &&
+          base::StartsWithASCII("/", login->origin.path(), true) &&
           credential_scores[i] > 0 && !login->blacklisted_by_user;
       // Passwords generated on a signup form must show on a login form even if
       // there are better-matching saved credentials. TODO(gcasto): We don't
diff --git a/components/plugins.gypi b/components/plugins.gypi
index fde25c607..9061833 100644
--- a/components/plugins.gypi
+++ b/components/plugins.gypi
@@ -36,14 +36,19 @@
           ],
           'sources': [
             # Note: sources list duplicated in GN build.
-            'plugins/renderer/loadable_plugin_placeholder.cc',
-            'plugins/renderer/loadable_plugin_placeholder.h',
             'plugins/renderer/plugin_placeholder.cc',
             'plugins/renderer/plugin_placeholder.h',
             'plugins/renderer/webview_plugin.cc',
             'plugins/renderer/webview_plugin.h',
           ],
           'conditions' : [
+            ['enable_plugins==1', {
+              'sources': [
+                # Note: sources list duplicated in GN build.
+                'plugins/renderer/loadable_plugin_placeholder.cc',
+                'plugins/renderer/loadable_plugin_placeholder.h',
+              ]
+            }],
             ['OS=="android"', {
               'sources': [
                 # Note: sources list duplicated in GN build.
diff --git a/components/plugins/renderer/BUILD.gn b/components/plugins/renderer/BUILD.gn
index ef7e8f1..446ad99 100644
--- a/components/plugins/renderer/BUILD.gn
+++ b/components/plugins/renderer/BUILD.gn
@@ -2,15 +2,21 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/features.gni")
+
 static_library("renderer") {
   sources = [
-    "loadable_plugin_placeholder.cc",
-    "loadable_plugin_placeholder.h",
     "plugin_placeholder.cc",
     "plugin_placeholder.h",
     "webview_plugin.cc",
     "webview_plugin.h",
   ]
+  if (enable_plugins) {
+    sources += [
+      "loadable_plugin_placeholder.cc",
+      "loadable_plugin_placeholder.h",
+    ]
+  }
   if (is_android) {
     sources += [
       "mobile_youtube_plugin.cc",
diff --git a/components/plugins/renderer/loadable_plugin_placeholder.cc b/components/plugins/renderer/loadable_plugin_placeholder.cc
index 90c3f9ba..eb884da5 100644
--- a/components/plugins/renderer/loadable_plugin_placeholder.cc
+++ b/components/plugins/renderer/loadable_plugin_placeholder.cc
@@ -9,8 +9,8 @@
 #include "base/command_line.h"
 #include "base/json/string_escape.h"
 #include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "content/public/child/v8_value_converter.h"
 #include "content/public/common/content_switches.h"
@@ -28,24 +28,18 @@
 #include "third_party/WebKit/public/web/WebScriptSource.h"
 #include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
 #include "third_party/WebKit/public/web/WebView.h"
-#include "third_party/re2/re2/re2.h"
 
 using base::UserMetricsAction;
-using blink::WebElement;
-using blink::WebLocalFrame;
-using blink::WebMouseEvent;
-using blink::WebNode;
-using blink::WebPlugin;
-using blink::WebPluginContainer;
-using blink::WebPluginParams;
-using blink::WebScriptSource;
-using blink::WebURLRequest;
 using content::PluginInstanceThrottler;
 using content::RenderThread;
 
 namespace plugins {
 
-#if defined(ENABLE_PLUGINS)
+// TODO(tommycli): After an unthrottling size update, re-check the size after
+// this delay, as Blink can report incorrect sizes to plugins while the
+// compositing state is dirty. Chosen because it seems to work.
+const int kSizeChangeRecheckDelayMilliseconds = 100;
+
 void LoadablePluginPlaceholder::BlockForPowerSaverPoster() {
   DCHECK(!is_blocked_for_power_saver_poster_);
   is_blocked_for_power_saver_poster_ = true;
@@ -63,34 +57,27 @@
   DCHECK(!premade_throttler_);
   premade_throttler_ = throttler;
 }
-#endif
 
 LoadablePluginPlaceholder::LoadablePluginPlaceholder(
     content::RenderFrame* render_frame,
-    WebLocalFrame* frame,
-    const WebPluginParams& params,
-    const std::string& html_data,
-    GURL placeholderDataUrl)
-    : PluginPlaceholder(render_frame,
-                        frame,
-                        params,
-                        html_data,
-                        placeholderDataUrl),
+    blink::WebLocalFrame* frame,
+    const blink::WebPluginParams& params,
+    const std::string& html_data)
+    : PluginPlaceholderBase(render_frame, frame, params, html_data),
       is_blocked_for_background_tab_(false),
       is_blocked_for_prerendering_(false),
       is_blocked_for_power_saver_poster_(false),
       power_saver_enabled_(false),
       premade_throttler_(nullptr),
-      allow_loading_(false),
-      hidden_(false),
+      allow_loading_(true),
       finished_loading_(false),
+      in_size_recheck_(false),
       weak_factory_(this) {
 }
 
 LoadablePluginPlaceholder::~LoadablePluginPlaceholder() {
 }
 
-#if defined(ENABLE_PLUGINS)
 void LoadablePluginPlaceholder::MarkPluginEssential(
     PluginInstanceThrottler::PowerSaverUnthrottleMethod method) {
   if (!power_saver_enabled_)
@@ -109,39 +96,17 @@
       LoadPlugin();
   }
 }
-#endif
 
-void LoadablePluginPlaceholder::BindWebFrame(blink::WebFrame* frame) {
-  v8::Isolate* isolate = blink::mainThreadIsolate();
-  v8::HandleScope handle_scope(isolate);
-  v8::Local<v8::Context> context = frame->mainWorldScriptContext();
-  DCHECK(!context.IsEmpty());
-
-  v8::Context::Scope context_scope(context);
-  v8::Local<v8::Object> global = context->Global();
-  global->Set(gin::StringToV8(isolate, "plugin"),
-              gin::CreateHandle(isolate, this).ToV8());
-}
-
-gin::ObjectTemplateBuilder LoadablePluginPlaceholder::GetObjectTemplateBuilder(
-    v8::Isolate* isolate) {
-  return gin::Wrappable<PluginPlaceholder>::GetObjectTemplateBuilder(isolate)
-      .SetMethod("load", &LoadablePluginPlaceholder::LoadCallback)
-      .SetMethod("hide", &LoadablePluginPlaceholder::HideCallback)
-      .SetMethod("didFinishLoading",
-                 &LoadablePluginPlaceholder::DidFinishLoadingCallback);
-}
-
-void LoadablePluginPlaceholder::ReplacePlugin(WebPlugin* new_plugin) {
+void LoadablePluginPlaceholder::ReplacePlugin(blink::WebPlugin* new_plugin) {
   CHECK(plugin());
   if (!new_plugin)
     return;
-  WebPluginContainer* container = plugin()->container();
+  blink::WebPluginContainer* container = plugin()->container();
   // Set the new plugin on the container before initializing it.
   container->setPlugin(new_plugin);
   // Save the element in case the plugin is removed from the page during
   // initialization.
-  WebElement element = container->element();
+  blink::WebElement element = container->element();
   bool plugin_needs_initialization =
       !premade_throttler_ || new_plugin != premade_throttler_->GetWebPlugin();
   if (plugin_needs_initialization && !new_plugin->initialize(container)) {
@@ -169,54 +134,6 @@
   plugin()->destroy();
 }
 
-void LoadablePluginPlaceholder::HidePlugin() {
-  hidden_ = true;
-  if (!plugin())
-    return;
-  WebPluginContainer* container = plugin()->container();
-  WebElement element = container->element();
-  element.setAttribute("style", "display: none;");
-  // If we have a width and height, search for a parent (often <div>) with the
-  // same dimensions. If we find such a parent, hide that as well.
-  // This makes much more uncovered page content usable (including clickable)
-  // as opposed to merely visible.
-  // TODO(cevans) -- it's a foul heuristic but we're going to tolerate it for
-  // now for these reasons:
-  // 1) Makes the user experience better.
-  // 2) Foulness is encapsulated within this single function.
-  // 3) Confidence in no fasle positives.
-  // 4) Seems to have a good / low false negative rate at this time.
-  if (element.hasAttribute("width") && element.hasAttribute("height")) {
-    std::string width_str("width:[\\s]*");
-    width_str += element.getAttribute("width").utf8().data();
-    if (EndsWith(width_str, "px", false)) {
-      width_str = width_str.substr(0, width_str.length() - 2);
-    }
-    base::TrimWhitespace(width_str, base::TRIM_TRAILING, &width_str);
-    width_str += "[\\s]*px";
-    std::string height_str("height:[\\s]*");
-    height_str += element.getAttribute("height").utf8().data();
-    if (EndsWith(height_str, "px", false)) {
-      height_str = height_str.substr(0, height_str.length() - 2);
-    }
-    base::TrimWhitespace(height_str, base::TRIM_TRAILING, &height_str);
-    height_str += "[\\s]*px";
-    WebNode parent = element;
-    while (!parent.parentNode().isNull()) {
-      parent = parent.parentNode();
-      if (!parent.isElementNode())
-        continue;
-      element = parent.toConst<WebElement>();
-      if (element.hasAttribute("style")) {
-        std::string style_str = element.getAttribute("style").utf8();
-        if (RE2::PartialMatch(style_str, width_str) &&
-            RE2::PartialMatch(style_str, height_str))
-          element.setAttribute("style", "display: none;");
-      }
-    }
-  }
-}
-
 void LoadablePluginPlaceholder::SetMessage(const base::string16& message) {
   message_ = message;
   if (finished_loading_)
@@ -229,11 +146,10 @@
   std::string script =
       "window.setMessage(" + base::GetQuotedJSONString(message_) + ")";
   plugin()->web_view()->mainFrame()->executeScript(
-      WebScriptSource(base::UTF8ToUTF16(script)));
+      blink::WebScriptSource(base::UTF8ToUTF16(script)));
 }
 
 void LoadablePluginPlaceholder::PluginDestroyed() {
-#if defined(ENABLE_PLUGINS)
   if (power_saver_enabled_) {
     if (premade_throttler_) {
       // Since the premade plugin has been detached from the container, it will
@@ -249,22 +165,51 @@
     // Prevent processing subsequent calls to MarkPluginEssential.
     power_saver_enabled_ = false;
   }
-#endif
 
-  PluginPlaceholder::PluginDestroyed();
+  PluginPlaceholderBase::PluginDestroyed();
 }
 
 v8::Local<v8::Object> LoadablePluginPlaceholder::GetV8ScriptableObject(
     v8::Isolate* isolate) const {
-#if defined(ENABLE_PLUGINS)
   // Pass through JavaScript access to the underlying throttled plugin.
   if (premade_throttler_ && premade_throttler_->GetWebPlugin()) {
     return premade_throttler_->GetWebPlugin()->v8ScriptableObject(isolate);
   }
-#endif
   return v8::Local<v8::Object>();
 }
 
+void LoadablePluginPlaceholder::OnUnobscuredSizeUpdate(
+    const gfx::Size& unobscured_size) {
+  DCHECK(
+      content::RenderThread::Get()->GetTaskRunner()->BelongsToCurrentThread());
+  if (!power_saver_enabled_ || !premade_throttler_ || !finished_loading_)
+    return;
+
+  unobscured_size_ = unobscured_size;
+
+  // During a size recheck, we will get another notification into this method.
+  // Use this flag to early exit to prevent reentrancy issues.
+  if (in_size_recheck_)
+    return;
+
+  if (PluginInstanceThrottler::IsLargeContent(unobscured_size.width(),
+                                              unobscured_size.height())) {
+    if (!size_update_timer_.IsRunning()) {
+      // TODO(tommycli): We have to post a delayed task to recheck the size, as
+      // Blink can report wrong sizes for partially obscured plugins while the
+      // compositing state is dirty. https://crbug.com/343769
+      size_update_timer_.Start(
+          FROM_HERE, base::TimeDelta::FromMilliseconds(
+                         kSizeChangeRecheckDelayMilliseconds),
+          base::Bind(&LoadablePluginPlaceholder::RecheckSizeAndMaybeUnthrottle,
+                     weak_factory_.GetWeakPtr()));
+    }
+  } else {
+    // Cancel any pending unthrottle due to resize calls.
+    size_update_timer_.Stop();
+  }
+}
+
 void LoadablePluginPlaceholder::WasShown() {
   if (is_blocked_for_background_tab_) {
     is_blocked_for_background_tab_ = false;
@@ -296,7 +241,7 @@
 void LoadablePluginPlaceholder::LoadPlugin() {
   // This is not strictly necessary but is an important defense in case the
   // event propagation changes between "close" vs. "click-to-play".
-  if (hidden_)
+  if (hidden())
     return;
   if (!plugin())
     return;
@@ -316,19 +261,12 @@
 
 void LoadablePluginPlaceholder::LoadCallback() {
   RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Click"));
-#if defined(ENABLE_PLUGINS)
   // If the user specifically clicks on the plugin content's placeholder,
   // disable power saver throttling for this instance.
   MarkPluginEssential(PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_CLICK);
-#endif
   LoadPlugin();
 }
 
-void LoadablePluginPlaceholder::HideCallback() {
-  RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Hide_Click"));
-  HidePlugin();
-}
-
 void LoadablePluginPlaceholder::DidFinishLoadingCallback() {
   finished_loading_ = true;
   if (message_.length() > 0)
@@ -343,7 +281,7 @@
   // placeholder to be ready to receive simulated user input.
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnablePluginPlaceholderTesting)) {
-    WebElement element = plugin()->container()->element();
+    blink::WebElement element = plugin()->container()->element();
     element.setAttribute("placeholderLoaded", "true");
 
     scoped_ptr<content::V8ValueConverter> converter(
@@ -389,4 +327,26 @@
          is_blocked_for_prerendering_;
 }
 
+void LoadablePluginPlaceholder::RecheckSizeAndMaybeUnthrottle() {
+  DCHECK(
+      content::RenderThread::Get()->GetTaskRunner()->BelongsToCurrentThread());
+  DCHECK(!in_size_recheck_);
+
+  if (!plugin())
+    return;
+
+  in_size_recheck_ = true;
+
+  // Re-check the size in case the reported size was incorrect.
+  plugin()->container()->reportGeometry();
+
+  if (PluginInstanceThrottler::IsLargeContent(unobscured_size_.width(),
+                                              unobscured_size_.height())) {
+    MarkPluginEssential(
+        PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_SIZE_CHANGE);
+  }
+
+  in_size_recheck_ = false;
+}
+
 }  // namespace plugins
diff --git a/components/plugins/renderer/loadable_plugin_placeholder.h b/components/plugins/renderer/loadable_plugin_placeholder.h
index 7683ba7c..13b903df 100644
--- a/components/plugins/renderer/loadable_plugin_placeholder.h
+++ b/components/plugins/renderer/loadable_plugin_placeholder.h
@@ -6,14 +6,16 @@
 #define COMPONENTS_PLUGINS_RENDERER_LOADABLE_PLUGIN_PLACEHOLDER_H_
 
 #include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
 #include "components/plugins/renderer/plugin_placeholder.h"
 #include "content/public/common/webplugininfo.h"
 #include "content/public/renderer/plugin_instance_throttler.h"
+#include "content/public/renderer/render_thread.h"
 
 namespace plugins {
 // Placeholders can be used if a plugin is missing or not available
 // (blocked or disabled).
-class LoadablePluginPlaceholder : public PluginPlaceholder {
+class LoadablePluginPlaceholder : public PluginPlaceholderBase {
  public:
   void set_blocked_for_background_tab(bool blocked_for_background_tab) {
     is_blocked_for_background_tab_ = blocked_for_background_tab;
@@ -23,7 +25,6 @@
     is_blocked_for_prerendering_ = blocked_for_prerendering;
   }
 
-#if defined(ENABLE_PLUGINS)
   bool power_saver_enabled() const { return power_saver_enabled_; }
 
   void set_power_saver_enabled(bool power_saver_enabled) {
@@ -35,23 +36,19 @@
 
   // When we load the plugin, use this already-created plugin, not a new one.
   void SetPremadePlugin(content::PluginInstanceThrottler* throttler);
-#endif
 
-  void set_allow_loading(bool allow_loading) { allow_loading_ = allow_loading; }
+  void DisallowLoading() { allow_loading_ = false; }
 
  protected:
   LoadablePluginPlaceholder(content::RenderFrame* render_frame,
                             blink::WebLocalFrame* frame,
                             const blink::WebPluginParams& params,
-                            const std::string& html_data,
-                            GURL placeholderDataUrl);
+                            const std::string& html_data);
 
   ~LoadablePluginPlaceholder() override;
 
-#if defined(ENABLE_PLUGINS)
   void MarkPluginEssential(
       content::PluginInstanceThrottler::PowerSaverUnthrottleMethod method);
-#endif
 
   void OnLoadBlockedPlugins(const std::string& identifier);
   void OnSetIsPrerendering(bool is_prerendering);
@@ -67,36 +64,27 @@
   // a placeholder again).
   void ReplacePlugin(blink::WebPlugin* new_plugin);
 
-  // Hide this placeholder.
-  void HidePlugin();
-
   // Load the blocked plugin.
   void LoadPlugin();
 
-  // WebViewPlugin::Delegate (via PluginPlaceholder) method
-  void BindWebFrame(blink::WebFrame* frame) override;
-
-  // gin::Wrappable method:
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
+  // Javascript callbacks:
+  void LoadCallback();
+  void DidFinishLoadingCallback();
 
  private:
   // WebViewPlugin::Delegate methods:
   void PluginDestroyed() override;
   v8::Local<v8::Object> GetV8ScriptableObject(
       v8::Isolate* isolate) const override;
+  void OnUnobscuredSizeUpdate(const gfx::Size& unobscured_size) override;
 
   // RenderFrameObserver methods:
   void WasShown() override;
 
-  // Javascript callbacks:
-  void LoadCallback();
-  void HideCallback();
-  void DidFinishLoadingCallback();
-
   void UpdateMessage();
 
   bool LoadingBlocked() const;
+  void RecheckSizeAndMaybeUnthrottle();
 
   // Plugin creation is embedder-specific.
   virtual blink::WebPlugin* CreatePlugin() = 0;
@@ -125,10 +113,14 @@
 
   bool allow_loading_;
 
-  bool hidden_;
   bool finished_loading_;
   std::string identifier_;
 
+  // Used to prevent re-entrancy during the size recheck for throttled plugins.
+  bool in_size_recheck_;
+  gfx::Size unobscured_size_;
+  base::OneShotTimer<LoadablePluginPlaceholder> size_update_timer_;
+
   base::WeakPtrFactory<LoadablePluginPlaceholder> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(LoadablePluginPlaceholder);
diff --git a/components/plugins/renderer/mobile_youtube_plugin.cc b/components/plugins/renderer/mobile_youtube_plugin.cc
index 4664db7..9745a0a1 100644
--- a/components/plugins/renderer/mobile_youtube_plugin.cc
+++ b/components/plugins/renderer/mobile_youtube_plugin.cc
@@ -11,10 +11,8 @@
 #include "base/values.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/renderer/render_frame.h"
-#include "gin/handle.h"
 #include "gin/object_template_builder.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
-#include "third_party/WebKit/public/web/WebKit.h"
 #include "ui/base/webui/jstemplate_builder.h"
 
 using blink::WebFrame;
@@ -73,16 +71,17 @@
 
 namespace plugins {
 
+gin::WrapperInfo MobileYouTubePlugin::kWrapperInfo = {gin::kEmbedderNativeGin};
+
 MobileYouTubePlugin::MobileYouTubePlugin(content::RenderFrame* render_frame,
                                          blink::WebLocalFrame* frame,
                                          const blink::WebPluginParams& params,
-                                         base::StringPiece& template_html,
-                                         GURL placeholderDataUrl)
-    : PluginPlaceholder(render_frame,
-                        frame,
-                        params,
-                        HtmlData(params, template_html),
-                        placeholderDataUrl) {}
+                                         base::StringPiece& template_html)
+    : PluginPlaceholderBase(render_frame,
+                            frame,
+                            params,
+                            HtmlData(params, template_html)) {
+}
 
 MobileYouTubePlugin::~MobileYouTubePlugin() {}
 
@@ -94,7 +93,8 @@
                     EndsWith(host, "youtube-nocookie.com", true);
 
   return is_youtube && IsValidYouTubeVideo(url.path()) &&
-         LowerCaseEqualsASCII(mime_type, content::kFlashPluginSwfMimeType);
+         base::LowerCaseEqualsASCII(mime_type,
+                                    content::kFlashPluginSwfMimeType);
 }
 
 void MobileYouTubePlugin::OpenYoutubeUrlCallback() {
@@ -107,22 +107,15 @@
       GetFrame(), request, blink::WebNavigationPolicyNewForegroundTab);
 }
 
-void MobileYouTubePlugin::BindWebFrame(WebFrame* frame) {
-  v8::Isolate* isolate = blink::mainThreadIsolate();
-  v8::HandleScope handle_scope(isolate);
-  v8::Local<v8::Context> context = frame->mainWorldScriptContext();
-  DCHECK(!context.IsEmpty());
-
-  v8::Context::Scope context_scope(context);
-  v8::Local<v8::Object> global = context->Global();
-  global->Set(gin::StringToV8(isolate, "plugin"),
-              gin::CreateHandle(isolate, this).ToV8());
+v8::Local<v8::Value> MobileYouTubePlugin::GetV8Handle(v8::Isolate* isolate) {
+  return gin::CreateHandle(isolate, this).ToV8();
 }
 
 gin::ObjectTemplateBuilder MobileYouTubePlugin::GetObjectTemplateBuilder(
     v8::Isolate* isolate) {
-  return PluginPlaceholder::GetObjectTemplateBuilder(isolate)
-    .SetMethod("openYoutubeURL", &MobileYouTubePlugin::OpenYoutubeUrlCallback);
+  return gin::Wrappable<MobileYouTubePlugin>::GetObjectTemplateBuilder(isolate)
+      .SetMethod("openYoutubeURL",
+                 &MobileYouTubePlugin::OpenYoutubeUrlCallback);
 }
 
 }  // namespace plugins
diff --git a/components/plugins/renderer/mobile_youtube_plugin.h b/components/plugins/renderer/mobile_youtube_plugin.h
index 99a6213..9d467002 100644
--- a/components/plugins/renderer/mobile_youtube_plugin.h
+++ b/components/plugins/renderer/mobile_youtube_plugin.h
@@ -14,13 +14,15 @@
 // of http://www.youtube.com/v/VIDEO_ID. This placeholder replaces the url with
 // a simple html page and clicking the play image redirects the user to the
 // mobile youtube app.
-class MobileYouTubePlugin : public PluginPlaceholder {
+class MobileYouTubePlugin final : public PluginPlaceholderBase,
+                                  public gin::Wrappable<MobileYouTubePlugin> {
  public:
+  static gin::WrapperInfo kWrapperInfo;
+
   MobileYouTubePlugin(content::RenderFrame* render_frame,
                       blink::WebLocalFrame* frame,
                       const blink::WebPluginParams& params,
-                      base::StringPiece& template_html,
-                      GURL placeholderDataUrl);
+                      base::StringPiece& template_html);
 
   // Whether this is a youtube url.
   static bool IsYouTubeURL(const GURL& url, const std::string& mime_type);
@@ -31,12 +33,12 @@
   // Opens a youtube app in the current tab.
   void OpenYoutubeUrlCallback();
 
-  // WebViewPlugin::Delegate (via PluginPlaceholder) method
-  void BindWebFrame(blink::WebFrame* frame) override;
+  // WebViewPlugin::Delegate methods:
+  v8::Local<v8::Value> GetV8Handle(v8::Isolate* isolate) override;
 
   // gin::Wrappable (via PluginPlaceholder) method
   gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
+      v8::Isolate* isolate) final;
 
   DISALLOW_COPY_AND_ASSIGN(MobileYouTubePlugin);
 };
diff --git a/components/plugins/renderer/plugin_placeholder.cc b/components/plugins/renderer/plugin_placeholder.cc
index 180e913..98fc8cb9 100644
--- a/components/plugins/renderer/plugin_placeholder.cc
+++ b/components/plugins/renderer/plugin_placeholder.cc
@@ -4,18 +4,26 @@
 
 #include "components/plugins/renderer/plugin_placeholder.h"
 
+#include "base/strings/string_util.h"
 #include "content/public/common/web_preferences.h"
 #include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
+#include "gin/object_template_builder.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "third_party/re2/re2/re2.h"
 
 namespace plugins {
 
-gin::WrapperInfo PluginPlaceholder::kWrapperInfo = {gin::kEmbedderNativeGin};
+// The placeholder is loaded in normal web renderer processes, so it should not
+// have a chrome:// scheme that might let it be confused with a WebUI page.
+const char kPluginPlaceholderDataURL[] = "data:text/html,pluginplaceholderdata";
 
-PluginPlaceholder::PluginPlaceholder(content::RenderFrame* render_frame,
-                                     blink::WebLocalFrame* frame,
-                                     const blink::WebPluginParams& params,
-                                     const std::string& html_data,
-                                     GURL placeholderDataUrl)
+PluginPlaceholderBase::PluginPlaceholderBase(
+    content::RenderFrame* render_frame,
+    blink::WebLocalFrame* frame,
+    const blink::WebPluginParams& params,
+    const std::string& html_data)
     : content::RenderFrameObserver(render_frame),
       frame_(frame),
       plugin_params_(params),
@@ -24,36 +32,116 @@
                                         ? render_frame->GetWebkitPreferences()
                                         : content::WebPreferences(),
                                     html_data,
-                                    placeholderDataUrl)) {
-  DCHECK(placeholderDataUrl.is_valid())
-      << "Blink requires the placeholder to have a valid URL.";
+                                    GURL(kPluginPlaceholderDataURL))),
+      hidden_(false) {
 }
 
-PluginPlaceholder::~PluginPlaceholder() {}
+PluginPlaceholderBase::~PluginPlaceholderBase() {
+}
 
-const blink::WebPluginParams& PluginPlaceholder::GetPluginParams() const {
+const blink::WebPluginParams& PluginPlaceholderBase::GetPluginParams() const {
   return plugin_params_;
 }
 
-void PluginPlaceholder::ShowContextMenu(const blink::WebMouseEvent& event) {
+void PluginPlaceholderBase::ShowContextMenu(const blink::WebMouseEvent& event) {
   // Does nothing by default. Will be overridden if a specific browser wants
   // a context menu.
   return;
 }
 
-void PluginPlaceholder::PluginDestroyed() {
+void PluginPlaceholderBase::PluginDestroyed() {
   plugin_ = NULL;
 }
 
-v8::Local<v8::Object> PluginPlaceholder::GetV8ScriptableObject(
+v8::Local<v8::Object> PluginPlaceholderBase::GetV8ScriptableObject(
     v8::Isolate* isolate) const {
   return v8::Local<v8::Object>();
 }
 
-void PluginPlaceholder::OnDestruct() {
+void PluginPlaceholderBase::HidePlugin() {
+  hidden_ = true;
+  if (!plugin())
+    return;
+  blink::WebPluginContainer* container = plugin()->container();
+  blink::WebElement element = container->element();
+  element.setAttribute("style", "display: none;");
+  // If we have a width and height, search for a parent (often <div>) with the
+  // same dimensions. If we find such a parent, hide that as well.
+  // This makes much more uncovered page content usable (including clickable)
+  // as opposed to merely visible.
+  // TODO(cevans) -- it's a foul heuristic but we're going to tolerate it for
+  // now for these reasons:
+  // 1) Makes the user experience better.
+  // 2) Foulness is encapsulated within this single function.
+  // 3) Confidence in no fasle positives.
+  // 4) Seems to have a good / low false negative rate at this time.
+  if (element.hasAttribute("width") && element.hasAttribute("height")) {
+    std::string width_str("width:[\\s]*");
+    width_str += element.getAttribute("width").utf8().data();
+    if (EndsWith(width_str, "px", false)) {
+      width_str = width_str.substr(0, width_str.length() - 2);
+    }
+    base::TrimWhitespace(width_str, base::TRIM_TRAILING, &width_str);
+    width_str += "[\\s]*px";
+    std::string height_str("height:[\\s]*");
+    height_str += element.getAttribute("height").utf8().data();
+    if (EndsWith(height_str, "px", false)) {
+      height_str = height_str.substr(0, height_str.length() - 2);
+    }
+    base::TrimWhitespace(height_str, base::TRIM_TRAILING, &height_str);
+    height_str += "[\\s]*px";
+    blink::WebNode parent = element;
+    while (!parent.parentNode().isNull()) {
+      parent = parent.parentNode();
+      if (!parent.isElementNode())
+        continue;
+      element = parent.toConst<blink::WebElement>();
+      if (element.hasAttribute("style")) {
+        std::string style_str = element.getAttribute("style").utf8();
+        if (RE2::PartialMatch(style_str, width_str) &&
+            RE2::PartialMatch(style_str, height_str))
+          element.setAttribute("style", "display: none;");
+      }
+    }
+  }
+}
+
+void PluginPlaceholderBase::HideCallback() {
+  content::RenderThread::Get()->RecordAction(
+      base::UserMetricsAction("Plugin_Hide_Click"));
+  HidePlugin();
+}
+
+void PluginPlaceholderBase::OnDestruct() {
   frame_ = NULL;
 }
 
-blink::WebLocalFrame* PluginPlaceholder::GetFrame() { return frame_; }
+blink::WebLocalFrame* PluginPlaceholderBase::GetFrame() {
+  return frame_;
+}
+
+// static
+gin::WrapperInfo PluginPlaceholder::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+PluginPlaceholder::PluginPlaceholder(content::RenderFrame* render_frame,
+                                     blink::WebLocalFrame* frame,
+                                     const blink::WebPluginParams& params,
+                                     const std::string& html_data)
+    : PluginPlaceholderBase(render_frame, frame, params, html_data) {
+}
+
+PluginPlaceholder::~PluginPlaceholder() {
+}
+
+v8::Local<v8::Value> PluginPlaceholder::GetV8Handle(v8::Isolate* isolate) {
+  return gin::CreateHandle(isolate, this).ToV8();
+}
+
+gin::ObjectTemplateBuilder PluginPlaceholder::GetObjectTemplateBuilder(
+    v8::Isolate* isolate) {
+  return gin::Wrappable<PluginPlaceholder>::GetObjectTemplateBuilder(isolate)
+      .SetMethod<void (plugins::PluginPlaceholder::*)()>(
+          "hide", &PluginPlaceholder::HideCallback);
+}
 
 }  // namespace plugins
diff --git a/components/plugins/renderer/plugin_placeholder.h b/components/plugins/renderer/plugin_placeholder.h
index 5d9caa10..63a1d08 100644
--- a/components/plugins/renderer/plugin_placeholder.h
+++ b/components/plugins/renderer/plugin_placeholder.h
@@ -8,30 +8,29 @@
 #include "base/memory/weak_ptr.h"
 #include "components/plugins/renderer/webview_plugin.h"
 #include "content/public/renderer/render_frame_observer.h"
+#include "gin/handle.h"
 #include "gin/wrappable.h"
+#include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebPluginParams.h"
 
 namespace plugins {
 
-class PluginPlaceholder : public content::RenderFrameObserver,
-                          public WebViewPlugin::Delegate,
-                          public gin::Wrappable<PluginPlaceholder> {
+// This abstract class is the base class of all plugin placeholders.
+class PluginPlaceholderBase : public content::RenderFrameObserver,
+                              public WebViewPlugin::Delegate {
  public:
-  static gin::WrapperInfo kWrapperInfo;
+  // |render_frame| and |frame| are weak pointers. If either one is going away,
+  // our |plugin_| will be destroyed as well and will notify us.
+  PluginPlaceholderBase(content::RenderFrame* render_frame,
+                        blink::WebLocalFrame* frame,
+                        const blink::WebPluginParams& params,
+                        const std::string& html_data);
+
+  ~PluginPlaceholderBase() override;
 
   WebViewPlugin* plugin() { return plugin_; }
 
  protected:
-  // |render_frame| and |frame| are weak pointers. If either one is going away,
-  // our |plugin_| will be destroyed as well and will notify us.
-  PluginPlaceholder(content::RenderFrame* render_frame,
-                    blink::WebLocalFrame* frame,
-                    const blink::WebPluginParams& params,
-                    const std::string& html_data,
-                    GURL placeholderDataUrl);
-
-  ~PluginPlaceholder() override;
-
   blink::WebLocalFrame* GetFrame();
   const blink::WebPluginParams& GetPluginParams() const;
 
@@ -41,6 +40,14 @@
   v8::Local<v8::Object> GetV8ScriptableObject(
       v8::Isolate* isolate) const override;
 
+ protected:
+  // Hide this placeholder.
+  void HidePlugin();
+  bool hidden() { return hidden_; }
+
+  // JavaScript callbacks:
+  void HideCallback();
+
  private:
   // RenderFrameObserver methods:
   void OnDestruct() override;
@@ -49,7 +56,30 @@
   blink::WebPluginParams plugin_params_;
   WebViewPlugin* plugin_;
 
-  DISALLOW_COPY_AND_ASSIGN(PluginPlaceholder);
+  bool hidden_;
+
+  DISALLOW_COPY_AND_ASSIGN(PluginPlaceholderBase);
+};
+
+// A basic placeholder that supports only hiding.
+class PluginPlaceholder final : public PluginPlaceholderBase,
+                                public gin::Wrappable<PluginPlaceholder> {
+ public:
+  static gin::WrapperInfo kWrapperInfo;
+
+  PluginPlaceholder(content::RenderFrame* render_frame,
+                    blink::WebLocalFrame* frame,
+                    const blink::WebPluginParams& params,
+                    const std::string& html_data);
+  ~PluginPlaceholder() override;
+
+ private:
+  // WebViewPlugin::Delegate methods:
+  v8::Local<v8::Value> GetV8Handle(v8::Isolate* isolate) final;
+
+  // gin::Wrappable method:
+  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) override;
 };
 
 }  // namespace plugins
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc
index f436254..0779566f 100644
--- a/components/plugins/renderer/webview_plugin.cc
+++ b/components/plugins/renderer/webview_plugin.cc
@@ -9,6 +9,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "content/public/common/web_preferences.h"
 #include "content/public/renderer/render_view.h"
+#include "gin/converter.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/WebKit/public/platform/WebSize.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
@@ -61,6 +62,7 @@
                                      const WebPreferences& preferences,
                                      const std::string& html_data,
                                      const GURL& url) {
+  DCHECK(url.is_valid()) << "Blink requires the WebView to have a valid URL.";
   WebViewPlugin* plugin = new WebViewPlugin(delegate, preferences);
   plugin->web_view()->mainFrame()->loadHTMLString(html_data, url);
   return plugin;
@@ -171,6 +173,9 @@
     WebSize newSize(window_rect.width, window_rect.height);
     web_view_->resize(newSize);
   }
+
+  if (delegate_)
+    delegate_->OnUnobscuredSizeUpdate(gfx::Rect(unobscured_rect).size());
 }
 
 void WebViewPlugin::updateFocus(bool focused, blink::WebFocusType focus_type) {
@@ -261,8 +266,19 @@
 }
 
 void WebViewPlugin::didClearWindowObject(WebLocalFrame* frame) {
-  if (delegate_)
-    delegate_->BindWebFrame(frame);
+  if (!delegate_)
+    return;
+
+  v8::Isolate* isolate = blink::mainThreadIsolate();
+  v8::HandleScope handle_scope(isolate);
+  v8::Local<v8::Context> context = frame->mainWorldScriptContext();
+  DCHECK(!context.IsEmpty());
+
+  v8::Context::Scope context_scope(context);
+  v8::Local<v8::Object> global = context->Global();
+
+  global->Set(gin::StringToV8(isolate, "plugin"),
+              delegate_->GetV8Handle(isolate));
 }
 
 void WebViewPlugin::didReceiveResponse(WebLocalFrame* frame,
diff --git a/components/plugins/renderer/webview_plugin.h b/components/plugins/renderer/webview_plugin.h
index 08f5296c..fdb9777 100644
--- a/components/plugins/renderer/webview_plugin.h
+++ b/components/plugins/renderer/webview_plugin.h
@@ -13,6 +13,7 @@
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
 #include "third_party/WebKit/public/web/WebFrameClient.h"
+#include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebPlugin.h"
 #include "third_party/WebKit/public/web/WebViewClient.h"
 
@@ -25,6 +26,10 @@
 struct WebPreferences;
 }
 
+namespace gfx {
+class Size;
+}
+
 // This class implements the WebPlugin interface by forwarding drawing and
 // handling input events to a WebView.
 // It can be used as a placeholder for an actual plugin, using HTML for the UI.
@@ -38,10 +43,8 @@
  public:
   class Delegate {
    public:
-    // Bind |frame| to a Javascript object, enabling the delegate to receive
-    // callback methods from Javascript inside the WebFrame.
-    // This method is called from WebFrameClient::didClearWindowObject.
-    virtual void BindWebFrame(blink::WebFrame* frame) = 0;
+    // Called to get the V8 handle used to bind the lifetime to the frame.
+    virtual v8::Local<v8::Value> GetV8Handle(v8::Isolate*) = 0;
 
     // Called upon a context menu event.
     virtual void ShowContextMenu(const blink::WebMouseEvent&) = 0;
@@ -52,6 +55,9 @@
     // Called to enable JavaScript pass-through to a throttled plugin, which is
     // loaded but idle. Doesn't work for blocked plugins, which is not loaded.
     virtual v8::Local<v8::Object> GetV8ScriptableObject(v8::Isolate*) const = 0;
+
+    // Called when the unobscured size of the plugin is updated.
+    virtual void OnUnobscuredSizeUpdate(const gfx::Size& unobscured_size) {}
   };
 
   // Convenience method to set up a new WebViewPlugin using |preferences|
diff --git a/components/policy/core/common/cloud/cloud_policy_validator_unittest.cc b/components/policy/core/common/cloud/cloud_policy_validator_unittest.cc
index e88d4317..28a3d21 100644
--- a/components/policy/core/common/cloud/cloud_policy_validator_unittest.cc
+++ b/components/policy/core/common/cloud/cloud_policy_validator_unittest.cc
@@ -162,7 +162,7 @@
 
 TEST_F(CloudPolicyValidatorTest, UsernameCanonicalization) {
   policy_.policy_data().set_username(
-      StringToUpperASCII(std::string(PolicyBuilder::kFakeUsername)));
+      base::StringToUpperASCII(std::string(PolicyBuilder::kFakeUsername)));
   Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK));
 }
 
diff --git a/components/policy/core/common/policy_loader_win.cc b/components/policy/core/common/policy_loader_win.cc
index 449b99f5..f199a20d 100644
--- a/components/policy/core/common/policy_loader_win.cc
+++ b/components/policy/core/common/policy_loader_win.cc
@@ -156,7 +156,8 @@
       if (pos == std::string::npos)
         continue;
       // Only allow custom update urls in enterprise environments.
-      if (!LowerCaseEqualsASCII(entry.substr(pos), kExpectedWebStoreUrl)) {
+      if (!base::LowerCaseEqualsASCII(entry.substr(pos),
+                                      kExpectedWebStoreUrl)) {
         entry = kBlockedExtensionPrefix + entry;
         invalid_policies++;
       }
diff --git a/components/policy/core/common/preg_parser_win.cc b/components/policy/core/common/preg_parser_win.cc
index 96813474..4c13068 100644
--- a/components/policy/core/common/preg_parser_win.cc
+++ b/components/policy/core/common/preg_parser_win.cc
@@ -176,7 +176,7 @@
     return;
 
   std::string value_name(base::UTF16ToUTF8(value));
-  if (!StartsWithASCII(value_name, kActionTriggerPrefix, true)) {
+  if (!base::StartsWithASCII(value_name, kActionTriggerPrefix, true)) {
     scoped_ptr<base::Value> value;
     if (DecodePRegValue(type, data, &value))
       dict->SetValue(value_name, value.Pass());
@@ -192,22 +192,25 @@
          value != values.end(); ++value) {
       dict->RemoveValue(*value);
     }
-  } else if (StartsWithASCII(action_trigger, kActionTriggerDeleteKeys, true)) {
+  } else if (base::StartsWithASCII(action_trigger, kActionTriggerDeleteKeys,
+                                   true)) {
     std::vector<std::string> keys;
     Tokenize(DecodePRegStringValue(data), ";", &keys);
     for (std::vector<std::string>::const_iterator key(keys.begin());
          key != keys.end(); ++key) {
       dict->RemoveKey(*key);
     }
-  } else if (StartsWithASCII(action_trigger, kActionTriggerDel, true)) {
+  } else if (base::StartsWithASCII(action_trigger, kActionTriggerDel, true)) {
     dict->RemoveValue(
         value_name.substr(arraysize(kActionTriggerPrefix) - 1 +
                           arraysize(kActionTriggerDel) - 1));
-  } else if (StartsWithASCII(action_trigger, kActionTriggerDelVals, true)) {
+  } else if (base::StartsWithASCII(action_trigger, kActionTriggerDelVals,
+                                   true)) {
     // Delete all values.
     dict->ClearValues();
-  } else if (StartsWithASCII(action_trigger, kActionTriggerSecureKey, true) ||
-             StartsWithASCII(action_trigger, kActionTriggerSoft, true)) {
+  } else if (base::StartsWithASCII(action_trigger, kActionTriggerSecureKey,
+                                   true) ||
+             base::StartsWithASCII(action_trigger, kActionTriggerSoft, true)) {
     // Doesn't affect values.
   } else {
     LOG(ERROR) << "Bad action trigger " << value_name;
@@ -295,7 +298,7 @@
       break;
 
     // Process the record if it is within the |root| subtree.
-    if (StartsWith(key_name, root, false))
+    if (base::StartsWith(key_name, root, false))
       HandleRecord(key_name.substr(root.size()), value, type, data, dict);
   }
 
diff --git a/components/precache.gypi b/components/precache.gypi
index 0bd41da..6d71683 100644
--- a/components/precache.gypi
+++ b/components/precache.gypi
@@ -47,7 +47,6 @@
         'precache/core/precache_switches.h',
         'precache/core/precache_url_table.cc',
         'precache/core/precache_url_table.h',
-        'precache/core/url_list_provider.h',
       ],
       'includes': [ 'precache/precache_defines.gypi', ],
       'direct_dependent_settings': {
diff --git a/components/precache/content/DEPS b/components/precache/content/DEPS
index 8a2bc75..ee4913c 100644
--- a/components/precache/content/DEPS
+++ b/components/precache/content/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+components/data_reduction_proxy/core/common",
+  "+components/history/core/browser",
   "+components/keyed_service",
   "+components/user_prefs",
   "+content/public/browser",
diff --git a/components/precache/content/precache_manager.cc b/components/precache/content/precache_manager.cc
index 08f9cb8..c8fc3db 100644
--- a/components/precache/content/precache_manager.cc
+++ b/components/precache/content/precache_manager.cc
@@ -4,6 +4,10 @@
 
 #include "components/precache/content/precache_manager.h"
 
+#include <string>
+#include <utility>
+#include <vector>
+
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -12,9 +16,9 @@
 #include "base/prefs/pref_service.h"
 #include "base/time/time.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
+#include "components/history/core/browser/history_service.h"
 #include "components/precache/core/precache_database.h"
 #include "components/precache/core/precache_switches.h"
-#include "components/precache/core/url_list_provider.h"
 #include "components/user_prefs/user_prefs.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -26,11 +30,16 @@
 
 const char kPrecacheFieldTrialName[] = "Precache";
 const char kPrecacheFieldTrialEnabledGroup[] = "Enabled";
+const int kNumTopHosts = 100;
 
 }  // namespace
 
 namespace precache {
 
+int NumTopHosts() {
+  return kNumTopHosts;
+}
+
 PrecacheManager::PrecacheManager(content::BrowserContext* browser_context)
     : browser_context_(browser_context),
       precache_database_(new PrecacheDatabase()),
@@ -62,7 +71,7 @@
 
 void PrecacheManager::StartPrecaching(
     const PrecacheCompletionCallback& precache_completion_callback,
-    URLListProvider* url_list_provider) {
+    const history::HistoryService& history_service) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (is_precaching_) {
@@ -79,8 +88,12 @@
 
   precache_completion_callback_ = precache_completion_callback;
 
-  url_list_provider->GetURLs(
-      base::Bind(&PrecacheManager::OnURLsReceived, AsWeakPtr()));
+  // Request NumTopHosts() top hosts. Note that PrecacheFetcher is further bound
+  // by the value of PrecacheConfigurationSettings.top_sites_count, as retrieved
+  // from the server.
+  history_service.TopHosts(
+      NumTopHosts(),
+      base::Bind(&PrecacheManager::OnHostsReceived, AsWeakPtr()));
 }
 
 void PrecacheManager::CancelPrecaching() {
@@ -155,18 +168,23 @@
   precache_completion_callback_.Reset();
 }
 
-void PrecacheManager::OnURLsReceived(const std::list<GURL>& urls) {
+void PrecacheManager::OnHostsReceived(
+    const history::TopHostsList& host_counts) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (!is_precaching_) {
     // Don't start precaching if it was canceled while waiting for the list of
-    // URLs.
+    // hosts.
     return;
   }
 
+  std::vector<std::string> hosts;
+  for (const auto& host_count : host_counts)
+    hosts.push_back(host_count.first);
+
   // Start precaching.
   precache_fetcher_.reset(
-      new PrecacheFetcher(urls, browser_context_->GetRequestContext(), this));
+      new PrecacheFetcher(hosts, browser_context_->GetRequestContext(), this));
   precache_fetcher_->Start();
 }
 
diff --git a/components/precache/content/precache_manager.h b/components/precache/content/precache_manager.h
index 56d5d22..b69ad13 100644
--- a/components/precache/content/precache_manager.h
+++ b/components/precache/content/precache_manager.h
@@ -6,12 +6,16 @@
 #define COMPONENTS_PRECACHE_CONTENT_PRECACHE_MANAGER_H_
 
 #include <list>
+#include <string>
+#include <utility>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "components/history/core/browser/history_types.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/precache/core/precache_fetcher.h"
 #include "url/gurl.h"
@@ -24,10 +28,16 @@
 class BrowserContext;
 }
 
+namespace history {
+class HistoryService;
+}
+
 namespace precache {
 
 class PrecacheDatabase;
-class URLListProvider;
+
+// Visible for test.
+int NumTopHosts();
 
 // Class that manages all precaching-related activities. Owned by the
 // BrowserContext that it is constructed for. Use
@@ -58,7 +68,7 @@
   // precaching finishes, but will not be run if precaching is canceled.
   void StartPrecaching(
       const PrecacheCompletionCallback& precache_completion_callback,
-      URLListProvider* url_list_provider);
+      const history::HistoryService& history_service);
 
   // Cancels precaching if it is in progress.
   void CancelPrecaching();
@@ -79,7 +89,8 @@
   // From PrecacheFetcher::PrecacheDelegate.
   void OnDone() override;
 
-  void OnURLsReceived(const std::list<GURL>& urls);
+  // From history::HistoryService::TopHosts.
+  void OnHostsReceived(const history::TopHostsList& host_counts);
 
   // The browser context that owns this PrecacheManager.
   content::BrowserContext* browser_context_;
diff --git a/components/precache/content/precache_manager_unittest.cc b/components/precache/content/precache_manager_unittest.cc
index 48dfd18d..6f5fd89 100644
--- a/components/precache/content/precache_manager_unittest.cc
+++ b/components/precache/content/precache_manager_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "components/precache/content/precache_manager.h"
 
-#include <list>
 #include <map>
 #include <set>
 #include <string>
@@ -20,14 +19,16 @@
 #include "base/metrics/statistics_recorder.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/browser/history_types.h"
 #include "components/precache/core/precache_switches.h"
-#include "components/precache/core/url_list_provider.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_status.h"
 #include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -35,11 +36,16 @@
 
 namespace {
 
+using ::testing::_;
+using ::testing::SaveArg;
+
 // A map of histogram names to the total sample counts.
 typedef std::map<std::string, base::HistogramBase::Count> HistogramCountMap;
 
 const char kConfigURL[] = "http://config-url.com";
 const char kManifestURLPrefix[] = "http://manifest-url-prefix.com/";
+const char kGoodManifestURL[] =
+    "http://manifest-url-prefix.com/good-manifest.com";
 
 base::HistogramBase::Count GetHistogramTotalCount(const char* histogram_name) {
   base::HistogramBase* histogram =
@@ -84,35 +90,16 @@
   std::multiset<GURL> requested_urls_;
 };
 
-class FakeURLListProvider : public URLListProvider {
+class MockHistoryService : public history::HistoryService {
  public:
-  FakeURLListProvider(const std::list<GURL>& urls, bool run_immediately)
-      : urls_(urls),
-        run_immediately_(run_immediately),
-        was_get_urls_called_(false) {}
-
-  void GetURLs(const GetURLsCallback& callback) override {
-    was_get_urls_called_ = true;
-
-    if (run_immediately_) {
-      callback.Run(urls_);
-    } else {
-      // Post the callback to be run later in the message loop.
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(callback, urls_));
-    }
-  }
-
-  bool was_get_urls_called() const {
-    return was_get_urls_called_;
-  }
-
- private:
-  const std::list<GURL> urls_;
-  const bool run_immediately_;
-  bool was_get_urls_called_;
+  MOCK_CONST_METHOD2(TopHosts,
+                     void(int num_hosts, const TopHostsCallback& callback));
 };
 
+ACTION_P(ReturnHosts, starting_hosts) {
+  arg1.Run(starting_hosts);
+}
+
 class TestPrecacheCompletionCallback {
  public:
   TestPrecacheCompletionCallback() : was_on_done_called_(false) {}
@@ -168,39 +155,50 @@
 TEST_F(PrecacheManagerTest, StartAndFinishPrecaching) {
   EXPECT_FALSE(precache_manager_.IsPrecaching());
 
-  FakeURLListProvider url_list_provider(
-      std::list<GURL>(1, GURL("http://starting-url.com")), false);
+  MockHistoryService history_service;
+  MockHistoryService::TopHostsCallback top_hosts_callback;
+  EXPECT_CALL(history_service, TopHosts(NumTopHosts(), _))
+      .WillOnce(SaveArg<1>(&top_hosts_callback));
+
+  factory_.SetFakeResponse(GURL(kGoodManifestURL), "", net::HTTP_OK,
+                           net::URLRequestStatus::SUCCESS);
+
   precache_manager_.StartPrecaching(precache_callback_.GetCallback(),
-                                    &url_list_provider);
+                                    history_service);
 
   EXPECT_TRUE(precache_manager_.IsPrecaching());
 
-  base::MessageLoop::current()->RunUntilIdle();
+  top_hosts_callback.Run(
+      history::TopHostsList(1, std::make_pair("good-manifest.com", 1)));
+  base::MessageLoop::current()->RunUntilIdle();  // For PrecacheFetcher.
   EXPECT_FALSE(precache_manager_.IsPrecaching());
-  EXPECT_TRUE(url_list_provider.was_get_urls_called());
   EXPECT_TRUE(precache_callback_.was_on_done_called());
 
   std::multiset<GURL> expected_requested_urls;
   expected_requested_urls.insert(GURL(kConfigURL));
+  expected_requested_urls.insert(GURL(kGoodManifestURL));
   EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
 }
 
 TEST_F(PrecacheManagerTest, StartAndCancelPrecachingBeforeURLsReceived) {
   EXPECT_FALSE(precache_manager_.IsPrecaching());
 
-  FakeURLListProvider url_list_provider(
-      std::list<GURL>(1, GURL("http://starting-url.com")), false);
+  MockHistoryService history_service;
+  MockHistoryService::TopHostsCallback top_hosts_callback;
+  EXPECT_CALL(history_service, TopHosts(NumTopHosts(), _))
+      .WillOnce(SaveArg<1>(&top_hosts_callback));
 
   precache_manager_.StartPrecaching(precache_callback_.GetCallback(),
-                                    &url_list_provider);
+                                    history_service);
   EXPECT_TRUE(precache_manager_.IsPrecaching());
 
   precache_manager_.CancelPrecaching();
   EXPECT_FALSE(precache_manager_.IsPrecaching());
 
-  base::MessageLoop::current()->RunUntilIdle();
+  top_hosts_callback.Run(
+      history::TopHostsList(1, std::make_pair("starting-url.com", 1)));
+  base::MessageLoop::current()->RunUntilIdle();  // For PrecacheFetcher.
   EXPECT_FALSE(precache_manager_.IsPrecaching());
-  EXPECT_TRUE(url_list_provider.was_get_urls_called());
   EXPECT_FALSE(precache_callback_.was_on_done_called());
   EXPECT_TRUE(url_callback_.requested_urls().empty());
 }
@@ -208,13 +206,15 @@
 TEST_F(PrecacheManagerTest, StartAndCancelPrecachingAfterURLsReceived) {
   EXPECT_FALSE(precache_manager_.IsPrecaching());
 
-  FakeURLListProvider url_list_provider(
-      std::list<GURL>(1, GURL("http://starting-url.com")), true);
+  MockHistoryService history_service;
+  EXPECT_CALL(history_service, TopHosts(NumTopHosts(), _))
+      .WillOnce(ReturnHosts(
+          history::TopHostsList(1, std::make_pair("starting-url.com", 1))));
 
   precache_manager_.StartPrecaching(precache_callback_.GetCallback(),
-                                    &url_list_provider);
+                                    history_service);
 
-  // Since the |url_list_provider| ran the callback immediately, Start() has
+  // Since the |history_service| ran the callback immediately, Start() has
   // been called on the PrecacheFetcher, and the precache config settings have
   // been requested. The response has not yet been received though, so
   // precaching is still in progress.
@@ -223,9 +223,8 @@
   precache_manager_.CancelPrecaching();
   EXPECT_FALSE(precache_manager_.IsPrecaching());
 
-  base::MessageLoop::current()->RunUntilIdle();
+  base::MessageLoop::current()->RunUntilIdle();  // For PrecacheFetcher.
   EXPECT_FALSE(precache_manager_.IsPrecaching());
-  EXPECT_TRUE(url_list_provider.was_get_urls_called());
   EXPECT_FALSE(precache_callback_.was_on_done_called());
 
   // Even though the response for the precache config settings should not have
@@ -259,9 +258,12 @@
 TEST_F(PrecacheManagerTest, RecordStatsForFetchDuringPrecaching) {
   HistogramCountMap expected_histogram_count_map = GetHistogramCountMap();
 
-  FakeURLListProvider url_list_provider(std::list<GURL>(), false);
+  MockHistoryService history_service;
+  EXPECT_CALL(history_service, TopHosts(NumTopHosts(), _))
+      .WillOnce(ReturnHosts(history::TopHostsList()));
+
   precache_manager_.StartPrecaching(precache_callback_.GetCallback(),
-                                    &url_list_provider);
+                                    history_service);
 
   EXPECT_TRUE(precache_manager_.IsPrecaching());
   precache_manager_.RecordStatsForFetch(GURL("http://url.com"), base::Time(),
@@ -269,6 +271,7 @@
 
   precache_manager_.CancelPrecaching();
 
+  // For PrecacheFetcher and RecordURLPrecached.
   base::MessageLoop::current()->RunUntilIdle();
   expected_histogram_count_map["Precache.DownloadedPrecacheMotivated"]++;
   EXPECT_EQ(expected_histogram_count_map, GetHistogramCountMap());
@@ -301,9 +304,13 @@
   const base::Time kCurrentTime = base::Time::Now();
   HistogramCountMap expected_histogram_count_map = GetHistogramCountMap();
 
-  FakeURLListProvider url_list_provider(std::list<GURL>(), false);
+  MockHistoryService history_service;
+  EXPECT_CALL(history_service, TopHosts(NumTopHosts(), _))
+      .Times(2)
+      .WillRepeatedly(ReturnHosts(history::TopHostsList()));
+
   precache_manager_.StartPrecaching(precache_callback_.GetCallback(),
-                                    &url_list_provider);
+                                    history_service);
   EXPECT_TRUE(precache_manager_.IsPrecaching());
 
   // Precache a bunch of URLs, with different fetch times.
@@ -319,15 +326,17 @@
   expected_histogram_count_map["Precache.DownloadedPrecacheMotivated"] += 3;
 
   precache_manager_.CancelPrecaching();
+  // For PrecacheFetcher and RecordURLPrecached.
   base::MessageLoop::current()->RunUntilIdle();
   EXPECT_EQ(expected_histogram_count_map, GetHistogramCountMap());
 
   // The expired precache will be deleted during precaching this time.
   precache_manager_.StartPrecaching(precache_callback_.GetCallback(),
-                                    &url_list_provider);
+                                    history_service);
   EXPECT_TRUE(precache_manager_.IsPrecaching());
 
   precache_manager_.CancelPrecaching();
+  // For PrecacheFetcher and RecordURLPrecached.
   base::MessageLoop::current()->RunUntilIdle();
   EXPECT_FALSE(precache_manager_.IsPrecaching());
 
diff --git a/components/precache/core/BUILD.gn b/components/precache/core/BUILD.gn
index 29d6ed9..ca97225 100644
--- a/components/precache/core/BUILD.gn
+++ b/components/precache/core/BUILD.gn
@@ -4,10 +4,12 @@
 
 import("//third_party/protobuf/proto_library.gni")
 
+# These values are duplicated in the GYP build in:
+# //components/precache/precache_defines.gypi
 precache_config_settings_url =
     "http://www.gstatic.com/chrome/wifiprefetch/precache_config"
 precache_manifest_url_prefix =
-    "http://www.gstatic.com/chrome/wifiprefetch/precache_manifest_"
+    "http://www.gstatic.com/chrome/wifiprefetch/hosts/"
 
 config("precache_config") {
   defines = [
@@ -26,7 +28,6 @@
     "precache_switches.h",
     "precache_url_table.cc",
     "precache_url_table.h",
-    "url_list_provider.h",
   ]
 
   # Note the GYP build sets this as direct dependent settings, but this is
diff --git a/components/precache/core/precache_fetcher.cc b/components/precache/core/precache_fetcher.cc
index b6e75af..4563bd8 100644
--- a/components/precache/core/precache_fetcher.cc
+++ b/components/precache/core/precache_fetcher.cc
@@ -5,6 +5,7 @@
 #include "components/precache/core/precache_fetcher.h"
 
 #include <string>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -60,14 +61,13 @@
 #endif
 }
 
-// Construct the URL of the precache manifest for the given starting URL.
-// The server is expecting a request for a URL consisting of the manifest URL
-// prefix followed by the doubly escaped starting URL.
-GURL ConstructManifestURL(const GURL& starting_url) {
-  return GURL(
-      GetManifestURLPrefix() +
-      net::EscapeQueryParamValue(
-          net::EscapeQueryParamValue(starting_url.spec(), false), false));
+// Construct the URL of the precache manifest for the given name (either host or
+// URL). The server is expecting a request for a URL consisting of the manifest
+// URL prefix followed by the doubly escaped name.
+std::string ConstructManifestURL(const std::string& name) {
+  return GetManifestURLPrefix() +
+         net::EscapeQueryParamValue(net::EscapeQueryParamValue(name, false),
+                                    false);
 }
 
 // Attempts to parse a protobuf message from the response string of a
@@ -123,6 +123,8 @@
     : callback_(callback) {
   url_fetcher_ = URLFetcher::Create(url, URLFetcher::GET, this);
   url_fetcher_->SetRequestContext(request_context);
+  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
+                             net::LOAD_DO_NOT_SEND_COOKIES);
   url_fetcher_->Start();
 }
 
@@ -131,10 +133,10 @@
 }
 
 PrecacheFetcher::PrecacheFetcher(
-    const std::list<GURL>& starting_urls,
+    const std::vector<std::string>& starting_hosts,
     net::URLRequestContextGetter* request_context,
     PrecacheFetcher::PrecacheDelegate* precache_delegate)
-    : starting_urls_(starting_urls),
+    : starting_hosts_(starting_hosts),
       request_context_(request_context),
       precache_delegate_(precache_delegate) {
   DCHECK(request_context_.get());  // Request context must be non-NULL.
@@ -194,42 +196,32 @@
 }
 
 void PrecacheFetcher::OnConfigFetchComplete(const URLFetcher& source) {
+  // Attempt to parse the config proto. On failure, continue on with the default
+  // configuration.
   PrecacheConfigurationSettings config;
+  ParseProtoFromFetchResponse(source, &config);
 
-  if (ParseProtoFromFetchResponse(source, &config)) {
-    // Keep track of starting URLs that manifests are being fetched for, in
-    // order to remove duplicates. This is a hash set on strings, and not GURLs,
-    // because there is no hash function defined for GURL.
-    base::hash_set<std::string> unique_starting_urls;
+  // Keep track of manifest URLs that are being fetched, in order to remove
+  // duplicates.
+  base::hash_set<std::string> unique_manifest_urls;
 
-    // Attempt to fetch manifests for starting URLs up to the maximum top sites
-    // count. If a manifest does not exist for a particular starting URL, then
-    // the fetch will fail, and that starting URL will be ignored.
-    int64 rank = 0;
-    for (std::list<GURL>::const_iterator it = starting_urls_.begin();
-         it != starting_urls_.end() && rank < config.top_sites_count();
-         ++it, ++rank) {
-      if (unique_starting_urls.find(it->spec()) == unique_starting_urls.end()) {
-        // Only add a fetch for the manifest URL if this manifest isn't already
-        // going to be fetched.
-        manifest_urls_to_fetch_.push_back(ConstructManifestURL(*it));
-        unique_starting_urls.insert(it->spec());
-      }
-    }
-
-    for (int i = 0; i < config.forced_starting_url_size(); ++i) {
-      // Convert the string URL into a GURL and take the spec() of it so that
-      // the URL string gets canonicalized.
-      GURL url(config.forced_starting_url(i));
-      if (unique_starting_urls.find(url.spec()) == unique_starting_urls.end()) {
-        // Only add a fetch for the manifest URL if this manifest isn't already
-        // going to be fetched.
-        manifest_urls_to_fetch_.push_back(ConstructManifestURL(url));
-        unique_starting_urls.insert(url.spec());
-      }
-    }
+  // Attempt to fetch manifests for starting hosts up to the maximum top sites
+  // count. If a manifest does not exist for a particular starting host, then
+  // the fetch will fail, and that starting host will be ignored.
+  int64 rank = 0;
+  for (const std::string& host : starting_hosts_) {
+    ++rank;
+    if (rank > config.top_sites_count())
+      break;
+    unique_manifest_urls.insert(ConstructManifestURL(host));
   }
 
+  for (const std::string& url : config.forced_site())
+    unique_manifest_urls.insert(ConstructManifestURL(url));
+
+  for (const std::string& manifest_url : unique_manifest_urls)
+    manifest_urls_to_fetch_.push_back(GURL(manifest_url));
+
   StartNextFetch();
 }
 
diff --git a/components/precache/core/precache_fetcher.h b/components/precache/core/precache_fetcher.h
index 1fc56d7..f860972 100644
--- a/components/precache/core/precache_fetcher.h
+++ b/components/precache/core/precache_fetcher.h
@@ -6,6 +6,8 @@
 #define COMPONENTS_PRECACHE_CORE_PRECACHE_FETCHER_H_
 
 #include <list>
+#include <string>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
@@ -24,10 +26,10 @@
 // Precaching is intended to be done when Chrome is not actively in use, likely
 // hours ahead of the time when the resources are actually needed.
 //
-// This class takes as input a prioritized list of page URLs that the user
-// commonly visits, referred to as starting URLs. This class interacts with a
-// server, sending it the list of starting URLs sequentially. For each starting
-// URL, the server returns a manifest of resource URLs that are good candidates
+// This class takes as input a prioritized list of URL domains that the user
+// commonly visits, referred to as starting hosts. This class interacts with a
+// server, sending it the list of starting hosts sequentially. For each starting
+// host, the server returns a manifest of resource URLs that are good candidates
 // for precaching. Every resource returned is fetched, and responses are cached
 // as they are received. Destroying the PrecacheFetcher while it is precaching
 // will cancel any fetch in progress and cancel precaching.
@@ -66,11 +68,11 @@
     virtual void OnDone() = 0;
   };
 
-  // Constructs a new PrecacheFetcher. The |starting_urls| parameter is a
-  // prioritized list of page URLs that the user commonly visits. These URLs are
+  // Constructs a new PrecacheFetcher. The |starting_hosts| parameter is a
+  // prioritized list of hosts that the user commonly visits. These hosts are
   // used by a server side component to construct a list of resource URLs that
   // the user is likely to fetch.
-  PrecacheFetcher(const std::list<GURL>& starting_urls,
+  PrecacheFetcher(const std::vector<std::string>& starting_hosts,
                   net::URLRequestContextGetter* request_context,
                   PrecacheDelegate* precache_delegate);
 
@@ -92,7 +94,7 @@
 
   // Called when the precache configuration settings have been fetched.
   // Determines the list of manifest URLs to fetch according to the list of
-  // |starting_urls_| and information from the precache configuration settings.
+  // |starting_hosts_| and information from the precache configuration settings.
   // If the fetch of the configuration settings fails, then precaching ends.
   void OnConfigFetchComplete(const net::URLFetcher& source);
 
@@ -104,9 +106,9 @@
   // Called when a resource has been fetched.
   void OnResourceFetchComplete(const net::URLFetcher& source);
 
-  // The prioritized list of starting URLs that the server will pick resource
+  // The prioritized list of starting hosts that the server will pick resource
   // URLs to be precached for.
-  const std::list<GURL> starting_urls_;
+  const std::vector<std::string> starting_hosts_;
 
   // The request context used when fetching URLs.
   scoped_refptr<net::URLRequestContextGetter> request_context_;
diff --git a/components/precache/core/precache_fetcher_unittest.cc b/components/precache/core/precache_fetcher_unittest.cc
index b909ed1..4fc2764 100644
--- a/components/precache/core/precache_fetcher_unittest.cc
+++ b/components/precache/core/precache_fetcher_unittest.cc
@@ -4,9 +4,9 @@
 
 #include "components/precache/core/precache_fetcher.h"
 
-#include <list>
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/bind.h"
@@ -90,17 +90,15 @@
 const char kConfigURL[] = "http://config-url.com";
 const char kManfiestURLPrefix[] = "http://manifest-url-prefix.com/";
 const char kManifestFetchFailureURL[] =
-    "http://manifest-url-prefix.com/"
-    "http%253A%252F%252Fmanifest-fetch-failure.com%252F";
+    "http://manifest-url-prefix.com/manifest-fetch-failure.com";
 const char kBadManifestURL[] =
-    "http://manifest-url-prefix.com/http%253A%252F%252Fbad-manifest.com%252F";
+    "http://manifest-url-prefix.com/bad-manifest.com";
 const char kGoodManifestURL[] =
-    "http://manifest-url-prefix.com/http%253A%252F%252Fgood-manifest.com%252F";
+    "http://manifest-url-prefix.com/good-manifest.com";
 const char kResourceFetchFailureURL[] = "http://resource-fetch-failure.com";
 const char kGoodResourceURL[] = "http://good-resource.com";
 const char kForcedStartingURLManifestURL[] =
-    "http://manifest-url-prefix.com/"
-    "http%253A%252F%252Fforced-starting-url.com%252F";
+    "http://manifest-url-prefix.com/forced-starting-url.com";
 
 TEST_F(PrecacheFetcherTest, FullPrecache) {
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
@@ -108,17 +106,17 @@
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kPrecacheManifestURLPrefix, kManfiestURLPrefix);
 
-  std::list<GURL> starting_urls;
-  starting_urls.push_back(GURL("http://manifest-fetch-failure.com"));
-  starting_urls.push_back(GURL("http://bad-manifest.com"));
-  starting_urls.push_back(GURL("http://good-manifest.com"));
-  starting_urls.push_back(GURL("http://not-in-top-3.com"));
+  std::vector<std::string> starting_hosts;
+  starting_hosts.push_back("manifest-fetch-failure.com");
+  starting_hosts.push_back("bad-manifest.com");
+  starting_hosts.push_back("good-manifest.com");
+  starting_hosts.push_back("not-in-top-3.com");
 
   PrecacheConfigurationSettings config;
   config.set_top_sites_count(3);
-  config.add_forced_starting_url("http://forced-starting-url.com");
+  config.add_forced_site("forced-starting-url.com");
   // Duplicate starting URL, the manifest for this should only be fetched once.
-  config.add_forced_starting_url("http://good-manifest.com");
+  config.add_forced_site("good-manifest.com");
 
   PrecacheManifest good_manifest;
   good_manifest.add_resource()->set_url(kResourceFetchFailureURL);
@@ -144,7 +142,7 @@
                            PrecacheManifest().SerializeAsString(), net::HTTP_OK,
                            net::URLRequestStatus::SUCCESS);
 
-  PrecacheFetcher precache_fetcher(starting_urls, request_context_.get(),
+  PrecacheFetcher precache_fetcher(starting_hosts, request_context_.get(),
                                    &precache_delegate_);
   precache_fetcher.Start();
 
@@ -167,14 +165,18 @@
 TEST_F(PrecacheFetcherTest, ConfigFetchFailure) {
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kPrecacheConfigSettingsURL, kConfigURL);
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kPrecacheManifestURLPrefix, kManfiestURLPrefix);
 
-  std::list<GURL> starting_urls(1, GURL("http://starting-url.com"));
+  std::vector<std::string> starting_hosts(1, "good-manifest.com");
 
   factory_.SetFakeResponse(GURL(kConfigURL), "",
                            net::HTTP_INTERNAL_SERVER_ERROR,
                            net::URLRequestStatus::FAILED);
+  factory_.SetFakeResponse(GURL(kGoodManifestURL), "", net::HTTP_OK,
+                           net::URLRequestStatus::SUCCESS);
 
-  PrecacheFetcher precache_fetcher(starting_urls, request_context_.get(),
+  PrecacheFetcher precache_fetcher(starting_hosts, request_context_.get(),
                                    &precache_delegate_);
   precache_fetcher.Start();
 
@@ -182,6 +184,7 @@
 
   std::multiset<GURL> expected_requested_urls;
   expected_requested_urls.insert(GURL(kConfigURL));
+  expected_requested_urls.insert(GURL(kGoodManifestURL));
   EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
 
   EXPECT_TRUE(precache_delegate_.was_on_done_called());
@@ -190,13 +193,17 @@
 TEST_F(PrecacheFetcherTest, BadConfig) {
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kPrecacheConfigSettingsURL, kConfigURL);
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      switches::kPrecacheManifestURLPrefix, kManfiestURLPrefix);
 
-  std::list<GURL> starting_urls(1, GURL("http://starting-url.com"));
+  std::vector<std::string> starting_hosts(1, "good-manifest.com");
 
   factory_.SetFakeResponse(GURL(kConfigURL), "bad protobuf", net::HTTP_OK,
                            net::URLRequestStatus::SUCCESS);
+  factory_.SetFakeResponse(GURL(kGoodManifestURL), "", net::HTTP_OK,
+                           net::URLRequestStatus::SUCCESS);
 
-  PrecacheFetcher precache_fetcher(starting_urls, request_context_.get(),
+  PrecacheFetcher precache_fetcher(starting_hosts, request_context_.get(),
                                    &precache_delegate_);
   precache_fetcher.Start();
 
@@ -204,6 +211,7 @@
 
   std::multiset<GURL> expected_requested_urls;
   expected_requested_urls.insert(GURL(kConfigURL));
+  expected_requested_urls.insert(GURL(kGoodManifestURL));
   EXPECT_EQ(expected_requested_urls, url_callback_.requested_urls());
 
   EXPECT_TRUE(precache_delegate_.was_on_done_called());
@@ -213,7 +221,7 @@
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kPrecacheConfigSettingsURL, kConfigURL);
 
-  std::list<GURL> starting_urls(1, GURL("http://starting-url.com"));
+  std::vector<std::string> starting_hosts(1, "starting-url.com");
 
   PrecacheConfigurationSettings config;
   config.set_top_sites_count(1);
@@ -222,7 +230,7 @@
                            net::HTTP_OK, net::URLRequestStatus::SUCCESS);
 
   scoped_ptr<PrecacheFetcher> precache_fetcher(new PrecacheFetcher(
-      starting_urls, request_context_.get(), &precache_delegate_));
+      starting_hosts, request_context_.get(), &precache_delegate_));
   precache_fetcher->Start();
 
   // Destroy the PrecacheFetcher to cancel precaching. This should not cause
@@ -243,7 +251,7 @@
 // If the default precache configuration settings URL is defined, then test that
 // it works with the PrecacheFetcher.
 TEST_F(PrecacheFetcherTest, PrecacheUsingDefaultConfigSettingsURL) {
-  std::list<GURL> starting_urls(1, GURL("http://starting-url.com"));
+  std::vector<std::string> starting_hosts(1, "starting-url.com");
 
   PrecacheConfigurationSettings config;
   config.set_top_sites_count(0);
@@ -252,7 +260,7 @@
                            config.SerializeAsString(), net::HTTP_OK,
                            net::URLRequestStatus::SUCCESS);
 
-  PrecacheFetcher precache_fetcher(starting_urls, request_context_.get(),
+  PrecacheFetcher precache_fetcher(starting_hosts, request_context_.get(),
                                    &precache_delegate_);
   precache_fetcher.Start();
 
@@ -275,20 +283,19 @@
   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
       switches::kPrecacheConfigSettingsURL, kConfigURL);
 
-  std::list<GURL> starting_urls(1, GURL("http://starting-url.com"));
+  std::vector<std::string> starting_hosts(1, "starting-url.com");
 
   PrecacheConfigurationSettings config;
   config.set_top_sites_count(1);
 
-  GURL manifest_url(PRECACHE_MANIFEST_URL_PREFIX
-                    "http%253A%252F%252Fstarting-url.com%252F");
+  GURL manifest_url(PRECACHE_MANIFEST_URL_PREFIX "starting-url.com");
 
   factory_.SetFakeResponse(GURL(kConfigURL), config.SerializeAsString(),
                            net::HTTP_OK, net::URLRequestStatus::SUCCESS);
   factory_.SetFakeResponse(manifest_url, PrecacheManifest().SerializeAsString(),
                            net::HTTP_OK, net::URLRequestStatus::SUCCESS);
 
-  PrecacheFetcher precache_fetcher(starting_urls, request_context_.get(),
+  PrecacheFetcher precache_fetcher(starting_hosts, request_context_.get(),
                                    &precache_delegate_);
   precache_fetcher.Start();
 
diff --git a/components/precache/core/proto/precache.proto b/components/precache/core/proto/precache.proto
index ace5384..5cdfbad 100644
--- a/components/precache/core/proto/precache.proto
+++ b/components/precache/core/proto/precache.proto
@@ -15,27 +15,26 @@
   optional string url = 1;
 };
 
-// A manifest of cacheable resources to be precached for a specific starting
-// URL.
+// A manifest of cacheable resources to be precached for a specific host.
 message PrecacheManifest {
   // List of resources that we predict that the user will need if they are
-  // likely to fetch the starting URL.
+  // likely to fetch the host.
   repeated PrecacheResource resource = 1;
 };
 
 message PrecacheConfigurationSettings {
-  // The maximum rank of the user's most visited URLs to consider precaching
+  // The maximum rank of the user's most visited hosts to consider precaching
   // resources for, starting from 1. For example, a value of 10 means that only
-  // URLs that are in the user's top 10 most visited URLs will be considered as
-  // starting URLs for resource precaching. This is specified by the server for
-  // testing purposes, so that it's easy to adjust how aggressively resources
-  // are precached.
+  // hosts that are in the user's top 10 most visited hosts will be considered
+  // as starting URLs for resource precaching. This is specified by the server
+  // for testing purposes, so that it's easy to adjust how aggressively
+  // resources are precached.
   // Values that are zero or lower indicate that none of the user's top sites
   // will be used for precaching.
-  optional int64 top_sites_count = 1 [default = 10];
+  optional int64 top_sites_count = 1 [default = 100];
 
-  // List of additional starting URLs that resources will be precached for.
-  // These are URLs that the server predicts that the user will visit, as a
+  // List of additional hosts that resources will be precached for.
+  // These are hosts that the server predicts that the user will visit, as a
   // result of server-side analytics.
-  repeated string forced_starting_url = 2;
+  repeated string forced_site = 2;
 };
diff --git a/components/precache/core/url_list_provider.h b/components/precache/core/url_list_provider.h
deleted file mode 100644
index 5b879b74..0000000
--- a/components/precache/core/url_list_provider.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PRECACHE_CORE_URL_LIST_PROVIDER_H_
-#define COMPONENTS_PRECACHE_CORE_URL_LIST_PROVIDER_H_
-
-#include <list>
-
-#include "base/callback.h"
-#include "url/gurl.h"
-
-namespace precache {
-
-// Interface for classes that can provide a list of URLs.
-class URLListProvider {
- public:
-  typedef base::Callback<void(const std::list<GURL>&)> GetURLsCallback;
-
-  // Runs |callback| with a list of URLs. |callback| may be run before the call
-  // to GetURLs returns. |callback| will be run on the same thread that this
-  // method was called on.
-  virtual void GetURLs(const GetURLsCallback& callback) = 0;
-};
-
-}  // namespace precache
-
-#endif  // COMPONENTS_PRECACHE_CORE_URL_LIST_PROVIDER_H_
diff --git a/components/precache/precache_defines.gypi b/components/precache/precache_defines.gypi
index 82f611e..a7868e7 100644
--- a/components/precache/precache_defines.gypi
+++ b/components/precache/precache_defines.gypi
@@ -7,7 +7,7 @@
     # These values are duplicated in the GN build in:
     # //components/precache/core:precache_config
     'precache_config_settings_url%': 'https://www.gstatic.com/chrome/wifiprefetch/precache_config',
-    'precache_manifest_url_prefix%': 'https://www.gstatic.com/chrome/wifiprefetch/precache_manifest_',
+    'precache_manifest_url_prefix%': 'https://www.gstatic.com/chrome/wifiprefetch/hosts/',
   },
   'conditions': [
     ['precache_config_settings_url != ""', {
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc
index 313d12d..0b00713 100644
--- a/components/printing/renderer/print_web_view_helper.cc
+++ b/components/printing/renderer/print_web_view_helper.cc
@@ -327,6 +327,12 @@
     return false;
 
   int dpi = GetDPI(&params);
+  if (!dpi) {
+    // Likely |params| is invalid, in which case the return result does not
+    // matter. Check for this so ConvertUnit() does not divide by zero.
+    return true;
+  }
+
   blink::WebSize page_size(
       ConvertUnit(params.page_size.width(), dpi, kPointsPerInch),
       ConvertUnit(params.page_size.height(), dpi, kPointsPerInch));
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection.cc
index d5d7860..17f46c44 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection.cc
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection.cc
@@ -29,7 +29,14 @@
 
 namespace proximity_auth {
 namespace {
+
+// Deprecated signal send as the first byte in send byte operations.
 const int kFirstByteZero = 0;
+
+// The maximum number of bytes written in a remote characteristic with a single
+// request.
+const int kMaxChunkSize = 100;
+
 }  // namespace
 
 BluetoothLowEnergyConnection::BluetoothLowEnergyConnection(
@@ -50,6 +57,7 @@
       receiving_bytes_(false),
       write_remote_characteristic_pending_(false),
       max_number_of_write_attempts_(max_number_of_write_attempts),
+      max_chunk_size_(kMaxChunkSize),
       weak_ptr_factory_(this) {
   DCHECK(adapter_);
   DCHECK(adapter_->IsInitialized());
@@ -115,8 +123,6 @@
   }
 }
 
-// TODO(sacomoto): Implement a sender with full support for messages larger than
-// a single characteristic value.
 void BluetoothLowEnergyConnection::SendMessageImpl(
     scoped_ptr<WireMessage> message) {
   VLOG(1) << "Sending message " << message->Serialize();
@@ -128,10 +134,27 @@
       ToByteVector(static_cast<uint32>(serialized_msg.size())), false);
   WriteRemoteCharacteristic(write_request);
 
-  write_request = BuildWriteRequest(
-      std::vector<uint8>{static_cast<uint8>(kFirstByteZero)},
-      std::vector<uint8>(serialized_msg.begin(), serialized_msg.end()), true);
-  WriteRemoteCharacteristic(write_request);
+  // Each chunk has to include a deprecated signal: |kFirstByteZero| as the
+  // first byte.
+  int chunk_size = max_chunk_size_ - 1;
+  std::vector<uint8> kFirstByteZeroVector;
+  kFirstByteZeroVector.push_back(static_cast<uint8>(kFirstByteZero));
+
+  int message_size = static_cast<int>(serialized_msg.size());
+  int start_index = 0;
+  while (start_index < message_size) {
+    int end_index = (start_index + chunk_size) <= message_size
+                        ? (start_index + chunk_size)
+                        : message_size;
+    bool is_last_write_request = (end_index == message_size);
+    write_request = BuildWriteRequest(
+        kFirstByteZeroVector,
+        std::vector<uint8>(serialized_msg.begin() + start_index,
+                           serialized_msg.begin() + end_index),
+        is_last_write_request);
+    WriteRemoteCharacteristic(write_request);
+    start_index = end_index;
+  }
 }
 
 void BluetoothLowEnergyConnection::DeviceRemoved(BluetoothAdapter* adapter,
@@ -142,8 +165,6 @@
   }
 }
 
-// TODO(sacomoto): Implement a receiver with full support for messages larger
-// than a single characteristic value.
 void BluetoothLowEnergyConnection::GattCharacteristicValueChanged(
     BluetoothAdapter* adapter,
     BluetoothGattCharacteristic* characteristic,
@@ -157,8 +178,11 @@
     if (receiving_bytes_) {
       // Ignoring the first byte, as it contains a deprecated signal.
       const std::string bytes(value.begin() + 1, value.end());
-      OnBytesReceived(bytes);
-      receiving_bytes_ = false;
+      incoming_bytes_buffer_.append(bytes);
+      if (incoming_bytes_buffer_.size() >= expected_number_of_incoming_bytes_) {
+        OnBytesReceived(incoming_bytes_buffer_);
+        receiving_bytes_ = false;
+      }
       return;
     }
 
@@ -175,9 +199,19 @@
         break;
       case ControlSignal::kInviteToConnectSignal:
         break;
-      case ControlSignal::kSendSignal:
+      case ControlSignal::kSendSignal: {
+        if (value.size() < 8) {
+          VLOG(1)
+              << "Incoming data corrupted, expected message size not found.";
+          return;
+        }
+        std::vector<uint8> size(value.begin() + 4, value.end());
+        expected_number_of_incoming_bytes_ =
+            static_cast<size_t>(ToUint32(size));
         receiving_bytes_ = true;
+        incoming_bytes_buffer_.clear();
         break;
+      }
       case ControlSignal::kDisconnectSignal:
         Disconnect();
         break;
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection.h b/components/proximity_auth/ble/bluetooth_low_energy_connection.h
index 41ff414..decb203 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection.h
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_LOW_ENERGY_CONNECTION_H
 
 #include <queue>
+#include <string>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -262,6 +263,12 @@
   // ControlSignal::kSendSignal was received from the remote device.
   bool receiving_bytes_;
 
+  // Total number of bytes expected for the current receive operation.
+  std::size_t expected_number_of_incoming_bytes_;
+
+  // Bytes already received for the current receive operation.
+  std::string incoming_bytes_buffer_;
+
   // Indicates there is a BluetoothGattCharacteristic::WriteRemoteCharacteristic
   // operation pending.
   bool write_remote_characteristic_pending_;
@@ -271,6 +278,13 @@
   // Maximum number of tries to send any write request.
   int max_number_of_write_attempts_;
 
+  // Maximum number of bytes that fit in a single chunk to be written in
+  // |to_peripheral_char_|. Ideally, this should be the maximum value the
+  // peripheral supports and it should be agreed when the GATT connection is
+  // created. Currently, there is no API to find this value. The implementation
+  // uses a hard-coded constant.
+  int max_chunk_size_;
+
   // Stores when the instace was created.
   base::TimeTicks start_time_;
 
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
index b989a35..8c8c1bf 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
@@ -89,6 +89,7 @@
 
   MOCK_METHOD2(OnDidSendMessage,
                void(const WireMessage& message, bool success));
+  MOCK_METHOD1(OnBytesReceived, void(const std::string& bytes));
 
   // Exposing inherited protected methods for testing.
   using BluetoothLowEnergyConnection::GattCharacteristicValueChanged;
@@ -267,9 +268,7 @@
               kInviteToConnectSignal);
 
     EXPECT_CALL(*connection, OnDidSendMessage(_, _)).Times(0);
-    EXPECT_FALSE(write_remote_characteristic_error_callback_.is_null());
-    ASSERT_FALSE(write_remote_characteristic_success_callback_.is_null());
-    write_remote_characteristic_success_callback_.Run();
+    RunWriteCharacteristicSuccessCallback();
 
     // Received the
     // BluetoothLowEneryConnection::ControlSignal::kInvitationResponseSignal.
@@ -298,6 +297,27 @@
     EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
   }
 
+  void InitializeConnection(MockBluetoothLowEnergyConnection* connection) {
+    ConnectWithExistingGattConnection(connection);
+    CharacteristicsFound(connection);
+    NotifySessionStarted(connection);
+    ResponseSignalReceived(connection);
+  }
+
+  void RunWriteCharacteristicSuccessCallback() {
+    EXPECT_FALSE(write_remote_characteristic_error_callback_.is_null());
+    ASSERT_FALSE(write_remote_characteristic_success_callback_.is_null());
+    write_remote_characteristic_success_callback_.Run();
+  }
+
+  std::vector<uint8> CreateSendSignalWithSize(int message_size) {
+    std::vector<uint8> value = ToByteVector(static_cast<uint32>(
+        BluetoothLowEnergyConnection::ControlSignal::kSendSignal));
+    std::vector<uint8> size = ToByteVector(static_cast<uint32>(message_size));
+    value.insert(value.end(), size.begin(), size.end());
+    return value;
+  }
+
   std::vector<uint8> ToByteVector(uint32 value) {
     std::vector<uint8> bytes(4, 0);
     bytes[0] = static_cast<uint8>(value);
@@ -377,10 +397,7 @@
 TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
        Connect_Success_Disconnect) {
   scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
-  ConnectWithExistingGattConnection(connection.get());
-  CharacteristicsFound(connection.get());
-  NotifySessionStarted(connection.get());
-  ResponseSignalReceived(connection.get());
+  InitializeConnection(connection.get());
   Disconnect(connection.get());
 }
 
@@ -507,4 +524,171 @@
   EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
 }
 
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Receive_MessageSmallerThanCharacteristicSize) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  InitializeConnection(connection.get());
+
+  std::string received_bytes;
+  EXPECT_CALL(*connection, OnBytesReceived(_))
+      .WillOnce(SaveArg<0>(&received_bytes));
+
+  // Message (bytes) that is going to be received.
+  int message_size = 75;
+  std::string message(message_size, 'A');
+
+  // Sending the |kSendSignal| + |message_size|.
+  connection->GattCharacteristicValueChanged(
+      adapter_.get(), from_peripheral_char_.get(),
+      CreateSendSignalWithSize(message_size));
+
+  // Sending the message.
+  std::vector<uint8> value;
+  value.push_back(0);
+  value.insert(value.end(), message.begin(), message.end());
+  connection->GattCharacteristicValueChanged(
+      adapter_.get(), from_peripheral_char_.get(), value);
+
+  EXPECT_EQ(received_bytes, message);
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Receive_MessageLargerThanCharacteristicSize) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  InitializeConnection(connection.get());
+
+  std::string received_bytes;
+  int chunk_size = 100;
+  EXPECT_CALL(*connection, OnBytesReceived(_))
+      .WillOnce(SaveArg<0>(&received_bytes));
+
+  // Message (bytes) that is going to be received.
+  int message_size = 150;
+  std::string message(message_size, 'A');
+
+  // Sending the |kSendSignal| + |message_size|.
+  connection->GattCharacteristicValueChanged(
+      adapter_.get(), from_peripheral_char_.get(),
+      CreateSendSignalWithSize(message_size));
+
+  // Sending the first chunk.
+  std::vector<uint8> value;
+  value.push_back(0);
+  value.insert(value.end(), message.begin(), message.begin() + chunk_size);
+  connection->GattCharacteristicValueChanged(
+      adapter_.get(), from_peripheral_char_.get(), value);
+
+  // Sending the second chunk.
+  value.clear();
+  value.push_back(0);
+  value.insert(value.end(), message.begin() + chunk_size, message.end());
+  connection->GattCharacteristicValueChanged(
+      adapter_.get(), from_peripheral_char_.get(), value);
+
+  EXPECT_EQ(received_bytes, message);
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       SendMessage_SmallerThanCharacteristicSize) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  InitializeConnection(connection.get());
+
+  // Expecting a first call of WriteRemoteCharacteristic, after SendMessage is
+  // called.
+  EXPECT_CALL(*to_peripheral_char_, WriteRemoteCharacteristic(_, _, _))
+      .WillOnce(
+          DoAll(SaveArg<0>(&last_value_written_on_to_peripheral_char_),
+                SaveArg<1>(&write_remote_characteristic_success_callback_),
+                SaveArg<2>(&write_remote_characteristic_error_callback_)));
+
+  // Message (bytes) that is going to be sent.
+  int message_size = 75;
+  std::string message(message_size, 'A');
+  message[0] = 'B';
+  connection->SendMessage(make_scoped_ptr(new FakeWireMessage(message)));
+
+  // Expecting that |kSendSignal| + |message_size| was written.
+  EXPECT_EQ(last_value_written_on_to_peripheral_char_,
+            CreateSendSignalWithSize(message_size));
+
+  // Expecting a second call of WriteRemoteCharacteristic, after success
+  // callback is called.
+  EXPECT_CALL(*to_peripheral_char_, WriteRemoteCharacteristic(_, _, _))
+      .WillOnce(
+          DoAll(SaveArg<0>(&last_value_written_on_to_peripheral_char_),
+                SaveArg<1>(&write_remote_characteristic_success_callback_),
+                SaveArg<2>(&write_remote_characteristic_error_callback_)));
+
+  RunWriteCharacteristicSuccessCallback();
+
+  // Expecting that the message was written.
+  std::vector<uint8> expected_value(message.begin(), message.end());
+  std::vector<uint8> written_value(
+      last_value_written_on_to_peripheral_char_.begin() + 1,
+      last_value_written_on_to_peripheral_char_.end());
+  EXPECT_EQ(expected_value, written_value);
+  EXPECT_EQ(expected_value.size(), written_value.size());
+
+  EXPECT_CALL(*connection, OnDidSendMessage(_, _));
+  RunWriteCharacteristicSuccessCallback();
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       SendMessage_LagerThanCharacteristicSize) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  InitializeConnection(connection.get());
+
+  // Expecting a first call of WriteRemoteCharacteristic, after SendMessage is
+  // called.
+  EXPECT_CALL(*to_peripheral_char_, WriteRemoteCharacteristic(_, _, _))
+      .WillOnce(
+          DoAll(SaveArg<0>(&last_value_written_on_to_peripheral_char_),
+                SaveArg<1>(&write_remote_characteristic_success_callback_),
+                SaveArg<2>(&write_remote_characteristic_error_callback_)));
+
+  // Message (bytes) that is going to be sent.
+  int message_size = 150;
+  std::string message(message_size, 'A');
+  message[0] = 'B';
+  connection->SendMessage(make_scoped_ptr(new FakeWireMessage(message)));
+
+  // Expecting that |kSendSignal| + |message_size| was written.
+  EXPECT_EQ(last_value_written_on_to_peripheral_char_,
+            CreateSendSignalWithSize(message_size));
+
+  // Expecting a second call of WriteRemoteCharacteristic, after success
+  // callback is called.
+  EXPECT_CALL(*to_peripheral_char_, WriteRemoteCharacteristic(_, _, _))
+      .WillOnce(
+          DoAll(SaveArg<0>(&last_value_written_on_to_peripheral_char_),
+                SaveArg<1>(&write_remote_characteristic_success_callback_),
+                SaveArg<2>(&write_remote_characteristic_error_callback_)));
+
+  RunWriteCharacteristicSuccessCallback();
+  std::vector<uint8> bytes_received(
+      last_value_written_on_to_peripheral_char_.begin() + 1,
+      last_value_written_on_to_peripheral_char_.end());
+
+  // Expecting a third call of WriteRemoteCharacteristic, after success callback
+  // is called.
+  EXPECT_CALL(*to_peripheral_char_, WriteRemoteCharacteristic(_, _, _))
+      .WillOnce(
+          DoAll(SaveArg<0>(&last_value_written_on_to_peripheral_char_),
+                SaveArg<1>(&write_remote_characteristic_success_callback_),
+                SaveArg<2>(&write_remote_characteristic_error_callback_)));
+
+  RunWriteCharacteristicSuccessCallback();
+  bytes_received.insert(bytes_received.end(),
+                        last_value_written_on_to_peripheral_char_.begin() + 1,
+                        last_value_written_on_to_peripheral_char_.end());
+
+  // Expecting that the message was written.
+  std::vector<uint8> expected_value(message.begin(), message.end());
+  EXPECT_EQ(expected_value.size(), bytes_received.size());
+  EXPECT_EQ(expected_value, bytes_received);
+
+  EXPECT_CALL(*connection, OnDidSendMessage(_, _));
+  RunWriteCharacteristicSuccessCallback();
+}
+
 }  // namespace proximity_auth
diff --git a/components/proximity_auth/cryptauth/base64url.cc b/components/proximity_auth/cryptauth/base64url.cc
index a38043f..d32f188 100644
--- a/components/proximity_auth/cryptauth/base64url.cc
+++ b/components/proximity_auth/cryptauth/base64url.cc
@@ -18,6 +18,12 @@
 
 bool Base64UrlDecode(const std::string& encoded_input,
                      std::string* decoded_output) {
+  // Bail on malformed strings, which already contain a '+' or a '/'. All valid
+  // strings should escape these special characters as '-' and '_',
+  // respectively.
+  if (encoded_input.find_first_of("+/") != std::string::npos)
+    return false;
+
   std::string adjusted_encoded_input = encoded_input;
   base::ReplaceChars(adjusted_encoded_input, "-", "+", &adjusted_encoded_input);
   base::ReplaceChars(adjusted_encoded_input, "_", "/", &adjusted_encoded_input);
diff --git a/components/proximity_auth/cryptauth/base64url_unittest.cc b/components/proximity_auth/cryptauth/base64url_unittest.cc
index 88fd16c..487ea444 100644
--- a/components/proximity_auth/cryptauth/base64url_unittest.cc
+++ b/components/proximity_auth/cryptauth/base64url_unittest.cc
@@ -64,4 +64,22 @@
   EXPECT_EQ("/+Y=", non_web_safe_encoded);
 }
 
+TEST(ProximityAuthBase64UrlTest, DecodeBailsOnPlus) {
+  // Note that "_-Y=" is a valid encoded string, as tested above. This test
+  // simply verifies that an otherwise correctly encoded string cannot use '+'
+  // in place of '-', since the proximity auth code expects websafe encodings.
+  const std::string encoded = "_+Y=";
+  std::string decoded;
+  EXPECT_FALSE(Base64UrlDecode(encoded, &decoded));
+}
+
+TEST(ProximityAuthBase64UrlTest, DecodeBailsOnSlash) {
+  // Note that "_-Y=" is a valid encoded string, as tested above. This test
+  // simply verifies that an otherwise correctly encoded string cannot use '/'
+  // in place of '_', since the proximity auth code expects websafe encodings.
+  const std::string encoded = "/-Y=";
+  std::string decoded;
+  EXPECT_FALSE(Base64UrlDecode(encoded, &decoded));
+}
+
 }  // namespace proximity_auth
diff --git a/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc b/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc
index 5fa5c5f..d05361c2 100644
--- a/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc
+++ b/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc
@@ -76,7 +76,7 @@
     signing_key = key;
   } else {
     std::string prefix = kPrivateKeyPrefix;
-    bool is_private_key = StartsWithASCII(key, prefix, true);
+    bool is_private_key = base::StartsWithASCII(key, prefix, true);
     signing_key = is_private_key ? key.substr(prefix.size()) : prefix + key;
   }
 
@@ -113,7 +113,7 @@
   // private key so it is equal to its corresponding public key.
   std::string prefix(kPrivateKeyPrefix);
   std::string normalized_private_key =
-      StartsWithASCII(private_key, prefix, true)
+      base::StartsWithASCII(private_key, prefix, true)
           ? private_key.substr(prefix.size())
           : private_key;
 
diff --git a/components/resource_provider/BUILD.gn b/components/resource_provider/BUILD.gn
index 48a0749..aea501a 100644
--- a/components/resource_provider/BUILD.gn
+++ b/components/resource_provider/BUILD.gn
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 import("//mojo/mojo_application_package.gni")
+import("//mojo/public/mojo_application.gni")
 import("//testing/test.gni")
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
 
 if (is_android) {
   import("//build/config/android/rules.gni")
diff --git a/components/resource_provider/public/cpp/BUILD.gn b/components/resource_provider/public/cpp/BUILD.gn
index c89c982..ad13d1f 100644
--- a/components/resource_provider/public/cpp/BUILD.gn
+++ b/components/resource_provider/public/cpp/BUILD.gn
@@ -2,9 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
-import("//third_party/mojo/src/mojo/public/mojo_sdk.gni")
-
 source_set("cpp") {
   sources = [
     "resource_loader.cc",
diff --git a/components/resource_provider/public/interfaces/BUILD.gn b/components/resource_provider/public/interfaces/BUILD.gn
index d3cb620..d99f3c2 100644
--- a/components/resource_provider/public/interfaces/BUILD.gn
+++ b/components/resource_provider/public/interfaces/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
diff --git a/components/resources/dom_distiller_resources.grdp b/components/resources/dom_distiller_resources.grdp
index 9e81af2..ef5b6093 100644
--- a/components/resources/dom_distiller_resources.grdp
+++ b/components/resources/dom_distiller_resources.grdp
@@ -7,6 +7,7 @@
   <include name="IDR_DOM_DISTILLER_VIEWER_JS" file="../dom_distiller/core/javascript/dom_distiller_viewer.js" type="BINDATA" />
   <include name="IDR_DISTILLER_JS" file="../dom_distiller/core/javascript/domdistiller.js" flattenhtml="true" type="BINDATA" />
   <include name="IDR_DISTILLER_CSS" file="../dom_distiller/core/css/distilledpage.css" type="BINDATA" />
+  <include name="IDR_DISTILLER_IOS_CSS" file="../dom_distiller/core/css/distilledpage_ios.css" type="BINDATA" />
   <include name="IDR_IS_DISTILLABLE_JS" file="../dom_distiller/core/javascript/is_distillable_trigger.js" type="BINDATA" />
   <include name="IDR_EXTRACT_PAGE_FEATURES_JS" file="../dom_distiller/core/javascript/extract_features.js" type="BINDATA" />
   <include name="IDR_DISTILLABLE_PAGE_SERIALIZED_MODEL" file="../dom_distiller/core/data/distillable_page_model.bin" type="BINDATA" />
diff --git a/components/scheduler/renderer/null_renderer_scheduler.cc b/components/scheduler/renderer/null_renderer_scheduler.cc
index e33da0ac..e5052ad7 100644
--- a/components/scheduler/renderer/null_renderer_scheduler.cc
+++ b/components/scheduler/renderer/null_renderer_scheduler.cc
@@ -71,6 +71,9 @@
 void NullRendererScheduler::OnRendererVisible() {
 }
 
+void NullRendererScheduler::OnPageLoadStarted() {
+}
+
 bool NullRendererScheduler::IsHighPriorityWorkAnticipated() {
   return false;
 }
diff --git a/components/scheduler/renderer/null_renderer_scheduler.h b/components/scheduler/renderer/null_renderer_scheduler.h
index 4267ffc3..753bc9a8 100644
--- a/components/scheduler/renderer/null_renderer_scheduler.h
+++ b/components/scheduler/renderer/null_renderer_scheduler.h
@@ -30,6 +30,7 @@
       const blink::WebInputEvent& web_input_event) override;
   void OnRendererHidden() override;
   void OnRendererVisible() override;
+  void OnPageLoadStarted() override;
   void DidAnimateForInputOnCompositorThread() override;
   bool IsHighPriorityWorkAnticipated() override;
   bool ShouldYieldForHighPriorityWork() override;
diff --git a/components/scheduler/renderer/renderer_scheduler.h b/components/scheduler/renderer/renderer_scheduler.h
index 7bbe8c5..2348511 100644
--- a/components/scheduler/renderer/renderer_scheduler.h
+++ b/components/scheduler/renderer/renderer_scheduler.h
@@ -79,6 +79,11 @@
   // Must be called on the main thread.
   virtual void OnRendererVisible() = 0;
 
+  // Tells the scheduler that a page load has started.  The scheduler will
+  // prioritize loading tasks for a short duration afterwards.
+  // Must be called from the main thread.
+  virtual void OnPageLoadStarted() = 0;
+
   // Returns true if the scheduler has reason to believe that high priority work
   // may soon arrive on the main thread, e.g., if gesture events were observed
   // recently.
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc
index 9b168f8..3b0eb9b 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -36,15 +36,7 @@
           base::Bind(&RendererSchedulerImpl::UpdatePolicy,
                      base::Unretained(this)),
           helper_.ControlTaskRunner()),
-      current_policy_(Policy::NORMAL),
-      renderer_hidden_(false),
-      was_shutdown_(false),
-      pending_main_thread_input_event_count_(0),
-      awaiting_touch_start_response_(false),
-      last_input_type_(blink::WebInputEvent::Undefined),
-      policy_may_need_update_(&incoming_signals_lock_),
-      timer_queue_suspend_count_(0),
-      in_idle_period_(false),
+      policy_may_need_update_(&any_thread_lock_),
       weak_factory_(this) {
   update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy,
                                       weak_factory_.GetWeakPtr());
@@ -67,12 +59,33 @@
   // Ensure the renderer scheduler was shut down explicitly, because otherwise
   // we could end up having stale pointers to the Blink heap which has been
   // terminated by this point.
-  DCHECK(was_shutdown_);
+  DCHECK(MainThreadOnly().was_shutdown_);
+}
+
+RendererSchedulerImpl::MainThreadOnly::MainThreadOnly()
+    : current_policy_(Policy::NORMAL),
+      timer_queue_suspend_count_(0),
+      renderer_hidden_(false),
+      was_shutdown_(false),
+      in_idle_period_(false),
+      begin_main_frame_on_critical_path_(false) {
+}
+
+RendererSchedulerImpl::AnyThread::AnyThread()
+    : pending_main_thread_input_event_count_(0),
+      awaiting_touch_start_response_(false) {
+}
+
+RendererSchedulerImpl::CompositorThreadOnly::CompositorThreadOnly()
+    : last_input_type_(blink::WebInputEvent::Undefined) {
+}
+
+RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {
 }
 
 void RendererSchedulerImpl::Shutdown() {
   helper_.Shutdown();
-  was_shutdown_ = true;
+  MainThreadOnly().was_shutdown_ = true;
 }
 
 scoped_refptr<base::SingleThreadTaskRunner>
@@ -125,7 +138,9 @@
     return;
 
   EndIdlePeriod();
-  estimated_next_frame_begin_ = args.frame_time + args.interval;
+  MainThreadOnly().estimated_next_frame_begin_ =
+      args.frame_time + args.interval;
+  MainThreadOnly().begin_main_frame_on_critical_path_ = args.on_critical_path;
 }
 
 void RendererSchedulerImpl::DidCommitFrameToCompositor() {
@@ -136,12 +151,12 @@
     return;
 
   base::TimeTicks now(helper_.Now());
-  if (now < estimated_next_frame_begin_) {
+  if (now < MainThreadOnly().estimated_next_frame_begin_) {
     // TODO(rmcilroy): Consider reducing the idle period based on the runtime of
     // the next pending delayed tasks (as currently done in for long idle times)
     idle_helper_.StartIdlePeriod(
         IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, now,
-        estimated_next_frame_begin_);
+        MainThreadOnly().estimated_next_frame_begin_);
   }
 }
 
@@ -159,7 +174,7 @@
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
                "RendererSchedulerImpl::OnRendererHidden");
   helper_.CheckOnValidThread();
-  if (helper_.IsShutdown() || renderer_hidden_)
+  if (helper_.IsShutdown() || MainThreadOnly().renderer_hidden_)
     return;
 
   idle_helper_.EnableLongIdlePeriod();
@@ -171,7 +186,7 @@
   control_task_runner_->PostDelayedTask(
       FROM_HERE, end_renderer_hidden_idle_period_closure_.callback(),
       end_idle_when_hidden_delay);
-  renderer_hidden_ = true;
+  MainThreadOnly().renderer_hidden_ = true;
 
   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
       TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
@@ -182,11 +197,11 @@
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
                "RendererSchedulerImpl::OnRendererVisible");
   helper_.CheckOnValidThread();
-  if (helper_.IsShutdown() || !renderer_hidden_)
+  if (helper_.IsShutdown() || !MainThreadOnly().renderer_hidden_)
     return;
 
   end_renderer_hidden_idle_period_closure_.Cancel();
-  renderer_hidden_ = false;
+  MainThreadOnly().renderer_hidden_ = false;
   EndIdlePeriod();
 
   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
@@ -244,15 +259,16 @@
 void RendererSchedulerImpl::UpdateForInputEventOnCompositorThread(
     blink::WebInputEvent::Type type,
     InputEventState input_event_state) {
-  base::AutoLock lock(incoming_signals_lock_);
+  base::AutoLock lock(any_thread_lock_);
   base::TimeTicks now = helper_.Now();
   bool was_in_compositor_priority = InputSignalsSuggestCompositorPriority(now);
-  bool was_awaiting_touch_start_response_ = awaiting_touch_start_response_;
+  bool was_awaiting_touch_start_response =
+      AnyThread().awaiting_touch_start_response_;
 
   if (type) {
     switch (type) {
       case blink::WebInputEvent::TouchStart:
-        awaiting_touch_start_response_ = true;
+        AnyThread().awaiting_touch_start_response_ = true;
         break;
 
       case blink::WebInputEvent::TouchMove:
@@ -261,9 +277,10 @@
         // response prioritization is no longer necessary. Otherwise, the
         // initial touchmove should preserve the touchstart response pending
         // state.
-        if (awaiting_touch_start_response_ &&
-            last_input_type_ == blink::WebInputEvent::TouchMove) {
-          awaiting_touch_start_response_ = false;
+        if (AnyThread().awaiting_touch_start_response_ &&
+            CompositorThreadOnly().last_input_type_ ==
+                blink::WebInputEvent::TouchMove) {
+          AnyThread().awaiting_touch_start_response_ = false;
         }
         break;
 
@@ -276,21 +293,22 @@
         break;
 
       default:
-        awaiting_touch_start_response_ = false;
+        AnyThread().awaiting_touch_start_response_ = false;
         break;
     }
   }
 
   // Avoid unnecessary policy updates, while in compositor priority.
   if (!was_in_compositor_priority ||
-      was_awaiting_touch_start_response_ != awaiting_touch_start_response_) {
+      was_awaiting_touch_start_response !=
+          AnyThread().awaiting_touch_start_response_) {
     EnsureUrgentPolicyUpdatePostedOnMainThread(FROM_HERE);
   }
-  last_input_signal_time_ = now;
-  last_input_type_ = type;
+  AnyThread().last_input_signal_time_ = now;
+  CompositorThreadOnly().last_input_type_ = type;
 
   if (input_event_state == InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD)
-    pending_main_thread_input_event_count_++;
+    AnyThread().pending_main_thread_input_event_count_++;
 }
 
 void RendererSchedulerImpl::DidHandleInputEventOnMainThread(
@@ -299,10 +317,10 @@
                "RendererSchedulerImpl::DidHandleInputEventOnMainThread");
   helper_.CheckOnValidThread();
   if (ShouldPrioritizeInputEvent(web_input_event)) {
-    base::AutoLock lock(incoming_signals_lock_);
-    last_input_signal_time_ = helper_.Now();
-    if (pending_main_thread_input_event_count_ > 0)
-      pending_main_thread_input_event_count_--;
+    base::AutoLock lock(any_thread_lock_);
+    AnyThread().last_input_signal_time_ = helper_.Now();
+    if (AnyThread().pending_main_thread_input_event_count_ > 0)
+      AnyThread().pending_main_thread_input_event_count_--;
   }
 }
 
@@ -314,8 +332,8 @@
   MaybeUpdatePolicy();
   // The touchstart and compositor policies indicate a strong likelihood of
   // high-priority work in the near future.
-  return SchedulerPolicy() == Policy::COMPOSITOR_PRIORITY ||
-         SchedulerPolicy() == Policy::TOUCHSTART_PRIORITY;
+  return MainThreadOnly().current_policy_ == Policy::COMPOSITOR_PRIORITY ||
+         MainThreadOnly().current_policy_ == Policy::TOUCHSTART_PRIORITY;
 }
 
 bool RendererSchedulerImpl::ShouldYieldForHighPriorityWork() {
@@ -329,7 +347,7 @@
   // Note: even though the control queue is higher priority we don't yield for
   // it since these tasks are not user-provided work and they are only intended
   // to run before the next task, not interrupt the tasks.
-  switch (SchedulerPolicy()) {
+  switch (MainThreadOnly().current_policy_) {
     case Policy::NORMAL:
       return false;
 
@@ -339,6 +357,9 @@
     case Policy::TOUCHSTART_PRIORITY:
       return true;
 
+    case Policy::LOADING_PRIORITY:
+      return false;
+
     default:
       NOTREACHED();
       return false;
@@ -350,11 +371,6 @@
   return idle_helper_.CurrentIdleTaskDeadline();
 }
 
-RendererSchedulerImpl::Policy RendererSchedulerImpl::SchedulerPolicy() const {
-  helper_.CheckOnValidThread();
-  return current_policy_;
-}
-
 void RendererSchedulerImpl::MaybeUpdatePolicy() {
   helper_.CheckOnValidThread();
   if (policy_may_need_update_.IsSet()) {
@@ -366,7 +382,7 @@
     const tracked_objects::Location& from_here) {
   // TODO(scheduler-dev): Check that this method isn't called from the main
   // thread.
-  incoming_signals_lock_.AssertAcquired();
+  any_thread_lock_.AssertAcquired();
   if (!policy_may_need_update_.IsSet()) {
     policy_may_need_update_.SetWhileLocked(true);
     control_task_runner_->PostTask(from_here, update_policy_closure_);
@@ -374,18 +390,18 @@
 }
 
 void RendererSchedulerImpl::UpdatePolicy() {
-  base::AutoLock lock(incoming_signals_lock_);
+  base::AutoLock lock(any_thread_lock_);
   UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
 }
 
 void RendererSchedulerImpl::ForceUpdatePolicy() {
-  base::AutoLock lock(incoming_signals_lock_);
+  base::AutoLock lock(any_thread_lock_);
   UpdatePolicyLocked(UpdateType::FORCE_UPDATE);
 }
 
 void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) {
   helper_.CheckOnValidThread();
-  incoming_signals_lock_.AssertAcquired();
+  any_thread_lock_.AssertAcquired();
   if (helper_.IsShutdown())
     return;
 
@@ -395,18 +411,21 @@
   base::TimeDelta new_policy_duration;
   Policy new_policy = ComputeNewPolicy(now, &new_policy_duration);
   if (new_policy_duration > base::TimeDelta()) {
-    current_policy_expiration_time_ = now + new_policy_duration;
+    MainThreadOnly().current_policy_expiration_time_ =
+        now + new_policy_duration;
     delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration,
                                               now);
   } else {
-    current_policy_expiration_time_ = base::TimeTicks();
+    MainThreadOnly().current_policy_expiration_time_ = base::TimeTicks();
   }
 
   if (update_type == UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED &&
-      new_policy == current_policy_)
+      new_policy == MainThreadOnly().current_policy_)
     return;
 
   bool policy_disables_timers = false;
+  PrioritizingTaskQueueSelector::QueuePriority timer_priority =
+      PrioritizingTaskQueueSelector::NORMAL_PRIORITY;
 
   switch (new_policy) {
     case Policy::COMPOSITOR_PRIORITY:
@@ -422,8 +441,7 @@
       helper_.SetQueuePriority(COMPOSITOR_TASK_QUEUE,
                                PrioritizingTaskQueueSelector::HIGH_PRIORITY);
       helper_.DisableQueue(LOADING_TASK_QUEUE);
-      // TODO(alexclarke): Set policy_disables_timers once the blink TimerBase
-      // refactor is safely landed.
+      policy_disables_timers = true;
       break;
     case Policy::NORMAL:
       helper_.SetQueuePriority(COMPOSITOR_TASK_QUEUE,
@@ -431,26 +449,35 @@
       helper_.SetQueuePriority(LOADING_TASK_QUEUE,
                                PrioritizingTaskQueueSelector::NORMAL_PRIORITY);
       break;
+    case Policy::LOADING_PRIORITY:
+      // We prioritize loading tasks by deprioritizing compositing and timers.
+      helper_.SetQueuePriority(
+          COMPOSITOR_TASK_QUEUE,
+          PrioritizingTaskQueueSelector::BEST_EFFORT_PRIORITY);
+      timer_priority = PrioritizingTaskQueueSelector::BEST_EFFORT_PRIORITY;
+      // TODO(alexclarke): See if we can safely mark the loading task queue as
+      // high priority.
+      break;
     default:
       NOTREACHED();
   }
-  if (timer_queue_suspend_count_ != 0 || policy_disables_timers) {
+  if (MainThreadOnly().timer_queue_suspend_count_ != 0 ||
+      policy_disables_timers) {
     helper_.DisableQueue(TIMER_TASK_QUEUE);
   } else {
-    helper_.SetQueuePriority(TIMER_TASK_QUEUE,
-                             PrioritizingTaskQueueSelector::NORMAL_PRIORITY);
+    helper_.SetQueuePriority(TIMER_TASK_QUEUE, timer_priority);
   }
   DCHECK(helper_.IsQueueEnabled(COMPOSITOR_TASK_QUEUE));
   if (new_policy != Policy::TOUCHSTART_PRIORITY)
     DCHECK(helper_.IsQueueEnabled(LOADING_TASK_QUEUE));
 
-  current_policy_ = new_policy;
+  MainThreadOnly().current_policy_ = new_policy;
 
   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
       TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererScheduler",
       this, AsValueLocked(now));
   TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
-                 "RendererScheduler.policy", current_policy_);
+                 "RendererScheduler.policy", MainThreadOnly().current_policy_);
 }
 
 bool RendererSchedulerImpl::InputSignalsSuggestCompositorPriority(
@@ -470,32 +497,40 @@
 RendererSchedulerImpl::Policy RendererSchedulerImpl::ComputeNewPolicy(
     base::TimeTicks now,
     base::TimeDelta* new_policy_duration) const {
-  incoming_signals_lock_.AssertAcquired();
+  any_thread_lock_.AssertAcquired();
+  // Above all else we want to be responsive to user input.
   *new_policy_duration = TimeLeftInInputEscalatedPolicy(now);
+  if (*new_policy_duration > base::TimeDelta()) {
+    return AnyThread().awaiting_touch_start_response_
+               ? Policy::TOUCHSTART_PRIORITY
+               : Policy::COMPOSITOR_PRIORITY;
+  }
 
-  if (*new_policy_duration == base::TimeDelta())
-    return Policy::NORMAL;
+  if (AnyThread().rails_loading_priority_deadline_ > now) {
+    *new_policy_duration = AnyThread().rails_loading_priority_deadline_ - now;
+    return Policy::LOADING_PRIORITY;
+  }
 
-  return awaiting_touch_start_response_ ? Policy::TOUCHSTART_PRIORITY
-                                        : Policy::COMPOSITOR_PRIORITY;
+  return Policy::NORMAL;
 }
 
 base::TimeDelta RendererSchedulerImpl::TimeLeftInInputEscalatedPolicy(
     base::TimeTicks now) const {
-  incoming_signals_lock_.AssertAcquired();
+  any_thread_lock_.AssertAcquired();
 
   base::TimeDelta escalated_priority_duration =
       base::TimeDelta::FromMilliseconds(kPriorityEscalationAfterInputMillis);
 
   // If the input event is still pending, go into input prioritized policy
   // and check again later.
-  if (pending_main_thread_input_event_count_ > 0)
+  if (AnyThread().pending_main_thread_input_event_count_ > 0)
     return escalated_priority_duration;
-  if (last_input_signal_time_.is_null() ||
-      last_input_signal_time_ + escalated_priority_duration < now) {
+  if (AnyThread().last_input_signal_time_.is_null() ||
+      AnyThread().last_input_signal_time_ + escalated_priority_duration < now) {
     return base::TimeDelta();
   }
-  return last_input_signal_time_ + escalated_priority_duration - now;
+  return AnyThread().last_input_signal_time_ + escalated_priority_duration -
+         now;
 }
 
 bool RendererSchedulerImpl::CanEnterLongIdlePeriod(
@@ -504,10 +539,11 @@
   helper_.CheckOnValidThread();
 
   MaybeUpdatePolicy();
-  if (SchedulerPolicy() == Policy::TOUCHSTART_PRIORITY) {
+  if (MainThreadOnly().current_policy_ == Policy::TOUCHSTART_PRIORITY) {
     // Don't start a long idle task in touch start priority, try again when
     // the policy is scheduled to end.
-    *next_long_idle_period_delay_out = current_policy_expiration_time_ - now;
+    *next_long_idle_period_delay_out =
+        MainThreadOnly().current_policy_expiration_time_ - now;
     return false;
   }
   return true;
@@ -518,16 +554,14 @@
 }
 
 void RendererSchedulerImpl::SuspendTimerQueue() {
-  helper_.CheckOnValidThread();
-  timer_queue_suspend_count_++;
+  MainThreadOnly().timer_queue_suspend_count_++;
   ForceUpdatePolicy();
   DCHECK(!helper_.IsQueueEnabled(TIMER_TASK_QUEUE));
 }
 
 void RendererSchedulerImpl::ResumeTimerQueue() {
-  helper_.CheckOnValidThread();
-  timer_queue_suspend_count_--;
-  DCHECK_GE(timer_queue_suspend_count_, 0);
+  MainThreadOnly().timer_queue_suspend_count_--;
+  DCHECK_GE(MainThreadOnly().timer_queue_suspend_count_, 0);
   ForceUpdatePolicy();
 }
 
@@ -557,6 +591,8 @@
       return "compositor";
     case Policy::TOUCHSTART_PRIORITY:
       return "touchstart";
+    case Policy::LOADING_PRIORITY:
+      return "loading";
     default:
       NOTREACHED();
       return nullptr;
@@ -565,49 +601,63 @@
 
 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 RendererSchedulerImpl::AsValue(base::TimeTicks optional_now) const {
-  base::AutoLock lock(incoming_signals_lock_);
+  base::AutoLock lock(any_thread_lock_);
   return AsValueLocked(optional_now);
 }
 
 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 RendererSchedulerImpl::AsValueLocked(base::TimeTicks optional_now) const {
   helper_.CheckOnValidThread();
-  incoming_signals_lock_.AssertAcquired();
+  any_thread_lock_.AssertAcquired();
 
   if (optional_now.is_null())
     optional_now = helper_.Now();
   scoped_refptr<base::trace_event::TracedValue> state =
       new base::trace_event::TracedValue();
 
-  state->SetString("current_policy", PolicyToString(current_policy_));
+  state->SetString("current_policy",
+                   PolicyToString(MainThreadOnly().current_policy_));
   state->SetString("idle_period_state",
                    IdleHelper::IdlePeriodStateToString(
                        idle_helper_.SchedulerIdlePeriodState()));
-  state->SetBoolean("renderer_hidden", renderer_hidden_);
+  state->SetBoolean("renderer_hidden", MainThreadOnly().renderer_hidden_);
   state->SetDouble("now", (optional_now - base::TimeTicks()).InMillisecondsF());
-  state->SetDouble(
-      "last_input_signal_time",
-      (last_input_signal_time_ - base::TimeTicks()).InMillisecondsF());
+  state->SetDouble("last_input_signal_time",
+                   (AnyThread().last_input_signal_time_ - base::TimeTicks())
+                       .InMillisecondsF());
+  state->SetDouble("rails_loading_priority_deadline",
+                   (AnyThread().rails_loading_priority_deadline_ -
+                    base::TimeTicks()).InMillisecondsF());
   state->SetInteger("pending_main_thread_input_event_count",
-                    pending_main_thread_input_event_count_);
+                    AnyThread().pending_main_thread_input_event_count_);
   state->SetBoolean("awaiting_touch_start_response",
-                    awaiting_touch_start_response_);
-  state->SetDouble(
-      "estimated_next_frame_begin",
-      (estimated_next_frame_begin_ - base::TimeTicks()).InMillisecondsF());
-  state->SetBoolean("in_idle_period", in_idle_period_);
+                    AnyThread().awaiting_touch_start_response_);
+  state->SetBoolean("begin_main_frame_on_critical_path",
+                    MainThreadOnly().begin_main_frame_on_critical_path_);
+  state->SetDouble("estimated_next_frame_begin",
+                   (MainThreadOnly().estimated_next_frame_begin_ -
+                    base::TimeTicks()).InMillisecondsF());
+  state->SetBoolean("in_idle_period", MainThreadOnly().in_idle_period_);
 
   return state;
 }
 
 void RendererSchedulerImpl::OnIdlePeriodStarted() {
-  in_idle_period_ = true;
+  MainThreadOnly().in_idle_period_ = true;
   // TODO(alexclarke): Force update the policy
 }
 
 void RendererSchedulerImpl::OnIdlePeriodEnded() {
-  in_idle_period_ = false;
+  MainThreadOnly().in_idle_period_ = false;
   // TODO(alexclarke): Force update the policy
 }
 
+void RendererSchedulerImpl::OnPageLoadStarted() {
+  base::AutoLock lock(any_thread_lock_);
+  AnyThread().rails_loading_priority_deadline_ =
+      helper_.Now() + base::TimeDelta::FromMilliseconds(
+                          kRailsInitialLoadingPrioritizationMillis);
+  UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
+}
+
 }  // namespace scheduler
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.h b/components/scheduler/renderer/renderer_scheduler_impl.h
index faf44de..42cdf110 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.h
+++ b/components/scheduler/renderer/renderer_scheduler_impl.h
@@ -46,6 +46,7 @@
   void DidAnimateForInputOnCompositorThread() override;
   void OnRendererHidden() override;
   void OnRendererVisible() override;
+  void OnPageLoadStarted() override;
   bool IsHighPriorityWorkAnticipated() override;
   bool ShouldYieldForHighPriorityWork() override;
   bool CanExceedIdleDeadlineIfRequired() const override;
@@ -79,6 +80,7 @@
     NORMAL,
     COMPOSITOR_PRIORITY,
     TOUCHSTART_PRIORITY,
+    LOADING_PRIORITY,
     // Must be the last entry.
     POLICY_COUNT,
     FIRST_POLICY = NORMAL,
@@ -130,11 +132,12 @@
   // renderer has been hidden, before going to sleep for good.
   static const int kEndIdleWhenHiddenDelayMillis = 10000;
 
-  // Returns the current scheduler policy. Must be called from the main thread.
-  Policy SchedulerPolicy() const;
+  // The amount of time for which loading tasks will be prioritized over
+  // other tasks during the initial page load.
+  static const int kRailsInitialLoadingPrioritizationMillis = 1000;
 
   // Schedules an immediate PolicyUpdate, if there isn't one already pending and
-  // sets |policy_may_need_update_|. Note |incoming_signals_lock_| must be
+  // sets |policy_may_need_update_|. Note |any_thread_lock_| must be
   // locked.
   void EnsureUrgentPolicyUpdatePostedOnMainThread(
       const tracked_objects::Location& from_here);
@@ -143,7 +146,7 @@
   // thread.
   void MaybeUpdatePolicy();
 
-  // Locks |incoming_signals_lock_| and updates the scheduler policy.  May early
+  // Locks |any_thread_lock_| and updates the scheduler policy.  May early
   // out if the policy is unchanged. Must be called from the main thread.
   void UpdatePolicy();
 
@@ -166,7 +169,7 @@
   // Helper for computing the new policy. |new_policy_duration| will be filled
   // with the amount of time after which the policy should be updated again. If
   // the duration is zero, a new policy update will not be scheduled. Must be
-  // called with |incoming_signals_lock_| held. Can be called from any thread.
+  // called with |any_thread_lock_| held. Can be called from any thread.
   Policy ComputeNewPolicy(base::TimeTicks now,
                           base::TimeDelta* new_policy_duration) const;
 
@@ -181,38 +184,89 @@
   SchedulerHelper helper_;
   IdleHelper idle_helper_;
 
-  scoped_refptr<base::SingleThreadTaskRunner> control_task_runner_;
-  scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
-  scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner_;
-  scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner_;
+  const scoped_refptr<base::SingleThreadTaskRunner> control_task_runner_;
+  const scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
+  const scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner_;
+  const scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner_;
 
   base::Closure update_policy_closure_;
   DeadlineTaskRunner delayed_update_policy_runner_;
   CancelableClosureHolder end_renderer_hidden_idle_period_closure_;
 
-  // Don't access current_policy_ directly, instead use SchedulerPolicy().
-  Policy current_policy_;
-  base::TimeTicks current_policy_expiration_time_;
-  bool renderer_hidden_;
-  bool was_shutdown_;
+  // We have decided to improve thread safety at the cost of some boilerplate
+  // (the accessors) for the following data members.
 
-  base::TimeTicks estimated_next_frame_begin_;
+  struct MainThreadOnly {
+    MainThreadOnly();
 
-  // The incoming_signals_lock_ mutex protects access to all variables in the
-  // (contiguous) block below.
-  mutable base::Lock incoming_signals_lock_;
-  base::TimeTicks last_input_signal_time_;
-  int pending_main_thread_input_event_count_;
-  bool awaiting_touch_start_response_;
+    Policy current_policy_;
+    base::TimeTicks current_policy_expiration_time_;
+    base::TimeTicks estimated_next_frame_begin_;
+    int timer_queue_suspend_count_;  // TIMER_TASK_QUEUE suspended if non-zero.
+    bool renderer_hidden_;
+    bool was_shutdown_;
+    bool in_idle_period_;
+    bool begin_main_frame_on_critical_path_;
+  };
 
-  // Variables in this (contiguous) block are only accessed from the compositor
-  // thread.
-  blink::WebInputEvent::Type last_input_type_;
+  struct AnyThread {
+    AnyThread();
+
+    base::TimeTicks last_input_signal_time_;
+    base::TimeTicks rails_loading_priority_deadline_;
+    int pending_main_thread_input_event_count_;
+    bool awaiting_touch_start_response_;
+  };
+
+  struct CompositorThreadOnly {
+    CompositorThreadOnly();
+    ~CompositorThreadOnly();
+
+    blink::WebInputEvent::Type last_input_type_;
+    scoped_ptr<base::ThreadChecker> compositor_thread_checker_;
+
+    void CheckOnValidThread() {
+#if DCHECK_IS_ON()
+      // We don't actually care which thread this called from, just so long as
+      // its consistent.
+      if (!compositor_thread_checker_)
+        compositor_thread_checker_.reset(new base::ThreadChecker());
+      DCHECK(compositor_thread_checker_->CalledOnValidThread());
+#endif
+    }
+  };
+
+  // Don't access main_thread_only_, instead use MainThreadOnly().
+  MainThreadOnly main_thread_only_;
+  MainThreadOnly& MainThreadOnly() {
+    helper_.CheckOnValidThread();
+    return main_thread_only_;
+  }
+  const struct MainThreadOnly& MainThreadOnly() const {
+    helper_.CheckOnValidThread();
+    return main_thread_only_;
+  }
+
+  mutable base::Lock any_thread_lock_;
+  // Don't access any_thread_, instead use AnyThread().
+  AnyThread any_thread_;
+  AnyThread& AnyThread() {
+    any_thread_lock_.AssertAcquired();
+    return any_thread_;
+  }
+  const struct AnyThread& AnyThread() const {
+    any_thread_lock_.AssertAcquired();
+    return any_thread_;
+  }
+
+  // Don't access compositor_thread_only_, instead use CompositorThreadOnly().
+  CompositorThreadOnly compositor_thread_only_;
+  CompositorThreadOnly& CompositorThreadOnly() {
+    compositor_thread_only_.CheckOnValidThread();
+    return compositor_thread_only_;
+  }
 
   PollableThreadSafeFlag policy_may_need_update_;
-  int timer_queue_suspend_count_;  // TIMER_TASK_QUEUE suspended if non-zero.
-
-  bool in_idle_period_;
   base::WeakPtrFactory<RendererSchedulerImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImpl);
diff --git a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
index 9a6cb38d..e6c4b56f 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -141,6 +141,39 @@
 }
 };  // namespace
 
+class RendererSchedulerImplForTest : public RendererSchedulerImpl {
+ public:
+  using RendererSchedulerImpl::Policy;
+  using RendererSchedulerImpl::PolicyToString;
+
+  RendererSchedulerImplForTest(
+      scoped_refptr<NestableSingleThreadTaskRunner> main_task_runner)
+      : RendererSchedulerImpl(main_task_runner), update_policy_count_(0) {}
+
+  void UpdatePolicyLocked(UpdateType update_type) override {
+    update_policy_count_++;
+    RendererSchedulerImpl::UpdatePolicyLocked(update_type);
+  }
+
+  void EnsureUrgentPolicyUpdatePostedOnMainThread() {
+    base::AutoLock lock(any_thread_lock_);
+    RendererSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread(
+        FROM_HERE);
+  }
+
+  void ScheduleDelayedPolicyUpdate(base::TimeTicks now, base::TimeDelta delay) {
+    delayed_update_policy_runner_.SetDeadline(FROM_HERE, delay, now);
+  }
+
+  int update_policy_count_;
+};
+
+// Lets gtest print human readable Policy values.
+::std::ostream& operator<<(::std::ostream& os,
+                           const RendererSchedulerImplForTest::Policy& policy) {
+  return os << RendererSchedulerImplForTest::PolicyToString(policy);
+}
+
 class RendererSchedulerImplTest : public testing::Test {
  public:
   using Policy = RendererSchedulerImpl::Policy;
@@ -162,11 +195,11 @@
       nestable_task_runner_ =
           NestableTaskRunnerForTest::Create(mock_task_runner_);
     }
-    Initialize(
-        make_scoped_ptr(new RendererSchedulerImpl(nestable_task_runner_)));
+    Initialize(make_scoped_ptr(
+        new RendererSchedulerImplForTest(nestable_task_runner_)));
   }
 
-  void Initialize(scoped_ptr<RendererSchedulerImpl> scheduler) {
+  void Initialize(scoped_ptr<RendererSchedulerImplForTest> scheduler) {
     scheduler_ = scheduler.Pass();
     default_task_runner_ = scheduler_->DefaultTaskRunner();
     compositor_task_runner_ = scheduler_->CompositorTaskRunner();
@@ -212,7 +245,13 @@
 
   void EnableIdleTasks() { DoMainFrame(); }
 
-  Policy CurrentPolicy() { return scheduler_->current_policy_; }
+  Policy CurrentPolicy() {
+    return scheduler_->MainThreadOnly().current_policy_;
+  }
+
+  bool BeginMainFrameOnCriticalPath() {
+    return scheduler_->MainThreadOnly().begin_main_frame_on_critical_path_;
+  }
 
   // Helper for posting several tasks of specific types. |task_descriptor| is a
   // string with space delimited task identifiers. The first letter of each
@@ -302,7 +341,7 @@
   scoped_ptr<base::MessageLoop> message_loop_;
 
   scoped_refptr<NestableSingleThreadTaskRunner> nestable_task_runner_;
-  scoped_ptr<RendererSchedulerImpl> scheduler_;
+  scoped_ptr<RendererSchedulerImplForTest> scheduler_;
   scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner_;
@@ -312,38 +351,6 @@
   DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplTest);
 };
 
-class RendererSchedulerImplForTest : public RendererSchedulerImpl {
- public:
-  using RendererSchedulerImpl::PolicyToString;
-
-  RendererSchedulerImplForTest(
-      scoped_refptr<NestableSingleThreadTaskRunner> main_task_runner)
-      : RendererSchedulerImpl(main_task_runner), update_policy_count_(0) {}
-
-  void UpdatePolicyLocked(UpdateType update_type) override {
-    update_policy_count_++;
-    RendererSchedulerImpl::UpdatePolicyLocked(update_type);
-  }
-
-  void EnsureUrgentPolicyUpdatePostedOnMainThread() {
-    base::AutoLock lock(incoming_signals_lock_);
-    RendererSchedulerImpl::EnsureUrgentPolicyUpdatePostedOnMainThread(
-        FROM_HERE);
-  }
-
-  void ScheduleDelayedPolicyUpdate(base::TimeTicks now, base::TimeDelta delay) {
-    delayed_update_policy_runner_.SetDeadline(FROM_HERE, delay, now);
-  }
-
-  int update_policy_count_;
-};
-
-// Lets gtest print human readable Policy values.
-::std::ostream& operator<<(::std::ostream& os,
-                           const RendererSchedulerImplTest::Policy& policy) {
-  return os << RendererSchedulerImplForTest::PolicyToString(policy);
-}
-
 TEST_F(RendererSchedulerImplTest, TestPostDefaultTask) {
   std::vector<std::string> run_order;
   PostTestTasks(&run_order, "D1 D2 D3 D4");
@@ -610,7 +617,8 @@
   std::vector<std::string> run_order;
   PostTestTasks(&run_order, "L1 D1 C1 D2 C2 T1 T2");
 
-  // Observation of touchstart should defer execution of idle and loading tasks.
+  // Observation of touchstart should defer execution of timer, idle and loading
+  // tasks.
   scheduler_->DidHandleInputEventOnCompositorThread(
       FakeInputEvent(blink::WebInputEvent::TouchStart),
       RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
@@ -618,8 +626,7 @@
   RunUntilIdle();
   EXPECT_THAT(run_order,
               testing::ElementsAre(std::string("C1"), std::string("C2"),
-                                   std::string("D1"), std::string("D2"),
-                                   std::string("T1"), std::string("T2")));
+                                   std::string("D1"), std::string("D2")));
 
   // Meta events like TapDown/FlingCancel shouldn't affect the priority.
   run_order.clear();
@@ -640,7 +647,9 @@
       RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR);
   RunUntilIdle();
 
-  EXPECT_THAT(run_order, testing::ElementsAre(std::string("L1")));
+  EXPECT_THAT(run_order,
+              testing::ElementsAre(std::string("T1"), std::string("T2"),
+                                   std::string("L1")));
 }
 
 TEST_F(RendererSchedulerImplTest, TestTouchstartPolicy_MainThread) {
@@ -657,8 +666,7 @@
   RunUntilIdle();
   EXPECT_THAT(run_order,
               testing::ElementsAre(std::string("C1"), std::string("C2"),
-                                   std::string("D1"), std::string("D2"),
-                                   std::string("T1"), std::string("T2")));
+                                   std::string("D1"), std::string("D2")));
 
   // Meta events like TapDown/FlingCancel shouldn't affect the priority.
   run_order.clear();
@@ -685,7 +693,35 @@
       FakeInputEvent(blink::WebInputEvent::GestureScrollBegin));
   RunUntilIdle();
 
-  EXPECT_THAT(run_order, testing::ElementsAre(std::string("L1")));
+  EXPECT_THAT(run_order,
+              testing::ElementsAre(std::string("T1"), std::string("T2"),
+                                   std::string("L1")));
+}
+
+TEST_F(RendererSchedulerImplTest, LoadingPriorityPolicy) {
+  std::vector<std::string> run_order;
+  PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
+
+  scheduler_->OnPageLoadStarted();
+  EnableIdleTasks();
+  RunUntilIdle();
+  // In loading policy compositor tasks are best effort and should be run last.
+  EXPECT_THAT(run_order,
+              testing::ElementsAre(std::string("L1"), std::string("D1"),
+                                   std::string("D2"), std::string("I1"),
+                                   std::string("C1"), std::string("C2")));
+
+  // Advance 1.5s and try again, the loading policy should have ended and the
+  // task order should return to normal.
+  clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(1500));
+  run_order.clear();
+  PostTestTasks(&run_order, "L1 I1 D1 C1 D2 C2");
+  EnableIdleTasks();
+  RunUntilIdle();
+  EXPECT_THAT(run_order,
+              testing::ElementsAre(std::string("L1"), std::string("D1"),
+                                   std::string("C1"), std::string("D2"),
+                                   std::string("C2"), std::string("I1")));
 }
 
 TEST_F(RendererSchedulerImplTest,
@@ -1642,4 +1678,26 @@
       FakeInputEvent(blink::WebInputEvent::GestureFlingStart));
 }
 
+TEST_F(RendererSchedulerImplTest, BeginMainFrameOnCriticalPath) {
+  ASSERT_FALSE(BeginMainFrameOnCriticalPath());
+
+  cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create(
+      BEGINFRAME_FROM_HERE, clock_->Now(), base::TimeTicks(),
+      base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL);
+  scheduler_->WillBeginFrame(begin_frame_args);
+  ASSERT_TRUE(BeginMainFrameOnCriticalPath());
+
+  begin_frame_args.on_critical_path = false;
+  scheduler_->WillBeginFrame(begin_frame_args);
+  ASSERT_FALSE(BeginMainFrameOnCriticalPath());
+}
+
+TEST_F(RendererSchedulerImplTest, ShutdownPreventsPostingOfNewTasks) {
+  scheduler_->Shutdown();
+  std::vector<std::string> run_order;
+  PostTestTasks(&run_order, "D1 C1");
+  RunUntilIdle();
+  EXPECT_TRUE(run_order.empty());
+}
+
 }  // namespace scheduler
diff --git a/components/search/search.cc b/components/search/search.cc
index c2d4b4e..9afd666 100644
--- a/components/search/search.cc
+++ b/components/search/search.cc
@@ -35,8 +35,6 @@
 const uint64 kEmbeddedPageVersionDefault = 2;
 #endif
 
-const char kHideVerbatimFlagName[] = "hide_verbatim";
-
 // Constants for the field trial name and group prefix.
 // Note in M30 and below this field trial was named "InstantExtended" and in
 // M31 was renamed to EmbeddedSearch for clarity and cleanliness.  Since we
@@ -145,10 +143,4 @@
   return !!GetUInt64ValueForFlagWithDefault(flag, default_value ? 1 : 0, flags);
 }
 
-bool ShouldHideTopVerbatimMatch() {
-  FieldTrialFlags flags;
-  return GetFieldTrialInfo(&flags) && GetBoolValueForFlagWithDefault(
-      kHideVerbatimFlagName, false, flags);
-}
-
 }  // namespace chrome
diff --git a/components/search/search.h b/components/search/search.h
index 9558ee8..0a7a55b8 100644
--- a/components/search/search.h
+++ b/components/search/search.h
@@ -55,11 +55,6 @@
                                     bool default_value,
                                     const FieldTrialFlags& flags);
 
-// Returns true if 'hide_verbatim' flag is enabled in field trials
-// to hide the top match in the native suggestions dropdown if it is a verbatim
-// match.  See comments on ShouldHideTopMatch in autocomplete_result.h.
-bool ShouldHideTopVerbatimMatch();
-
 }  // namespace chrome
 
 #endif  // COMPONENTS_SEARCH_SEARCH_H_
diff --git a/components/search/search_unittest.cc b/components/search/search_unittest.cc
index d3bd8734..2fd5a23 100644
--- a/components/search/search_unittest.cc
+++ b/components/search/search_unittest.cc
@@ -130,36 +130,4 @@
   EXPECT_EQ(3ul, flags.size());
 }
 
-typedef EmbeddedSearchFieldTrialTest ShouldHideTopVerbatimTest;
-
-TEST_F(ShouldHideTopVerbatimTest, DoNotHideByDefault) {
-  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
-                                                     "Control"));
-  EXPECT_FALSE(ShouldHideTopVerbatimMatch());
-}
-
-TEST_F(ShouldHideTopVerbatimTest, DoNotHideInInstantExtended) {
-  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
-                                                     "Group1"));
-  EXPECT_FALSE(ShouldHideTopVerbatimMatch());
-}
-
-TEST_F(ShouldHideTopVerbatimTest, EnableByFlagInInstantExtended) {
-  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
-                                                     "Group1 hide_verbatim:1"));
-  EXPECT_TRUE(ShouldHideTopVerbatimMatch());
-}
-
-TEST_F(ShouldHideTopVerbatimTest, EnableByFlagOutsideInstantExtended) {
-  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
-      "EmbeddedSearch", "Controll1 hide_verbatim:1"));
-  EXPECT_TRUE(ShouldHideTopVerbatimMatch());
-}
-
-TEST_F(ShouldHideTopVerbatimTest, DisableByFlag) {
-  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch",
-                                                     "Group1 hide_verbatim:0"));
-  EXPECT_FALSE(ShouldHideTopVerbatimMatch());
-}
-
 }  // namespace chrome
diff --git a/components/search_engines/template_url_parser.cc b/components/search_engines/template_url_parser.cc
index edcc1dcb..394512c 100644
--- a/components/search_engines/template_url_parser.cc
+++ b/components/search_engines/template_url_parser.cc
@@ -364,7 +364,7 @@
     } else if (name == kURLTemplateAttribute) {
       template_url = XMLCharToString(value);
     } else if (name == kParamMethodAttribute) {
-      is_post = LowerCaseEqualsASCII(XMLCharToString(value), "post");
+      is_post = base::LowerCaseEqualsASCII(XMLCharToString(value), "post");
     }
   }
 
diff --git a/components/search_engines/template_url_service_util_unittest.cc b/components/search_engines/template_url_service_util_unittest.cc
index 65b992a..f2939834 100644
--- a/components/search_engines/template_url_service_util_unittest.cc
+++ b/components/search_engines/template_url_service_util_unittest.cc
@@ -95,7 +95,7 @@
             prepopulated_turls.size() + num_non_prepopulated_urls);
   for (TemplateURLService::TemplateURLVector::const_iterator itr =
        local_turls.begin(); itr != local_turls.end(); ++itr) {
-    EXPECT_TRUE(
-        StartsWith((*itr)->keyword(), base::ASCIIToUTF16("winner"), true));
+    EXPECT_TRUE(base::StartsWith((*itr)->keyword(),
+                                 base::ASCIIToUTF16("winner"), true));
   }
 }
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc
index 34738b7..934458da 100644
--- a/components/signin/core/browser/account_reconcilor.cc
+++ b/components/signin/core/browser/account_reconcilor.cc
@@ -24,34 +24,23 @@
 
 namespace {
 
-class EmailEqualToFunc : public std::equal_to<gaia::ListedAccount> {
+class AccountEqualToFunc : public std::equal_to<gaia::ListedAccount> {
  public:
   bool operator()(const gaia::ListedAccount& p1,
                   const gaia::ListedAccount& p2) const;
 };
 
-bool EmailEqualToFunc::operator()(
+bool AccountEqualToFunc::operator()(
     const gaia::ListedAccount& p1,
     const gaia::ListedAccount& p2) const {
-  return p1.valid == p2.valid && gaia::AreEmailsSame(p1.email, p2.email);
+  return p1.valid == p2.valid && p1.id == p2.id;
 }
 
-class AreEmailsSameFunc : public std::equal_to<std::string> {
- public:
-  bool operator()(const std::string& p1,
-                  const std::string& p2) const;
-};
-
-bool AreEmailsSameFunc::operator()(
-    const std::string& p1,
-    const std::string& p2) const {
-  return gaia::AreEmailsSame(p1, p2);
-}
-
-gaia::ListedAccount AccountFromEmail(const std::string& email) {
+gaia::ListedAccount AccountForId(const std::string& account_id) {
   gaia::ListedAccount account;
-  account.email = email;
+  account.id = account_id;
   account.gaia_id = std::string();
+  account.email = std::string();
   account.valid = true;
   return account;
 }
@@ -339,19 +328,17 @@
   DCHECK(add_to_cookie_.empty());
   int number_gaia_accounts = gaia_accounts_.size();
   bool are_primaries_equal = number_gaia_accounts > 0 &&
-      gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].email);
+      primary_account_ == gaia_accounts_[0].id;
 
   // If there are any accounts in the gaia cookie but not in chrome, then
   // those accounts need to be removed from the cookie.  This means we need
   // to blow the cookie away.
   int removed_from_cookie = 0;
   for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
-    const std::string& gaia_account = gaia_accounts_[i].email;
     if (gaia_accounts_[i].valid &&
-        chrome_accounts_.end() ==
-            std::find_if(chrome_accounts_.begin(),
-                         chrome_accounts_.end(),
-                         std::bind1st(AreEmailsSameFunc(), gaia_account))) {
+        chrome_accounts_.end() == std::find(chrome_accounts_.begin(),
+                                            chrome_accounts_.end(),
+                                            gaia_accounts_[i].id)) {
       ++removed_from_cookie;
     }
   }
@@ -387,9 +374,8 @@
     if (gaia_accounts_.end() !=
             std::find_if(gaia_accounts_.begin(),
                          gaia_accounts_.end(),
-                         std::bind1st(EmailEqualToFunc(),
-                                      AccountFromEmail(add_to_cookie_copy[i]
-                                                       )))) {
+                         std::bind1st(AccountEqualToFunc(),
+                                      AccountForId(add_to_cookie_copy[i])))) {
       cookie_manager_service_->SignalComplete(
           add_to_cookie_copy[i],
           GoogleServiceAuthError::AuthErrorNone());
@@ -398,9 +384,8 @@
       if (original_gaia_accounts.end() ==
               std::find_if(original_gaia_accounts.begin(),
                            original_gaia_accounts.end(),
-                           std::bind1st(EmailEqualToFunc(),
-                                        AccountFromEmail(add_to_cookie_copy[i]
-                                                         )))) {
+                           std::bind1st(AccountEqualToFunc(),
+                                        AccountForId(add_to_cookie_copy[i])))) {
         added_to_cookie++;
       }
     }
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc
index 4db5fa6..4beff36 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -561,7 +561,8 @@
     return;
   }
 
-  for (gaia::ListedAccount account : listed_accounts_) {
+  for (gaia::ListedAccount& account : listed_accounts_) {
+    DCHECK(account.id.empty());
     account.id = AccountTrackerService::PickAccountIdForAccount(
         signin_client_->GetPrefs(), account.gaia_id, account.email);
   }
diff --git a/components/startup_metric_utils/OWNERS b/components/startup_metric_utils/OWNERS
index b112a84..f75fe2eb 100644
--- a/components/startup_metric_utils/OWNERS
+++ b/components/startup_metric_utils/OWNERS
@@ -1 +1,2 @@
-jeremy@chromium.org
\ No newline at end of file
+erikchen@chromium.org
+gab@chromium.org
diff --git a/components/startup_metric_utils/startup_metric_utils.cc b/components/startup_metric_utils/startup_metric_utils.cc
index b82da00f..1d546fe 100644
--- a/components/startup_metric_utils/startup_metric_utils.cc
+++ b/components/startup_metric_utils/startup_metric_utils.cc
@@ -7,12 +7,9 @@
 #include "base/containers/hash_tables.h"
 #include "base/environment.h"
 #include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/histogram_base.h"
-#include "base/metrics/statistics_recorder.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/process/process_info.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/synchronization/lock.h"
 #include "base/sys_info.h"
 #include "base/time/time.h"
 
@@ -32,19 +29,6 @@
   return &main_start_time;
 }
 
-typedef base::hash_map<std::string,base::TimeDelta> SubsystemStartupTimeHash;
-
-SubsystemStartupTimeHash* GetSubsystemStartupTimeHash() {
-  static SubsystemStartupTimeHash* slow_startup_time_hash =
-                                    new SubsystemStartupTimeHash;
-  return slow_startup_time_hash;
-}
-
-base::Lock* GetSubsystemStartupTimeHashLock() {
-  static base::Lock* slow_startup_time_hash_lock = new base::Lock;
-  return slow_startup_time_hash_lock;
-}
-
 #if defined(OS_WIN)
 
 // The struct used to return system process information via the NT internal
@@ -218,8 +202,6 @@
 }
 
 bool g_main_entry_time_was_recorded = false;
-bool g_startup_stats_collection_finished = false;
-bool g_was_slow_startup = false;
 
 // Environment variable that stores the timestamp when the executable's main()
 // function was entered.
@@ -272,10 +254,8 @@
   // autostarted and the machine is under io pressure.
   const int64 kSevenMinutesInMilliseconds =
       base::TimeDelta::FromMinutes(7).InMilliseconds();
-  if (base::SysInfo::Uptime() < kSevenMinutesInMilliseconds) {
-    g_startup_stats_collection_finished = true;
+  if (base::SysInfo::Uptime() < kSevenMinutesInMilliseconds)
     return;
-  }
 
   // The Startup.BrowserMessageLoopStartTime histogram recorded in
   // chrome_browser_main.cc exhibits instability in the field which limits its
@@ -329,54 +309,6 @@
     }
   }
 #endif
-
-  // Record histograms for the subsystem times for startups > 10 seconds.
-  const base::TimeDelta kTenSeconds = base::TimeDelta::FromSeconds(10);
-  if (startup_time_from_main_entry < kTenSeconds) {
-    g_startup_stats_collection_finished = true;
-    return;
-  }
-
-  // If we got here this was what we consider to be a slow startup which we
-  // want to record stats for.
-  g_was_slow_startup = true;
-}
-
-void OnInitialPageLoadComplete() {
-  if (!g_was_slow_startup)
-    return;
-  DCHECK(!g_startup_stats_collection_finished);
-
-  const base::TimeDelta kStartupTimeMin(
-      base::TimeDelta::FromMilliseconds(1));
-  const base::TimeDelta kStartupTimeMax(base::TimeDelta::FromMinutes(5));
-  static const size_t kStartupTimeBuckets = 100;
-
-  // Set UMA flag for histograms outside chrome/ that can't use the
-  // ScopedSlowStartupUMA class.
-  base::HistogramBase* histogram =
-      base::StatisticsRecorder::FindHistogram("Startup.SlowStartupNSSInit");
-  if (histogram)
-    histogram->SetFlags(base::HistogramBase::kUmaTargetedHistogramFlag);
-
-  // Iterate over the stats recorded by ScopedSlowStartupUMA and create
-  // histograms for them.
-  base::AutoLock locker(*GetSubsystemStartupTimeHashLock());
-  SubsystemStartupTimeHash* time_hash = GetSubsystemStartupTimeHash();
-  for (SubsystemStartupTimeHash::iterator i = time_hash->begin();
-      i != time_hash->end();
-      ++i) {
-    const std::string histogram_name = i->first;
-    base::HistogramBase* counter = base::Histogram::FactoryTimeGet(
-        histogram_name,
-        kStartupTimeMin,
-        kStartupTimeMax,
-        kStartupTimeBuckets,
-        base::Histogram::kUmaTargetedHistogramFlag);
-    counter->AddTime(i->second);
-  }
-
-  g_startup_stats_collection_finished = true;
 }
 
 const base::Time* MainEntryPointTime() {
@@ -385,18 +317,4 @@
   return MainEntryPointTimeInternal();
 }
 
-ScopedSlowStartupUMA::~ScopedSlowStartupUMA() {
-  if (g_startup_stats_collection_finished)
-    return;
-
-  base::AutoLock locker(*GetSubsystemStartupTimeHashLock());
-  SubsystemStartupTimeHash* hash = GetSubsystemStartupTimeHash();
-  // Only record the initial sample for a given histogram.
-  if (hash->find(histogram_name_) !=  hash->end())
-    return;
-
-  (*hash)[histogram_name_] =
-      base::TimeTicks::Now() - start_time_;
-}
-
 }  // namespace startup_metric_utils
diff --git a/components/startup_metric_utils/startup_metric_utils.h b/components/startup_metric_utils/startup_metric_utils.h
index 3f62947..952abf95 100644
--- a/components/startup_metric_utils/startup_metric_utils.h
+++ b/components/startup_metric_utils/startup_metric_utils.h
@@ -48,33 +48,11 @@
 // |is_first_run| - is the current launch part of a first run.
 void OnBrowserStartupComplete(bool is_first_run);
 
-// Called when the initial page load has finished in order to record startup
-// stats.
-void OnInitialPageLoadComplete();
-
 // Returns the time of main entry recorded from RecordMainEntryPointTime.
 // Returns NULL if that method has not yet been called.
 // This method is expected to be called from the UI thread.
 const base::Time* MainEntryPointTime();
 
-// Scoper that records the time period before it's destructed in a histogram
-// with the given name. The histogram is only recorded for slow chrome startups.
-// Useful for trying to figure out what parts of Chrome cause slow startup.
-class ScopedSlowStartupUMA {
- public:
-  explicit ScopedSlowStartupUMA(const std::string& histogram_name)
-      : start_time_(base::TimeTicks::Now()),
-        histogram_name_(histogram_name) {}
-
-  ~ScopedSlowStartupUMA();
-
- private:
-  const base::TimeTicks start_time_;
-  const std::string histogram_name_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedSlowStartupUMA);
-};
-
 }  // namespace startup_metric_utils
 
 #endif  // COMPONENTS_STARTUP_METRIC_UTILS_STARTUP_METRIC_UTILS_H_
diff --git a/components/storage_monitor/portable_device_watcher_win.cc b/components/storage_monitor/portable_device_watcher_win.cc
index 9b581bf..ed850738 100644
--- a/components/storage_monitor/portable_device_watcher_win.cc
+++ b/components/storage_monitor/portable_device_watcher_win.cc
@@ -301,7 +301,7 @@
                                  const base::string16& device_name) {
   // Based on testing, if the pnp device id starts with "\\?\wpdbusenumroot#",
   // then the attached device belongs to a mass storage class.
-  if (StartsWith(pnp_device_id, L"\\\\?\\wpdbusenumroot#", false))
+  if (base::StartsWith(pnp_device_id, L"\\\\?\\wpdbusenumroot#", false))
     return true;
 
   // If the device is a volume mounted device, |device_name| will be
diff --git a/components/suggestions/image_encoder.cc b/components/suggestions/image_encoder.cc
index bcceaae..5e92b65 100644
--- a/components/suggestions/image_encoder.cc
+++ b/components/suggestions/image_encoder.cc
@@ -9,8 +9,9 @@
 
 namespace suggestions {
 
-SkBitmap* DecodeJPEGToSkBitmap(const std::vector<unsigned char>& encoded_data) {
-  return gfx::JPEGCodec::Decode(&encoded_data[0], encoded_data.size());
+SkBitmap* DecodeJPEGToSkBitmap(const void* encoded_data, size_t size) {
+  return gfx::JPEGCodec::Decode(static_cast<const unsigned char*>(encoded_data),
+                                size);
 }
 
 bool EncodeSkBitmapToJPEG(const SkBitmap& bitmap,
diff --git a/components/suggestions/image_encoder.h b/components/suggestions/image_encoder.h
index f32314ab0..d0aa71d 100644
--- a/components/suggestions/image_encoder.h
+++ b/components/suggestions/image_encoder.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_SUGGESTIONS_IMAGE_ENCODER_H_
 #define COMPONENTS_SUGGESTIONS_IMAGE_ENCODER_H_
 
+#include <stddef.h>
 #include <vector>
 
 class SkBitmap;
@@ -13,7 +14,12 @@
 
 // From encoded bytes to SkBitmap. It's the caller's responsibility to delete
 // the bitmap.
-SkBitmap* DecodeJPEGToSkBitmap(const std::vector<unsigned char>& encoded_data);
+SkBitmap* DecodeJPEGToSkBitmap(const void* encoded_data, size_t size);
+
+inline SkBitmap* DecodeJPEGToSkBitmap(
+    const std::vector<unsigned char>& encoded_data) {
+  return DecodeJPEGToSkBitmap(&encoded_data[0], encoded_data.size());
+}
 
 // From SkBitmap to a vector of JPEG-encoded bytes, |dst|.
 bool EncodeSkBitmapToJPEG(const SkBitmap& bitmap,
diff --git a/components/suggestions/image_encoder_ios.mm b/components/suggestions/image_encoder_ios.mm
index e81fb305..ffac9a2 100644
--- a/components/suggestions/image_encoder_ios.mm
+++ b/components/suggestions/image_encoder_ios.mm
@@ -11,11 +11,9 @@
 
 namespace suggestions {
 
-SkBitmap* DecodeJPEGToSkBitmap(const std::vector<unsigned char>& encoded_data) {
-  NSData* data =
-      [NSData dataWithBytes:encoded_data.data() length:encoded_data.size()];
-  UIImage* image =
-     [UIImage imageWithData:data scale:1.0];
+SkBitmap* DecodeJPEGToSkBitmap(const void* encoded_data, size_t size) {
+  NSData* data = [NSData dataWithBytes:encoded_data length:size];
+  UIImage* image = [UIImage imageWithData:data scale:1.0];
   return new SkBitmap(gfx::CGImageToSkBitmap(image.CGImage, [image size], YES));
 }
 
diff --git a/components/suggestions/image_manager.cc b/components/suggestions/image_manager.cc
index 2837e63..329b4d9 100644
--- a/components/suggestions/image_manager.cc
+++ b/components/suggestions/image_manager.cc
@@ -5,20 +5,35 @@
 #include "components/suggestions/image_manager.h"
 
 #include "base/bind.h"
+#include "base/location.h"
+#include "base/task_runner_util.h"
 #include "components/suggestions/image_encoder.h"
 #include "components/suggestions/image_fetcher.h"
 
 using leveldb_proto::ProtoDatabase;
 
+namespace {
+
+scoped_ptr<SkBitmap> DecodeImage(
+    scoped_refptr<base::RefCountedMemory> encoded_data) {
+  return scoped_ptr<SkBitmap>(suggestions::DecodeJPEGToSkBitmap(
+      encoded_data->front(), encoded_data->size()));
+}
+
+}  // namespace
+
 namespace suggestions {
 
 ImageManager::ImageManager() : weak_ptr_factory_(this) {}
 
-ImageManager::ImageManager(scoped_ptr<ImageFetcher> image_fetcher,
-                           scoped_ptr<ProtoDatabase<ImageData> > database,
-                           const base::FilePath& database_dir)
+ImageManager::ImageManager(
+    scoped_ptr<ImageFetcher> image_fetcher,
+    scoped_ptr<ProtoDatabase<ImageData>> database,
+    const base::FilePath& database_dir,
+    scoped_refptr<base::TaskRunner> background_task_runner)
     : image_fetcher_(image_fetcher.Pass()),
       database_(database.Pass()),
+      background_task_runner_(background_task_runner),
       database_ready_(false),
       weak_ptr_factory_(this) {
   image_fetcher_->SetImageFetcherDelegate(this);
@@ -95,57 +110,68 @@
   }
 }
 
-void ImageManager::ServeFromCacheOrNetwork(
-    const GURL& url, const GURL& image_url,
-    base::Callback<void(const GURL&, const SkBitmap*)> callback) {
-  // If there is a image available in memory, return it.
-  if (!ServeFromCache(url, callback)) {
+void ImageManager::OnCacheImageDecoded(
+    const GURL& url,
+    const GURL& image_url,
+    base::Callback<void(const GURL&, const SkBitmap*)> callback,
+    scoped_ptr<SkBitmap> bitmap) {
+  if (bitmap.get()) {
+    callback.Run(url, bitmap.get());
+  } else {
     image_fetcher_->StartOrQueueNetworkRequest(url, image_url, callback);
   }
 }
 
-bool ImageManager::ServeFromCache(
-    const GURL& url,
-    base::Callback<void(const GURL&, const SkBitmap*)> callback) {
-  SkBitmap* bitmap = GetBitmapFromCache(url);
-  if (bitmap) {
-    callback.Run(url, bitmap);
-    return true;
-  }
-  return false;
-}
-
-SkBitmap* ImageManager::GetBitmapFromCache(const GURL& url) {
+scoped_refptr<base::RefCountedMemory> ImageManager::GetEncodedImageFromCache(
+    const GURL& url) {
   ImageMap::iterator image_iter = image_map_.find(url.spec());
   if (image_iter != image_map_.end()) {
-    return &image_iter->second;
+    return image_iter->second;
   }
-  return NULL;
+  return nullptr;
+}
+
+void ImageManager::ServeFromCacheOrNetwork(
+    const GURL& url,
+    const GURL& image_url,
+    base::Callback<void(const GURL&, const SkBitmap*)> callback) {
+  scoped_refptr<base::RefCountedMemory> encoded_data =
+      GetEncodedImageFromCache(url);
+  if (encoded_data.get()) {
+    base::PostTaskAndReplyWithResult(
+        background_task_runner_.get(), FROM_HERE,
+        base::Bind(&DecodeImage, encoded_data),
+        base::Bind(&ImageManager::OnCacheImageDecoded,
+                   weak_ptr_factory_.GetWeakPtr(), url, image_url, callback));
+  } else {
+    image_fetcher_->StartOrQueueNetworkRequest(url, image_url, callback);
+  }
 }
 
 void ImageManager::SaveImage(const GURL& url, const SkBitmap& bitmap) {
+  scoped_refptr<base::RefCountedBytes> encoded_data(
+      new base::RefCountedBytes());
+  if (!EncodeSkBitmapToJPEG(bitmap, &encoded_data->data())) {
+    return;
+  }
+
   // Update the image map.
-  image_map_.insert(std::make_pair(url.spec(), bitmap));
+  image_map_.insert({url.spec(), encoded_data});
 
   if (!database_ready_) return;
 
-  // Attempt to save a JPEG representation to the database. If not successful,
-  // the fetched bitmap will still be inserted in the cache, above.
-  std::vector<unsigned char> encoded_data;
-  if (EncodeSkBitmapToJPEG(bitmap, &encoded_data)) {
-    // Save the resulting bitmap to the database.
-    ImageData data;
-    data.set_url(url.spec());
-    data.set_data(std::string(encoded_data.begin(), encoded_data.end()));
-    scoped_ptr<ProtoDatabase<ImageData>::KeyEntryVector> entries_to_save(
-        new ProtoDatabase<ImageData>::KeyEntryVector());
-    scoped_ptr<std::vector<std::string> > keys_to_remove(
-        new std::vector<std::string>());
-    entries_to_save->push_back(std::make_pair(data.url(), data));
-    database_->UpdateEntries(entries_to_save.Pass(), keys_to_remove.Pass(),
-                             base::Bind(&ImageManager::OnDatabaseSave,
-                                        weak_ptr_factory_.GetWeakPtr()));
-  }
+  // Save the resulting bitmap to the database.
+  ImageData data;
+  data.set_url(url.spec());
+  data.set_data(encoded_data->front(), encoded_data->size());
+  scoped_ptr<ProtoDatabase<ImageData>::KeyEntryVector> entries_to_save(
+      new ProtoDatabase<ImageData>::KeyEntryVector());
+  scoped_ptr<std::vector<std::string>> keys_to_remove(
+      new std::vector<std::string>());
+  entries_to_save->push_back(std::make_pair(data.url(), data));
+  database_->UpdateEntries(entries_to_save.Pass(), keys_to_remove.Pass(),
+                           base::Bind(&ImageManager::OnDatabaseSave,
+                                      weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ImageManager::OnDatabaseInit(bool success) {
@@ -187,10 +213,8 @@
     std::vector<unsigned char> encoded_data(it->data().begin(),
                                             it->data().end());
 
-    scoped_ptr<SkBitmap> bitmap(DecodeJPEGToSkBitmap(encoded_data));
-    if (bitmap.get()) {
-      image_map_.insert(std::make_pair(it->url(), *bitmap));
-    }
+    image_map_.insert(
+        {it->url(), base::RefCountedBytes::TakeVector(&encoded_data)});
   }
 }
 
diff --git a/components/suggestions/image_manager.h b/components/suggestions/image_manager.h
index 99ae55e..851d1cd 100644
--- a/components/suggestions/image_manager.h
+++ b/components/suggestions/image_manager.h
@@ -12,8 +12,10 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/task_runner.h"
 #include "base/threading/thread_checker.h"
 #include "components/leveldb_proto/proto_database.h"
 #include "components/suggestions/image_fetcher_delegate.h"
@@ -38,8 +40,9 @@
   typedef std::vector<ImageData> ImageDataVector;
 
   ImageManager(scoped_ptr<ImageFetcher> image_fetcher,
-               scoped_ptr<leveldb_proto::ProtoDatabase<ImageData> > database,
-               const base::FilePath& database_dir);
+               scoped_ptr<leveldb_proto::ProtoDatabase<ImageData>> database,
+               const base::FilePath& database_dir,
+               scoped_refptr<base::TaskRunner> background_task_runner);
   ~ImageManager() override;
 
   virtual void Initialize(const SuggestionsProfile& suggestions);
@@ -66,7 +69,8 @@
 
   typedef std::vector<base::Callback<void(const GURL&, const SkBitmap*)> >
       CallbackVector;
-  typedef base::hash_map<std::string, SkBitmap> ImageMap;
+  typedef base::hash_map<std::string, scoped_refptr<base::RefCountedMemory>>
+      ImageMap;
 
   // State related to an image fetch (associated website url, image_url,
   // pending callbacks).
@@ -95,14 +99,15 @@
       const GURL& url, const GURL& image_url,
       base::Callback<void(const GURL&, const SkBitmap*)> callback);
 
-  // Will return false if no bitmap was found corresponding to |url|, else
-  // return true and call |callback| with the found bitmap.
-  bool ServeFromCache(
+  void OnCacheImageDecoded(
       const GURL& url,
-      base::Callback<void(const GURL&, const SkBitmap*)> callback);
+      const GURL& image_url,
+      base::Callback<void(const GURL&, const SkBitmap*)> callback,
+      scoped_ptr<SkBitmap> bitmap);
 
   // Returns null if the |url| had no entry in the cache.
-  SkBitmap* GetBitmapFromCache(const GURL& url);
+  scoped_refptr<base::RefCountedMemory> GetEncodedImageFromCache(
+      const GURL& url);
 
   // Save the image bitmap in the cache and in the database.
   void SaveImage(const GURL& url, const SkBitmap& bitmap);
@@ -134,6 +139,8 @@
 
   scoped_ptr<leveldb_proto::ProtoDatabase<ImageData> > database_;
 
+  scoped_refptr<base::TaskRunner> background_task_runner_;
+
   bool database_ready_;
 
   base::ThreadChecker thread_checker_;
diff --git a/components/suggestions/image_manager_unittest.cc b/components/suggestions/image_manager_unittest.cc
index e9d16e3..c52b54c 100644
--- a/components/suggestions/image_manager_unittest.cc
+++ b/components/suggestions/image_manager_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file_path.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "components/leveldb_proto/proto_database.h"
 #include "components/leveldb_proto/testing/fake_db.h"
 #include "components/suggestions/image_encoder.h"
@@ -113,8 +114,9 @@
     EXPECT_CALL(*mock_image_fetcher_, SetImageFetcherDelegate(_));
     return new ImageManager(
         scoped_ptr<ImageFetcher>(mock_image_fetcher_),
-        scoped_ptr<leveldb_proto::ProtoDatabase<ImageData> >(fake_db),
-        FakeDB<ImageData>::DirectoryForTestDB());
+        scoped_ptr<leveldb_proto::ProtoDatabase<ImageData>>(fake_db),
+        FakeDB<ImageData>::DirectoryForTestDB(),
+        base::ThreadTaskRunnerHandle::Get());
   }
 
   EntryMap db_model_;
@@ -125,6 +127,9 @@
 
   int num_callback_null_called_;
   int num_callback_valid_called_;
+
+  base::MessageLoop message_loop_;
+
   // Under test.
   scoped_ptr<ImageManager> image_manager_;
 };
@@ -181,8 +186,9 @@
   fake_db->InitCallback(true);
   fake_db->LoadCallback(true);
   // Expect something in the cache.
-  SkBitmap* bitmap = image_manager_->GetBitmapFromCache(GURL(kTestUrl1));
-  EXPECT_FALSE(bitmap->isNull());
+  auto encoded_image =
+      image_manager_->GetEncodedImageFromCache(GURL(kTestUrl1));
+  EXPECT_NE(nullptr, encoded_image);
 
   base::RunLoop run_loop;
   image_manager_->GetImageForURL(GURL(kTestUrl1),
diff --git a/components/suggestions/suggestions_service.cc b/components/suggestions/suggestions_service.cc
index dde38a1..f8f13988 100644
--- a/components/suggestions/suggestions_service.cc
+++ b/components/suggestions/suggestions_service.cc
@@ -178,9 +178,8 @@
 // static
 bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request,
                                            GURL* url) {
-  bool is_blacklist_request = StartsWithASCII(request.GetOriginalURL().spec(),
-                                              kSuggestionsBlacklistURLPrefix,
-                                              true);
+  bool is_blacklist_request = base::StartsWithASCII(
+      request.GetOriginalURL().spec(), kSuggestionsBlacklistURLPrefix, true);
   if (!is_blacklist_request) return false;
 
   // Extract the blacklisted URL from the blacklist request.
diff --git a/components/sync_driver.gypi b/components/sync_driver.gypi
index d21d558..b26789e 100644
--- a/components/sync_driver.gypi
+++ b/components/sync_driver.gypi
@@ -105,6 +105,8 @@
         'sync_driver/fake_data_type_controller.h',
         'sync_driver/fake_generic_change_processor.cc',
         'sync_driver/fake_generic_change_processor.h',
+        'sync_driver/fake_sync_service.cc',
+        'sync_driver/fake_sync_service.h',
         'sync_driver/local_device_info_provider_mock.cc',
         'sync_driver/local_device_info_provider_mock.h',
         'sync_driver/model_associator_mock.cc',
diff --git a/components/sync_driver/DEPS b/components/sync_driver/DEPS
index 409d433..c0baa83 100644
--- a/components/sync_driver/DEPS
+++ b/components/sync_driver/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+components/os_crypt",
   "+components/pref_registry",
+  "+google_apis",
   "+sync",
 ]
diff --git a/components/sync_driver/fake_sync_service.cc b/components/sync_driver/fake_sync_service.cc
new file mode 100644
index 0000000..51d0f0908
--- /dev/null
+++ b/components/sync_driver/fake_sync_service.cc
@@ -0,0 +1,125 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync_driver/fake_sync_service.h"
+
+namespace sync_driver {
+
+FakeSyncService::FakeSyncService() : error_(GoogleServiceAuthError::NONE) {
+}
+
+FakeSyncService::~FakeSyncService() {
+}
+
+bool FakeSyncService::HasSyncSetupCompleted() const {
+  return false;
+}
+
+bool FakeSyncService::IsSyncAllowed() const {
+  return false;
+}
+
+bool FakeSyncService::IsSyncActive() const {
+  return false;
+}
+
+syncer::ModelTypeSet FakeSyncService::GetActiveDataTypes() const {
+  return syncer::ModelTypeSet();
+}
+
+void FakeSyncService::AddObserver(sync_driver::SyncServiceObserver* observer) {
+}
+
+void FakeSyncService::RemoveObserver(
+    sync_driver::SyncServiceObserver* observer) {
+}
+
+bool FakeSyncService::HasObserver(
+    const sync_driver::SyncServiceObserver* observer) const {
+  return false;
+}
+
+bool FakeSyncService::IsSyncEnabledAndLoggedIn() {
+  return false;
+}
+
+void FakeSyncService::DisableForUser() {
+}
+
+void FakeSyncService::RequestStop() {
+}
+
+void FakeSyncService::RequestStart() {
+}
+
+syncer::ModelTypeSet FakeSyncService::GetPreferredDataTypes() const {
+  return syncer::ModelTypeSet();
+}
+
+void FakeSyncService::OnUserChoseDatatypes(bool sync_everything,
+                                           syncer::ModelTypeSet chosen_types) {
+}
+
+void FakeSyncService::SetSyncSetupCompleted() {
+}
+
+bool FakeSyncService::FirstSetupInProgress() const {
+  return false;
+}
+
+void FakeSyncService::SetSetupInProgress(bool setup_in_progress) {
+}
+
+bool FakeSyncService::setup_in_progress() const {
+  return false;
+}
+
+bool FakeSyncService::ConfigurationDone() const {
+  return false;
+}
+
+const GoogleServiceAuthError& FakeSyncService::GetAuthError() const {
+  return error_;
+}
+
+bool FakeSyncService::HasUnrecoverableError() const {
+  return false;
+}
+
+bool FakeSyncService::backend_initialized() const {
+  return false;
+}
+
+bool FakeSyncService::IsPassphraseRequiredForDecryption() const {
+  return false;
+}
+
+base::Time FakeSyncService::GetExplicitPassphraseTime() const {
+  return base::Time();
+}
+
+bool FakeSyncService::IsUsingSecondaryPassphrase() const {
+  return false;
+}
+
+void FakeSyncService::EnableEncryptEverything() {
+}
+
+void FakeSyncService::SetEncryptionPassphrase(const std::string& passphrase,
+                                              PassphraseType type) {
+}
+
+bool FakeSyncService::SetDecryptionPassphrase(const std::string& passphrase) {
+  return false;
+}
+
+bool FakeSyncService::IsPassphraseRequired() const {
+  return false;
+}
+
+syncer::ModelTypeSet FakeSyncService::GetEncryptedDataTypes() const {
+  return syncer::ModelTypeSet();
+}
+
+}  // namespace sync_driver
diff --git a/components/sync_driver/fake_sync_service.h b/components/sync_driver/fake_sync_service.h
new file mode 100644
index 0000000..0892f4a3
--- /dev/null
+++ b/components/sync_driver/fake_sync_service.h
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_DRIVER_FAKE_SYNC_SERVICE_H_
+#define COMPONENTS_SYNC_DRIVER_FAKE_SYNC_SERVICE_H_
+
+#include "components/sync_driver/sync_service.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+
+namespace sync_driver {
+
+// Fake implementation of sync_driver::SyncService, used for testing.
+class FakeSyncService : public sync_driver::SyncService {
+ public:
+  FakeSyncService();
+  ~FakeSyncService() override;
+
+ private:
+  // sync_driver::SyncService:
+  bool HasSyncSetupCompleted() const override;
+  bool IsSyncAllowed() const override;
+  bool IsSyncActive() const override;
+  syncer::ModelTypeSet GetActiveDataTypes() const override;
+  void AddObserver(sync_driver::SyncServiceObserver* observer) override;
+  void RemoveObserver(sync_driver::SyncServiceObserver* observer) override;
+  bool HasObserver(
+      const sync_driver::SyncServiceObserver* observer) const override;
+  bool IsSyncEnabledAndLoggedIn() override;
+  void DisableForUser() override;
+  void RequestStop() override;
+  void RequestStart() override;
+  syncer::ModelTypeSet GetPreferredDataTypes() const override;
+  void OnUserChoseDatatypes(bool sync_everything,
+                            syncer::ModelTypeSet chosen_types) override;
+  void SetSyncSetupCompleted() override;
+  bool FirstSetupInProgress() const override;
+  void SetSetupInProgress(bool setup_in_progress) override;
+  bool setup_in_progress() const override;
+  bool ConfigurationDone() const override;
+  const GoogleServiceAuthError& GetAuthError() const override;
+  bool HasUnrecoverableError() const override;
+  bool backend_initialized() const override;
+  bool IsPassphraseRequiredForDecryption() const override;
+  base::Time GetExplicitPassphraseTime() const override;
+  bool IsUsingSecondaryPassphrase() const override;
+  void EnableEncryptEverything() override;
+  void SetEncryptionPassphrase(const std::string& passphrase,
+                               PassphraseType type) override;
+  bool SetDecryptionPassphrase(const std::string& passphrase) override;
+
+  // sync_driver::DataTypeEncryptionHandler:
+  bool IsPassphraseRequired() const override;
+  syncer::ModelTypeSet GetEncryptedDataTypes() const override;
+
+  GoogleServiceAuthError error_;
+};
+
+}  // namespace sync_driver
+
+#endif  // COMPONENTS_SYNC_DRIVER_FAKE_SYNC_SERVICE_H_
diff --git a/components/sync_driver/generic_change_processor.cc b/components/sync_driver/generic_change_processor.cc
index 2bd0264..114c655 100644
--- a/components/sync_driver/generic_change_processor.cc
+++ b/components/sync_driver/generic_change_processor.cc
@@ -521,13 +521,6 @@
         LOG(ERROR) << "Create: Empty tag.";
         return error;
       }
-      case syncer::WriteNode::INIT_FAILED_ENTRY_ALREADY_EXISTS: {
-        syncer::SyncError error;
-        error.Reset(FROM_HERE, error_prefix + "entry already exists", type_);
-        error_handler()->OnSingleDataTypeUnrecoverableError(error);
-        LOG(ERROR) << "Create: Entry exists.";
-        return error;
-      }
       case syncer::WriteNode::INIT_FAILED_COULD_NOT_CREATE_ENTRY: {
         syncer::SyncError error;
         error.Reset(FROM_HERE, error_prefix + "failed to create entry", type_);
@@ -575,8 +568,6 @@
     const syncer::WriteTransaction& trans,
     syncer::WriteNode* sync_node,
     syncer::AttachmentIdSet* new_attachments) {
-  // TODO(zea): consider having this logic for all possible changes?
-
   const syncer::SyncDataLocal sync_data_local(change.sync_data());
   syncer::BaseNode::InitByLookupResult result =
       sync_node->InitByClientTagLookup(sync_data_local.GetDataType(),
diff --git a/components/sync_driver/generic_change_processor_unittest.cc b/components/sync_driver/generic_change_processor_unittest.cc
index 9d34f11..f7ed432 100644
--- a/components/sync_driver/generic_change_processor_unittest.cc
+++ b/components/sync_driver/generic_change_processor_unittest.cc
@@ -479,6 +479,41 @@
               testing::UnorderedElementsAre(id1));
 }
 
+// Test that attempting to add an entry that already exists still works.
+TEST_F(SyncGenericChangeProcessorTest, AddExistingEntry) {
+  InitializeForType(syncer::SESSIONS);
+  sync_pb::EntitySpecifics sessions_specifics;
+  sessions_specifics.mutable_session()->set_session_tag("session tag");
+  syncer::SyncChangeList changes;
+
+  // First add it normally.
+  changes.push_back(syncer::SyncChange(
+      FROM_HERE, syncer::SyncChange::ACTION_ADD,
+      syncer::SyncData::CreateLocalData(base::StringPrintf("tag"),
+                                        base::StringPrintf("title"),
+                                        sessions_specifics)));
+  ASSERT_FALSE(
+      change_processor()->ProcessSyncChanges(FROM_HERE, changes).IsSet());
+
+  // Now attempt to add it again, but with different specifics. Should not
+  // result in an error and should still update the specifics.
+  sessions_specifics.mutable_session()->set_session_tag("session tag 2");
+  changes[0] =
+      syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD,
+                         syncer::SyncData::CreateLocalData(
+                             base::StringPrintf("tag"),
+                             base::StringPrintf("title"), sessions_specifics));
+  ASSERT_FALSE(
+      change_processor()->ProcessSyncChanges(FROM_HERE, changes).IsSet());
+
+  // Verify the data was updated properly.
+  syncer::SyncDataList sync_data =
+      change_processor()->GetAllSyncData(syncer::SESSIONS);
+  ASSERT_EQ(sync_data.size(), 1U);
+  ASSERT_EQ("session tag 2",
+            sync_data[0].GetSpecifics().session().session_tag());
+}
+
 }  // namespace
 
 }  // namespace sync_driver
diff --git a/components/sync_driver/sync_prefs.cc b/components/sync_driver/sync_prefs.cc
index d2cf0980..03fb65a 100644
--- a/components/sync_driver/sync_prefs.cc
+++ b/components/sync_driver/sync_prefs.cc
@@ -120,7 +120,7 @@
 void SyncPrefs::SetSyncSetupCompleted() {
   DCHECK(CalledOnValidThread());
   pref_service_->SetBoolean(prefs::kSyncHasSetupCompleted, true);
-  SetStartSuppressed(false);
+  SetSyncRequested(true);
 }
 
 bool SyncPrefs::SyncHasAuthError() const {
@@ -133,14 +133,17 @@
   pref_service_->SetBoolean(prefs::kSyncHasAuthError, error);
 }
 
-bool SyncPrefs::IsStartSuppressed() const {
+bool SyncPrefs::IsSyncRequested() const {
   DCHECK(CalledOnValidThread());
-  return pref_service_->GetBoolean(prefs::kSyncSuppressStart);
+  // IsSyncRequested is the inverse of the old SuppressStart pref.
+  // Since renaming a pref value is hard, here we still use the old one.
+  return !pref_service_->GetBoolean(prefs::kSyncSuppressStart);
 }
 
-void SyncPrefs::SetStartSuppressed(bool is_suppressed) {
+void SyncPrefs::SetSyncRequested(bool is_requested) {
   DCHECK(CalledOnValidThread());
-  pref_service_->SetBoolean(prefs::kSyncSuppressStart, is_suppressed);
+  // See IsSyncRequested for why we use this pref and !is_requested.
+  pref_service_->SetBoolean(prefs::kSyncSuppressStart, !is_requested);
 }
 
 base::Time SyncPrefs::GetLastSyncedTime() const {
diff --git a/components/sync_driver/sync_prefs.h b/components/sync_driver/sync_prefs.h
index 4521c4e..372335e 100644
--- a/components/sync_driver/sync_prefs.h
+++ b/components/sync_driver/sync_prefs.h
@@ -74,8 +74,8 @@
   bool SyncHasAuthError() const;
   void SetSyncAuthError(bool error);
 
-  bool IsStartSuppressed() const;
-  void SetStartSuppressed(bool is_suppressed);
+  bool IsSyncRequested() const;
+  void SetSyncRequested(bool is_requested);
 
   base::Time GetLastSyncedTime() const;
   void SetLastSyncedTime(base::Time time);
diff --git a/components/sync_driver/sync_prefs_unittest.cc b/components/sync_driver/sync_prefs_unittest.cc
index 69c0066b..d87b0117 100644
--- a/components/sync_driver/sync_prefs_unittest.cc
+++ b/components/sync_driver/sync_prefs_unittest.cc
@@ -42,11 +42,11 @@
   sync_prefs.SetSyncSetupCompleted();
   EXPECT_TRUE(sync_prefs.HasSyncSetupCompleted());
 
-  EXPECT_FALSE(sync_prefs.IsStartSuppressed());
-  sync_prefs.SetStartSuppressed(true);
-  EXPECT_TRUE(sync_prefs.IsStartSuppressed());
-  sync_prefs.SetStartSuppressed(false);
-  EXPECT_FALSE(sync_prefs.IsStartSuppressed());
+  EXPECT_TRUE(sync_prefs.IsSyncRequested());
+  sync_prefs.SetSyncRequested(false);
+  EXPECT_FALSE(sync_prefs.IsSyncRequested());
+  sync_prefs.SetSyncRequested(true);
+  EXPECT_TRUE(sync_prefs.IsSyncRequested());
 
   EXPECT_EQ(base::Time(), sync_prefs.GetLastSyncedTime());
   const base::Time& now = base::Time::Now();
diff --git a/components/sync_driver/sync_service.h b/components/sync_driver/sync_service.h
index afe1e29..476f1de 100644
--- a/components/sync_driver/sync_service.h
+++ b/components/sync_driver/sync_service.h
@@ -35,6 +35,11 @@
   // is actually running.
   virtual bool HasSyncSetupCompleted() const = 0;
 
+  // Whether sync is allowed to start. Command line flags, platform-level
+  // overrides, and account-level overrides are examples of reasons this
+  // might be false.
+  virtual bool IsSyncAllowed() const = 0;
+
   // Returns true if sync is fully initialized and active. This implies that
   // an initial configuration has successfully completed, although there may
   // be datatype specific, auth, or other transient errors. To see which
@@ -69,17 +74,20 @@
   // Virtual to enable mocking in tests.
   // TODO(tim): Remove this? Nothing in ProfileSyncService uses it, and outside
   // callers use a seemingly arbitrary / redundant / bug prone combination of
-  // this method, IsSyncAccessible, and others.
+  // this method, IsSyncAllowed, and others.
   virtual bool IsSyncEnabledAndLoggedIn() = 0;
 
   // Disables sync for user. Use ShowLoginDialog to enable.
   virtual void DisableForUser() = 0;
 
-  // Stops the sync backend and sets the flag for suppressing sync startup.
-  virtual void StopAndSuppress() = 0;
+  // Stops sync at the user's request.
+  virtual void RequestStop() = 0;
 
-  // Resets the flag for suppressing sync startup and starts the sync backend.
-  virtual void UnsuppressAndStart() = 0;
+  // The user requests that sync start. This only actually starts sync if
+  // IsSyncAllowed is true and the user is signed in. Once sync starts,
+  // other things such as HasSyncSetupCompleted being false can still prevent
+  // it from moving into the "active" state.
+  virtual void RequestStart() = 0;
 
   // Returns the set of types which are preferred for enabling. This is a
   // superset of the active types (see GetActiveDataTypes()).
diff --git a/components/test/data/dom_distiller/pinch_tester.html b/components/test/data/dom_distiller/pinch_tester.html
index 9dbb48d..b6accd34 100644
--- a/components/test/data/dom_distiller/pinch_tester.html
+++ b/components/test/data/dom_distiller/pinch_tester.html
@@ -2,7 +2,7 @@
 <head><title>Test Page for Pinch to Zoom</title></head>
 <body>
 <div id="contentWrap">
-<p id="showOriginal">Original</p>
+<p id="closeReaderView">Original</p>
 </div>
 <div id="feedbackContainer">
   <div id="feedbackYes"></div>
diff --git a/components/test_runner/mock_screen_orientation_client.h b/components/test_runner/mock_screen_orientation_client.h
index 3985c89..2a2b442 100644
--- a/components/test_runner/mock_screen_orientation_client.h
+++ b/components/test_runner/mock_screen_orientation_client.h
@@ -8,10 +8,10 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "components/test_runner/test_runner_export.h"
-#include "third_party/WebKit/public/platform/WebLockOrientationCallback.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationClient.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationCallback.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationClient.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
 
 namespace blink {
 class WebLocalFrame;
diff --git a/components/test_runner/web_ax_object_proxy.cc b/components/test_runner/web_ax_object_proxy.cc
index ae12816..125507b 100644
--- a/components/test_runner/web_ax_object_proxy.cc
+++ b/components/test_runner/web_ax_object_proxy.cc
@@ -498,6 +498,7 @@
                    &WebAXObjectProxy::SelectionEndLineNumber)
       .SetProperty("isEnabled", &WebAXObjectProxy::IsEnabled)
       .SetProperty("isRequired", &WebAXObjectProxy::IsRequired)
+      .SetProperty("isRichlyEditable", &WebAXObjectProxy::IsRichlyEditable)
       .SetProperty("isFocused", &WebAXObjectProxy::IsFocused)
       .SetProperty("isFocusable", &WebAXObjectProxy::IsFocusable)
       .SetProperty("isSelected", &WebAXObjectProxy::IsSelected)
@@ -760,6 +761,11 @@
   return accessibility_object_.isRequired();
 }
 
+bool WebAXObjectProxy::IsRichlyEditable() {
+  accessibility_object_.updateLayoutAndCheckValidity();
+  return accessibility_object_.isRichlyEditable();
+}
+
 bool WebAXObjectProxy::IsFocused() {
   accessibility_object_.updateLayoutAndCheckValidity();
   return accessibility_object_.isFocused();
diff --git a/components/test_runner/web_ax_object_proxy.h b/components/test_runner/web_ax_object_proxy.h
index b9abcaf..1b8c469 100644
--- a/components/test_runner/web_ax_object_proxy.h
+++ b/components/test_runner/web_ax_object_proxy.h
@@ -75,6 +75,7 @@
   int SelectionEndLineNumber();
   bool IsEnabled();
   bool IsRequired();
+  bool IsRichlyEditable();
   bool IsFocused();
   bool IsFocusable();
   bool IsSelected();
diff --git a/components/test_runner/web_test_delegate.h b/components/test_runner/web_test_delegate.h
index e921eae..a1bc3c3 100644
--- a/components/test_runner/web_test_delegate.h
+++ b/components/test_runner/web_test_delegate.h
@@ -10,10 +10,10 @@
 
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
 
 #define WEBTESTRUNNER_NEW_HISTORY_CAPTURE
 
diff --git a/components/translate/content/renderer/translate_helper.cc b/components/translate/content/renderer/translate_helper.cc
index a17f351..a020f0a5 100644
--- a/components/translate/content/renderer/translate_helper.cc
+++ b/components/translate/content/renderer/translate_helper.cc
@@ -116,7 +116,7 @@
       attribute = element.getAttribute(content);
     if (attribute.isNull())
       continue;
-    if (LowerCaseEqualsASCII(attribute, "notranslate"))
+    if (base::LowerCaseEqualsASCII(attribute, "notranslate"))
       return true;
   }
   return false;
diff --git a/components/translate/core/browser/translate_language_list.cc b/components/translate/core/browser/translate_language_list.cc
index 959b576..1b1bfed 100644
--- a/components/translate/core/browser/translate_language_list.cc
+++ b/components/translate/core/browser/translate_language_list.cc
@@ -264,9 +264,9 @@
   // })
   // Where "sl(" is set in kLanguageListCallbackName, "tl" is
   // kTargetLanguagesKey and "al" kAlphaLanguagesKey.
-  if (!StartsWithASCII(language_list,
-                       TranslateLanguageList::kLanguageListCallbackName,
-                       false) ||
+  if (!base::StartsWithASCII(language_list,
+                             TranslateLanguageList::kLanguageListCallbackName,
+                             false) ||
       !EndsWith(language_list, ")", false)) {
     // We don't have a NOTREACHED here since this can happen in ui_tests, even
     // though the the BrowserMain function won't call us with parameters.ui_task
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc
index d31dab4..768be0e 100644
--- a/components/translate/core/browser/translate_prefs.cc
+++ b/components/translate/core/browser/translate_prefs.cc
@@ -509,8 +509,8 @@
   const std::string& app_locale =
       TranslateDownloadManager::GetInstance()->application_locale();
   std::string ui_lang = TranslateDownloadManager::GetLanguageCode(app_locale);
-  bool is_ui_english = ui_lang == "en" ||
-      StartsWithASCII(ui_lang, "en-", false);
+  bool is_ui_english =
+      ui_lang == "en" || base::StartsWithASCII(ui_lang, "en-", false);
 
   for (std::vector<std::string>::const_iterator it = accept_languages.begin();
        it != accept_languages.end(); ++it) {
diff --git a/components/translate/core/language_detection/language_detection_util.cc b/components/translate/core/language_detection/language_detection_util.cc
index ab25a7530..9556bb9 100644
--- a/components/translate/core/language_detection/language_detection_util.cc
+++ b/components/translate/core/language_detection/language_detection_util.cc
@@ -197,7 +197,8 @@
   // CLD agree that the language is Chinese and Content-Language doesn't know
   // which dialect is used, CLD language has priority.
   // TODO(hajimehoshi): How about the other dialects like zh-MO?
-  return page_language == "zh" && StartsWithASCII(cld_language, "zh-", false);
+  return page_language == "zh" &&
+         base::StartsWithASCII(cld_language, "zh-", false);
 }
 
 }  // namespace
@@ -301,7 +302,7 @@
   size_t dash_index = code->find('-');
   if (dash_index != std::string::npos) {
     *code = base::StringToLowerASCII(code->substr(0, dash_index)) +
-        StringToUpperASCII(code->substr(dash_index));
+        base::StringToUpperASCII(code->substr(dash_index));
   } else {
     *code = base::StringToLowerASCII(*code);
   }
@@ -380,7 +381,7 @@
 bool MaybeServerWrongConfiguration(const std::string& page_language,
                                    const std::string& cld_language) {
   // If |page_language| is not "en-*", respect it and just return false here.
-  if (!StartsWithASCII(page_language, "en", false))
+  if (!base::StartsWithASCII(page_language, "en", false))
     return false;
 
   // A server provides a language meta information representing "en-*". But it
diff --git a/components/update_client/configurator.h b/components/update_client/configurator.h
index 4bb103e..3cd3b674 100644
--- a/components/update_client/configurator.h
+++ b/components/update_client/configurator.h
@@ -78,9 +78,6 @@
   // XML element.
   virtual std::string ExtraRequestParams() const = 0;
 
-  // How big each update request can be. Don't go above 2000.
-  virtual size_t UrlSizeLimit() const = 0;
-
   // The source of contexts for all the url requests.
   virtual net::URLRequestContextGetter* RequestContext() const = 0;
 
diff --git a/components/update_client/request_sender.cc b/components/update_client/request_sender.cc
index 6b89ca7..f91cbabf 100644
--- a/components/update_client/request_sender.cc
+++ b/components/update_client/request_sender.cc
@@ -28,7 +28,8 @@
                          const RequestSenderCallback& request_sender_callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (urls.empty()) {
-    request_sender_callback.Run(NULL);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(request_sender_callback, nullptr));
     return;
   }
 
@@ -64,7 +65,8 @@
     return;
   }
 
-  request_sender_callback_.Run(source);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(request_sender_callback_, source));
 }
 
 }  // namespace update_client
diff --git a/components/update_client/request_sender_unittest.cc b/components/update_client/request_sender_unittest.cc
index 459aea5..4f7a309 100644
--- a/components/update_client/request_sender_unittest.cc
+++ b/components/update_client/request_sender_unittest.cc
@@ -45,8 +45,8 @@
   scoped_ptr<RequestSender> request_sender_;
   scoped_ptr<InterceptorFactory> interceptor_factory_;
 
-  URLRequestPostInterceptor* post_interceptor_1;  // Owned by the factory.
-  URLRequestPostInterceptor* post_interceptor_2;  // Owned by the factory.
+  URLRequestPostInterceptor* post_interceptor_1_;  // Owned by the factory.
+  URLRequestPostInterceptor* post_interceptor_2_;  // Owned by the factory.
 
   const net::URLFetcher* url_fetcher_source_;
 
@@ -58,9 +58,9 @@
 };
 
 RequestSenderTest::RequestSenderTest()
-    : post_interceptor_1(NULL),
-      post_interceptor_2(NULL),
-      url_fetcher_source_(NULL) {
+    : post_interceptor_1_(nullptr),
+      post_interceptor_2_(nullptr),
+      url_fetcher_source_(nullptr) {
 }
 
 RequestSenderTest::~RequestSenderTest() {
@@ -71,12 +71,12 @@
                                  base::ThreadTaskRunnerHandle::Get());
   interceptor_factory_.reset(
       new InterceptorFactory(base::ThreadTaskRunnerHandle::Get()));
-  post_interceptor_1 =
+  post_interceptor_1_ =
       interceptor_factory_->CreateInterceptorForPath(kUrlPath1);
-  post_interceptor_2 =
+  post_interceptor_2_ =
       interceptor_factory_->CreateInterceptorForPath(kUrlPath2);
-  EXPECT_TRUE(post_interceptor_1);
-  EXPECT_TRUE(post_interceptor_2);
+  EXPECT_TRUE(post_interceptor_1_);
+  EXPECT_TRUE(post_interceptor_2_);
 
   request_sender_.reset();
 }
@@ -84,8 +84,8 @@
 void RequestSenderTest::TearDown() {
   request_sender_.reset();
 
-  post_interceptor_1 = NULL;
-  post_interceptor_2 = NULL;
+  post_interceptor_1_ = nullptr;
+  post_interceptor_2_ = nullptr;
 
   interceptor_factory_.reset();
 
@@ -123,7 +123,7 @@
 // Tests that when a request to the first url succeeds, the subsequent urls are
 // not tried.
 TEST_F(RequestSenderTest, RequestSendSuccess) {
-  EXPECT_TRUE(post_interceptor_1->ExpectRequest(new PartialMatch("test")));
+  EXPECT_TRUE(post_interceptor_1_->ExpectRequest(new PartialMatch("test")));
 
   std::vector<GURL> urls;
   urls.push_back(GURL(kUrl1));
@@ -134,12 +134,12 @@
                                    base::Unretained(this)));
   RunThreads();
 
-  EXPECT_EQ(1, post_interceptor_1->GetHitCount())
-      << post_interceptor_1->GetRequestsAsString();
-  EXPECT_EQ(1, post_interceptor_1->GetCount())
-      << post_interceptor_1->GetRequestsAsString();
+  EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
+      << post_interceptor_1_->GetRequestsAsString();
+  EXPECT_EQ(1, post_interceptor_1_->GetCount())
+      << post_interceptor_1_->GetRequestsAsString();
 
-  EXPECT_STREQ("test", post_interceptor_1->GetRequests()[0].c_str());
+  EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
   EXPECT_EQ(GURL(kUrl1), url_fetcher_source_->GetOriginalURL());
   EXPECT_EQ(200, url_fetcher_source_->GetResponseCode());
 }
@@ -147,8 +147,9 @@
 // Tests that the request succeeds using the second url after the first url
 // has failed.
 TEST_F(RequestSenderTest, RequestSendSuccessWithFallback) {
-  EXPECT_TRUE(post_interceptor_1->ExpectRequest(new PartialMatch("test"), 403));
-  EXPECT_TRUE(post_interceptor_2->ExpectRequest(new PartialMatch("test")));
+  EXPECT_TRUE(
+      post_interceptor_1_->ExpectRequest(new PartialMatch("test"), 403));
+  EXPECT_TRUE(post_interceptor_2_->ExpectRequest(new PartialMatch("test")));
 
   std::vector<GURL> urls;
   urls.push_back(GURL(kUrl1));
@@ -159,25 +160,27 @@
                                    base::Unretained(this)));
   RunThreads();
 
-  EXPECT_EQ(1, post_interceptor_1->GetHitCount())
-      << post_interceptor_1->GetRequestsAsString();
-  EXPECT_EQ(1, post_interceptor_1->GetCount())
-      << post_interceptor_1->GetRequestsAsString();
-  EXPECT_EQ(1, post_interceptor_2->GetHitCount())
-      << post_interceptor_2->GetRequestsAsString();
-  EXPECT_EQ(1, post_interceptor_2->GetCount())
-      << post_interceptor_2->GetRequestsAsString();
+  EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
+      << post_interceptor_1_->GetRequestsAsString();
+  EXPECT_EQ(1, post_interceptor_1_->GetCount())
+      << post_interceptor_1_->GetRequestsAsString();
+  EXPECT_EQ(1, post_interceptor_2_->GetHitCount())
+      << post_interceptor_2_->GetRequestsAsString();
+  EXPECT_EQ(1, post_interceptor_2_->GetCount())
+      << post_interceptor_2_->GetRequestsAsString();
 
-  EXPECT_STREQ("test", post_interceptor_1->GetRequests()[0].c_str());
-  EXPECT_STREQ("test", post_interceptor_2->GetRequests()[0].c_str());
+  EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
+  EXPECT_STREQ("test", post_interceptor_2_->GetRequests()[0].c_str());
   EXPECT_EQ(GURL(kUrl2), url_fetcher_source_->GetOriginalURL());
   EXPECT_EQ(200, url_fetcher_source_->GetResponseCode());
 }
 
 // Tests that the request fails when both urls have failed.
 TEST_F(RequestSenderTest, RequestSendFailed) {
-  EXPECT_TRUE(post_interceptor_1->ExpectRequest(new PartialMatch("test"), 403));
-  EXPECT_TRUE(post_interceptor_2->ExpectRequest(new PartialMatch("test"), 403));
+  EXPECT_TRUE(
+      post_interceptor_1_->ExpectRequest(new PartialMatch("test"), 403));
+  EXPECT_TRUE(
+      post_interceptor_2_->ExpectRequest(new PartialMatch("test"), 403));
 
   std::vector<GURL> urls;
   urls.push_back(GURL(kUrl1));
@@ -188,19 +191,31 @@
                                    base::Unretained(this)));
   RunThreads();
 
-  EXPECT_EQ(1, post_interceptor_1->GetHitCount())
-      << post_interceptor_1->GetRequestsAsString();
-  EXPECT_EQ(1, post_interceptor_1->GetCount())
-      << post_interceptor_1->GetRequestsAsString();
-  EXPECT_EQ(1, post_interceptor_2->GetHitCount())
-      << post_interceptor_2->GetRequestsAsString();
-  EXPECT_EQ(1, post_interceptor_2->GetCount())
-      << post_interceptor_2->GetRequestsAsString();
+  EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
+      << post_interceptor_1_->GetRequestsAsString();
+  EXPECT_EQ(1, post_interceptor_1_->GetCount())
+      << post_interceptor_1_->GetRequestsAsString();
+  EXPECT_EQ(1, post_interceptor_2_->GetHitCount())
+      << post_interceptor_2_->GetRequestsAsString();
+  EXPECT_EQ(1, post_interceptor_2_->GetCount())
+      << post_interceptor_2_->GetRequestsAsString();
 
-  EXPECT_STREQ("test", post_interceptor_1->GetRequests()[0].c_str());
-  EXPECT_STREQ("test", post_interceptor_2->GetRequests()[0].c_str());
+  EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
+  EXPECT_STREQ("test", post_interceptor_2_->GetRequests()[0].c_str());
   EXPECT_EQ(GURL(kUrl2), url_fetcher_source_->GetOriginalURL());
   EXPECT_EQ(403, url_fetcher_source_->GetResponseCode());
 }
 
+// Tests that the request fails when no urls are provided.
+TEST_F(RequestSenderTest, RequestSendFailedNoUrls) {
+  std::vector<GURL> urls;
+  request_sender_.reset(new RequestSender(*config_));
+  request_sender_->Send("test", urls,
+                        base::Bind(&RequestSenderTest::RequestSenderComplete,
+                                   base::Unretained(this)));
+  RunThreads();
+
+  EXPECT_EQ(nullptr, url_fetcher_source_);
+}
+
 }  // namespace update_client
diff --git a/components/update_client/test_configurator.cc b/components/update_client/test_configurator.cc
index a1dc0e5..a5cbd445 100644
--- a/components/update_client/test_configurator.cc
+++ b/components/update_client/test_configurator.cc
@@ -82,10 +82,6 @@
   return "extra=\"foo\"";
 }
 
-size_t TestConfigurator::UrlSizeLimit() const {
-  return 256;
-}
-
 net::URLRequestContextGetter* TestConfigurator::RequestContext() const {
   return context_.get();
 }
diff --git a/components/update_client/test_configurator.h b/components/update_client/test_configurator.h
index 8d67046..d979ba5 100644
--- a/components/update_client/test_configurator.h
+++ b/components/update_client/test_configurator.h
@@ -67,7 +67,6 @@
   std::string GetLang() const override;
   std::string GetOSLongName() const override;
   std::string ExtraRequestParams() const override;
-  size_t UrlSizeLimit() const override;
   net::URLRequestContextGetter* RequestContext() const override;
   scoped_refptr<OutOfProcessPatcher> CreateOutOfProcessPatcher() const override;
   bool DeltasEnabled() const override;
diff --git a/components/update_client/update_checker.cc b/components/update_client/update_checker.cc
index 9a38a5a..be686ef 100644
--- a/components/update_client/update_checker.cc
+++ b/components/update_client/update_checker.cc
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_checker.h"
 #include "components/update_client/configurator.h"
 #include "components/update_client/crx_update_item.h"
@@ -128,30 +129,39 @@
 void UpdateCheckerImpl::OnRequestSenderComplete(const net::URLFetcher* source) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  const GURL original_url(source->GetOriginalURL());
-  VLOG(1) << "Update check request went to: " << original_url.spec();
-
+  GURL original_url;
   int error = 0;
   std::string error_message;
   UpdateResponse update_response;
 
-  if (FetchSuccess(*source)) {
-    std::string xml;
-    source->GetResponseAsString(&xml);
-    if (!update_response.Parse(xml)) {
-      error = -1;
-      error_message = update_response.errors();
-      VLOG(1) << "Update request failed: " << error_message;
+  if (source) {
+    original_url = source->GetOriginalURL();
+    VLOG(1) << "Update check request went to: " << original_url.spec();
+    if (FetchSuccess(*source)) {
+      std::string xml;
+      source->GetResponseAsString(&xml);
+      if (!update_response.Parse(xml)) {
+        error = -1;
+        error_message = update_response.errors();
+      }
+    } else {
+      error = GetFetchError(*source);
+      error_message.assign("network error");
     }
   } else {
-    error = GetFetchError(*source);
-    error_message.assign("network error");
-    VLOG(1) << "Update request failed: network error";
+    error = -1;
+    error_message = "no fetcher";
+  }
+
+  if (error) {
+    VLOG(1) << "Update request failed: " << error_message;
   }
 
   request_sender_.reset();
-  update_check_callback_.Run(original_url, error, error_message,
-                             update_response.results());
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(update_check_callback_, original_url, error,
+                            error_message, update_response.results()));
 }
 
 }  // namespace
diff --git a/components/update_client/update_checker_unittest.cc b/components/update_client/update_checker_unittest.cc
index 117aca29..0bea7985 100644
--- a/components/update_client/update_checker_unittest.cc
+++ b/components/update_client/update_checker_unittest.cc
@@ -181,7 +181,7 @@
 
   EXPECT_EQ(1, post_interceptor_->GetHitCount())
       << post_interceptor_->GetRequestsAsString();
-  EXPECT_EQ(1, post_interceptor_->GetCount())
+  ASSERT_EQ(1, post_interceptor_->GetCount())
       << post_interceptor_->GetRequestsAsString();
 
   // Sanity check the request.
@@ -197,6 +197,7 @@
             post_interceptor_->GetRequests()[0].find("<hw physmemory="));
 
   // Sanity check the arguments of the callback after parsing.
+  ASSERT_FALSE(config_->UpdateUrl().empty());
   EXPECT_EQ(config_->UpdateUrl().front(), original_url_);
   EXPECT_EQ(0, error_);
   EXPECT_TRUE(error_message_.empty());
@@ -228,6 +229,7 @@
   EXPECT_EQ(1, post_interceptor_->GetCount())
       << post_interceptor_->GetRequestsAsString();
 
+  ASSERT_FALSE(config_->UpdateUrl().empty());
   EXPECT_EQ(config_->UpdateUrl().front(), original_url_);
   EXPECT_EQ(403, error_);
   EXPECT_STREQ("network error", error_message_.c_str());
diff --git a/components/url_fixer/url_fixer.cc b/components/url_fixer/url_fixer.cc
index 811f1fb..f20159d 100644
--- a/components/url_fixer/url_fixer.cc
+++ b/components/url_fixer/url_fixer.cc
@@ -436,8 +436,8 @@
     if (!found_scheme) {
       // Couldn't determine the scheme, so just pick one.
       parts->scheme.reset();
-      scheme = StartsWithASCII(*text, "ftp.", false) ? url::kFtpScheme
-                                                     : url::kHttpScheme;
+      scheme = base::StartsWithASCII(*text, "ftp.", false) ? url::kFtpScheme
+                                                           : url::kHttpScheme;
     }
   }
 
@@ -527,7 +527,7 @@
   if (scheme == kViewSourceScheme) {
     // Reject "view-source:view-source:..." to avoid deep recursion.
     std::string view_source(kViewSourceScheme + std::string(":"));
-    if (!StartsWithASCII(text, view_source + view_source, false)) {
+    if (!base::StartsWithASCII(text, view_source + view_source, false)) {
       return GURL(kViewSourceScheme + std::string(":") +
                   FixupURL(trimmed.substr(scheme.length() + 1), desired_tld)
                       .possibly_invalid_spec());
@@ -547,7 +547,7 @@
 
   // Parse and rebuild about: and chrome: URLs, except about:blank.
   bool chrome_url =
-      !LowerCaseEqualsASCII(trimmed, url::kAboutBlankURL) &&
+      !base::LowerCaseEqualsASCII(trimmed, url::kAboutBlankURL) &&
       ((scheme == url::kAboutScheme) || (scheme == kChromeUIScheme));
 
   // For some schemes whose layouts we understand, we rebuild it.
diff --git a/components/user_manager/user_image/default_user_images.cc b/components/user_manager/user_image/default_user_images.cc
index 2d9936b..d4edf09 100644
--- a/components/user_manager/user_image/default_user_images.cc
+++ b/components/user_manager/user_image/default_user_images.cc
@@ -79,7 +79,7 @@
                           const std::string& prefix,
                           int* image_id) {
   DCHECK(image_id);
-  if (!StartsWithASCII(s, prefix, true))
+  if (!base::StartsWithASCII(s, prefix, true))
     return false;
 
   int image_index = -1;
diff --git a/components/variations/net/variations_http_header_provider.cc b/components/variations/net/variations_http_header_provider.cc
index fc0e089..fae7c955 100644
--- a/components/variations/net/variations_http_header_provider.cc
+++ b/components/variations/net/variations_http_header_provider.cc
@@ -97,7 +97,7 @@
       default_trigger_id_set_.clear();
       return false;
     }
-    bool trigger_id = StartsWithASCII(*it, "t", true);
+    bool trigger_id = base::StartsWithASCII(*it, "t", true);
     // Remove the "t" prefix if it's there.
     std::string entry = trigger_id ? it->substr(1) : *it;
 
diff --git a/components/view_manager/BUILD.gn b/components/view_manager/BUILD.gn
index 44b2bc3..e91eec3e 100644
--- a/components/view_manager/BUILD.gn
+++ b/components/view_manager/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//build/config/ui.gni")
 import("//testing/test.gni")
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application.gni")
 
 if (is_android) {
   import("//build/config/android/config.gni")
diff --git a/components/view_manager/connection_manager.cc b/components/view_manager/connection_manager.cc
index 1022048..bcc224d 100644
--- a/components/view_manager/connection_manager.cc
+++ b/components/view_manager/connection_manager.cc
@@ -117,11 +117,11 @@
       next_connection_id_(1),
       event_dispatcher_(this),
       display_manager_(display_manager.Pass()),
-      root_(CreateServerView(RootViewId())),
+      root_(CreateServerView(RootViewId(0))),
       current_change_(nullptr),
       in_destructor_(false),
       animation_runner_(base::TimeTicks::Now()),
-      focus_controller_(new FocusController(this, root_.get())) {
+      focus_controller_(new FocusController(this)) {
   root_->SetBounds(gfx::Rect(800, 600));
   root_->SetVisible(true);
 
@@ -176,45 +176,29 @@
   }
 }
 
-void ConnectionManager::EmbedAtView(
-    ConnectionSpecificId creator_id,
-    mojo::URLRequestPtr request,
-    const ViewId& view_id,
-    mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services) {
-  std::string creator_url;
-  ConnectionMap::const_iterator it = connection_map_.find(creator_id);
-  if (it != connection_map_.end())
-    creator_url = it->second->service()->url();
-
+void ConnectionManager::EmbedAtView(mojo::ConnectionSpecificId creator_id,
+                                    const ViewId& view_id,
+                                    mojo::URLRequestPtr request) {
   mojo::ViewManagerServicePtr service_ptr;
   ClientConnection* client_connection =
       delegate_->CreateClientConnectionForEmbedAtView(
-          this, GetProxy(&service_ptr), creator_id, creator_url, request.Pass(),
-          view_id);
+          this, GetProxy(&service_ptr), creator_id, request.Pass(), view_id);
   AddConnection(client_connection);
   client_connection->service()->Init(client_connection->client(),
-                                     service_ptr.Pass(), services.Pass(),
-                                     exposed_services.Pass());
+                                     service_ptr.Pass());
   OnConnectionMessagedClient(client_connection->service()->id());
 }
 
 void ConnectionManager::EmbedAtView(mojo::ConnectionSpecificId creator_id,
                                     const ViewId& view_id,
                                     mojo::ViewManagerClientPtr client) {
-  std::string creator_url;
-  ConnectionMap::const_iterator it = connection_map_.find(creator_id);
-  if (it != connection_map_.end())
-    creator_url = it->second->service()->url();
-
   mojo::ViewManagerServicePtr service_ptr;
   ClientConnection* client_connection =
       delegate_->CreateClientConnectionForEmbedAtView(
-          this, GetProxy(&service_ptr), creator_id, creator_url, view_id,
-          client.Pass());
+          this, GetProxy(&service_ptr), creator_id, view_id, client.Pass());
   AddConnection(client_connection);
   client_connection->service()->Init(client_connection->client(),
-                                     service_ptr.Pass(), nullptr, nullptr);
+                                     service_ptr.Pass());
   OnConnectionMessagedClient(client_connection->service()->id());
 }
 
@@ -243,6 +227,11 @@
   return focus_controller_->GetFocusedView();
 }
 
+bool ConnectionManager::IsViewAttachedToRoot(const ServerView* view) const {
+  // TODO(fsamuel): Iterate over all roots once we support multiple roots.
+  return root_->Contains(view) && view != root_.get();
+}
+
 void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id) {
   if (current_change_)
     current_change_->MarkConnectionAsMessaged(id);
@@ -284,7 +273,7 @@
   window_manager_client_connection_ = connection.release();
   AddConnection(window_manager_client_connection_);
   window_manager_client_connection_->service()->Init(
-      window_manager_client_connection_->client(), nullptr, nullptr, nullptr);
+      window_manager_client_connection_->client(), nullptr);
 }
 
 mojo::ViewManagerClient*
@@ -295,7 +284,7 @@
 
 bool ConnectionManager::CloneAndAnimate(const ViewId& view_id) {
   ServerView* view = GetView(view_id);
-  if (!view || !view->IsDrawn(root_.get()) || view == root_.get())
+  if (!view || !view->IsDrawn() || view == root_.get())
     return false;
   if (!animation_timer_.IsRunning()) {
     animation_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(100),
@@ -314,6 +303,11 @@
 
 void ConnectionManager::DispatchInputEventToView(const ServerView* view,
                                                  mojo::EventPtr event) {
+  // It's possible for events to flow through here from the platform_window
+  // before any connections are established with the view_manager.
+  if (!has_window_manager_client_connection())
+    return;
+
   // If the view is an embed root, forward to the embedded view, not the owner.
   ViewManagerServiceImpl* connection = GetConnectionWithRoot(view->id());
   if (!connection)
@@ -402,7 +396,7 @@
 }
 
 void ConnectionManager::PrepareToDestroyView(ServerView* view) {
-  if (!in_destructor_ && root_->Contains(view) && view != root_.get() &&
+  if (!in_destructor_ && IsViewAttachedToRoot(view) &&
       view->id() != ClonedViewId()) {
     // We're about to destroy a view. Any cloned views need to be reparented
     // else the animation would no longer be visible. By moving to a visible
@@ -420,7 +414,7 @@
   if (view->id() == ClonedViewId() || in_destructor_)
     return;
 
-  if (root_->Contains(view) && view != root_.get()) {
+  if (IsViewAttachedToRoot(view)) {
     // We're about to reparent a view. Any cloned views need to be reparented
     // else the animation may be effected in unusual ways. For example, the view
     // could move to a new location such that the animation is entirely clipped.
@@ -436,16 +430,15 @@
   if (in_destructor_)
     return;
 
-  if (view != root_.get() && view->id() != ClonedViewId() &&
-      root_->Contains(view) && view->IsDrawn(root_.get())) {
+  if (IsViewAttachedToRoot(view) && view->id() != ClonedViewId() &&
+      view->IsDrawn()) {
     // We're about to hide |view|, this would implicitly make any cloned views
     // hide too. Reparent so that animations are still visible.
     ServerView* parent_above = view;
     ReparentClonedViews(view->parent(), &parent_above, view);
   }
 
-  const bool is_parent_drawn =
-      view->parent() && view->parent()->IsDrawn(root_.get());
+  const bool is_parent_drawn = view->parent() && view->parent()->IsDrawn();
   if (!is_parent_drawn || !view->visible())
     animation_runner_.CancelAnimationForView(view);
 }
@@ -455,6 +448,15 @@
     display_manager_->SchedulePaint(view, gfx::Rect(view->bounds().size()));
 }
 
+bool ConnectionManager::IsViewDrawn(const ServerView* view) const {
+  // TODO(fsamuel): Iterate over all roots once we support multiple roots.
+  if (!root_->visible())
+    return false;
+  while (view && view != root_.get() && view->visible())
+    view = view->parent();
+  return view == root_.get();
+}
+
 void ConnectionManager::OnViewDestroyed(ServerView* view) {
   if (!in_destructor_)
     ProcessViewDeleted(view->id());
@@ -516,8 +518,8 @@
 
   // Need to repaint if the view was drawn (which means it's in the process of
   // hiding) or the view is transitioning to drawn.
-  if (view->IsDrawn(root_.get()) || (!view->visible() && view->parent() &&
-                                     view->parent()->IsDrawn(root_.get()))) {
+  if (view->parent() && (view->IsDrawn() ||
+      (!view->visible() && view->parent()->IsDrawn()))) {
     display_manager_->SchedulePaint(view->parent(), view->bounds());
   }
 
diff --git a/components/view_manager/connection_manager.h b/components/view_manager/connection_manager.h
index d6834289..cdc133e 100644
--- a/components/view_manager/connection_manager.h
+++ b/components/view_manager/connection_manager.h
@@ -88,10 +88,8 @@
   // See description of ViewManagerService::Embed() for details. This assumes
   // |transport_view_id| is valid.
   void EmbedAtView(mojo::ConnectionSpecificId creator_id,
-                   mojo::URLRequestPtr request,
                    const ViewId& view_id,
-                   mojo::InterfaceRequest<mojo::ServiceProvider> services,
-                   mojo::ServiceProviderPtr exposed_services);
+                   mojo::URLRequestPtr request);
   void EmbedAtView(mojo::ConnectionSpecificId creator_id,
                    const ViewId& view_id,
                    mojo::ViewManagerClientPtr client);
@@ -107,6 +105,11 @@
   ServerView* GetFocusedView();
 
   ServerView* root() { return root_.get(); }
+
+  // Returns whether |view| is a descendant of some root view but not itself a
+  // root view.
+  bool IsViewAttachedToRoot(const ServerView* view) const;
+
   DisplayManager* display_manager() { return display_manager_.get(); }
 
   bool IsProcessingChange() const { return current_change_ != NULL; }
@@ -205,6 +208,7 @@
                                     ServerView* old_parent) override;
   void PrepareToChangeViewVisibility(ServerView* view) override;
   void OnScheduleViewPaint(const ServerView* view) override;
+  bool IsViewDrawn(const ServerView* view) const override;
 
   // Overridden from ServerViewObserver:
   void OnViewDestroyed(ServerView* view) override;
diff --git a/components/view_manager/connection_manager_delegate.h b/components/view_manager/connection_manager_delegate.h
index 61be93a..65115f90 100644
--- a/components/view_manager/connection_manager_delegate.h
+++ b/components/view_manager/connection_manager_delegate.h
@@ -31,14 +31,12 @@
       ConnectionManager* connection_manager,
       mojo::InterfaceRequest<mojo::ViewManagerService> service_request,
       mojo::ConnectionSpecificId creator_id,
-      const std::string& creator_url,
       mojo::URLRequestPtr request,
       const ViewId& root_id) = 0;
   virtual ClientConnection* CreateClientConnectionForEmbedAtView(
       ConnectionManager* connection_manager,
       mojo::InterfaceRequest<mojo::ViewManagerService> service_request,
       mojo::ConnectionSpecificId creator_id,
-      const std::string& creator_url,
       const ViewId& root_id,
       mojo::ViewManagerClientPtr view_manager_client) = 0;
 
diff --git a/components/view_manager/display_manager.cc b/components/view_manager/display_manager.cc
index 8e51e33f..fd181e5 100644
--- a/components/view_manager/display_manager.cc
+++ b/components/view_manager/display_manager.cc
@@ -130,7 +130,8 @@
 
 void DefaultDisplayManager::SchedulePaint(const ServerView* view,
                                           const gfx::Rect& bounds) {
-  if (!view->IsDrawn(connection_manager_->root()))
+  DCHECK(view);
+  if (!view->IsDrawn())
     return;
   const gfx::Rect root_relative_rect =
       ConvertRectBetweenViews(view, connection_manager_->root(), bounds);
diff --git a/components/view_manager/focus_controller.cc b/components/view_manager/focus_controller.cc
index 84ee559..014dec9 100644
--- a/components/view_manager/focus_controller.cc
+++ b/components/view_manager/focus_controller.cc
@@ -10,9 +10,8 @@
 
 namespace view_manager {
 
-FocusController::FocusController(FocusControllerDelegate* delegate,
-                                 ServerView* root)
-    : delegate_(delegate), root_(root) {
+FocusController::FocusController(FocusControllerDelegate* delegate)
+    : delegate_(delegate) {
 }
 
 FocusController::~FocusController() {
@@ -33,10 +32,10 @@
                                          ChangeSource change_source) {
   ServerView* old = GetFocusedView();
 
-  DCHECK(!view || view->IsDrawn(root_));
+  DCHECK(!view || view->IsDrawn());
 
   if (view)
-    drawn_tracker_.reset(new ServerViewDrawnTracker(root_, view, this));
+    drawn_tracker_.reset(new ServerViewDrawnTracker(view, this));
   else
     drawn_tracker_.reset();
 
diff --git a/components/view_manager/focus_controller.h b/components/view_manager/focus_controller.h
index 1ad5fe57..74599c5 100644
--- a/components/view_manager/focus_controller.h
+++ b/components/view_manager/focus_controller.h
@@ -18,7 +18,7 @@
 // of the focused view changes and the delegate is notified.
 class FocusController : public ServerViewDrawnTrackerObserver {
  public:
-  FocusController(FocusControllerDelegate* delegate, ServerView* root);
+  explicit FocusController(FocusControllerDelegate* delegate);
   ~FocusController() override;
 
   // Sets the focused view. Does nothing if |view| is currently focused. This
@@ -42,7 +42,6 @@
                            bool is_drawn) override;
 
   FocusControllerDelegate* delegate_;
-  ServerView* root_;
   scoped_ptr<ServerViewDrawnTracker> drawn_tracker_;
 
   DISALLOW_COPY_AND_ASSIGN(FocusController);
diff --git a/components/view_manager/focus_controller_unittest.cc b/components/view_manager/focus_controller_unittest.cc
index 95ea9c9..b4c2c446 100644
--- a/components/view_manager/focus_controller_unittest.cc
+++ b/components/view_manager/focus_controller_unittest.cc
@@ -49,6 +49,7 @@
 TEST(FocusControllerTest, Basic) {
   TestServerViewDelegate server_view_delegate;
   ServerView root(&server_view_delegate, ViewId());
+  server_view_delegate.set_root_view(&root);
   root.SetVisible(true);
   ServerView child(&server_view_delegate, ViewId());
   child.SetVisible(true);
@@ -58,7 +59,7 @@
   child.Add(&child_child);
 
   TestFocusControllerDelegate focus_delegate;
-  FocusController focus_controller(&focus_delegate, &root);
+  FocusController focus_controller(&focus_delegate);
 
   focus_controller.SetFocusedView(&child_child);
   EXPECT_EQ(0u, focus_delegate.change_count());
diff --git a/components/view_manager/gles2/BUILD.gn b/components/view_manager/gles2/BUILD.gn
index 29bd071..6af69d0 100644
--- a/components/view_manager/gles2/BUILD.gn
+++ b/components/view_manager/gles2/BUILD.gn
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
-
 source_set("gles2") {
   visibility = [
     "//components/view_manager/native_viewport:*",
diff --git a/components/view_manager/gles2/command_buffer_impl.cc b/components/view_manager/gles2/command_buffer_impl.cc
index 212e0e10..7725158 100644
--- a/components/view_manager/gles2/command_buffer_impl.cc
+++ b/components/view_manager/gles2/command_buffer_impl.cc
@@ -68,13 +68,6 @@
                             base::Unretained(this), base::Passed(&request)));
 }
 
-CommandBufferImpl::~CommandBufferImpl() {
-  if (observer_)
-    observer_->OnCommandBufferImplDestroyed();
-  driver_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&DestroyDriver, base::Passed(&driver_)));
-}
-
 void CommandBufferImpl::Initialize(
     mojo::CommandBufferSyncClientPtr sync_client,
     mojo::CommandBufferSyncPointClientPtr sync_point_client,
@@ -144,9 +137,24 @@
                                         base::Bind(&RunCallback, callback));
 }
 
+CommandBufferImpl::~CommandBufferImpl() {
+  if (observer_)
+    observer_->OnCommandBufferImplDestroyed();
+  driver_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&DestroyDriver, base::Passed(&driver_)));
+}
+
 void CommandBufferImpl::BindToRequest(
     mojo::InterfaceRequest<mojo::CommandBuffer> request) {
   binding_.Bind(request.Pass());
+  binding_.set_error_handler(this);
+}
+
+void CommandBufferImpl::OnConnectionError() {
+  // OnConnectionError() is called on the background thread
+  // |control_task_runner| but objects we own (such as CommandBufferDriver)
+  // need to be destroyed on the thread we were created on.
+  driver_task_runner_->DeleteSoon(FROM_HERE, this);
 }
 
 void CommandBufferImpl::DidLoseContext() {
diff --git a/components/view_manager/gles2/command_buffer_impl.h b/components/view_manager/gles2/command_buffer_impl.h
index 299a4db..bd4ddd8 100644
--- a/components/view_manager/gles2/command_buffer_impl.h
+++ b/components/view_manager/gles2/command_buffer_impl.h
@@ -10,7 +10,7 @@
 #include "base/single_thread_task_runner.h"
 #include "components/view_manager/public/interfaces/command_buffer.mojom.h"
 #include "components/view_manager/public/interfaces/viewport_parameter_listener.mojom.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
 
 namespace gpu {
 class SyncPointManager;
@@ -24,7 +24,8 @@
 // so that we can insert sync points without blocking on the GL driver. It
 // forwards most method calls to the CommandBufferDriver, which runs on the
 // same thread as the native viewport.
-class CommandBufferImpl : public mojo::CommandBuffer {
+class CommandBufferImpl : public mojo::CommandBuffer,
+                          public mojo::ErrorHandler {
  public:
   CommandBufferImpl(
       mojo::InterfaceRequest<CommandBuffer> request,
@@ -32,7 +33,6 @@
       scoped_refptr<base::SingleThreadTaskRunner> control_task_runner,
       gpu::SyncPointManager* sync_point_manager,
       scoped_ptr<CommandBufferDriver> driver);
-  ~CommandBufferImpl() override;
 
   void Initialize(mojo::CommandBufferSyncClientPtr sync_client,
                   mojo::CommandBufferSyncPointClientPtr sync_point_client,
@@ -58,14 +58,21 @@
   }
 
  private:
+  friend class base::DeleteHelper<CommandBufferImpl>;
+
+  ~CommandBufferImpl() override;
+
   void BindToRequest(mojo::InterfaceRequest<CommandBuffer> request);
 
+  // mojo::ErrorHandler:
+  void OnConnectionError() override;
+
   scoped_refptr<gpu::SyncPointManager> sync_point_manager_;
   scoped_refptr<base::SingleThreadTaskRunner> driver_task_runner_;
   scoped_ptr<CommandBufferDriver> driver_;
   mojo::CommandBufferSyncPointClientPtr sync_point_client_;
   mojo::ViewportParameterListenerPtr viewport_parameter_listener_;
-  mojo::StrongBinding<CommandBuffer> binding_;
+  mojo::Binding<CommandBuffer> binding_;
   CommandBufferImplObserver* observer_;
 
   base::WeakPtrFactory<CommandBufferImpl> weak_factory_;
diff --git a/components/view_manager/ids.h b/components/view_manager/ids.h
index 9e49645..a55d8b7 100644
--- a/components/view_manager/ids.h
+++ b/components/view_manager/ids.h
@@ -21,6 +21,10 @@
       : connection_id(connection_id), view_id(view_id) {}
   ViewId() : connection_id(0), view_id(0) {}
 
+  bool IsRoot() const {
+    return connection_id == kInvalidConnectionId && view_id >= 2;
+  }
+
   bool operator==(const ViewId& other) const {
     return other.connection_id == connection_id &&
         other.view_id == view_id;
@@ -42,10 +46,6 @@
   return (id.connection_id << 16) | id.view_id;
 }
 
-inline ViewId RootViewId() {
-  return ViewId(kInvalidConnectionId, 1);
-}
-
 // Returns a ViewId that is reserved to indicate no view. That is, no view will
 // ever be created with this id.
 inline ViewId InvalidViewId() {
@@ -54,7 +54,12 @@
 
 // All cloned views use this id.
 inline ViewId ClonedViewId() {
-  return ViewId(kInvalidConnectionId, 2);
+  return ViewId(kInvalidConnectionId, 1);
+}
+
+// Returns a root view id with a given index offset.
+inline ViewId RootViewId(uint16_t index) {
+  return ViewId(kInvalidConnectionId, 2 + index);
 }
 
 }  // namespace view_manager
diff --git a/components/view_manager/native_viewport/BUILD.gn b/components/view_manager/native_viewport/BUILD.gn
index 123e40e..ae0014c 100644
--- a/components/view_manager/native_viewport/BUILD.gn
+++ b/components/view_manager/native_viewport/BUILD.gn
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import("//build/config/ui.gni")
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
 
 source_set("native_viewport") {
   sources = [
diff --git a/components/view_manager/public/cpp/BUILD.gn b/components/view_manager/public/cpp/BUILD.gn
index 6f7b216e..8be7ee9 100644
--- a/components/view_manager/public/cpp/BUILD.gn
+++ b/components/view_manager/public/cpp/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/mojo_sdk.gni")
 
 mojo_sdk_source_set("cpp") {
@@ -32,10 +31,11 @@
 
   public_deps = [
     ":common",
+    "../interfaces",
+    "//mojo/services/network/public/interfaces",
   ]
 
   deps = [
-    "../interfaces",
     "//mojo/application/public/cpp",
     "//mojo/application/public/interfaces",
     "//ui/mojo/events:interfaces",
diff --git a/components/view_manager/public/cpp/lib/view.cc b/components/view_manager/public/cpp/lib/view.cc
index 3497dfa..dc4d5e8e 100644
--- a/components/view_manager/public/cpp/lib/view.cc
+++ b/components/view_manager/public/cpp/lib/view.cc
@@ -366,20 +366,6 @@
     static_cast<ViewManagerClientImpl*>(manager_)->SetFocus(id_);
 }
 
-void View::Embed(const String& url) {
-  if (PrepareForEmbed())
-    static_cast<ViewManagerClientImpl*>(manager_)->Embed(url, id_);
-}
-
-void View::Embed(mojo::URLRequestPtr request,
-                 InterfaceRequest<ServiceProvider> services,
-                 ServiceProviderPtr exposed_services) {
-  if (PrepareForEmbed()) {
-    static_cast<ViewManagerClientImpl*>(manager_)
-        ->Embed(request.Pass(), id_, services.Pass(), exposed_services.Pass());
-  }
-}
-
 void View::Embed(ViewManagerClientPtr client) {
   if (PrepareForEmbed())
     static_cast<ViewManagerClientImpl*>(manager_)->Embed(id_, client.Pass());
diff --git a/components/view_manager/public/cpp/lib/view_manager_client_impl.cc b/components/view_manager/public/cpp/lib/view_manager_client_impl.cc
index 7bea3efc..6ec387f 100644
--- a/components/view_manager/public/cpp/lib/view_manager_client_impl.cc
+++ b/components/view_manager/public/cpp/lib/view_manager_client_impl.cc
@@ -202,21 +202,6 @@
                             ActionCompletedCallback());
 }
 
-void ViewManagerClientImpl::Embed(const String& url, Id view_id) {
-  mojo::URLRequestPtr request(mojo::URLRequest::New());
-  request->url = mojo::String::From(url);
-  Embed(request.Pass(), view_id, nullptr, nullptr);
-}
-
-void ViewManagerClientImpl::Embed(mojo::URLRequestPtr request,
-                                  Id view_id,
-                                  InterfaceRequest<ServiceProvider> services,
-                                  ServiceProviderPtr exposed_services) {
-  DCHECK(service_);
-  service_->EmbedRequest(request.Pass(), view_id, services.Pass(),
-                         exposed_services.Pass(), ActionCompletedCallback());
-}
-
 void ViewManagerClientImpl::Embed(Id view_id, ViewManagerClientPtr client) {
   DCHECK(service_);
   service_->Embed(view_id, client.Pass(), ActionCompletedCallback());
@@ -225,7 +210,7 @@
 void ViewManagerClientImpl::EmbedAllowingReembed(mojo::URLRequestPtr request,
                                                  Id view_id) {
   DCHECK(service_);
-  service_->EmbedAllowingReembed(request.Pass(), view_id,
+  service_->EmbedAllowingReembed(view_id, request.Pass(),
                                  ActionCompletedCallback());
 }
 
@@ -262,10 +247,6 @@
   return view_id;
 }
 
-const std::string& ViewManagerClientImpl::GetEmbedderURL() const {
-  return creator_url_;
-}
-
 View* ViewManagerClientImpl::GetRoot() {
   return root_;
 }
@@ -295,11 +276,8 @@
 // ViewManagerClientImpl, ViewManagerClient implementation:
 
 void ViewManagerClientImpl::OnEmbed(ConnectionSpecificId connection_id,
-                                    const String& creator_url,
                                     ViewDataPtr root_data,
                                     ViewManagerServicePtr view_manager_service,
-                                    InterfaceRequest<ServiceProvider> services,
-                                    ServiceProviderPtr exposed_services,
                                     Id focused_view_id) {
   if (view_manager_service) {
     DCHECK(!service_);
@@ -307,7 +285,6 @@
     service_.set_error_handler(this);
   }
   connection_id_ = connection_id;
-  creator_url_ = String::From(creator_url);
 
   DCHECK(!root_);
   root_ = AddViewToViewManager(this, nullptr, root_data);
@@ -315,19 +292,18 @@
 
   focused_view_ = GetViewById(focused_view_id);
 
-  delegate_->OnEmbed(root_, services.Pass(), exposed_services.Pass());
+  delegate_->OnEmbed(root_);
 }
 
-void ViewManagerClientImpl::OnWillEmbed(
+void ViewManagerClientImpl::OnEmbedForDescendant(
     Id view_id,
-    InterfaceRequest<ServiceProvider> services,
-    ServiceProviderPtr exposed_services,
-    const OnWillEmbedCallback& callback) {
+    mojo::URLRequestPtr request,
+    const OnEmbedForDescendantCallback& callback) {
   View* view = GetViewById(view_id);
-  bool allow_embed = false;
+  ViewManagerClientPtr client;
   if (view)
-    allow_embed = delegate_->OnWillEmbed(view, &services, &exposed_services);
-  callback.Run(allow_embed, services.Pass(), exposed_services.Pass());
+    delegate_->OnEmbedForDescendant(view, request.Pass(), &client);
+  callback.Run(client.Pass());
 }
 
 void ViewManagerClientImpl::OnEmbeddedAppDisconnected(Id view_id) {
diff --git a/components/view_manager/public/cpp/lib/view_manager_client_impl.h b/components/view_manager/public/cpp/lib/view_manager_client_impl.h
index b2e7f64..a4064e0 100644
--- a/components/view_manager/public/cpp/lib/view_manager_client_impl.h
+++ b/components/view_manager/public/cpp/lib/view_manager_client_impl.h
@@ -83,7 +83,6 @@
   Id CreateViewOnServer();
 
   // Overridden from ViewManager:
-  const std::string& GetEmbedderURL() const override;
   View* GetRoot() override;
   View* GetViewById(Id id) override;
   View* GetFocusedView() override;
@@ -92,16 +91,13 @@
 
   // Overridden from ViewManagerClient:
   void OnEmbed(ConnectionSpecificId connection_id,
-               const String& creator_url,
                ViewDataPtr root,
                ViewManagerServicePtr view_manager_service,
-               InterfaceRequest<ServiceProvider> services,
-               ServiceProviderPtr exposed_services,
                Id focused_view_id) override;
-  void OnWillEmbed(Id view,
-                   InterfaceRequest<ServiceProvider> services,
-                   ServiceProviderPtr exposed_services,
-                   const OnWillEmbedCallback& callback) override;
+  void OnEmbedForDescendant(
+      Id view,
+      mojo::URLRequestPtr request,
+      const OnEmbedForDescendantCallback& callback) override;
   void OnEmbeddedAppDisconnected(Id view_id) override;
   void OnViewBoundsChanged(Id view_id,
                            RectPtr old_bounds,
@@ -138,8 +134,6 @@
   ConnectionSpecificId connection_id_;
   ConnectionSpecificId next_id_;
 
-  std::string creator_url_;
-
   Callback<void(void)> change_acked_callback_;
 
   ViewManagerDelegate* delegate_;
diff --git a/components/view_manager/public/cpp/lib/view_manager_delegate.cc b/components/view_manager/public/cpp/lib/view_manager_delegate.cc
index 4c5c2be..f91ce62 100644
--- a/components/view_manager/public/cpp/lib/view_manager_delegate.cc
+++ b/components/view_manager/public/cpp/lib/view_manager_delegate.cc
@@ -6,11 +6,10 @@
 
 namespace mojo {
 
-bool ViewManagerDelegate::OnWillEmbed(
+void ViewManagerDelegate::OnEmbedForDescendant(
     View* view,
-    InterfaceRequest<ServiceProvider>* services,
-    ServiceProviderPtr* exposed_services) {
-  return true;
+    mojo::URLRequestPtr request,
+    mojo::ViewManagerClientPtr* client) {
 }
 
 }  // namespace mojo
diff --git a/components/view_manager/public/cpp/view.h b/components/view_manager/public/cpp/view.h
index bf519eee..7629a0c 100644
--- a/components/view_manager/public/cpp/view.h
+++ b/components/view_manager/public/cpp/view.h
@@ -129,10 +129,6 @@
   void SetFocus();
 
   // Embedding. See view_manager.mojom for details.
-  void Embed(const String& url);
-  void Embed(mojo::URLRequestPtr request,
-             InterfaceRequest<ServiceProvider> services,
-             ServiceProviderPtr exposed_services);
   void Embed(ViewManagerClientPtr client);
   void EmbedAllowingReembed(mojo::URLRequestPtr request);
 
diff --git a/components/view_manager/public/cpp/view_manager.h b/components/view_manager/public/cpp/view_manager.h
index 78dcab9..7841f41 100644
--- a/components/view_manager/public/cpp/view_manager.h
+++ b/components/view_manager/public/cpp/view_manager.h
@@ -18,9 +18,6 @@
  public:
   virtual ~ViewManager() {}
 
-  // Returns the URL of the application that embedded this application.
-  virtual const std::string& GetEmbedderURL() const = 0;
-
   // Returns the root of this connection.
   virtual View* GetRoot() = 0;
 
diff --git a/components/view_manager/public/cpp/view_manager_delegate.h b/components/view_manager/public/cpp/view_manager_delegate.h
index 602ed0b..295c5725 100644
--- a/components/view_manager/public/cpp/view_manager_delegate.h
+++ b/components/view_manager/public/cpp/view_manager_delegate.h
@@ -7,7 +7,9 @@
 
 #include <string>
 
+#include "components/view_manager/public/interfaces/view_manager.mojom.h"
 #include "mojo/application/public/interfaces/service_provider.mojom.h"
+#include "mojo/services/network/public/interfaces/url_loader.mojom.h"
 
 namespace mojo {
 
@@ -41,9 +43,7 @@
   // the pipes connecting |services| and |exposed_services| to the embedder and
   // any services obtained from them are not broken and will continue to be
   // valid.
-  virtual void OnEmbed(View* root,
-                       InterfaceRequest<ServiceProvider> services,
-                       ServiceProviderPtr exposed_services) = 0;
+  virtual void OnEmbed(View* root) = 0;
 
   // Only invoked if the connection has been marked as an embed root. This
   // allows the delegate to disallow the embed (return false), or change
@@ -53,9 +53,9 @@
   // the supplied ServiceProviders.
   //
   // See the mojom for more details.
-  virtual bool OnWillEmbed(View* view,
-                           InterfaceRequest<ServiceProvider>* services,
-                           ServiceProviderPtr* exposed_services);
+  virtual void OnEmbedForDescendant(View* view,
+                                    URLRequestPtr request,
+                                    ViewManagerClientPtr* client);
 
   // Called from the destructor of ViewManager after all the Views have been
   // destroyed. |view_manager| is no longer valid after this call.
diff --git a/components/view_manager/public/interfaces/BUILD.gn b/components/view_manager/public/interfaces/BUILD.gn
index 09afdb9..2bc3f67 100644
--- a/components/view_manager/public/interfaces/BUILD.gn
+++ b/components/view_manager/public/interfaces/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
diff --git a/components/view_manager/public/interfaces/quads.mojom b/components/view_manager/public/interfaces/quads.mojom
index 221d27f2..b3af3d59 100644
--- a/components/view_manager/public/interfaces/quads.mojom
+++ b/components/view_manager/public/interfaces/quads.mojom
@@ -20,7 +20,7 @@
 
 struct RenderPassId {
   int32 layer_id;
-  int32 index;
+  uint32 index;
 };
 
 struct RenderPassQuadState {
diff --git a/components/view_manager/public/interfaces/view_manager.mojom b/components/view_manager/public/interfaces/view_manager.mojom
index 70afc08..80d6360 100644
--- a/components/view_manager/public/interfaces/view_manager.mojom
+++ b/components/view_manager/public/interfaces/view_manager.mojom
@@ -112,8 +112,8 @@
   SetViewSurfaceId(uint32 view_id, SurfaceId surface_id) => (bool success);
 
   // Tells the ViewManagerService that the ViewManagerClient wants to get
-  // OnWillEmbed() when Embed() is invoked on any descendant Views created by
-  // other ViewManagerClients.
+  // OnEmbedForDescendant() when EmbedAllowingReembed() is invoked on any
+  // descendant Views.
   //
   // See Embed() docs for more details.
   //
@@ -124,12 +124,12 @@
   // A connection may grant access to a view from another connection by way of
   // the embed functions. The following variants exist:
   //
-  // . EmbedRequest: the ViewManager connects to the app at the supplied request
-  //   and asks it for a ViewManagerClient.
-  // . Embed: the client supplies the ViewManagerClient to use.
-  // . EmbedAllowingReembed: similar to EmbedRequest(), but no
-  //   ServiceProviders are supplied. Additionally this version allows an
-  //   EmbedRoot ancestor to call Embed() in this view at a later date.
+  // . Embed: the client supplies the ViewManagerClient to embed.
+  // . EmbedAllowingReembed: walks the view tree for the first embed root
+  //   ancestor and asks it to perform the embed (OnEmbedForDescendant()).
+  //   The embed root ancestor may allow or disallow the request. If there is no
+  //   embed root ancestor ViewManager connects to the application and requests
+  //   a ViewManagerClient from it.
   //
   // In all cases the new ViewManagerClient is configured with a root of
   // |view_id|.
@@ -137,9 +137,9 @@
   // The caller must have created |view_id|. If not the request fails and the
   // response is false.
   //
-  // A view may only be a root of one connection at a time. Subsequent calls to
-  // Embed() for the same view result in the view being removed from the
-  // currently embedded app. The embedded app is told this by way of
+  // A view may only have one embedding in it at a time. Subsequent calls to
+  // Embed() for the same view result in the currently embedded
+  // ViewManagerClient being removed. The embedded app is told this by way of
   // OnViewDeleted().
   //
   // The embedder can detect when the embedded app disconnects by way of
@@ -148,23 +148,10 @@
   // When a connection embeds an app the connection no longer has priviledges
   // to access or see any of the children of the view. If the view had existing
   // children the children are removed. The one exception is the root
-  // connection and any embed roots. Embed roots always see the full tree.
-  //
-  // The embed functions call OnWillEmbed() on the first ancestor that has
-  // been set as an embed root.
-  //
-  // |services| encapsulates services offered by the embedder to the embedded
-  // app alongside this Embed() call. |exposed_services| provides a means for
-  // the embedder to connect to services exposed by the embedded app. Note that
-  // if a different app is subsequently embedded at |view_id| the
-  // ServiceProvider connections to its client in the embedded app and any
-  // services it provided are not broken and continue to be valid.
-  EmbedRequest(URLRequest request,
-               uint32 view_id,
-               ServiceProvider&? services,
-               ServiceProvider? exposed_services) => (bool success);
+  // connection and any embed roots. The root always see the full tree, and
+  // embed roots see the complete tree at their embed point.
   Embed(uint32 view_id, ViewManagerClient client) => (bool success);
-  EmbedAllowingReembed(URLRequest request, uint32 view_id) => (bool success);
+  EmbedAllowingReembed(uint32 view_id, URLRequest request) => (bool success);
 
   SetFocus(uint32 view_id) => (bool success);
 };
@@ -178,24 +165,15 @@
   // will be a handle back to the view manager service, unless the connection is
   // to the WindowManager in which case it will be null.
   OnEmbed(uint16 connection_id,
-          string embedder_url,
           ViewData root,
           ViewManagerService? view_manager_service,
-          ServiceProvider&? services,
-          ServiceProvider? exposed_services,
           uint32 focused_view);
 
-  // Notifies a ViewManagerClient that an embed is about to happen. The
-  // ViewManagerClient can decide not to allow the embed as well as changing
-  // the ServiceProviders that are exposed as a result of the embed. This is
-  // only invoked once per embed, and is invoked on the first ancestor that has
-  // invoked SetEmbedRoot().
-  OnWillEmbed(uint32 view,
-              ServiceProvider&? services,
-              ServiceProvider? exposed_services) =>
-      (bool proceed_with_embed,
-       ServiceProvider&? services,
-       ServiceProvider? exposed_services);
+  // Asks the ViewManagerClient that was marked as an embed root for the
+  // ViewManagerClient to embed in |view|. The embed can be disallowed by
+  // calling the callback with nullptr.
+  OnEmbedForDescendant(uint32 view, URLRequest request) =>
+      (ViewManagerClient? client);
 
   // Invoked when the application embedded at |view| is disconnected.
   OnEmbeddedAppDisconnected(uint32 view);
diff --git a/components/view_manager/server_view.cc b/components/view_manager/server_view.cc
index 0e89d99..a852c151 100644
--- a/components/view_manager/server_view.cc
+++ b/components/view_manager/server_view.cc
@@ -194,13 +194,8 @@
                     OnViewSharedPropertyChanged(this, name, value));
 }
 
-bool ServerView::IsDrawn(const ServerView* root) const {
-  if (!root->visible_)
-    return false;
-  const ServerView* view = this;
-  while (view && view != root && view->visible_)
-    view = view->parent_;
-  return view == root;
+bool ServerView::IsDrawn() const {
+  return delegate_->IsViewDrawn(this);
 }
 
 void ServerView::SetSurfaceId(cc::SurfaceId surface_id) {
diff --git a/components/view_manager/server_view.h b/components/view_manager/server_view.h
index 4f61f774..add79a9 100644
--- a/components/view_manager/server_view.h
+++ b/components/view_manager/server_view.h
@@ -80,9 +80,9 @@
   }
   void SetProperty(const std::string& name, const std::vector<uint8_t>* value);
 
-  // Returns true if this view is attached to |root| and all ancestors are
+  // Returns true if this view is attached to a root and all ancestors are
   // visible.
-  bool IsDrawn(const ServerView* root) const;
+  bool IsDrawn() const;
 
   void SetSurfaceId(cc::SurfaceId surface_id);
   const cc::SurfaceId& surface_id() const { return surface_id_; }
diff --git a/components/view_manager/server_view_delegate.h b/components/view_manager/server_view_delegate.h
index c815f9f..5551699 100644
--- a/components/view_manager/server_view_delegate.h
+++ b/components/view_manager/server_view_delegate.h
@@ -39,6 +39,8 @@
 
   virtual void OnScheduleViewPaint(const ServerView* view) = 0;
 
+  virtual bool IsViewDrawn(const ServerView* view) const = 0;
+
  protected:
   virtual ~ServerViewDelegate() {}
 };
diff --git a/components/view_manager/server_view_drawn_tracker.cc b/components/view_manager/server_view_drawn_tracker.cc
index 4ddf4df2..f513161 100644
--- a/components/view_manager/server_view_drawn_tracker.cc
+++ b/components/view_manager/server_view_drawn_tracker.cc
@@ -10,13 +10,9 @@
 namespace view_manager {
 
 ServerViewDrawnTracker::ServerViewDrawnTracker(
-    ServerView* root,
     ServerView* view,
     ServerViewDrawnTrackerObserver* observer)
-    : root_(root),
-      view_(view),
-      observer_(observer),
-      drawn_(view->IsDrawn(root)) {
+    : view_(view), observer_(observer), drawn_(view->IsDrawn()) {
   AddObservers();
 }
 
@@ -64,12 +60,12 @@
                                                     ServerView* old_parent) {
   RemoveObservers();
   AddObservers();
-  const bool is_drawn = view_->IsDrawn(root_);
+  const bool is_drawn = view_->IsDrawn();
   SetDrawn(is_drawn ? nullptr : old_parent, is_drawn);
 }
 
 void ServerViewDrawnTracker::OnViewVisibilityChanged(ServerView* view) {
-  const bool is_drawn = view_->IsDrawn(root_);
+  const bool is_drawn = view_->IsDrawn();
   SetDrawn(is_drawn ? nullptr : view->parent(), is_drawn);
 }
 
diff --git a/components/view_manager/server_view_drawn_tracker.h b/components/view_manager/server_view_drawn_tracker.h
index 46a9b0d..faee0ea 100644
--- a/components/view_manager/server_view_drawn_tracker.h
+++ b/components/view_manager/server_view_drawn_tracker.h
@@ -20,8 +20,7 @@
 // NOTE: you must ensure this class is destroyed before the root.
 class ServerViewDrawnTracker : public ServerViewObserver {
  public:
-  ServerViewDrawnTracker(ServerView* root,
-                         ServerView* view,
+  ServerViewDrawnTracker(ServerView* view,
                          ServerViewDrawnTrackerObserver* observer);
   ~ServerViewDrawnTracker() override;
 
@@ -43,7 +42,6 @@
                               ServerView* old_parent) override;
   void OnViewVisibilityChanged(ServerView* view) override;
 
-  ServerView* root_;
   ServerView* view_;
   ServerViewDrawnTrackerObserver* observer_;
   bool drawn_;
diff --git a/components/view_manager/server_view_drawn_tracker_unittest.cc b/components/view_manager/server_view_drawn_tracker_unittest.cc
index 58e34c8..45a0ecd 100644
--- a/components/view_manager/server_view_drawn_tracker_unittest.cc
+++ b/components/view_manager/server_view_drawn_tracker_unittest.cc
@@ -51,8 +51,9 @@
 TEST(ServerViewDrawnTrackerTest, ChangeBecauseOfDeletionAndVisibility) {
   TestServerViewDelegate server_view_delegate;
   scoped_ptr<ServerView> view(new ServerView(&server_view_delegate, ViewId()));
+  server_view_delegate.set_root_view(view.get());
   TestServerViewDrawnTrackerObserver drawn_observer;
-  ServerViewDrawnTracker tracker(view.get(), view.get(), &drawn_observer);
+  ServerViewDrawnTracker tracker(view.get(), &drawn_observer);
   view->SetVisible(true);
   EXPECT_EQ(1u, drawn_observer.change_count());
   EXPECT_EQ(view.get(), drawn_observer.view());
@@ -84,13 +85,14 @@
 TEST(ServerViewDrawnTrackerTest, ChangeBecauseOfRemovingFromRoot) {
   TestServerViewDelegate server_view_delegate;
   ServerView root(&server_view_delegate, ViewId());
+  server_view_delegate.set_root_view(&root);
   root.SetVisible(true);
   ServerView child(&server_view_delegate, ViewId());
   child.SetVisible(true);
   root.Add(&child);
 
   TestServerViewDrawnTrackerObserver drawn_observer;
-  ServerViewDrawnTracker tracker(&root, &child, &drawn_observer);
+  ServerViewDrawnTracker tracker(&child, &drawn_observer);
   root.Remove(&child);
   EXPECT_EQ(1u, drawn_observer.change_count());
   EXPECT_EQ(&child, drawn_observer.view());
@@ -108,6 +110,7 @@
 TEST(ServerViewDrawnTrackerTest, ChangeBecauseOfRemovingAncestorFromRoot) {
   TestServerViewDelegate server_view_delegate;
   ServerView root(&server_view_delegate, ViewId());
+  server_view_delegate.set_root_view(&root);
   root.SetVisible(true);
   ServerView child(&server_view_delegate, ViewId());
   child.SetVisible(true);
@@ -118,7 +121,7 @@
   child.Add(&child_child);
 
   TestServerViewDrawnTrackerObserver drawn_observer;
-  ServerViewDrawnTracker tracker(&root, &child_child, &drawn_observer);
+  ServerViewDrawnTracker tracker(&child_child, &drawn_observer);
   root.Remove(&child);
   EXPECT_EQ(1u, drawn_observer.change_count());
   EXPECT_EQ(&child_child, drawn_observer.view());
diff --git a/components/view_manager/surfaces/BUILD.gn b/components/view_manager/surfaces/BUILD.gn
index d2e6d5e4..308373a 100644
--- a/components/view_manager/surfaces/BUILD.gn
+++ b/components/view_manager/surfaces/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application.gni")
 
 mojo_native_application("surfaces") {
   output_name = "surfaces_service"
diff --git a/components/view_manager/surfaces/public/interfaces/BUILD.gn b/components/view_manager/surfaces/public/interfaces/BUILD.gn
index f0150ebf..3ee12d4 100644
--- a/components/view_manager/surfaces/public/interfaces/BUILD.gn
+++ b/components/view_manager/surfaces/public/interfaces/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
diff --git a/components/view_manager/surfaces/surfaces_context_provider.cc b/components/view_manager/surfaces/surfaces_context_provider.cc
index 252c1008..34ab9d4 100644
--- a/components/view_manager/surfaces/surfaces_context_provider.cc
+++ b/components/view_manager/surfaces/surfaces_context_provider.cc
@@ -11,9 +11,7 @@
 
 SurfacesContextProvider::SurfacesContextProvider(
     mojo::ScopedMessagePipeHandle command_buffer_handle)
-    : command_buffer_handle_(command_buffer_handle.Pass()),
-      context_(nullptr),
-      context_lost_(false) {
+    : command_buffer_handle_(command_buffer_handle.Pass()), context_(nullptr) {
 }
 
 bool SurfacesContextProvider::BindToCurrentThread() {
@@ -58,9 +56,6 @@
   return &context_lock_;
 }
 
-bool SurfacesContextProvider::IsContextLost() {
-  return context_lost_;
-}
 bool SurfacesContextProvider::DestroyedOnMainThread() {
   return !context_;
 }
@@ -76,7 +71,6 @@
 }
 
 void SurfacesContextProvider::ContextLost() {
-  context_lost_ = true;
   if (!lost_context_callback_.is_null())
     lost_context_callback_.Run();
 }
diff --git a/components/view_manager/surfaces/surfaces_context_provider.h b/components/view_manager/surfaces/surfaces_context_provider.h
index ba20d5f8..b891c7b 100644
--- a/components/view_manager/surfaces/surfaces_context_provider.h
+++ b/components/view_manager/surfaces/surfaces_context_provider.h
@@ -25,7 +25,6 @@
   class GrContext* GrContext() override;
   void InvalidateGrContext(uint32_t state) override;
   Capabilities ContextCapabilities() override;
-  bool IsContextLost() override;
   void VerifyContexts() override {}
   void DeleteCachedResources() override {}
   bool DestroyedOnMainThread() override;
@@ -50,7 +49,6 @@
   cc::ContextProvider::Capabilities capabilities_;
   mojo::ScopedMessagePipeHandle command_buffer_handle_;
   MojoGLES2Context context_;
-  bool context_lost_;
   LostContextCallback lost_context_callback_;
 
   base::Lock context_lock_;
diff --git a/components/view_manager/test_change_tracker.cc b/components/view_manager/test_change_tracker.cc
index 0b607b2..33e0f96 100644
--- a/components/view_manager/test_change_tracker.cc
+++ b/components/view_manager/test_change_tracker.cc
@@ -35,15 +35,14 @@
 std::string ChangeToDescription1(const Change& change) {
   switch (change.type) {
     case CHANGE_TYPE_EMBED:
-      return base::StringPrintf("OnEmbed creator=%s",
-                                change.creator_url.data());
+      return "OnEmbed";
 
     case CHANGE_TYPE_EMBEDDED_APP_DISCONNECTED:
       return base::StringPrintf("OnEmbeddedAppDisconnected view=%s",
                                 ViewIdToString(change.view_id).c_str());
 
-    case CHANGE_TYPE_WILL_EMBED:
-      return base::StringPrintf("OnWillEmbed view=%s",
+    case CHANGE_TYPE_EMBED_FOR_DESCENDANT:
+      return base::StringPrintf("OnEmbedForDescendant view=%s",
                                 ViewIdToString(change.view_id).c_str());
 
     case CHANGE_TYPE_NODE_BOUNDS_CHANGED:
@@ -176,19 +175,17 @@
 }
 
 void TestChangeTracker::OnEmbed(mojo::ConnectionSpecificId connection_id,
-                                const String& creator_url,
                                 ViewDataPtr root) {
   Change change;
   change.type = CHANGE_TYPE_EMBED;
   change.connection_id = connection_id;
-  change.creator_url = creator_url;
   change.views.push_back(ViewDataToTestView(root));
   AddChange(change);
 }
 
-void TestChangeTracker::OnWillEmbed(mojo::Id view_id) {
+void TestChangeTracker::OnEmbedForDescendant(mojo::Id view_id) {
   Change change;
-  change.type = CHANGE_TYPE_WILL_EMBED;
+  change.type = CHANGE_TYPE_EMBED_FOR_DESCENDANT;
   change.view_id = view_id;
   AddChange(change);
 }
diff --git a/components/view_manager/test_change_tracker.h b/components/view_manager/test_change_tracker.h
index 9a207af..93ed9b3 100644
--- a/components/view_manager/test_change_tracker.h
+++ b/components/view_manager/test_change_tracker.h
@@ -19,7 +19,7 @@
 enum ChangeType {
   CHANGE_TYPE_EMBED,
   CHANGE_TYPE_EMBEDDED_APP_DISCONNECTED,
-  CHANGE_TYPE_WILL_EMBED,
+  CHANGE_TYPE_EMBED_FOR_DESCENDANT,
   // TODO(sky): nuke NODE.
   CHANGE_TYPE_NODE_BOUNDS_CHANGED,
   CHANGE_TYPE_NODE_VIEWPORT_METRICS_CHANGED,
@@ -67,7 +67,6 @@
   mojo::Rect bounds;
   mojo::Rect bounds2;
   int32_t event_action;
-  mojo::String creator_url;
   mojo::String embed_url;
   mojo::OrderDirection direction;
   bool bool_value;
@@ -121,9 +120,8 @@
   // Each of these functions generate a Change. There is one per
   // ViewManagerClient function.
   void OnEmbed(mojo::ConnectionSpecificId connection_id,
-               const mojo::String& creator_url,
                mojo::ViewDataPtr root);
-  void OnWillEmbed(mojo::Id view_id);
+  void OnEmbedForDescendant(mojo::Id view_id);
   void OnEmbeddedAppDisconnected(mojo::Id view_id);
   void OnViewBoundsChanged(mojo::Id view_id,
                            mojo::RectPtr old_bounds,
diff --git a/components/view_manager/test_server_view_delegate.cc b/components/view_manager/test_server_view_delegate.cc
index 9a03712..f5dd051 100644
--- a/components/view_manager/test_server_view_delegate.cc
+++ b/components/view_manager/test_server_view_delegate.cc
@@ -3,10 +3,11 @@
 // found in the LICENSE file.
 
 #include "components/view_manager/test_server_view_delegate.h"
+#include "components/view_manager/server_view.h"
 
 namespace view_manager {
 
-TestServerViewDelegate::TestServerViewDelegate() {
+TestServerViewDelegate::TestServerViewDelegate() : root_view_(nullptr) {
 }
 
 TestServerViewDelegate::~TestServerViewDelegate() {
@@ -27,4 +28,14 @@
 void TestServerViewDelegate::OnScheduleViewPaint(const ServerView* view) {
 }
 
+bool TestServerViewDelegate::IsViewDrawn(const ServerView* view) const {
+  if (!root_view_)
+    return false;
+  if (!root_view_->visible())
+    return false;
+  while (view && view != root_view_ && view->visible())
+    view = view->parent();
+  return view == root_view_;
+}
+
 }  // namespace view_manager
diff --git a/components/view_manager/test_server_view_delegate.h b/components/view_manager/test_server_view_delegate.h
index b432752..db23cbef 100644
--- a/components/view_manager/test_server_view_delegate.h
+++ b/components/view_manager/test_server_view_delegate.h
@@ -15,6 +15,7 @@
   TestServerViewDelegate();
   ~TestServerViewDelegate() override;
 
+  void set_root_view(const ServerView* view) { root_view_ = view; }
  private:
   // ServerViewDelegate:
   void PrepareToDestroyView(ServerView* view) override;
@@ -23,6 +24,9 @@
                                     ServerView* old_parent) override;
   void PrepareToChangeViewVisibility(ServerView* view) override;
   void OnScheduleViewPaint(const ServerView* view) override;
+  bool IsViewDrawn(const ServerView* view) const override;
+
+  const ServerView* root_view_;
 
   DISALLOW_COPY_AND_ASSIGN(TestServerViewDelegate);
 };
diff --git a/components/view_manager/view_manager_app.cc b/components/view_manager/view_manager_app.cc
index 0dac932b..46da7ffc 100644
--- a/components/view_manager/view_manager_app.cc
+++ b/components/view_manager/view_manager_app.cc
@@ -81,15 +81,13 @@
     ConnectionManager* connection_manager,
     mojo::InterfaceRequest<mojo::ViewManagerService> service_request,
     mojo::ConnectionSpecificId creator_id,
-    const std::string& creator_url,
     mojo::URLRequestPtr request,
     const ViewId& root_id) {
   mojo::ViewManagerClientPtr client;
-  std::string url = request->url.To<std::string>();
   app_impl_->ConnectToService(request.Pass(), &client);
 
-  scoped_ptr<ViewManagerServiceImpl> service(new ViewManagerServiceImpl(
-      connection_manager, creator_id, creator_url, url, root_id));
+  scoped_ptr<ViewManagerServiceImpl> service(
+      new ViewManagerServiceImpl(connection_manager, creator_id, root_id));
   return new DefaultClientConnection(service.Pass(), connection_manager,
                                      service_request.Pass(), client.Pass());
 }
@@ -98,11 +96,10 @@
     ConnectionManager* connection_manager,
     mojo::InterfaceRequest<mojo::ViewManagerService> service_request,
     mojo::ConnectionSpecificId creator_id,
-    const std::string& creator_url,
     const ViewId& root_id,
     mojo::ViewManagerClientPtr view_manager_client) {
-  scoped_ptr<ViewManagerServiceImpl> service(new ViewManagerServiceImpl(
-      connection_manager, creator_id, creator_url, std::string(), root_id));
+  scoped_ptr<ViewManagerServiceImpl> service(
+      new ViewManagerServiceImpl(connection_manager, creator_id, root_id));
   return new DefaultClientConnection(service.Pass(), connection_manager,
                                      service_request.Pass(),
                                      view_manager_client.Pass());
@@ -116,8 +113,7 @@
   }
 
   scoped_ptr<ViewManagerServiceImpl> service(new ViewManagerServiceImpl(
-      connection_manager_.get(), kInvalidConnectionId, std::string(),
-      connection->GetRemoteApplicationURL(), RootViewId()));
+      connection_manager_.get(), kInvalidConnectionId, RootViewId(0)));
   mojo::ViewManagerClientPtr client;
   connection->ConnectToService(&client);
   scoped_ptr<ClientConnection> client_connection(
diff --git a/components/view_manager/view_manager_app.h b/components/view_manager/view_manager_app.h
index a2fa9dd6..c86765c 100644
--- a/components/view_manager/view_manager_app.h
+++ b/components/view_manager/view_manager_app.h
@@ -49,14 +49,12 @@
       ConnectionManager* connection_manager,
       mojo::InterfaceRequest<mojo::ViewManagerService> service_request,
       mojo::ConnectionSpecificId creator_id,
-      const std::string& creator_url,
       mojo::URLRequestPtr request,
       const ViewId& root_id) override;
   ClientConnection* CreateClientConnectionForEmbedAtView(
       ConnectionManager* connection_manager,
       mojo::InterfaceRequest<mojo::ViewManagerService> service_request,
       mojo::ConnectionSpecificId creator_id,
-      const std::string& creator_url,
       const ViewId& root_id,
       mojo::ViewManagerClientPtr view_manager_client) override;
 
diff --git a/components/view_manager/view_manager_client_apptest.cc b/components/view_manager/view_manager_client_apptest.cc
index 867c7d5..217781e 100644
--- a/components/view_manager/view_manager_client_apptest.cc
+++ b/components/view_manager/view_manager_client_apptest.cc
@@ -224,13 +224,29 @@
 
   ViewManager* window_manager() { return window_manager_; }
 
-  // Embeds another version of the test app @ view; returns nullptr on timeout.
-  ViewManager* Embed(ViewManager* view_manager, View* view) {
-    return EmbedImpl(view_manager, view, EmbedType::NO_REEMBED);
+  // Embeds another version of the test app @ view. This runs a run loop until
+  // a response is received, or a timeout. On success the new ViewManager is
+  // returned.
+  ViewManager* Embed(View* view) {
+    return EmbedImpl(view, EmbedType::NO_REEMBED);
   }
 
-  ViewManager* EmbedAllowingReembed(ViewManager* view_manager, View* view) {
-    return EmbedImpl(view_manager, view, EmbedType::ALLOW_REEMBED);
+  // Same as Embed(), but uses EmbedAllowingReembed().
+  ViewManager* EmbedAllowingReembed(View* view) {
+    return EmbedImpl(view, EmbedType::ALLOW_REEMBED);
+  }
+
+  // Establishes a connection to this application and asks for a
+  // ViewManagerClient. The ViewManagerClient is then embedded in |view|.
+  // This does *not* wait for the connection to complete.
+  void ConnectToApplicationAndEmbed(View* view) {
+    mojo::URLRequestPtr request(mojo::URLRequest::New());
+    request->url = mojo::String::From(application_impl()->url());
+    ApplicationConnection* connection =
+        application_impl()->ConnectToApplication(request.Pass());
+    mojo::ViewManagerClientPtr client;
+    connection->ConnectToService(&client);
+    view->Embed(client.Pass());
   }
 
   bool got_disconnect() const { return got_disconnect_; }
@@ -238,19 +254,21 @@
   ApplicationDelegate* GetApplicationDelegate() override { return this; }
 
   // Overridden from ViewManagerDelegate:
-  void OnEmbed(View* root,
-               InterfaceRequest<ServiceProvider> services,
-               ServiceProviderPtr exposed_services) override {
+  void OnEmbed(View* root) override {
     most_recent_view_manager_ = root->view_manager();
     QuitRunLoop();
   }
-  bool OnWillEmbed(View* view,
-                   InterfaceRequest<ServiceProvider>* services,
-                   ServiceProviderPtr* exposed_services) override {
-    if (!on_will_embed_return_value_)
-      QuitRunLoop();
+  void OnEmbedForDescendant(View* view,
+                            mojo::URLRequestPtr request,
+                            mojo::ViewManagerClientPtr* client) override {
     on_will_embed_count_++;
-    return on_will_embed_return_value_;
+    if (on_will_embed_return_value_) {
+      ApplicationConnection* connection =
+          application_impl()->ConnectToApplication(request.Pass());
+      connection->ConnectToService(client);
+    } else {
+      QuitRunLoop();
+    }
   }
   void OnViewManagerDestroyed(ViewManager* view_manager) override {
     got_disconnect_ = true;
@@ -262,17 +280,14 @@
     NO_REEMBED,
   };
 
-  ViewManager* EmbedImpl(ViewManager* view_manager,
-                         View* view,
-                         EmbedType type) {
-    DCHECK_EQ(view_manager, view->view_manager());
+  ViewManager* EmbedImpl(View* view, EmbedType type) {
     most_recent_view_manager_ = nullptr;
     if (type == EmbedType::ALLOW_REEMBED) {
       mojo::URLRequestPtr request(mojo::URLRequest::New());
       request->url = mojo::String::From(application_impl()->url());
       view->EmbedAllowingReembed(request.Pass());
     } else {
-      view->Embed(application_impl()->url());
+      ConnectToApplicationAndEmbed(view);
     }
     if (!DoRunLoopWithTimeout())
       return nullptr;
@@ -321,8 +336,6 @@
 TEST_F(ViewManagerTest, RootView) {
   ASSERT_NE(nullptr, window_manager());
   EXPECT_NE(nullptr, window_manager()->GetRoot());
-  // No one embedded the window_manager(), so it has no url.
-  EXPECT_TRUE(window_manager()->GetEmbedderURL().empty());
 }
 
 TEST_F(ViewManagerTest, Embed) {
@@ -330,7 +343,7 @@
   ASSERT_NE(nullptr, view);
   view->SetVisible(true);
   window_manager()->GetRoot()->AddChild(view);
-  ViewManager* embedded = Embed(window_manager(), view);
+  ViewManager* embedded = Embed(view);
   ASSERT_NE(nullptr, embedded);
 
   View* view_in_embedded = embedded->GetRoot();
@@ -352,7 +365,7 @@
   nested->SetVisible(true);
   view->AddChild(nested);
 
-  ViewManager* embedded = Embed(window_manager(), view);
+  ViewManager* embedded = Embed(view);
   ASSERT_NE(nullptr, embedded);
   View* view_in_embedded = embedded->GetRoot();
   EXPECT_EQ(view->id(), view_in_embedded->id());
@@ -378,7 +391,7 @@
   View* view = window_manager()->CreateView();
   view->SetVisible(true);
   window_manager()->GetRoot()->AddChild(view);
-  ViewManager* embedded = Embed(window_manager(), view);
+  ViewManager* embedded = Embed(view);
   ASSERT_NE(nullptr, embedded);
 
   View* view_in_embedded = embedded->GetViewById(view->id());
@@ -397,7 +410,7 @@
   View* view = window_manager()->CreateView();
   view->SetVisible(true);
   window_manager()->GetRoot()->AddChild(view);
-  ViewManager* embedded = Embed(window_manager(), view);
+  ViewManager* embedded = Embed(view);
   ASSERT_NE(nullptr, embedded);
 
   View* view_in_embedded = embedded->GetViewById(view->id());
@@ -419,7 +432,7 @@
   View* view = window_manager()->CreateView();
   view->SetVisible(true);
   window_manager()->GetRoot()->AddChild(view);
-  ViewManager* embedded = Embed(window_manager(), view);
+  ViewManager* embedded = Embed(view);
   ASSERT_NE(nullptr, embedded);
 
   View* view_in_embedded = embedded->GetViewById(view->id());
@@ -441,22 +454,13 @@
   View* view2 = window_manager()->CreateView();
   view2->SetVisible(true);
   window_manager()->GetRoot()->AddChild(view2);
-  ViewManager* embedded1 = Embed(window_manager(), view1);
+  ViewManager* embedded1 = Embed(view1);
   ASSERT_NE(nullptr, embedded1);
-  ViewManager* embedded2 = Embed(window_manager(), view2);
+  ViewManager* embedded2 = Embed(view2);
   ASSERT_NE(nullptr, embedded2);
   EXPECT_NE(embedded1, embedded2);
 }
 
-TEST_F(ViewManagerTest, EmbeddingIdentity) {
-  View* view = window_manager()->CreateView();
-  view->SetVisible(true);
-  window_manager()->GetRoot()->AddChild(view);
-  ViewManager* embedded = Embed(window_manager(), view);
-  ASSERT_NE(nullptr, embedded);
-  EXPECT_EQ(application_impl()->url(), embedded->GetEmbedderURL());
-}
-
 // TODO(alhaad): Currently, the RunLoop gets stuck waiting for order change.
 // Debug and re-enable this.
 TEST_F(ViewManagerTest, DISABLED_Reorder) {
@@ -464,7 +468,7 @@
   view1->SetVisible(true);
   window_manager()->GetRoot()->AddChild(view1);
 
-  ViewManager* embedded = Embed(window_manager(), view1);
+  ViewManager* embedded = Embed(view1);
   ASSERT_NE(nullptr, embedded);
 
   View* view11 = embedded->CreateView();
@@ -528,7 +532,7 @@
   window_manager()->GetRoot()->AddChild(view1);
 
   // Embed another app and verify initial state.
-  ViewManager* embedded = Embed(window_manager(), view1);
+  ViewManager* embedded = Embed(view1);
   ASSERT_NE(nullptr, embedded);
   ASSERT_NE(nullptr, embedded->GetRoot());
   View* embedded_root = embedded->GetRoot();
@@ -592,7 +596,7 @@
   window_manager()->GetRoot()->AddChild(view1);
 
   // Embed another app and verify initial state.
-  ViewManager* embedded = Embed(window_manager(), view1);
+  ViewManager* embedded = Embed(view1);
   ASSERT_NE(nullptr, embedded);
   ASSERT_NE(nullptr, embedded->GetRoot());
   View* embedded_root = embedded->GetRoot();
@@ -653,7 +657,7 @@
   view1->SetVisible(true);
   window_manager()->GetRoot()->AddChild(view1);
 
-  ViewManager* embedded = Embed(window_manager(), view1);
+  ViewManager* embedded = Embed(view1);
   ASSERT_NE(nullptr, embedded);
   View* view11 = embedded->CreateView();
   view11->SetVisible(true);
@@ -717,7 +721,7 @@
   ASSERT_NE(nullptr, view);
   view->SetVisible(true);
   window_manager()->GetRoot()->AddChild(view);
-  ViewManager* view_manager = Embed(window_manager(), view);
+  ViewManager* view_manager = Embed(view);
   ASSERT_TRUE(view_manager);
   bool got_destroy = false;
   DestroyedChangedObserver observer(view_manager->GetRoot(), &got_destroy);
@@ -733,14 +737,14 @@
   ASSERT_NE(nullptr, view);
   view->SetVisible(true);
   window_manager()->GetRoot()->AddChild(view);
-  ViewManager* view_manager = Embed(window_manager(), view);
+  ViewManager* view_manager = Embed(view);
   EXPECT_NE(view_manager, window_manager());
   View* embedded_view = view_manager->CreateView();
   // Embed again, this should trigger disconnect and deletion of view_manager.
   bool got_destroy;
   DestroyedChangedObserver observer(embedded_view, &got_destroy);
   EXPECT_FALSE(got_disconnect());
-  Embed(window_manager(), view);
+  Embed(view);
   EXPECT_TRUE(got_disconnect());
 }
 
@@ -774,7 +778,7 @@
   view1->AddChild(view2);
 
   ViewRemovedFromParentObserver observer(view2);
-  view1->Embed(application_impl()->url());
+  ConnectToApplicationAndEmbed(view1);
   EXPECT_TRUE(observer.was_removed());
   EXPECT_EQ(nullptr, view2->parent());
   EXPECT_TRUE(view1->children().empty());
@@ -791,11 +795,11 @@
   View* view1 = window_manager()->CreateView();
   window_manager()->GetRoot()->AddChild(view1);
 
-  ViewManager* view_manager = Embed(window_manager(), view1);
+  ViewManager* view_manager = EmbedAllowingReembed(view1);
   View* view2 = view_manager->CreateView();
   view_manager->GetRoot()->AddChild(view2);
 
-  Embed(view_manager, view2);
+  EmbedAllowingReembed(view2);
   EXPECT_EQ(1u, on_will_embed_count());
 }
 
@@ -806,13 +810,15 @@
   View* view1 = window_manager()->CreateView();
   window_manager()->GetRoot()->AddChild(view1);
 
-  ViewManager* view_manager = Embed(window_manager(), view1);
+  ViewManager* view_manager = Embed(view1);
   View* view2 = view_manager->CreateView();
   view_manager->GetRoot()->AddChild(view2);
 
   clear_on_will_embed_count();
   set_on_will_embed_return_value(false);
-  view2->Embed(application_impl()->url());
+  mojo::URLRequestPtr request(mojo::URLRequest::New());
+  request->url = application_impl()->url();
+  view2->EmbedAllowingReembed(request.Pass());
 
   EXPECT_TRUE(DoRunLoopWithTimeout());
   EXPECT_EQ(1u, on_will_embed_count());
@@ -833,16 +839,16 @@
   View* view1 = window_manager()->CreateView();
   window_manager()->GetRoot()->AddChild(view1);
 
-  ViewManager* view_manager = Embed(window_manager(), view1);
+  ViewManager* view_manager = Embed(view1);
   ASSERT_TRUE(view_manager);
   View* view2 = view_manager->CreateView();
   view_manager->GetRoot()->AddChild(view2);
-  Embed(view_manager, view2);
+  Embed(view2);
 
   // Try to embed in view2 from the window_manager. This should fail as the
   // Embed() didn't grab reembed.
   View* view2_in_wm = window_manager()->GetViewById(view2->id());
-  view2_in_wm->Embed(application_impl()->url());
+  ConnectToApplicationAndEmbed(view2_in_wm);
 
   // The Embed() call above returns immediately. To ensure the server has
   // processed it nudge the bounds and wait for it to be processed.
@@ -859,13 +865,13 @@
   View* view1 = window_manager()->CreateView();
   window_manager()->GetRoot()->AddChild(view1);
 
-  ViewManager* view_manager = Embed(window_manager(), view1);
+  ViewManager* view_manager = Embed(view1);
   View* view2 = view_manager->CreateView();
   view_manager->GetRoot()->AddChild(view2);
-  EmbedAllowingReembed(view_manager, view2);
+  EmbedAllowingReembed(view2);
 
   View* view2_in_wm = window_manager()->GetViewById(view2->id());
-  ViewManager* view_manager2 = Embed(window_manager(), view2_in_wm);
+  ViewManager* view_manager2 = Embed(view2_in_wm);
   ASSERT_TRUE(view_manager2);
 
   // The Embed() call above returns immediately. To ensure the server has
diff --git a/components/view_manager/view_manager_service_apptest.cc b/components/view_manager/view_manager_service_apptest.cc
index 789d02a8..9503f93 100644
--- a/components/view_manager/view_manager_service_apptest.cc
+++ b/components/view_manager/view_manager_service_apptest.cc
@@ -69,7 +69,7 @@
 // -----------------------------------------------------------------------------
 
 // The following functions call through to the supplied ViewManagerService. They
-// block until call completes and return the result.
+// block until the call completes and return the result.
 bool CreateView(ViewManagerService* vm, Id view_id) {
   ErrorCode result = ERROR_CODE_NONE;
   base::RunLoop run_loop;
@@ -79,14 +79,38 @@
   return result == ERROR_CODE_NONE;
 }
 
-bool EmbedUrl(ViewManagerService* vm, const String& url, Id root_id) {
+bool EmbedUrl(mojo::ApplicationImpl* app,
+              ViewManagerService* vm,
+              const String& url,
+              Id root_id) {
   bool result = false;
   base::RunLoop run_loop;
   {
     mojo::URLRequestPtr request(mojo::URLRequest::New());
     request->url = mojo::String::From(url);
-    vm->EmbedRequest(request.Pass(), root_id, nullptr, nullptr,
-                     base::Bind(&BoolResultCallback, &run_loop, &result));
+    ApplicationConnection* connection =
+        app->ConnectToApplication(request.Pass());
+    mojo::ViewManagerClientPtr client;
+    connection->ConnectToService(&client);
+    vm->Embed(root_id, client.Pass(),
+              base::Bind(&BoolResultCallback, &run_loop, &result));
+  }
+  run_loop.Run();
+  return result;
+}
+
+bool EmbedAllowingReembed(mojo::ApplicationImpl* app,
+                          ViewManagerService* vm,
+                          const String& url,
+                          Id root_id) {
+  bool result = false;
+  base::RunLoop run_loop;
+  {
+    mojo::URLRequestPtr request(mojo::URLRequest::New());
+    request->url = mojo::String::From(url);
+    vm->EmbedAllowingReembed(
+        root_id, request.Pass(),
+        base::Bind(&BoolResultCallback, &run_loop, &result));
   }
   run_loop.Run();
   return result;
@@ -231,7 +255,10 @@
 class ViewManagerClientImpl : public mojo::ViewManagerClient,
                               public TestChangeTracker::Delegate {
  public:
-  ViewManagerClientImpl() : binding_(this) { tracker_.set_delegate(this); }
+  explicit ViewManagerClientImpl(mojo::ApplicationImpl* app)
+      : binding_(this), app_(app) {
+    tracker_.set_delegate(this);
+  }
 
   void Bind(mojo::InterfaceRequest<mojo::ViewManagerClient> request) {
     binding_.Bind(request.Pass());
@@ -286,24 +313,25 @@
 
   // ViewManagerClient:
   void OnEmbed(ConnectionSpecificId connection_id,
-               const String& creator_url,
                ViewDataPtr root,
                mojo::ViewManagerServicePtr view_manager_service,
-               InterfaceRequest<ServiceProvider> services,
-               ServiceProviderPtr exposed_services,
                mojo::Id focused_view_id) override {
     // TODO(sky): add coverage of |focused_view_id|.
     service_ = view_manager_service.Pass();
-    tracker()->OnEmbed(connection_id, creator_url, root.Pass());
+    tracker()->OnEmbed(connection_id, root.Pass());
     if (embed_run_loop_)
       embed_run_loop_->Quit();
   }
-  void OnWillEmbed(uint32_t view,
-                   mojo::InterfaceRequest<mojo::ServiceProvider> services,
-                   mojo::ServiceProviderPtr exposed_services,
-                   const OnWillEmbedCallback& callback) override {
-    tracker()->OnWillEmbed(view);
-    callback.Run(true, services.Pass(), exposed_services.Pass());
+  void OnEmbedForDescendant(
+      uint32_t view,
+      mojo::URLRequestPtr request,
+      const OnEmbedForDescendantCallback& callback) override {
+    tracker()->OnEmbedForDescendant(view);
+    mojo::ViewManagerClientPtr client;
+    ApplicationConnection* connection =
+        app_->ConnectToApplication(request.Pass());
+    connection->ConnectToService(&client);
+    callback.Run(client.Pass());
   }
   void OnEmbeddedAppDisconnected(Id view_id) override {
     tracker()->OnEmbeddedAppDisconnected(view_id);
@@ -311,13 +339,18 @@
   void OnViewBoundsChanged(Id view_id,
                            RectPtr old_bounds,
                            RectPtr new_bounds) override {
+    // The bounds of the root may change during startup on Android at random
+    // times. As this doesn't matter, and shouldn't impact test exepctations,
+    // it is ignored.
+    if (view_id == ViewIdToTransportId(RootViewId(0)))
+        return;
     tracker()->OnViewBoundsChanged(view_id, old_bounds.Pass(),
                                    new_bounds.Pass());
   }
   void OnViewViewportMetricsChanged(ViewportMetricsPtr old_metrics,
                                     ViewportMetricsPtr new_metrics) override {
-    tracker()->OnViewViewportMetricsChanged(old_metrics.Pass(),
-                                            new_metrics.Pass());
+    // Don't track the metrics as they are available at an indeterministic time
+    // on Android.
   }
   void OnViewHierarchyChanged(Id view,
                               Id new_parent,
@@ -364,6 +397,8 @@
   scoped_ptr<WaitState> wait_state_;
 
   mojo::Binding<ViewManagerClient> binding_;
+  mojo::ApplicationImpl* app_;
+
   DISALLOW_COPY_AND_ASSIGN(ViewManagerClientImpl);
 };
 
@@ -373,7 +408,7 @@
 class ViewManagerClientFactory
     : public mojo::InterfaceFactory<ViewManagerClient> {
  public:
-  ViewManagerClientFactory() {}
+  explicit ViewManagerClientFactory(mojo::ApplicationImpl* app) : app_(app) {}
   ~ViewManagerClientFactory() override {}
 
   // Runs a nested MessageLoop until a new instance has been created.
@@ -391,12 +426,13 @@
   // InterfaceFactory<ViewManagerClient>:
   void Create(ApplicationConnection* connection,
               InterfaceRequest<ViewManagerClient> request) override {
-    client_impl_.reset(new ViewManagerClientImpl);
+    client_impl_.reset(new ViewManagerClientImpl(app_));
     client_impl_->Bind(request.Pass());
     if (run_loop_.get())
       run_loop_->Quit();
   }
 
+  mojo::ApplicationImpl* app_;
   scoped_ptr<ViewManagerClientImpl> client_impl_;
   scoped_ptr<base::RunLoop> run_loop_;
 
@@ -410,6 +446,11 @@
   ~ViewManagerServiceAppTest() override {}
 
  protected:
+  enum class EmbedType {
+    ALLOW_REEMBED,
+    NO_REEMBED,
+  };
+
   // Returns the changes from the various connections.
   std::vector<Change>* changes1() { return vm_client1_->tracker()->changes(); }
   std::vector<Change>* changes2() { return vm_client2_->tracker()->changes(); }
@@ -423,7 +464,8 @@
 
   void EstablishSecondConnectionWithRoot(Id root_id) {
     ASSERT_TRUE(vm_client2_.get() == nullptr);
-    vm_client2_ = EstablishConnectionViaEmbed(vm1(), root_id);
+    vm_client2_ =
+        EstablishConnectionViaEmbed(vm1(), root_id, EmbedType::NO_REEMBED);
     ASSERT_TRUE(vm_client2_.get() != nullptr);
   }
 
@@ -439,7 +481,8 @@
 
   void EstablishThirdConnection(ViewManagerService* owner, Id root_id) {
     ASSERT_TRUE(vm_client3_.get() == nullptr);
-    vm_client3_ = EstablishConnectionViaEmbed(owner, root_id);
+    vm_client3_ =
+        EstablishConnectionViaEmbed(owner, root_id, EmbedType::NO_REEMBED);
     ASSERT_TRUE(vm_client3_.get() != nullptr);
   }
 
@@ -447,20 +490,28 @@
   // ViewManagerService.
   scoped_ptr<ViewManagerClientImpl> EstablishConnectionViaEmbed(
       ViewManagerService* owner,
-      Id root_id) {
-    if (!EmbedUrl(owner, application_impl()->url(), root_id)) {
+      Id root_id,
+      EmbedType embed_type) {
+    if (embed_type == EmbedType::NO_REEMBED &&
+        !EmbedUrl(application_impl(), owner, application_impl()->url(),
+                  root_id)) {
+      ADD_FAILURE() << "Embed() failed";
+      return nullptr;
+    } else if (embed_type == EmbedType::ALLOW_REEMBED &&
+               !EmbedAllowingReembed(application_impl(), owner,
+                                     application_impl()->url(), root_id)) {
       ADD_FAILURE() << "Embed() failed";
       return nullptr;
     }
     scoped_ptr<ViewManagerClientImpl> client =
-        client_factory_.WaitForInstance();
+        client_factory_->WaitForInstance();
     if (!client.get()) {
       ADD_FAILURE() << "WaitForInstance failed";
       return nullptr;
     }
     client->WaitForOnEmbed();
 
-    EXPECT_EQ("OnEmbed creator=" + application_impl()->url(),
+    EXPECT_EQ("OnEmbed",
               SingleChangeToDescription(*client->tracker()->changes()));
     return client.Pass();
   }
@@ -469,14 +520,15 @@
   ApplicationDelegate* GetApplicationDelegate() override { return this; }
   void SetUp() override {
     ApplicationTestBase::SetUp();
+    client_factory_.reset(new ViewManagerClientFactory(application_impl()));
     mojo::URLRequestPtr request(mojo::URLRequest::New());
     request->url = mojo::String::From("mojo:view_manager");
     ApplicationConnection* vm_connection =
         application_impl()->ConnectToApplication(request.Pass());
     vm_connection->ConnectToService(&vm1_);
     vm_connection->ConnectToService(&view_manager_root_);
-    vm_connection->AddService(&client_factory_);
-    vm_client1_ = client_factory_.WaitForInstance();
+    vm_connection->AddService(client_factory_.get());
+    vm_client1_ = client_factory_->WaitForInstance();
     ASSERT_TRUE(vm_client1_);
     // Next we should get an embed call on the "window manager" client.
     vm_client1_->WaitForIncomingMethodCall();
@@ -491,7 +543,7 @@
 
   // ApplicationDelegate implementation.
   bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
-    connection->AddService(&client_factory_);
+    connection->AddService(client_factory_.get());
     return true;
   }
 
@@ -503,7 +555,7 @@
 
  private:
   mojo::ViewManagerServicePtr vm1_;
-  ViewManagerClientFactory client_factory_;
+  scoped_ptr<ViewManagerClientFactory> client_factory_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(ViewManagerServiceAppTest);
 };
@@ -727,7 +779,7 @@
   {
     // Client 2 is now connected to the root, so it should have gotten a drawn
     // notification.
-    ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+    ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
     vm_client2_->WaitForChangeCount(1u);
     EXPECT_EQ("DrawnStateChanged view=1,1 drawn=true",
               SingleChangeToDescription(*changes2()));
@@ -757,7 +809,7 @@
   // 0,1->1,1->1,2->1,11->1,111
   {
     changes2()->clear();
-    ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+    ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
     vm_client2_->WaitForChangeCount(1);
     EXPECT_EQ("DrawnStateChanged view=1,1 drawn=true",
               SingleChangeToDescription(*changes2()));
@@ -774,7 +826,7 @@
   ASSERT_TRUE(CreateView(vm2(), BuildViewId(2, 21)));
 
   // Set up the hierarchy.
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
   ASSERT_TRUE(AddView(vm2(), BuildViewId(1, 1), BuildViewId(2, 11)));
   ASSERT_TRUE(AddView(vm2(), BuildViewId(2, 2), BuildViewId(2, 21)));
 
@@ -825,9 +877,9 @@
   ASSERT_TRUE(AddView(vm2(), view1_id, view2_id));
   ASSERT_TRUE(AddView(vm2(), view2_id, view6_id));
   ASSERT_TRUE(AddView(vm2(), view1_id, view3_id));
-  ASSERT_TRUE(AddView(vm1(), ViewIdToTransportId(RootViewId()), view4_id));
-  ASSERT_TRUE(AddView(vm1(), ViewIdToTransportId(RootViewId()), view5_id));
-  ASSERT_TRUE(AddView(vm1(), ViewIdToTransportId(RootViewId()), view1_id));
+  ASSERT_TRUE(AddView(vm1(), ViewIdToTransportId(RootViewId(0)), view4_id));
+  ASSERT_TRUE(AddView(vm1(), ViewIdToTransportId(RootViewId(0)), view5_id));
+  ASSERT_TRUE(AddView(vm1(), ViewIdToTransportId(RootViewId(0)), view1_id));
 
   {
     changes1()->clear();
@@ -941,7 +993,7 @@
 
   // Create 11 in first connection and make it a child of 1.
   ASSERT_TRUE(CreateView(vm1(), BuildViewId(1, 11)));
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
   ASSERT_TRUE(AddView(vm1(), BuildViewId(1, 1), BuildViewId(1, 11)));
 
   // Create two views in second connection, 2 and 3, both children of 1.
@@ -953,10 +1005,10 @@
   // Verifies GetViewTree() on the root. The root connection sees all.
   {
     std::vector<TestView> views;
-    GetViewTree(vm1(), BuildViewId(0, 1), &views);
+    GetViewTree(vm1(), BuildViewId(0, 2), &views);
     ASSERT_EQ(5u, views.size());
-    EXPECT_EQ("view=0,1 parent=null", views[0].ToString());
-    EXPECT_EQ("view=1,1 parent=0,1", views[1].ToString());
+    EXPECT_EQ("view=0,2 parent=null", views[0].ToString());
+    EXPECT_EQ("view=1,1 parent=0,2", views[1].ToString());
     EXPECT_EQ("view=1,11 parent=1,1", views[2].ToString());
     EXPECT_EQ("view=2,2 parent=1,1", views[3].ToString());
     EXPECT_EQ("view=2,3 parent=1,1", views[4].ToString());
@@ -976,14 +1028,14 @@
   // Connection 2 shouldn't be able to get the root tree.
   {
     std::vector<TestView> views;
-    GetViewTree(vm2(), BuildViewId(0, 1), &views);
+    GetViewTree(vm2(), BuildViewId(0, 2), &views);
     ASSERT_EQ(0u, views.size());
   }
 }
 
 TEST_F(ViewManagerServiceAppTest, SetViewBounds) {
   ASSERT_TRUE(CreateView(vm1(), BuildViewId(1, 1)));
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
 
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
 
@@ -1013,7 +1065,7 @@
 
   // Try to reparent 1 to the root. A connection is not allowed to reparent its
   // roots.
-  ASSERT_FALSE(AddView(vm2(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_FALSE(AddView(vm2(), BuildViewId(0, 2), BuildViewId(1, 1)));
 }
 
 // Verify RemoveViewFromParent fails for views that are descendants of the
@@ -1023,8 +1075,8 @@
   ASSERT_TRUE(CreateView(vm1(), BuildViewId(1, 1)));
   ASSERT_TRUE(CreateView(vm1(), BuildViewId(1, 2)));
 
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 2)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 2)));
 
   // Establish the second connection and give it the root 1.
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
@@ -1045,11 +1097,11 @@
   // Verify nothing was actually removed.
   {
     std::vector<TestView> views;
-    GetViewTree(vm1(), BuildViewId(0, 1), &views);
+    GetViewTree(vm1(), BuildViewId(0, 2), &views);
     ASSERT_EQ(3u, views.size());
-    EXPECT_EQ("view=0,1 parent=null", views[0].ToString());
-    EXPECT_EQ("view=1,1 parent=0,1", views[1].ToString());
-    EXPECT_EQ("view=1,2 parent=0,1", views[2].ToString());
+    EXPECT_EQ("view=0,2 parent=null", views[0].ToString());
+    EXPECT_EQ("view=1,1 parent=0,2", views[1].ToString());
+    EXPECT_EQ("view=1,2 parent=0,2", views[2].ToString());
   }
 }
 
@@ -1059,15 +1111,15 @@
   ASSERT_TRUE(CreateView(vm1(), BuildViewId(1, 1)));
   ASSERT_TRUE(CreateView(vm1(), BuildViewId(1, 2)));
 
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 2)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 2)));
 
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
 
   std::vector<TestView> views;
 
   // Should get nothing for the root.
-  GetViewTree(vm2(), BuildViewId(0, 1), &views);
+  GetViewTree(vm2(), BuildViewId(0, 2), &views);
   ASSERT_TRUE(views.empty());
 
   // Should get nothing for view 2.
@@ -1126,8 +1178,8 @@
     changes3()->clear();
 
     // We should get a new connection for the new embedding.
-    scoped_ptr<ViewManagerClientImpl> connection4(
-        EstablishConnectionViaEmbed(vm1(), BuildViewId(1, 1)));
+    scoped_ptr<ViewManagerClientImpl> connection4(EstablishConnectionViaEmbed(
+        vm1(), BuildViewId(1, 1), EmbedType::NO_REEMBED));
     ASSERT_TRUE(connection4.get());
     EXPECT_EQ("[view=1,1 parent=null]",
               ChangeViewDescription(*connection4->tracker()->changes()));
@@ -1168,14 +1220,14 @@
   ASSERT_TRUE(CreateView(vm1(), BuildViewId(1, 1)));
   ASSERT_TRUE(CreateView(vm1(), BuildViewId(1, 2)));
 
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
   {
     std::vector<TestView> views;
-    GetViewTree(vm1(), BuildViewId(0, 1), &views);
+    GetViewTree(vm1(), BuildViewId(0, 2), &views);
     ASSERT_EQ(2u, views.size());
-    EXPECT_EQ("view=0,1 parent=null visible=true drawn=true",
+    EXPECT_EQ("view=0,2 parent=null visible=true drawn=true",
               views[0].ToString2());
-    EXPECT_EQ("view=1,1 parent=0,1 visible=false drawn=false",
+    EXPECT_EQ("view=1,1 parent=0,2 visible=false drawn=false",
               views[1].ToString2());
   }
 
@@ -1184,11 +1236,11 @@
   ASSERT_TRUE(SetViewVisibility(vm1(), BuildViewId(1, 2), true));
   {
     std::vector<TestView> views;
-    GetViewTree(vm1(), BuildViewId(0, 1), &views);
+    GetViewTree(vm1(), BuildViewId(0, 2), &views);
     ASSERT_EQ(2u, views.size());
-    EXPECT_EQ("view=0,1 parent=null visible=true drawn=true",
+    EXPECT_EQ("view=0,2 parent=null visible=true drawn=true",
               views[0].ToString2());
-    EXPECT_EQ("view=1,1 parent=0,1 visible=true drawn=true",
+    EXPECT_EQ("view=1,1 parent=0,2 visible=true drawn=true",
               views[1].ToString2());
   }
 
@@ -1198,7 +1250,7 @@
     std::vector<TestView> views;
     GetViewTree(vm1(), BuildViewId(1, 1), &views);
     ASSERT_EQ(1u, views.size());
-    EXPECT_EQ("view=1,1 parent=0,1 visible=false drawn=false",
+    EXPECT_EQ("view=1,1 parent=0,2 visible=false drawn=false",
               views[0].ToString2());
   }
 
@@ -1208,7 +1260,7 @@
     std::vector<TestView> views;
     GetViewTree(vm1(), BuildViewId(1, 1), &views);
     ASSERT_EQ(2u, views.size());
-    EXPECT_EQ("view=1,1 parent=0,1 visible=false drawn=false",
+    EXPECT_EQ("view=1,1 parent=0,2 visible=false drawn=false",
               views[0].ToString2());
     EXPECT_EQ("view=1,2 parent=1,1 visible=true drawn=false",
               views[1].ToString2());
@@ -1220,7 +1272,7 @@
     std::vector<TestView> views;
     GetViewTree(vm1(), BuildViewId(1, 1), &views);
     ASSERT_EQ(2u, views.size());
-    EXPECT_EQ("view=1,1 parent=0,1 visible=true drawn=true",
+    EXPECT_EQ("view=1,1 parent=0,2 visible=true drawn=true",
               views[0].ToString2());
     EXPECT_EQ("view=1,2 parent=1,1 visible=true drawn=true",
               views[1].ToString2());
@@ -1234,7 +1286,7 @@
   ASSERT_TRUE(SetViewVisibility(vm1(), BuildViewId(1, 1), true));
   ASSERT_TRUE(CreateView(vm1(), BuildViewId(1, 2)));
   ASSERT_TRUE(SetViewVisibility(vm1(), BuildViewId(1, 2), true));
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
   ASSERT_TRUE(AddView(vm1(), BuildViewId(1, 1), BuildViewId(1, 2)));
 
   // Establish the second connection at 1,2.
@@ -1302,7 +1354,7 @@
 
   changes2()->clear();
   // Add 1,1 back to the root, connection 2 should see drawn state changed.
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
   {
     vm_client2_->WaitForChangeCount(1);
     EXPECT_EQ("DrawnStateChanged view=1,2 drawn=true",
@@ -1316,12 +1368,12 @@
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(false));
   changes2()->clear();
 
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
   {
     std::vector<TestView> views;
-    GetViewTree(vm1(), BuildViewId(0, 1), &views);
+    GetViewTree(vm1(), BuildViewId(0, 2), &views);
     ASSERT_EQ(2u, views.size());
-    EXPECT_EQ(BuildViewId(0, 1), views[0].view_id);
+    EXPECT_EQ(BuildViewId(0, 2), views[0].view_id);
     EXPECT_EQ(BuildViewId(1, 1), views[1].view_id);
     ASSERT_EQ(0u, views[1].properties.size());
   }
@@ -1376,7 +1428,7 @@
 TEST_F(ViewManagerServiceAppTest, OnParentOfEmbedDisconnects) {
   // Create connection 2 and 3.
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
   ASSERT_TRUE(CreateView(vm2(), BuildViewId(2, 2)));
   ASSERT_TRUE(AddView(vm2(), BuildViewId(1, 1), BuildViewId(2, 2)));
   ASSERT_TRUE(CreateView(vm2(), BuildViewId(2, 3)));
@@ -1409,7 +1461,7 @@
 TEST_F(ViewManagerServiceAppTest, CloneAndAnimate) {
   // Create connection 2 and 3.
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
   ASSERT_TRUE(CreateView(vm2(), BuildViewId(2, 2)));
   ASSERT_TRUE(CreateView(vm2(), BuildViewId(2, 3)));
   ASSERT_TRUE(AddView(vm2(), BuildViewId(1, 1), BuildViewId(2, 2)));
@@ -1443,19 +1495,19 @@
 TEST_F(ViewManagerServiceAppTest, EmbedSupplyingViewManagerClient) {
   ASSERT_TRUE(CreateView(vm1(), BuildViewId(1, 1)));
 
-  ViewManagerClientImpl client2;
+  ViewManagerClientImpl client2(application_impl());
   mojo::ViewManagerClientPtr client2_ptr;
   mojo::Binding<ViewManagerClient> client2_binding(&client2, &client2_ptr);
   ASSERT_TRUE(Embed(vm1(), BuildViewId(1, 1), client2_ptr.Pass()));
   client2.WaitForOnEmbed();
-  EXPECT_EQ("OnEmbed creator=" + application_impl()->url(),
+  EXPECT_EQ("OnEmbed",
             SingleChangeToDescription(*client2.tracker()->changes()));
 }
 
 TEST_F(ViewManagerServiceAppTest, OnWillEmbed) {
   // Create connections 2 and 3, marking 2 as an embed root.
   ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
-  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 1), BuildViewId(1, 1)));
+  ASSERT_TRUE(AddView(vm1(), BuildViewId(0, 2), BuildViewId(1, 1)));
   ASSERT_TRUE(CreateView(vm2(), BuildViewId(2, 2)));
   ASSERT_TRUE(AddView(vm2(), BuildViewId(1, 1), BuildViewId(2, 2)));
   ASSERT_NO_FATAL_FAILURE(EstablishThirdConnection(vm2(), BuildViewId(2, 2)));
@@ -1467,10 +1519,11 @@
   changes2()->clear();
 
   // Embed 4 into 3, connection 2 should get the OnWillEmbed.
-  scoped_ptr<ViewManagerClientImpl> connection4(
-      EstablishConnectionViaEmbed(vm3(), BuildViewId(3, 3)));
+  scoped_ptr<ViewManagerClientImpl> connection4(EstablishConnectionViaEmbed(
+      vm3(), BuildViewId(3, 3), EmbedType::ALLOW_REEMBED));
   ASSERT_TRUE(connection4.get());
-  EXPECT_EQ("OnWillEmbed view=3,3", SingleChangeToDescription(*changes2()));
+  EXPECT_EQ("OnEmbedForDescendant view=3,3",
+            SingleChangeToDescription(*changes2()));
 
   // Mark 3 as an embed root.
   vm3()->SetEmbedRoot();
@@ -1483,10 +1536,11 @@
   ASSERT_TRUE(CreateView(connection4->service(), BuildViewId(4, 4)));
   ASSERT_TRUE(
       AddView(connection4->service(), BuildViewId(3, 3), BuildViewId(4, 4)));
-  scoped_ptr<ViewManagerClientImpl> connection5(
-      EstablishConnectionViaEmbed(connection4->service(), BuildViewId(4, 4)));
+  scoped_ptr<ViewManagerClientImpl> connection5(EstablishConnectionViaEmbed(
+      connection4->service(), BuildViewId(4, 4), EmbedType::ALLOW_REEMBED));
   ASSERT_TRUE(connection5.get());
-  EXPECT_EQ("OnWillEmbed view=4,4", SingleChangeToDescription(*changes3()));
+  EXPECT_EQ("OnEmbedForDescendant view=4,4",
+            SingleChangeToDescription(*changes3()));
   ASSERT_TRUE(changes2()->empty());
 }
 
diff --git a/components/view_manager/view_manager_service_impl.cc b/components/view_manager/view_manager_service_impl.cc
index 96c34f6..31222fb 100644
--- a/components/view_manager/view_manager_service_impl.cc
+++ b/components/view_manager/view_manager_service_impl.cc
@@ -35,7 +35,6 @@
   PendingEmbed() : embed_root(nullptr) {}
 
   ViewManagerServiceImpl* embed_root;
-  mojo::URLRequestPtr url_request;
   ViewId view_id;
   mojo::Callback<void(bool)> callback;
 
@@ -48,19 +47,15 @@
 ViewManagerServiceImpl::ViewManagerServiceImpl(
     ConnectionManager* connection_manager,
     mojo::ConnectionSpecificId creator_id,
-    const std::string& creator_url,
-    const std::string& url,
     const ViewId& root_id)
     : connection_manager_(connection_manager),
       id_(connection_manager_->GetAndAdvanceNextConnectionId()),
-      url_(url),
       creator_id_(creator_id),
-      creator_url_(creator_url),
       client_(nullptr),
       is_embed_root_(false) {
   CHECK(GetView(root_id));
   root_.reset(new ViewId(root_id));
-  if (root_id == RootViewId())
+  if (root_id.IsRoot())
     access_policy_.reset(new WindowManagerAccessPolicy(id_, this));
   else
     access_policy_.reset(new DefaultAccessPolicy(id_, this));
@@ -71,9 +66,7 @@
 }
 
 void ViewManagerServiceImpl::Init(mojo::ViewManagerClient* client,
-                                  mojo::ViewManagerServicePtr service_ptr,
-                                  InterfaceRequest<ServiceProvider> services,
-                                  ServiceProviderPtr exposed_services) {
+                                  mojo::ViewManagerServicePtr service_ptr) {
   DCHECK(!client_);
   client_ = client;
   std::vector<const ServerView*> to_send;
@@ -86,8 +79,7 @@
   const mojo::Id focused_view_transport_id(
       ViewIdToTransportId(focused_view ? focused_view->id() : ViewId()));
 
-  client->OnEmbed(id_, creator_url_, ViewToViewData(to_send.front()),
-                  service_ptr.Pass(), services.Pass(), exposed_services.Pass(),
+  client->OnEmbed(id_, ViewToViewData(to_send.front()), service_ptr.Pass(),
                   focused_view_transport_id);
 }
 
@@ -161,16 +153,10 @@
   return true;
 }
 
-void ViewManagerServiceImpl::SetEmbedRoot() {
-  is_embed_root_ = true;
-}
-
-void ViewManagerServiceImpl::Embed(mojo::URLRequestPtr request,
-                                   const ViewId& view_id,
-                                   EmbedType type,
-                                   InterfaceRequest<ServiceProvider> services,
-                                   ServiceProviderPtr exposed_services,
-                                   const mojo::Callback<void(bool)>& callback) {
+void ViewManagerServiceImpl::EmbedAllowingReembed(
+    const ViewId& view_id,
+    mojo::URLRequestPtr request,
+    const mojo::Callback<void(bool)>& callback) {
   if (!CanEmbed(view_id)) {
     callback.Run(false);
     return;
@@ -178,11 +164,10 @@
 
   ViewManagerServiceImpl* embed_root = nullptr;
 
-  // Only the creator is allowed to reset reembed.
   ServerView* view = GetView(view_id);
   DCHECK(view);  // CanEmbed() returns true only if |view_id| is valid.
   if (view->id().connection_id == id_) {
-    view->set_allows_reembed(type == EmbedType::ALLOW_REEMBED);
+    view->set_allows_reembed(true);
 
     // Only consult the embed root if the creator is doing the embed. If someone
     // other than the creator is doing the embed they were granted embed access.
@@ -191,8 +176,7 @@
 
   if (!embed_root) {
     PrepareForEmbed(view_id);
-    connection_manager_->EmbedAtView(id_, request.Pass(), view_id,
-                                     services.Pass(), exposed_services.Pass());
+    connection_manager_->EmbedAtView(id_, view_id, request.Pass());
     callback.Run(true);
     return;
   }
@@ -202,18 +186,16 @@
   pending_embeds_.insert(pending_embed);
   pending_embed->embed_root = embed_root;
   pending_embed->view_id = view_id;
-  pending_embed->url_request = request.Pass();
   pending_embed->callback = callback;
   pending_embeds_.insert(pending_embed);
-  embed_root->client()->OnWillEmbed(
-      ViewIdToTransportId(view_id), services.Pass(), exposed_services.Pass(),
-      base::Bind(&ViewManagerServiceImpl::OnWillEmbedDone,
+  embed_root->client()->OnEmbedForDescendant(
+      ViewIdToTransportId(view_id), request.Pass(),
+      base::Bind(&ViewManagerServiceImpl::OnEmbedForDescendantDone,
                  base::Unretained(this), pending_embed));
 }
 
 bool ViewManagerServiceImpl::Embed(const ViewId& view_id,
                                    mojo::ViewManagerClientPtr client) {
-  // TODO(sky): wire up embed root.
   if (!client.get() || !CanEmbed(view_id))
     return false;
   PrepareForEmbed(view_id);
@@ -249,9 +231,8 @@
   if (originated_change)
     return;
 
-  const bool old_drawn = view->IsDrawn(connection_manager_->root());
-  const bool new_drawn = view->visible() && new_parent &&
-      new_parent->IsDrawn(connection_manager_->root());
+  const bool old_drawn = view->IsDrawn();
+  const bool new_drawn = view->visible() && new_parent && new_parent->IsDrawn();
   if (old_drawn == new_drawn)
     return;
 
@@ -358,8 +339,7 @@
     view_target_drawn_state = false;
   } else {
     // View is being shown. View will be drawn if its parent is drawn.
-    view_target_drawn_state =
-        view->parent() && view->parent()->IsDrawn(connection_manager_->root());
+    view_target_drawn_state = view->parent() && view->parent()->IsDrawn();
   }
 
   NotifyDrawnStateChanged(view, view_target_drawn_state);
@@ -483,7 +463,7 @@
   view_data->properties =
       mojo::Map<String, Array<uint8_t>>::From(view->properties());
   view_data->visible = view->visible();
-  view_data->drawn = view->IsDrawn(connection_manager_->root());
+  view_data->drawn = view->IsDrawn();
   view_data->viewport_metrics =
       connection_manager_->display_manager()->GetViewportMetrics().Clone();
   return view_data.Pass();
@@ -516,8 +496,7 @@
 
   const ServerView* root = GetView(*root_);
   DCHECK(root);
-  if (view->Contains(root) &&
-      (new_drawn_value != root->IsDrawn(connection_manager_->root()))) {
+  if (view->Contains(root) && (new_drawn_value != root->IsDrawn())) {
     client()->OnViewDrawnStateChanged(ViewIdToTransportId(root->id()),
                                       new_drawn_value);
   }
@@ -567,20 +546,17 @@
     view->Remove(children[i]);
 }
 
-void ViewManagerServiceImpl::OnWillEmbedDone(
+void ViewManagerServiceImpl::OnEmbedForDescendantDone(
     scoped_refptr<PendingEmbed> pending_embed,
-    bool allow_embed,
-    mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services) {
+    mojo::ViewManagerClientPtr client) {
   if (!pending_embeds_.count(pending_embed.get()))
     return;
 
-  allow_embed = allow_embed && CanEmbed(pending_embed->view_id);
+  const bool allow_embed = client.get() && CanEmbed(pending_embed->view_id);
   if (allow_embed) {
     PrepareForEmbed(pending_embed->view_id);
-    connection_manager_->EmbedAtView(id_, pending_embed->url_request.Pass(),
-                                     pending_embed->view_id, services.Pass(),
-                                     exposed_services.Pass());
+    connection_manager_->EmbedAtView(id_, pending_embed->view_id,
+                                     client.Pass());
   }
   RemovePendingEmbedAndNotifyCallback(pending_embed.get(), allow_embed);
 }
@@ -733,23 +709,8 @@
   callback.Run(success);
 }
 
-void ViewManagerServiceImpl::EmbedRequest(
-    mojo::URLRequestPtr request,
-    Id transport_view_id,
-    InterfaceRequest<ServiceProvider> services,
-    ServiceProviderPtr exposed_services,
-    const Callback<void(bool)>& callback) {
-  Embed(request.Pass(), ViewIdFromTransportId(transport_view_id),
-        EmbedType::NO_REEMBED, services.Pass(), exposed_services.Pass(),
-        callback);
-}
-
-void ViewManagerServiceImpl::EmbedAllowingReembed(
-    mojo::URLRequestPtr request,
-    mojo::Id transport_view_id,
-    const mojo::Callback<void(bool)>& callback) {
-  Embed(request.Pass(), ViewIdFromTransportId(transport_view_id),
-        EmbedType::ALLOW_REEMBED, nullptr, nullptr, callback);
+void ViewManagerServiceImpl::SetEmbedRoot() {
+  is_embed_root_ = true;
 }
 
 void ViewManagerServiceImpl::Embed(mojo::Id transport_view_id,
@@ -758,11 +719,18 @@
   callback.Run(Embed(ViewIdFromTransportId(transport_view_id), client.Pass()));
 }
 
+void ViewManagerServiceImpl::EmbedAllowingReembed(
+    mojo::Id transport_view_id,
+    mojo::URLRequestPtr request,
+    const mojo::Callback<void(bool)>& callback) {
+  EmbedAllowingReembed(ViewIdFromTransportId(transport_view_id), request.Pass(),
+                       callback);
+}
+
 void ViewManagerServiceImpl::SetFocus(uint32_t view_id,
                                       const SetFocusCallback& callback) {
   ServerView* view = GetView(ViewIdFromTransportId(view_id));
-  bool success = view && view->IsDrawn(connection_manager_->root()) &&
-                 access_policy_->CanSetFocus(view);
+  bool success = view && view->IsDrawn() && access_policy_->CanSetFocus(view);
   if (success) {
     ConnectionManager::ScopedChange change(this, connection_manager_, false);
     connection_manager_->SetFocusedView(view);
diff --git a/components/view_manager/view_manager_service_impl.h b/components/view_manager/view_manager_service_impl.h
index 643c868..335ab1e 100644
--- a/components/view_manager/view_manager_service_impl.h
+++ b/components/view_manager/view_manager_service_impl.h
@@ -35,28 +35,18 @@
 class ViewManagerServiceImpl : public mojo::ViewManagerService,
                                public AccessPolicyDelegate {
  public:
-  enum class EmbedType {
-    ALLOW_REEMBED,
-    NO_REEMBED,
-  };
-
   ViewManagerServiceImpl(ConnectionManager* connection_manager,
                          mojo::ConnectionSpecificId creator_id,
-                         const std::string& creator_url,
-                         const std::string& url,
                          const ViewId& root_id);
   ~ViewManagerServiceImpl() override;
 
   // |services| and |exposed_services| are the ServiceProviders to pass to the
   // client via OnEmbed().
   void Init(mojo::ViewManagerClient* client,
-            mojo::ViewManagerServicePtr service_ptr,
-            mojo::InterfaceRequest<mojo::ServiceProvider> services,
-            mojo::ServiceProviderPtr exposed_services);
+            mojo::ViewManagerServicePtr service_ptr);
 
   mojo::ConnectionSpecificId id() const { return id_; }
   mojo::ConnectionSpecificId creator_id() const { return creator_id_; }
-  const std::string& url() const { return url_; }
 
   mojo::ViewManagerClient* client() { return client_; }
 
@@ -86,12 +76,9 @@
   bool AddView(const ViewId& parent_id, const ViewId& child_id);
   std::vector<const ServerView*> GetViewTree(const ViewId& view_id) const;
   bool SetViewVisibility(const ViewId& view_id, bool visible);
-  void Embed(mojo::URLRequestPtr request,
-             const ViewId& view_id,
-             EmbedType type,
-             mojo::InterfaceRequest<mojo::ServiceProvider> services,
-             mojo::ServiceProviderPtr exposed_services,
-             const mojo::Callback<void(bool)>& callback);
+  void EmbedAllowingReembed(const ViewId& view_id,
+                            mojo::URLRequestPtr request,
+                            const mojo::Callback<void(bool)>& callback);
   bool Embed(const ViewId& view_id, mojo::ViewManagerClientPtr client);
 
   // The following methods are invoked after the corresponding change has been
@@ -180,10 +167,8 @@
   bool CanEmbed(const ViewId& view_id) const;
   void PrepareForEmbed(const ViewId& view_id);
   void RemoveChildrenAsPartOfEmbed(const ViewId& view_id);
-  void OnWillEmbedDone(scoped_refptr<PendingEmbed> pending_embed,
-                       bool allow_embed,
-                       mojo::InterfaceRequest<mojo::ServiceProvider> services,
-                       mojo::ServiceProviderPtr exposed_services);
+  void OnEmbedForDescendantDone(scoped_refptr<PendingEmbed> pending_embed,
+                                mojo::ViewManagerClientPtr client);
 
   // Invalidates any PendingEmbeds with |connection| as the embed root.
   void InvalidatePendingEmbedForConnection(ViewManagerServiceImpl* connection);
@@ -228,17 +213,12 @@
                        mojo::Array<uint8_t> value,
                        const mojo::Callback<void(bool)>& callback) override;
   void SetEmbedRoot() override;
-  void EmbedRequest(mojo::URLRequestPtr request,
-                    mojo::Id transport_view_id,
-                    mojo::InterfaceRequest<mojo::ServiceProvider> services,
-                    mojo::ServiceProviderPtr exposed_services,
-                    const mojo::Callback<void(bool)>& callback) override;
   void Embed(mojo::Id transport_view_id,
              mojo::ViewManagerClientPtr client,
              const mojo::Callback<void(bool)>& callback) override;
   void EmbedAllowingReembed(
-      mojo::URLRequestPtr request,
       mojo::Id transport_view_id,
+      mojo::URLRequestPtr request,
       const mojo::Callback<void(bool)>& callback) override;
   void SetFocus(uint32_t view_id, const SetFocusCallback& callback) override;
 
@@ -254,18 +234,10 @@
   // Id of this connection as assigned by ConnectionManager.
   const mojo::ConnectionSpecificId id_;
 
-  // URL this connection was created for.
-  const std::string url_;
-
   // ID of the connection that created us. If 0 it indicates either we were
   // created by the root, or the connection that created us has been destroyed.
   mojo::ConnectionSpecificId creator_id_;
 
-  // The URL of the app that embedded the app this connection was created for.
-  // NOTE: this is empty if the connection was created by way of directly
-  // supplying the ViewManagerClient.
-  const std::string creator_url_;
-
   mojo::ViewManagerClient* client_;
 
   scoped_ptr<AccessPolicy> access_policy_;
diff --git a/components/view_manager/view_manager_service_unittest.cc b/components/view_manager/view_manager_service_unittest.cc
index 6166449..215ab5a 100644
--- a/components/view_manager/view_manager_service_unittest.cc
+++ b/components/view_manager/view_manager_service_unittest.cc
@@ -47,19 +47,16 @@
  private:
   // ViewManagerClient:
   void OnEmbed(uint16_t connection_id,
-               const String& embedder_url,
                ViewDataPtr root,
                mojo::ViewManagerServicePtr view_manager_service,
-               InterfaceRequest<ServiceProvider> services,
-               ServiceProviderPtr exposed_services,
                mojo::Id focused_view_id) override {
     // TODO(sky): add test coverage of |focused_view_id|.
-    tracker_.OnEmbed(connection_id, embedder_url, root.Pass());
+    tracker_.OnEmbed(connection_id, root.Pass());
   }
-  void OnWillEmbed(uint32_t view,
-                   mojo::InterfaceRequest<mojo::ServiceProvider> services,
-                   mojo::ServiceProviderPtr exposed_services,
-                   const OnWillEmbedCallback& callback) override {}
+  void OnEmbedForDescendant(
+      uint32_t view,
+      mojo::URLRequestPtr request,
+      const OnEmbedForDescendantCallback& callback) override {}
   void OnEmbeddedAppDisconnected(uint32_t view) override {
     tracker_.OnEmbeddedAppDisconnected(view);
   }
@@ -150,11 +147,10 @@
       ConnectionManager* connection_manager,
       mojo::InterfaceRequest<mojo::ViewManagerService> service_request,
       mojo::ConnectionSpecificId creator_id,
-      const std::string& creator_url,
       mojo::URLRequestPtr request,
       const ViewId& root_id) override {
-    scoped_ptr<ViewManagerServiceImpl> service(new ViewManagerServiceImpl(
-        connection_manager, creator_id, creator_url, request->url, root_id));
+    scoped_ptr<ViewManagerServiceImpl> service(
+        new ViewManagerServiceImpl(connection_manager, creator_id, root_id));
     last_connection_ = new TestClientConnection(service.Pass());
     return last_connection_;
   }
@@ -162,7 +158,6 @@
       ConnectionManager* connection_manager,
       mojo::InterfaceRequest<mojo::ViewManagerService> service_request,
       mojo::ConnectionSpecificId creator_id,
-      const std::string& creator_url,
       const ViewId& root_id,
       mojo::ViewManagerClientPtr client) override {
     NOTIMPLEMENTED();
@@ -250,8 +245,7 @@
     connection_manager_.reset(new ConnectionManager(
         &delegate_, scoped_ptr<DisplayManager>(new TestDisplayManager)));
     scoped_ptr<ViewManagerServiceImpl> service(new ViewManagerServiceImpl(
-        connection_manager_.get(), kInvalidConnectionId, std::string(),
-        std::string("mojo:window_manager"), RootViewId()));
+        connection_manager_.get(), kInvalidConnectionId, RootViewId(0)));
     scoped_ptr<TestClientConnection> client_connection(
         new TestClientConnection(service.Pass()));
     wm_client_ = client_connection->client();
@@ -297,9 +291,8 @@
   EXPECT_TRUE(test->wm_connection()->AddView(*(test->wm_connection()->root()),
                                              *embed_view_id));
   mojo::URLRequestPtr request(mojo::URLRequest::New());
-  test->wm_connection()->Embed(request.Pass(), *embed_view_id,
-                               ViewManagerServiceImpl::EmbedType::NO_REEMBED,
-                               nullptr, nullptr, mojo::Callback<void(bool)>());
+  test->wm_connection()->EmbedAllowingReembed(*embed_view_id, request.Pass(),
+                                              mojo::Callback<void(bool)>());
   ViewManagerServiceImpl* connection1 =
       test->connection_manager()->GetConnectionWithRoot(*embed_view_id);
   ASSERT_TRUE(connection1 != nullptr);
@@ -436,9 +429,8 @@
   EXPECT_TRUE(
       wm_connection()->AddView(*(wm_connection()->root()), embed_view_id));
   mojo::URLRequestPtr request(mojo::URLRequest::New());
-  wm_connection()->Embed(request.Pass(), embed_view_id,
-                         ViewManagerServiceImpl::EmbedType::NO_REEMBED, nullptr,
-                         nullptr, mojo::Callback<void(bool)>());
+  wm_connection()->EmbedAllowingReembed(embed_view_id, request.Pass(),
+                                        mojo::Callback<void(bool)>());
   ViewManagerServiceImpl* connection1 =
       connection_manager()->GetConnectionWithRoot(embed_view_id);
   ASSERT_TRUE(connection1 != nullptr);
@@ -486,9 +478,8 @@
       wm_connection()->AddView(*(wm_connection()->root()), embed_view_id));
   connection_manager()->root()->SetBounds(gfx::Rect(0, 0, 100, 100));
   mojo::URLRequestPtr request(mojo::URLRequest::New());
-  wm_connection()->Embed(request.Pass(), embed_view_id,
-                         ViewManagerServiceImpl::EmbedType::NO_REEMBED, nullptr,
-                         nullptr, mojo::Callback<void(bool)>());
+  wm_connection()->EmbedAllowingReembed(embed_view_id, request.Pass(),
+                                        mojo::Callback<void(bool)>());
   ViewManagerServiceImpl* connection1 =
       connection_manager()->GetConnectionWithRoot(embed_view_id);
   ASSERT_TRUE(connection1 != nullptr);
@@ -532,7 +523,7 @@
   EXPECT_EQ(connection_manager()->root(),
             connection_manager()->GetFocusedView());
   ASSERT_GE(wm_client()->tracker()->changes()->size(), 1u);
-  EXPECT_EQ("Focused id=0,1",
+  EXPECT_EQ("Focused id=0,2",
             ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
   ASSERT_GE(connection1_client->tracker()->changes()->size(), 1u);
   EXPECT_EQ(
@@ -549,7 +540,7 @@
   EXPECT_EQ(connection_manager()->root(),
             connection_manager()->GetFocusedView());
   ASSERT_EQ(wm_client()->tracker()->changes()->size(), 1u);
-  EXPECT_EQ("InputEvent view=0,1 event_action=4",
+  EXPECT_EQ("InputEvent view=0,2 event_action=4",
             ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
   EXPECT_TRUE(connection1_client->tracker()->changes()->empty());
   ;
diff --git a/components/view_manager/window_manager_access_policy.cc b/components/view_manager/window_manager_access_policy.cc
index c84c20a..87cb0f1d 100644
--- a/components/view_manager/window_manager_access_policy.cc
+++ b/components/view_manager/window_manager_access_policy.cc
@@ -60,8 +60,7 @@
 bool WindowManagerAccessPolicy::CanChangeViewVisibility(
     const ServerView* view) const {
   // The WindowManager can change the visibility of the root too.
-  return view->id().connection_id == connection_id_ ||
-         view->id() == RootViewId();
+  return view->id().connection_id == connection_id_ || view->id().IsRoot();
 }
 
 bool WindowManagerAccessPolicy::CanSetViewSurfaceId(
diff --git a/components/webcrypto/test/test_helpers.cc b/components/webcrypto/test/test_helpers.cc
index 4684c40..5e3dc5a 100644
--- a/components/webcrypto/test/test_helpers.cc
+++ b/components/webcrypto/test/test_helpers.cc
@@ -495,8 +495,9 @@
   std::string k_value;
   if (!Base64DecodeUrlSafe(value_string, &k_value))
     return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(k) failed";
-  if (!LowerCaseEqualsASCII(base::HexEncode(k_value.data(), k_value.size()),
-                            k_expected_hex.c_str())) {
+  if (!base::LowerCaseEqualsASCII(
+          base::HexEncode(k_value.data(), k_value.size()),
+          k_expected_hex.c_str())) {
     return ::testing::AssertionFailure() << "Expected 'k' to be "
                                          << k_expected_hex
                                          << " but found something different";
@@ -534,8 +535,9 @@
   std::string e_value;
   if (!Base64DecodeUrlSafe(value_string, &e_value))
     return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(e) failed";
-  if (!LowerCaseEqualsASCII(base::HexEncode(e_value.data(), e_value.size()),
-                            e_expected_hex.c_str())) {
+  if (!base::LowerCaseEqualsASCII(
+          base::HexEncode(e_value.data(), e_value.size()),
+          e_expected_hex.c_str())) {
     return ::testing::AssertionFailure() << "Expected 'e' to be "
                                          << e_expected_hex
                                          << " but found something different";
diff --git a/components/webdata_services/web_data_service_wrapper.cc b/components/webdata_services/web_data_service_wrapper.cc
index d1aeea8..73d48e7 100644
--- a/components/webdata_services/web_data_service_wrapper.cc
+++ b/components/webdata_services/web_data_service_wrapper.cc
@@ -11,7 +11,6 @@
 #include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
-#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/password_manager/core/browser/webdata/logins_table.h"
@@ -48,9 +47,6 @@
       autofill_web_data.get(), autofill_backend, app_locale);
   autofill::AutofillWalletSyncableService::CreateForWebDataServiceAndBackend(
       autofill_web_data.get(), autofill_backend, app_locale);
-  autofill::AutofillWalletMetadataSyncableService::
-      CreateForWebDataServiceAndBackend(autofill_web_data.get(),
-                                        autofill_backend, app_locale);
 
   autofill::AutofillProfileSyncableService::FromWebDataService(
       autofill_web_data.get())->InjectStartSyncFlare(sync_flare);
diff --git a/content/OWNERS b/content/OWNERS
index af383e6..04767138 100644
--- a/content/OWNERS
+++ b/content/OWNERS
@@ -4,6 +4,7 @@
 davidben@chromium.org
 jam@chromium.org
 jochen@chromium.org
+kinuko@chromium.org
 nasko@chromium.org
 piman@chromium.org
 sievers@chromium.org
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index 1a39863..cdb519f 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -282,12 +282,7 @@
   ScopedVector<ZygoteForkDelegate> zygote_fork_delegates;
   if (delegate) {
     delegate->ZygoteStarting(&zygote_fork_delegates);
-    // Each Renderer we spawn will re-attempt initialization of the media
-    // libraries, at which point failure will be detected and handled, so
-    // we do not need to cope with initialization failures here.
-    base::FilePath media_path;
-    if (PathService::Get(DIR_MEDIA_LIBS, &media_path))
-      media::InitializeMediaLibrary(media_path);
+    media::InitializeMediaLibrary();
   }
 
   // This function call can return multiple times, once per fork().
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index a8bcd7a..3cdfc88 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -266,6 +266,7 @@
                            ".",
                            "//content")
     deps += [
+      "//ppapi/host",
       "//ppapi/proxy:ipc",
       "//ppapi/shared_impl",
     ]
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 400844e7..2ed7e5c 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -48,11 +48,11 @@
   "+third_party/WebKit/public/platform/WebGamepads.h",
   "+third_party/WebKit/public/platform/WebGeofencingEventType.h",
   "+third_party/WebKit/public/platform/WebGraphicsContext3D.h",
-  "+third_party/WebKit/public/platform/WebLockOrientationError.h",
+  "+third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationError.h",
   "+third_party/WebKit/public/platform/WebReferrerPolicy.h",
   "+third_party/WebKit/public/platform/WebScreenInfo.h",
-  "+third_party/WebKit/public/platform/WebScreenOrientationLockType.h",
-  "+third_party/WebKit/public/platform/WebScreenOrientationType.h",
+  "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
+  "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h",
   "+third_party/WebKit/public/platform/WebServiceWorkerCacheError.h",
   "+third_party/WebKit/public/platform/WebServiceWorkerError.h",
   "+third_party/WebKit/public/platform/WebServiceWorkerEventResult.h",
diff --git a/content/browser/accessibility/accessibility_event_recorder.cc b/content/browser/accessibility/accessibility_event_recorder.cc
index 01c5b0d..b443a14 100644
--- a/content/browser/accessibility/accessibility_event_recorder.cc
+++ b/content/browser/accessibility/accessibility_event_recorder.cc
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/port.h"
 #include "content/browser/accessibility/accessibility_event_recorder.h"
 
+#include "build/build_config.h"
+
 namespace content {
 
 AccessibilityEventRecorder::AccessibilityEventRecorder(
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 90d8a69..b50a476 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -580,16 +580,16 @@
   base::string16 value;
   if (!GetHtmlAttribute(html_attr, &value) ||
       value.empty() ||
-      EqualsASCII(value, "undefined")) {
+      base::EqualsASCII(value, "undefined")) {
     return false;  // Not set (and *is_defined is also false)
   }
 
   *is_defined = true;
 
-  if (EqualsASCII(value, "true"))
+  if (base::EqualsASCII(value, "true"))
     return true;
 
-  if (EqualsASCII(value, "mixed"))
+  if (base::EqualsASCII(value, "mixed"))
     *is_mixed = true;
 
   return false;  // Not set
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index 2ae0a28..f4a2d86f 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -859,8 +859,8 @@
 
 void BrowserAccessibilityAndroid::NotifyLiveRegionUpdate(
     base::string16& aria_live) {
-  if (!EqualsASCII(aria_live, aria_strings::kAriaLivePolite) &&
-      !EqualsASCII(aria_live, aria_strings::kAriaLiveAssertive))
+  if (!base::EqualsASCII(aria_live, aria_strings::kAriaLivePolite) &&
+      !base::EqualsASCII(aria_live, aria_strings::kAriaLiveAssertive))
     return;
 
   base::string16 text = GetText();
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 6a9c041..2b5903bd 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -623,8 +623,11 @@
 }
 
 - (NSString*)dropeffect {
-  return NSStringForStringAttribute(
-      browserAccessibility_, ui::AX_ATTR_DROPEFFECT);
+  std::string dropEffect;
+  if (browserAccessibility_->GetHtmlAttribute("aria-dropeffect", &dropEffect))
+    return base::SysUTF8ToNSString(dropEffect);
+
+  return nil;
 }
 
 - (NSNumber*)enabled {
@@ -645,8 +648,12 @@
 }
 
 - (NSNumber*)grabbed {
-  bool boolValue = browserAccessibility_->GetBoolAttribute(ui::AX_ATTR_GRABBED);
-  return [NSNumber numberWithBool:boolValue];
+  std::string grabbed;
+  if (browserAccessibility_->GetHtmlAttribute("aria-grabbed", &grabbed) &&
+      grabbed == "true")
+    return [NSNumber numberWithBool:YES];
+
+  return [NSNumber numberWithBool:NO];
 }
 
 - (id)header {
@@ -1784,15 +1791,15 @@
         nil]];
   }
 
-  if (browserAccessibility_->HasStringAttribute(
-          ui::AX_ATTR_DROPEFFECT)) {
+  std::string dropEffect;
+  if (browserAccessibility_->GetHtmlAttribute("aria-dropeffect", &dropEffect)) {
     [ret addObjectsFromArray:[NSArray arrayWithObjects:
         @"AXDropEffects",
         nil]];
   }
 
-  // Add aria-grabbed attribute only if it has true.
-  if (browserAccessibility_->HasBoolAttribute(ui::AX_ATTR_GRABBED)) {
+  std::string grabbed;
+  if (browserAccessibility_->GetHtmlAttribute("aria-grabbed", &grabbed)) {
     [ret addObjectsFromArray:[NSArray arrayWithObjects:
         @"AXGrabbed",
         nil]];
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_win.cc b/content/browser/accessibility/browser_accessibility_state_impl_win.cc
index ddce50ec..058e3a7c 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl_win.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl_win.cc
@@ -59,13 +59,13 @@
     TCHAR filename[MAX_PATH];
     GetModuleFileName(modules[i], filename, arraysize(filename));
     base::string16 module_name(base::FilePath(filename).BaseName().value());
-    if (LowerCaseEqualsASCII(module_name, "fsdomsrv.dll"))
+    if (base::LowerCaseEqualsASCII(module_name, "fsdomsrv.dll"))
       jaws = true;
-    if (LowerCaseEqualsASCII(module_name, "vbufbackend_gecko_ia2.dll"))
+    if (base::LowerCaseEqualsASCII(module_name, "vbufbackend_gecko_ia2.dll"))
       nvda = true;
-    if (LowerCaseEqualsASCII(module_name, "stsaw32.dll"))
+    if (base::LowerCaseEqualsASCII(module_name, "stsaw32.dll"))
       satogo = true;
-    if (LowerCaseEqualsASCII(module_name, "zslhook.dll"))
+    if (base::LowerCaseEqualsASCII(module_name, "zslhook.dll"))
       zoomtext = true;
   }
 
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index 6866ca9..3c79052a 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -3173,8 +3173,6 @@
 
   // Expose the "display" and "tag" attributes.
   StringAttributeToIA2(ui::AX_ATTR_DISPLAY, "display");
-  StringAttributeToIA2(ui::AX_ATTR_DROPEFFECT, "dropeffect");
-  StringAttributeToIA2(ui::AX_ATTR_TEXT_INPUT_TYPE, "text-input-type");
   StringAttributeToIA2(ui::AX_ATTR_HTML_TAG, "tag");
   StringAttributeToIA2(ui::AX_ATTR_ROLE, "xml-roles");
 
@@ -3199,9 +3197,6 @@
   BoolAttributeToIA2(ui::AX_ATTR_LIVE_ATOMIC, "atomic");
   BoolAttributeToIA2(ui::AX_ATTR_LIVE_BUSY, "busy");
 
-  // Expose aria-grabbed attributes.
-  BoolAttributeToIA2(ui::AX_ATTR_GRABBED, "grabbed");
-
   // Expose container live region attributes.
   StringAttributeToIA2(ui::AX_ATTR_CONTAINER_LIVE_STATUS,
                        "container-live");
@@ -3407,6 +3402,28 @@
     win_attributes_->ia2_attributes.push_back(L"valuetext:" + GetValueText());
   }
 
+  // Expose dropeffect attribute.
+  base::string16 dropEffect;
+  if (GetHtmlAttribute("aria-dropeffect", &dropEffect))
+    win_attributes_->ia2_attributes.push_back(L"dropeffect:" + dropEffect);
+
+  // Expose grabbed attribute.
+  base::string16 grabbed;
+  if (GetHtmlAttribute("aria-grabbed", &grabbed))
+    win_attributes_->ia2_attributes.push_back(L"grabbed:" + grabbed);
+
+  // Expose datetime attribute.
+  base::string16 datetime;
+  if (GetRole() == ui::AX_ROLE_TIME &&
+      GetHtmlAttribute("datetime", &datetime))
+    win_attributes_->ia2_attributes.push_back(L"datetime:" + datetime);
+
+  // Expose input-text type attribute.
+  base::string16 type;
+  if (GetRole() == ui::AX_ROLE_TEXT_FIELD &&
+      GetHtmlAttribute("type", &type))
+    win_attributes_->ia2_attributes.push_back(L"text-input-type:" + type);
+
   // If this is a web area for a presentational iframe, give it a role of
   // something other than DOCUMENT so that the fact that it's a separate doc
   // is not exposed to AT.
@@ -4285,6 +4302,7 @@
       ia2_state |= IA2_STATE_SELECTABLE_TEXT;
       break;
     case ui::AX_ROLE_TIME:
+      role_name = html_tag;
       ia_role = ROLE_SYSTEM_TEXT;
       ia2_role = IA2_ROLE_TEXT_FRAME;
       break;
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index d09b852..e68a4032 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -102,19 +102,19 @@
     const std::string& deny_str =
         AccessibilityTreeFormatter::GetDenyString();
     const std::string& wait_str = "@WAIT-FOR:";
-    if (StartsWithASCII(line, allow_empty_str, true)) {
+    if (base::StartsWithASCII(line, allow_empty_str, true)) {
       filters->push_back(
           Filter(base::UTF8ToUTF16(line.substr(allow_empty_str.size())),
                  Filter::ALLOW_EMPTY));
-    } else if (StartsWithASCII(line, allow_str, true)) {
+    } else if (base::StartsWithASCII(line, allow_str, true)) {
       filters->push_back(Filter(base::UTF8ToUTF16(
           line.substr(allow_str.size())),
                                 Filter::ALLOW));
-    } else if (StartsWithASCII(line, deny_str, true)) {
+    } else if (base::StartsWithASCII(line, deny_str, true)) {
       filters->push_back(Filter(base::UTF8ToUTF16(
           line.substr(deny_str.size())),
                                 Filter::DENY));
-    } else if (StartsWithASCII(line, wait_str, true)) {
+    } else if (base::StartsWithASCII(line, wait_str, true)) {
       *wait_for = line.substr(wait_str.size());
     }
   }
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index bae4365e..288e6e46 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -965,7 +965,7 @@
   RunHtmlTest(FILE_PATH_LITERAL("main.html"));
 }
 
-IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityMark) {
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, DISABLED_AccessibilityMark) {
   RunHtmlTest(FILE_PATH_LITERAL("mark.html"));
 }
 
diff --git a/content/browser/android/browser_surface_texture_manager.cc b/content/browser/android/browser_surface_texture_manager.cc
index 832036b1..93c10f1 100644
--- a/content/browser/android/browser_surface_texture_manager.cc
+++ b/content/browser/android/browser_surface_texture_manager.cc
@@ -73,12 +73,10 @@
 
 }  // namespace
 
-BrowserSurfaceTextureManager::BrowserSurfaceTextureManager() {
-  SurfaceTexturePeer::InitInstance(this);
-}
-
-BrowserSurfaceTextureManager::~BrowserSurfaceTextureManager() {
-  SurfaceTexturePeer::InitInstance(NULL);
+// static
+BrowserSurfaceTextureManager* BrowserSurfaceTextureManager::GetInstance() {
+  return Singleton<BrowserSurfaceTextureManager,
+                   LeakySingletonTraits<BrowserSurfaceTextureManager>>::get();
 }
 
 void BrowserSurfaceTextureManager::RegisterSurfaceTexture(
@@ -133,4 +131,12 @@
                                      player_id));
 }
 
+BrowserSurfaceTextureManager::BrowserSurfaceTextureManager() {
+  SurfaceTexturePeer::InitInstance(this);
+}
+
+BrowserSurfaceTextureManager::~BrowserSurfaceTextureManager() {
+  SurfaceTexturePeer::InitInstance(nullptr);
+}
+
 }  // namespace content
diff --git a/content/browser/android/browser_surface_texture_manager.h b/content/browser/android/browser_surface_texture_manager.h
index 959d2705..e276928 100644
--- a/content/browser/android/browser_surface_texture_manager.h
+++ b/content/browser/android/browser_surface_texture_manager.h
@@ -7,15 +7,17 @@
 
 #include "content/common/android/surface_texture_manager.h"
 
+#include "base/memory/singleton.h"
 #include "content/common/android/surface_texture_peer.h"
+#include "content/common/content_export.h"
 
 namespace content {
 
-class BrowserSurfaceTextureManager : public SurfaceTextureManager,
-                                     public SurfaceTexturePeer {
+class CONTENT_EXPORT BrowserSurfaceTextureManager
+    : public SurfaceTextureManager,
+      public SurfaceTexturePeer {
  public:
-  BrowserSurfaceTextureManager();
-  ~BrowserSurfaceTextureManager() override;
+  static BrowserSurfaceTextureManager* GetInstance();
 
   // Overridden from SurfaceTextureManager:
   void RegisterSurfaceTexture(int surface_texture_id,
@@ -33,6 +35,11 @@
       int player_id) override;
 
  private:
+  friend struct DefaultSingletonTraits<BrowserSurfaceTextureManager>;
+
+  BrowserSurfaceTextureManager();
+  ~BrowserSurfaceTextureManager() override;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserSurfaceTextureManager);
 };
 
diff --git a/content/browser/android/content_startup_flags.cc b/content/browser/android/content_startup_flags.cc
index 6ebe4e1..ebd585b 100644
--- a/content/browser/android/content_startup_flags.cc
+++ b/content/browser/android/content_startup_flags.cc
@@ -63,6 +63,14 @@
   parsed_command_line->AppendSwitch(switches::kEnableOverlayScrollbar);
   parsed_command_line->AppendSwitch(switches::kValidateInputEventStream);
 
+  // TODO(jdduke): Use the proper SDK version when available, crbug.com/466749.
+  if (base::android::BuildInfo::GetInstance()->sdk_int() >
+      base::android::SDK_VERSION_LOLLIPOP_MR1) {
+    parsed_command_line->AppendSwitch(switches::kEnableLongpressDragSelection);
+    parsed_command_line->AppendSwitchASCII(
+        switches::kTouchTextSelectionStrategy, "direction");
+  }
+
   // There is no software fallback on Android, so don't limit GPU crashes.
   parsed_command_line->AppendSwitch(switches::kDisableGpuProcessCrashLimit);
 
diff --git a/content/browser/android/in_process/context_provider_in_process.cc b/content/browser/android/in_process/context_provider_in_process.cc
index 3f0f341f..f9ab90e4 100644
--- a/content/browser/android/in_process/context_provider_in_process.cc
+++ b/content/browser/android/in_process/context_provider_in_process.cc
@@ -46,23 +46,6 @@
   return new ContextProviderInProcess(context3d.Pass(), debug_name);
 }
 
-// static
-scoped_refptr<ContextProviderInProcess>
-ContextProviderInProcess::CreateOffscreen(
-    bool lose_context_when_out_of_memory) {
-  blink::WebGraphicsContext3D::Attributes attributes;
-  attributes.depth = false;
-  attributes.stencil = true;
-  attributes.antialias = false;
-  attributes.shareResources = true;
-  attributes.noAutomaticFlushes = true;
-
-  return Create(
-      WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
-          attributes, lose_context_when_out_of_memory),
-      "Offscreen");
-}
-
 ContextProviderInProcess::ContextProviderInProcess(
     scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
     const std::string& debug_name)
@@ -176,18 +159,11 @@
   return &context_lock_;
 }
 
-bool ContextProviderInProcess::IsContextLost() {
-  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
-  DCHECK(context_thread_checker_.CalledOnValidThread());
-
-  return context3d_->isContextLost();
-}
-
 void ContextProviderInProcess::VerifyContexts() {
   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
   DCHECK(context_thread_checker_.CalledOnValidThread());
 
-  if (context3d_->isContextLost())
+  if (ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR)
     OnLostContext();
 }
 
diff --git a/content/browser/android/in_process/context_provider_in_process.h b/content/browser/android/in_process/context_provider_in_process.h
index 946184a..b2b2ba8 100644
--- a/content/browser/android/in_process/context_provider_in_process.h
+++ b/content/browser/android/in_process/context_provider_in_process.h
@@ -31,10 +31,6 @@
           context3d,
       const std::string& debug_name);
 
-  // Uses default attributes for creating an offscreen context.
-  static scoped_refptr<ContextProviderInProcess> CreateOffscreen(
-      bool lose_context_when_out_of_memory);
-
  private:
   ContextProviderInProcess(
       scoped_ptr<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl>
@@ -55,7 +51,6 @@
   void InvalidateGrContext(uint32_t state) override;
   void SetupLock() override;
   base::Lock* GetLock() override;
-  bool IsContextLost() override;
   void VerifyContexts() override;
   void DeleteCachedResources() override;
   bool DestroyedOnMainThread() override;
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc
index 4329ce5..43cb714 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -345,12 +345,21 @@
       compositor_client_->GetTotalRootLayerScrollOffset());
 }
 
-bool SynchronousCompositorImpl::IsExternalFlingActive() const {
+bool SynchronousCompositorImpl::IsExternalScrollActive() const {
   DCHECK(CalledOnValidThread());
   DCHECK(compositor_client_);
   if (!registered_with_client_)
     return false;
-  return compositor_client_->IsExternalFlingActive();
+  return compositor_client_->IsExternalScrollActive();
+}
+
+void SynchronousCompositorImpl::SetNeedsAnimate(
+    const AnimationCallback& animation) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(compositor_client_);
+  if (!registered_with_client_)
+    return;
+  compositor_client_->SetNeedsAnimateScroll(animation);
 }
 
 void SynchronousCompositorImpl::UpdateRootLayerState(
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.h b/content/browser/android/in_process/synchronous_compositor_impl.h
index 49334fe..7acad16 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.h
+++ b/content/browser/android/in_process/synchronous_compositor_impl.h
@@ -87,7 +87,8 @@
                             float page_scale_factor,
                             float min_page_scale_factor,
                             float max_page_scale_factor) override;
-  bool IsExternalFlingActive() const override;
+  bool IsExternalScrollActive() const override;
+  void SetNeedsAnimate(const AnimationCallback& scroll_animation) override;
 
   void DidOverscroll(const DidOverscrollParams& params);
   void DidStopFlinging();
diff --git a/content/browser/android/in_process_surface_texture_manager.cc b/content/browser/android/in_process_surface_texture_manager.cc
new file mode 100644
index 0000000..bdfb22ec
--- /dev/null
+++ b/content/browser/android/in_process_surface_texture_manager.cc
@@ -0,0 +1,70 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/in_process_surface_texture_manager.h"
+
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/logging.h"
+
+namespace content {
+
+// static
+InProcessSurfaceTextureManager* InProcessSurfaceTextureManager::GetInstance() {
+  return Singleton<InProcessSurfaceTextureManager,
+                   LeakySingletonTraits<InProcessSurfaceTextureManager>>::get();
+}
+
+void InProcessSurfaceTextureManager::RegisterSurfaceTexture(
+    int surface_texture_id,
+    int client_id,
+    gfx::SurfaceTexture* surface_texture) {
+  base::AutoLock lock(lock_);
+
+  DCHECK(surface_textures_.find(surface_texture_id) == surface_textures_.end());
+  surface_textures_.add(
+      surface_texture_id,
+      make_scoped_ptr(new gfx::ScopedJavaSurface(surface_texture)));
+}
+
+void InProcessSurfaceTextureManager::UnregisterSurfaceTexture(
+    int surface_texture_id,
+    int client_id) {
+  base::AutoLock lock(lock_);
+
+  DCHECK(surface_textures_.find(surface_texture_id) != surface_textures_.end());
+  surface_textures_.erase(surface_texture_id);
+}
+
+gfx::AcceleratedWidget
+InProcessSurfaceTextureManager::AcquireNativeWidgetForSurfaceTexture(
+    int surface_texture_id) {
+  base::AutoLock lock(lock_);
+
+  DCHECK(surface_textures_.find(surface_texture_id) != surface_textures_.end());
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return ANativeWindow_fromSurface(
+      env, surface_textures_.get(surface_texture_id)->j_surface().obj());
+}
+
+void InProcessSurfaceTextureManager::EstablishSurfaceTexturePeer(
+    base::ProcessHandle render_process_handle,
+    scoped_refptr<gfx::SurfaceTexture> surface_texture,
+    int render_frame_id,
+    int player_id) {
+  NOTIMPLEMENTED();
+}
+
+InProcessSurfaceTextureManager::InProcessSurfaceTextureManager() {
+  SurfaceTexturePeer::InitInstance(this);
+}
+
+InProcessSurfaceTextureManager::~InProcessSurfaceTextureManager() {
+  SurfaceTexturePeer::InitInstance(nullptr);
+}
+
+}  // namespace content
diff --git a/content/browser/android/in_process_surface_texture_manager.h b/content/browser/android/in_process_surface_texture_manager.h
new file mode 100644
index 0000000..26573eb7
--- /dev/null
+++ b/content/browser/android/in_process_surface_texture_manager.h
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_IN_PROCESS_SURFACE_TEXTURE_MANAGER_H_
+#define CONTENT_BROWSER_ANDROID_IN_PROCESS_SURFACE_TEXTURE_MANAGER_H_
+
+#include "content/common/android/surface_texture_manager.h"
+
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+#include "content/common/android/surface_texture_peer.h"
+#include "content/common/content_export.h"
+#include "ui/gl/android/scoped_java_surface.h"
+
+namespace content {
+
+class CONTENT_EXPORT InProcessSurfaceTextureManager
+    : public SurfaceTextureManager,
+      public SurfaceTexturePeer {
+ public:
+  static InProcessSurfaceTextureManager* GetInstance();
+
+  // Overridden from SurfaceTextureManager:
+  void RegisterSurfaceTexture(int surface_texture_id,
+                              int client_id,
+                              gfx::SurfaceTexture* surface_texture) override;
+  void UnregisterSurfaceTexture(int surface_texture_id, int client_id) override;
+  gfx::AcceleratedWidget AcquireNativeWidgetForSurfaceTexture(
+      int surface_texture_id) override;
+
+  // Overridden from SurfaceTexturePeer:
+  void EstablishSurfaceTexturePeer(
+      base::ProcessHandle render_process_handle,
+      scoped_refptr<gfx::SurfaceTexture> surface_texture,
+      int render_frame_id,
+      int player_id) override;
+
+ private:
+  friend struct DefaultSingletonTraits<InProcessSurfaceTextureManager>;
+
+  InProcessSurfaceTextureManager();
+  ~InProcessSurfaceTextureManager() override;
+
+  using SurfaceTextureMap =
+      base::ScopedPtrHashMap<int, scoped_ptr<gfx::ScopedJavaSurface>>;
+  SurfaceTextureMap surface_textures_;
+  base::Lock lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(InProcessSurfaceTextureManager);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_ANDROID_IN_PROCESS_SURFACE_TEXTURE_MANAGER_H_
diff --git a/content/browser/android/java/gin_java_script_to_java_types_coercion.cc b/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
index 84b20703..d7010ee9 100644
--- a/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
+++ b/content/browser/android/java/gin_java_script_to_java_types_coercion.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/android/java/gin_java_script_to_java_types_coercion.h"
 
+#include <stdint.h>
 #include <unistd.h>
 
 #include "base/android/jni_android.h"
@@ -37,7 +38,7 @@
   // compare to custom constants. kint64max is 2^63 - 1, but the spacing
   // between double values in the the range 2^62 to 2^63 is 2^10. The cast is
   // required to silence a spurious gcc warning for integer overflow.
-  const int64 kLimit = (GG_INT64_C(1) << 63) - static_cast<uint64>(1 << 10);
+  const int64 kLimit = (INT64_C(1) << 63) - static_cast<uint64>(1 << 10);
   DCHECK(kLimit > 0);
   const double kLargestDoubleLessThanInt64Max = kLimit;
   const double kSmallestDoubleGreaterThanInt64Min = -kLimit;
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index fe577b1..566027a 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -101,6 +101,13 @@
   FAMF_APPEND_SHARED_MEMORY_TO_STREAM = 75,
   IDBDH_CAN_READ_FILE = 76,
   IDBDH_GET_OR_TERMINATE = 77,
+  RMF_SET_COOKIE_BAD_ORIGIN = 78,
+  RMF_GET_COOKIES_BAD_ORIGIN = 79,
+  SWDH_GET_REGISTRATIONS_NO_HOST = 80,
+  SWDH_GET_REGISTRATIONS_INVALID_ORIGIN = 81,
+  ARH_UNAUTHORIZED_URL = 82,
+  BDH_INVALID_SERVICE_ID = 83,
+
   // Please add new elements here. The naming convention is abbreviated class
   // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
   // reason.
diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
index c11c203..a2c26ec 100644
--- a/content/browser/bluetooth/bluetooth_dispatcher_host.cc
+++ b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
@@ -5,15 +5,18 @@
 #include "content/browser/bluetooth/bluetooth_dispatcher_host.h"
 
 #include "base/strings/utf_string_conversions.h"
+#include "content/browser/bad_message.h"
 #include "content/common/bluetooth/bluetooth_messages.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/bluetooth_device.h"
 #include "device/bluetooth/bluetooth_discovery_session.h"
+#include "device/bluetooth/bluetooth_gatt_characteristic.h"
 #include "device/bluetooth/bluetooth_gatt_service.h"
 
 using device::BluetoothAdapter;
 using device::BluetoothAdapterFactory;
+using device::BluetoothGattCharacteristic;
 using device::BluetoothGattService;
 
 namespace content {
@@ -54,6 +57,7 @@
   IPC_MESSAGE_HANDLER(BluetoothHostMsg_RequestDevice, OnRequestDevice)
   IPC_MESSAGE_HANDLER(BluetoothHostMsg_ConnectGATT, OnConnectGATT)
   IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetPrimaryService, OnGetPrimaryService)
+  IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetCharacteristic, OnGetCharacteristic)
   IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -149,6 +153,58 @@
       base::TimeDelta::FromSeconds(current_delay_time_));
 }
 
+void BluetoothDispatcherHost::OnGetCharacteristic(
+    int thread_id,
+    int request_id,
+    const std::string& service_instance_id,
+    const std::string& characteristic_uuid) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  auto device_iter = service_to_device_.find(service_instance_id);
+  // A service_instance_id not in the map implies a hostile renderer
+  // because a renderer obtains the service id from this class and
+  // it will be added to the map at that time.
+  if (device_iter == service_to_device_.end()) {
+    // Kill the renderer
+    bad_message::ReceivedBadMessage(this, bad_message::BDH_INVALID_SERVICE_ID);
+    return;
+  }
+
+  // TODO(ortuno): Check if domain has access to device.
+  // https://crbug.com/493459
+  device::BluetoothDevice* device =
+      adapter_->GetDevice(device_iter->second /* device_instance_id */);
+
+  if (device == NULL) {
+    Send(new BluetoothMsg_GetCharacteristicError(
+        thread_id, request_id, BluetoothError::NETWORK_ERROR));
+    return;
+  }
+
+  // TODO(ortuno): Check if domain has access to service
+  // http://crbug.com/493460
+  device::BluetoothGattService* service =
+      device->GetGattService(service_instance_id);
+  if (!service) {
+    Send(new BluetoothMsg_GetCharacteristicError(
+        thread_id, request_id, BluetoothError::NETWORK_ERROR));
+    return;
+  }
+
+  for (BluetoothGattCharacteristic* characteristic :
+       service->GetCharacteristics()) {
+    if (characteristic->GetUUID().canonical_value() == characteristic_uuid) {
+      // TODO(ortuno): Use generated instance ID instead.
+      // https://crbug.com/495379
+      Send(new BluetoothMsg_GetCharacteristicSuccess(
+          thread_id, request_id, characteristic->GetIdentifier()));
+      return;
+    }
+  }
+  Send(new BluetoothMsg_GetCharacteristicError(thread_id, request_id,
+                                               BluetoothError::NOT_FOUND));
+}
+
 void BluetoothDispatcherHost::OnDiscoverySessionStarted(
     int thread_id,
     int request_id,
@@ -253,8 +309,19 @@
   }
   for (BluetoothGattService* service : device->GetGattServices()) {
     if (service->GetUUID().canonical_value() == service_uuid) {
+      // TODO(ortuno): Use generated instance ID instead.
+      // https://crbug.com/495379
+      const std::string& service_identifier = service->GetIdentifier();
+      auto insert_result = service_to_device_.insert(
+          make_pair(service_identifier, device_instance_id));
+
+      // If the service existed already check that device_instance_id is the
+      // same.
+      if (!insert_result.second)
+        DCHECK(insert_result.first->second == device_instance_id);
+
       Send(new BluetoothMsg_GetPrimaryServiceSuccess(thread_id, request_id,
-                                                     service->GetIdentifier()));
+                                                     service_identifier));
       return;
     }
   }
diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.h b/content/browser/bluetooth/bluetooth_dispatcher_host.h
index bd21686..fff3671 100644
--- a/content/browser/bluetooth/bluetooth_dispatcher_host.h
+++ b/content/browser/bluetooth/bluetooth_dispatcher_host.h
@@ -57,6 +57,10 @@
                            int request_id,
                            const std::string& device_instance_id,
                            const std::string& service_uuid);
+  void OnGetCharacteristic(int thread_id,
+                           int request_id,
+                           const std::string& service_instance_id,
+                           const std::string& characteristic_uuid);
 
   // Callbacks for BluetoothAdapter::StartDiscoverySession.
   void OnDiscoverySessionStarted(
@@ -95,6 +99,10 @@
                             const std::string& device_instance_id,
                             const std::string& service_uuid);
 
+  // Maps to get the object's parent based on it's instanceID
+  // Map of service_instance_id to device_instance_id.
+  std::map<std::string, std::string> service_to_device_;
+
   // Defines how long to scan for and how long to discover services for.
   int current_delay_time_;
 
diff --git a/content/browser/browser_io_surface_manager_mac.h b/content/browser/browser_io_surface_manager_mac.h
index 6b69297..6b9b5ea 100644
--- a/content/browser/browser_io_surface_manager_mac.h
+++ b/content/browser/browser_io_surface_manager_mac.h
@@ -17,6 +17,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
 #include "base/synchronization/lock.h"
+#include "content/common/content_export.h"
 #include "content/common/mac/io_surface_manager.h"
 #include "content/common/mac/io_surface_manager_messages.h"
 #include "content/common/mac/io_surface_manager_token.h"
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 9ed607ac..9f189de 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -86,6 +86,7 @@
 #include "base/android/jni_android.h"
 #include "content/browser/android/browser_startup_controller.h"
 #include "content/browser/android/browser_surface_texture_manager.h"
+#include "content/browser/android/in_process_surface_texture_manager.h"
 #include "content/browser/android/tracing_controller_android.h"
 #include "content/browser/screen_orientation/screen_orientation_delegate_android.h"
 #include "content/public/browser/screen_orientation_provider.h"
@@ -102,6 +103,7 @@
 #include "content/browser/browser_io_surface_manager_mac.h"
 #include "content/browser/cocoa/system_hotkey_helper_mac.h"
 #include "content/browser/compositor/browser_compositor_view_mac.h"
+#include "content/browser/in_process_io_surface_manager_mac.h"
 #include "content/browser/theme_helper_mac.h"
 #endif
 
@@ -548,7 +550,7 @@
 #if !defined(OS_IOS)
   {
     TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:MediaFeatures");
-    media::InitializeCPUSpecificMediaFeatures();
+    media::InitializeMediaLibrary();
   }
   {
     TRACE_EVENT0("startup",
@@ -589,7 +591,13 @@
 #if defined(OS_ANDROID)
   {
     TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:SurfaceTextureManager");
-    SurfaceTextureManager::SetInstance(new BrowserSurfaceTextureManager);
+    if (parsed_command_line_.HasSwitch(switches::kSingleProcess)) {
+      SurfaceTextureManager::SetInstance(
+          InProcessSurfaceTextureManager::GetInstance());
+    } else {
+      SurfaceTextureManager::SetInstance(
+          BrowserSurfaceTextureManager::GetInstance());
+    }
   }
 
   if (!parsed_command_line_.HasSwitch(
@@ -605,7 +613,11 @@
 #if defined(OS_MACOSX) && !defined(OS_IOS)
   {
     TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:IOSurfaceManager");
-    IOSurfaceManager::SetInstance(BrowserIOSurfaceManager::GetInstance());
+    if (parsed_command_line_.HasSwitch(switches::kSingleProcess)) {
+      IOSurfaceManager::SetInstance(InProcessIOSurfaceManager::GetInstance());
+    } else {
+      IOSurfaceManager::SetInstance(BrowserIOSurfaceManager::GetInstance());
+    }
   }
 #endif
 
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index f438805..f01c9f11 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -320,7 +320,7 @@
     WebContentsImpl* web_contents,
     BrowserPluginGuestDelegate* delegate) {
   return new BrowserPluginGuest(
-      web_contents->opener() != nullptr, web_contents, delegate);
+      web_contents->HasOpener(), web_contents, delegate);
 }
 
 // static
diff --git a/content/browser/cache_storage/cache_storage.cc b/content/browser/cache_storage/cache_storage.cc
index 24cc38b..71d2c35 100644
--- a/content/browser/cache_storage/cache_storage.cc
+++ b/content/browser/cache_storage/cache_storage.cc
@@ -24,6 +24,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "net/base/directory_lister.h"
 #include "net/base/net_errors.h"
+#include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 
@@ -52,12 +53,12 @@
 
   CacheLoader(
       base::SequencedTaskRunner* cache_task_runner,
-      net::URLRequestContext* request_context,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
       base::WeakPtr<storage::BlobStorageContext> blob_context,
       const GURL& origin)
       : cache_task_runner_(cache_task_runner),
-        request_context_(request_context),
+        request_context_getter_(request_context_getter),
         quota_manager_proxy_(quota_manager_proxy),
         blob_context_(blob_context),
         origin_(origin) {
@@ -90,7 +91,7 @@
 
  protected:
   scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
-  net::URLRequestContext* request_context_;
+  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
   scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
   base::WeakPtr<storage::BlobStorageContext> blob_context_;
   GURL origin_;
@@ -104,7 +105,7 @@
  public:
   MemoryLoader(
       base::SequencedTaskRunner* cache_task_runner,
-      net::URLRequestContext* request_context,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context,
       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
       base::WeakPtr<storage::BlobStorageContext> blob_context,
       const GURL& origin)
@@ -117,7 +118,7 @@
   scoped_refptr<CacheStorageCache> CreateCache(
       const std::string& cache_name) override {
     return CacheStorageCache::CreateMemoryCache(
-        origin_, request_context_, quota_manager_proxy_, blob_context_);
+        origin_, request_context_getter_, quota_manager_proxy_, blob_context_);
   }
 
   void CreateCache(const std::string& cache_name,
@@ -160,7 +161,7 @@
   SimpleCacheLoader(
       const base::FilePath& origin_path,
       base::SequencedTaskRunner* cache_task_runner,
-      net::URLRequestContext* request_context,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context,
       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
       base::WeakPtr<storage::BlobStorageContext> blob_context,
       const GURL& origin)
@@ -178,7 +179,7 @@
 
     return CacheStorageCache::CreatePersistentCache(
         origin_, CreatePersistentCachePath(origin_path_, cache_name),
-        request_context_, quota_manager_proxy_, blob_context_);
+        request_context_getter_, quota_manager_proxy_, blob_context_);
   }
 
   void CreateCache(const std::string& cache_name,
@@ -357,7 +358,7 @@
     const base::FilePath& path,
     bool memory_only,
     base::SequencedTaskRunner* cache_task_runner,
-    net::URLRequestContext* request_context,
+    const scoped_refptr<net::URLRequestContextGetter>& request_context,
     const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
     base::WeakPtr<storage::BlobStorageContext> blob_context,
     const GURL& origin)
diff --git a/content/browser/cache_storage/cache_storage.h b/content/browser/cache_storage/cache_storage.h
index 261eebd..6ec3e23 100644
--- a/content/browser/cache_storage/cache_storage.h
+++ b/content/browser/cache_storage/cache_storage.h
@@ -10,6 +10,7 @@
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "content/browser/cache_storage/cache_storage_cache.h"
 
@@ -18,7 +19,7 @@
 }
 
 namespace net {
-class URLRequestContext;
+class URLRequestContextGetter;
 }
 
 namespace storage {
@@ -48,7 +49,7 @@
       const base::FilePath& origin_path,
       bool memory_only,
       base::SequencedTaskRunner* cache_task_runner,
-      net::URLRequestContext* request_context,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
       base::WeakPtr<storage::BlobStorageContext> blob_context,
       const GURL& origin);
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc
index ab57e30..b7c92d7 100644
--- a/content/browser/cache_storage/cache_storage_cache.cc
+++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -19,7 +19,7 @@
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/disk_cache.h"
-#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/blob/blob_storage_context.h"
@@ -178,15 +178,20 @@
         weak_ptr_factory_(this) {}
 
   // |entry| is passed to the callback once complete.
-  void StreamBlobToCache(disk_cache::ScopedEntryPtr entry,
-                         net::URLRequestContext* request_context,
-                         scoped_ptr<storage::BlobDataHandle> blob_data_handle,
-                         const EntryAndBoolCallback& callback) {
+  void StreamBlobToCache(
+      disk_cache::ScopedEntryPtr entry,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
+      scoped_ptr<storage::BlobDataHandle> blob_data_handle,
+      const EntryAndBoolCallback& callback) {
     DCHECK(entry);
+    DCHECK(request_context_getter->GetURLRequestContext());
+
     entry_ = entry.Pass();
     callback_ = callback;
+
     blob_request_ = storage::BlobProtocolHandler::CreateBlobRequest(
-        blob_data_handle.Pass(), request_context, this);
+        blob_data_handle.Pass(), request_context_getter->GetURLRequestContext(),
+        this);
     blob_request_->Start();
   }
 
@@ -341,14 +346,14 @@
       scoped_ptr<ServiceWorkerResponse> response,
       scoped_ptr<storage::BlobDataHandle> blob_data_handle,
       const CacheStorageCache::ErrorCallback& callback,
-      net::URLRequestContext* request_context,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy)
       : origin(origin),
         request(request.Pass()),
         response(response.Pass()),
         blob_data_handle(blob_data_handle.Pass()),
         callback(callback),
-        request_context(request_context),
+        request_context_getter(request_context_getter),
         quota_manager_proxy(quota_manager_proxy),
         cache_entry(NULL) {}
   ~PutContext() {
@@ -362,7 +367,7 @@
   scoped_ptr<ServiceWorkerResponse> response;
   scoped_ptr<storage::BlobDataHandle> blob_data_handle;
   CacheStorageCache::ErrorCallback callback;
-  net::URLRequestContext* request_context;
+  scoped_refptr<net::URLRequestContextGetter> request_context_getter;
   scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy;
 
   // This isn't a scoped_ptr because the disk_cache needs an Entry** as input to
@@ -375,11 +380,11 @@
 // static
 scoped_refptr<CacheStorageCache> CacheStorageCache::CreateMemoryCache(
     const GURL& origin,
-    net::URLRequestContext* request_context,
+    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
     const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
     base::WeakPtr<storage::BlobStorageContext> blob_context) {
   return make_scoped_refptr(
-      new CacheStorageCache(origin, base::FilePath(), request_context,
+      new CacheStorageCache(origin, base::FilePath(), request_context_getter,
                             quota_manager_proxy, blob_context));
 }
 
@@ -387,11 +392,11 @@
 scoped_refptr<CacheStorageCache> CacheStorageCache::CreatePersistentCache(
     const GURL& origin,
     const base::FilePath& path,
-    net::URLRequestContext* request_context,
+    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
     const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
     base::WeakPtr<storage::BlobStorageContext> blob_context) {
   return make_scoped_refptr(new CacheStorageCache(
-      origin, path, request_context, quota_manager_proxy, blob_context));
+      origin, path, request_context_getter, quota_manager_proxy, blob_context));
 }
 
 CacheStorageCache::~CacheStorageCache() {
@@ -554,12 +559,12 @@
 CacheStorageCache::CacheStorageCache(
     const GURL& origin,
     const base::FilePath& path,
-    net::URLRequestContext* request_context,
+    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
     const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
     base::WeakPtr<storage::BlobStorageContext> blob_context)
     : origin_(origin),
       path_(path),
-      request_context_(request_context),
+      request_context_getter_(request_context_getter),
       quota_manager_proxy_(quota_manager_proxy),
       blob_storage_context_(blob_context),
       backend_state_(BACKEND_UNINITIALIZED),
@@ -794,7 +799,7 @@
 
   scoped_ptr<PutContext> put_context(new PutContext(
       origin_, request.Pass(), response.Pass(), blob_data_handle.Pass(),
-      pending_callback, request_context_, quota_manager_proxy_));
+      pending_callback, request_context_getter_, quota_manager_proxy_));
 
   scheduler_->ScheduleOperation(base::Bind(&CacheStorageCache::PutImpl,
                                            weak_ptr_factory_.GetWeakPtr(),
@@ -932,12 +937,13 @@
   BlobReader* reader_ptr = reader.get();
 
   // Grab some pointers before passing put_context in Bind.
-  net::URLRequestContext* request_context = put_context->request_context;
+  scoped_refptr<net::URLRequestContextGetter> request_context_getter =
+      put_context->request_context_getter;
   scoped_ptr<storage::BlobDataHandle> blob_data_handle =
       put_context->blob_data_handle.Pass();
 
   reader_ptr->StreamBlobToCache(
-      entry.Pass(), request_context, blob_data_handle.Pass(),
+      entry.Pass(), request_context_getter, blob_data_handle.Pass(),
       base::Bind(&CacheStorageCache::PutDidWriteBlobToCache,
                  weak_ptr_factory_.GetWeakPtr(),
                  base::Passed(put_context.Pass()),
diff --git a/content/browser/cache_storage/cache_storage_cache.h b/content/browser/cache_storage/cache_storage_cache.h
index 8e682ea..ccc2d1c83 100644
--- a/content/browser/cache_storage/cache_storage_cache.h
+++ b/content/browser/cache_storage/cache_storage_cache.h
@@ -16,7 +16,7 @@
 #include "net/disk_cache/disk_cache.h"
 
 namespace net {
-class URLRequestContext;
+class URLRequestContextGetter;
 class IOBufferWithSize;
 }
 
@@ -50,13 +50,13 @@
 
   static scoped_refptr<CacheStorageCache> CreateMemoryCache(
       const GURL& origin,
-      net::URLRequestContext* request_context,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
       base::WeakPtr<storage::BlobStorageContext> blob_context);
   static scoped_refptr<CacheStorageCache> CreatePersistentCache(
       const GURL& origin,
       const base::FilePath& path,
-      net::URLRequestContext* request_context,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
       base::WeakPtr<storage::BlobStorageContext> blob_context);
 
@@ -121,7 +121,7 @@
   CacheStorageCache(
       const GURL& origin,
       const base::FilePath& path,
-      net::URLRequestContext* request_context,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
       base::WeakPtr<storage::BlobStorageContext> blob_context);
 
@@ -206,7 +206,7 @@
 
   GURL origin_;
   base::FilePath path_;
-  net::URLRequestContext* request_context_;
+  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
   scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
   base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
   BackendState backend_state_;
diff --git a/content/browser/cache_storage/cache_storage_cache_unittest.cc b/content/browser/cache_storage/cache_storage_cache_unittest.cc
index 2f11ab7..6a9ce3d 100644
--- a/content/browser/cache_storage/cache_storage_cache_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/strings/string_split.h"
 #include "base/thread_task_runner_handle.h"
@@ -128,12 +129,12 @@
   TestCacheStorageCache(
       const GURL& origin,
       const base::FilePath& path,
-      net::URLRequestContext* request_context,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
       const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy,
       base::WeakPtr<storage::BlobStorageContext> blob_context)
       : CacheStorageCache(origin,
                           path,
-                          request_context,
+                          request_context_getter,
                           quota_manager_proxy,
                           blob_context),
         delay_backend_creation_(false) {}
@@ -204,7 +205,7 @@
     base::FilePath path = MemoryOnly() ? base::FilePath() : temp_dir_.path();
 
     cache_ = make_scoped_refptr(new TestCacheStorageCache(
-        GURL("http://example.com"), path, url_request_context,
+        GURL("http://example.com"), path, browser_context_.GetRequestContext(),
         quota_manager_proxy_, blob_storage_context->context()->AsWeakPtr()));
   }
 
diff --git a/content/browser/cache_storage/cache_storage_context_impl.cc b/content/browser/cache_storage/cache_storage_context_impl.cc
index 7e430709..aa5c030 100644
--- a/content/browser/cache_storage/cache_storage_context_impl.cc
+++ b/content/browser/cache_storage/cache_storage_context_impl.cc
@@ -71,14 +71,13 @@
 }
 
 void CacheStorageContextImpl::SetBlobParametersForCache(
-    net::URLRequestContextGetter* request_context,
+    net::URLRequestContextGetter* request_context_getter,
     ChromeBlobStorageContext* blob_storage_context) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  if (cache_manager_ && request_context && blob_storage_context) {
+  if (cache_manager_ && request_context_getter && blob_storage_context) {
     cache_manager_->SetBlobParametersForCache(
-        request_context->GetURLRequestContext(),
-        blob_storage_context->context()->AsWeakPtr());
+        request_context_getter, blob_storage_context->context()->AsWeakPtr());
   }
 }
 
diff --git a/content/browser/cache_storage/cache_storage_context_impl.h b/content/browser/cache_storage/cache_storage_context_impl.h
index 2944a40..9130b12 100644
--- a/content/browser/cache_storage/cache_storage_context_impl.h
+++ b/content/browser/cache_storage/cache_storage_context_impl.h
@@ -59,7 +59,7 @@
   // function immediately returns without forwarding to the
   // CacheStorageManager.
   void SetBlobParametersForCache(
-      net::URLRequestContextGetter* request_context,
+      net::URLRequestContextGetter* request_context_getter,
       ChromeBlobStorageContext* blob_storage_context);
 
  private:
diff --git a/content/browser/cache_storage/cache_storage_manager.cc b/content/browser/cache_storage/cache_storage_manager.cc
index 9b56c079..cc13c44 100644
--- a/content/browser/cache_storage/cache_storage_manager.cc
+++ b/content/browser/cache_storage/cache_storage_manager.cc
@@ -99,7 +99,7 @@
       old_manager->quota_manager_proxy_.get()));
   // These values may be NULL, in which case this will be called again later by
   // the dispatcher host per usual.
-  manager->SetBlobParametersForCache(old_manager->url_request_context(),
+  manager->SetBlobParametersForCache(old_manager->url_request_context_getter(),
                                      old_manager->blob_storage_context());
   return manager.Pass();
 }
@@ -173,13 +173,14 @@
 }
 
 void CacheStorageManager::SetBlobParametersForCache(
-    net::URLRequestContext* request_context,
+    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
     base::WeakPtr<storage::BlobStorageContext> blob_storage_context) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(cache_storage_map_.empty());
-  DCHECK(!request_context_ || request_context_ == request_context);
+  DCHECK(!request_context_getter_ ||
+         request_context_getter_.get() == request_context_getter.get());
   DCHECK(!blob_context_ || blob_context_.get() == blob_storage_context.get());
-  request_context_ = request_context;
+  request_context_getter_ = request_context_getter;
   blob_context_ = blob_storage_context;
 }
 
@@ -292,7 +293,6 @@
     : root_path_(path),
       cache_task_runner_(cache_task_runner),
       quota_manager_proxy_(quota_manager_proxy),
-      request_context_(NULL),
       weak_ptr_factory_(this) {
   if (quota_manager_proxy_.get()) {
     quota_manager_proxy_->RegisterClient(
@@ -303,13 +303,13 @@
 CacheStorage* CacheStorageManager::FindOrCreateCacheStorage(
     const GURL& origin) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(request_context_);
+  DCHECK(request_context_getter_);
   CacheStorageMap::const_iterator it = cache_storage_map_.find(origin);
   if (it == cache_storage_map_.end()) {
     MigrateOrigin(origin);
     CacheStorage* cache_storage = new CacheStorage(
         ConstructOriginPath(root_path_, origin), IsMemoryBacked(),
-        cache_task_runner_.get(), request_context_, quota_manager_proxy_,
+        cache_task_runner_.get(), request_context_getter_, quota_manager_proxy_,
         blob_context_, origin);
     // The map owns fetch_stores.
     cache_storage_map_.insert(std::make_pair(origin, cache_storage));
diff --git a/content/browser/cache_storage/cache_storage_manager.h b/content/browser/cache_storage/cache_storage_manager.h
index b9eeda69..b762a21 100644
--- a/content/browser/cache_storage/cache_storage_manager.h
+++ b/content/browser/cache_storage/cache_storage_manager.h
@@ -11,8 +11,10 @@
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
 #include "content/browser/cache_storage/cache_storage.h"
 #include "content/common/content_export.h"
+#include "net/url_request/url_request_context_getter.h"
 #include "storage/browser/quota/quota_client.h"
 #include "url/gurl.h"
 
@@ -20,10 +22,6 @@
 class SequencedTaskRunner;
 }
 
-namespace net {
-class URLRequestContext;
-}
-
 namespace storage {
 class BlobStorageContext;
 class QuotaManagerProxy;
@@ -73,7 +71,7 @@
   // This must be called before creating any of the public *Cache functions
   // above.
   void SetBlobParametersForCache(
-      net::URLRequestContext* request_context,
+      const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
       base::WeakPtr<storage::BlobStorageContext> blob_storage_context);
 
   base::WeakPtr<CacheStorageManager> AsWeakPtr() {
@@ -110,8 +108,9 @@
       scoped_ptr<CacheStorage> cache_storage,
       base::WeakPtr<CacheStorageManager> cache_manager);
 
-  net::URLRequestContext* url_request_context() const {
-    return request_context_;
+  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter()
+      const {
+    return request_context_getter_;
   }
   base::WeakPtr<storage::BlobStorageContext> blob_storage_context() const {
     return blob_context_;
@@ -147,7 +146,7 @@
   // |cache_task_runner_|.
   CacheStorageMap cache_storage_map_;
 
-  net::URLRequestContext* request_context_;
+  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
   base::WeakPtr<storage::BlobStorageContext> blob_context_;
 
   base::WeakPtrFactory<CacheStorageManager> weak_ptr_factory_;
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc
index 61963b1..fd6ffccb6 100644
--- a/content/browser/cache_storage/cache_storage_manager_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -41,8 +41,6 @@
     quota_manager_proxy_ = new MockQuotaManagerProxy(
         nullptr, base::ThreadTaskRunnerHandle::Get().get());
 
-    net::URLRequestContext* url_request_context =
-        browser_context_.GetRequestContext()->GetURLRequestContext();
     if (MemoryOnly()) {
       cache_manager_ = CacheStorageManager::Create(
           base::FilePath(), base::ThreadTaskRunnerHandle::Get(),
@@ -55,7 +53,8 @@
     }
 
     cache_manager_->SetBlobParametersForCache(
-        url_request_context, blob_storage_context->context()->AsWeakPtr());
+        browser_context_.GetRequestContext(),
+        blob_storage_context->context()->AsWeakPtr());
   }
 
   void TearDown() override {
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index 34caa5a4..bb4a3e21 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -235,26 +235,6 @@
     return origin_lock_ == site_gurl;
   }
 
-  bool CanSendCookiesForOrigin(const GURL& gurl) {
-    // We only block cross-site cookies on network requests if the
-    // --enable-strict-site-isolation flag is passed.  This is expected to break
-    // compatibility with many sites.  The similar --site-per-process flag only
-    // blocks JavaScript access to cross-site cookies (in
-    // CanAccessCookiesForOrigin).
-    const base::CommandLine& command_line =
-        *base::CommandLine::ForCurrentProcess();
-    if (!command_line.HasSwitch(switches::kEnableStrictSiteIsolation))
-      return true;
-
-    if (origin_lock_.is_empty())
-      return true;
-    // TODO(creis): We must pass the valid browser_context to convert hosted
-    // apps URLs.  Currently, hosted apps cannot set cookies in this mode.
-    // See http://crbug.com/160576.
-    GURL site_gurl = SiteInstanceImpl::GetSiteForURL(NULL, gurl);
-    return origin_lock_ == site_gurl;
-  }
-
   void LockToOrigin(const GURL& gurl) {
     origin_lock_ = gurl;
   }
@@ -618,7 +598,7 @@
       return CanRequestURL(child_id, child_url);
     }
 
-    if (LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL))
+    if (base::LowerCaseEqualsASCII(url.spec(), url::kAboutBlankURL))
       return true;  // Every child process can request <about:blank>.
 
     // URLs like <about:memory> and <about:crash> shouldn't be requestable by
@@ -822,26 +802,6 @@
   return state->second->CanAccessCookiesForOrigin(gurl);
 }
 
-bool ChildProcessSecurityPolicyImpl::CanSendCookiesForOrigin(int child_id,
-                                                             const GURL& gurl) {
-  for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
-    if (iter.GetData().id == child_id) {
-      if (iter.GetData().process_type == PROCESS_TYPE_PLUGIN) {
-        // NPAPI plugin processes are unsandboxed and so are trusted. Plugins
-        // can make request to any origin.
-        return true;
-      }
-      break;
-    }
-  }
-
-  base::AutoLock lock(lock_);
-  SecurityStateMap::iterator state = security_state_.find(child_id);
-  if (state == security_state_.end())
-    return false;
-  return state->second->CanSendCookiesForOrigin(gurl);
-}
-
 void ChildProcessSecurityPolicyImpl::LockToOrigin(int child_id,
                                                   const GURL& gurl) {
   // "gurl" can be currently empty in some cases, such as file://blah.
diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h
index db673c1..61486b9a 100644
--- a/content/browser/child_process_security_policy_impl.h
+++ b/content/browser/child_process_security_policy_impl.h
@@ -148,20 +148,12 @@
   // Returns true if the process is permitted to read and modify the cookies for
   // the given origin.  Does not affect cookies attached to or set by network
   // requests.
-  // Only might return false if the very experimental
-  // --enable-strict-site-isolation or --site-per-process flags are used.
+  // Only might return false if the --site-per-process flag is used.
   bool CanAccessCookiesForOrigin(int child_id, const GURL& gurl);
 
-  // Returns true if the process is permitted to attach cookies to (or have
-  // cookies set by) network requests.
-  // Only might return false if the very experimental
-  // --enable-strict-site-isolation or --site-per-process flags are used.
-  bool CanSendCookiesForOrigin(int child_id, const GURL& gurl);
-
   // Sets the process as only permitted to use and see the cookies for the
   // given origin.
-  // Only used if the very experimental --enable-strict-site-isolation or
-  // --site-per-process flags are used.
+  // Origin lock is applied only if the --site-per-process flag is used.
   void LockToOrigin(int child_id, const GURL& gurl);
 
   // Register FileSystem type and permission policy which should be used
diff --git a/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.cc b/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.cc
index 7a3c70d..d21121b 100644
--- a/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.cc
+++ b/content/browser/compositor/browser_compositor_overlay_candidate_validator_ozone.cc
@@ -57,6 +57,8 @@
     ozone_surface_list.at(i).display_rect = surfaces->at(i).display_rect;
     ozone_surface_list.at(i).crop_rect = surfaces->at(i).uv_rect;
     ozone_surface_list.at(i).plane_z_order = surfaces->at(i).plane_z_order;
+    ozone_surface_list.at(i).buffer_size =
+        surfaces->at(i).resource_size_in_pixels;
   }
 
   overlay_candidates_->CheckOverlaySupport(&ozone_surface_list);
diff --git a/content/browser/devtools/protocol/input_handler.cc b/content/browser/devtools/protocol/input_handler.cc
index f30edd20..fb24b02 100644
--- a/content/browser/devtools/protocol/input_handler.cc
+++ b/content/browser/devtools/protocol/input_handler.cc
@@ -237,12 +237,12 @@
   if (!SetMouseEventButton(&event, button))
     return Response::InvalidParams("Invalid mouse button");
 
-  event.x = x;
-  event.y = y;
-  event.windowX = x;
-  event.windowY = y;
-  event.globalX = x;
-  event.globalY = y;
+  event.x = x * page_scale_factor_;
+  event.y = y * page_scale_factor_;
+  event.windowX = x * page_scale_factor_;
+  event.windowY = y * page_scale_factor_;
+  event.globalX = x * page_scale_factor_;
+  event.globalY = y * page_scale_factor_;
   event.clickCount = click_count ? *click_count : 0;
 
   if (!host_)
diff --git a/content/browser/devtools/protocol/security_handler.cc b/content/browser/devtools/protocol/security_handler.cc
new file mode 100644
index 0000000..d3b52e4a
--- /dev/null
+++ b/content/browser/devtools/protocol/security_handler.cc
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/devtools/protocol/security_handler.h"
+
+namespace content {
+namespace devtools {
+namespace security {
+
+typedef DevToolsProtocolClient::Response Response;
+
+SecurityHandler::SecurityHandler() {
+}
+
+SecurityHandler::~SecurityHandler() {
+}
+
+void SecurityHandler::SetClient(scoped_ptr<DevToolsProtocolClient> client) {
+}
+
+Response SecurityHandler::Enable() {
+  return Response::OK();
+}
+
+Response SecurityHandler::Disable() {
+  return Response::OK();
+}
+
+}  // namespace security
+}  // namespace devtools
+}  // namespace content
diff --git a/content/browser/devtools/protocol/security_handler.h b/content/browser/devtools/protocol/security_handler.h
new file mode 100644
index 0000000..59b1400c
--- /dev/null
+++ b/content/browser/devtools/protocol/security_handler.h
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SECURITY_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SECURITY_HANDLER_H_
+
+#include "content/browser/devtools/devtools_protocol_handler.h"
+#include "content/browser/devtools/protocol/devtools_protocol_client.h"
+
+namespace content {
+namespace devtools {
+namespace security {
+
+class SecurityHandler {
+ public:
+  typedef DevToolsProtocolClient::Response Response;
+
+  SecurityHandler();
+  virtual ~SecurityHandler();
+
+  void SetClient(scoped_ptr<DevToolsProtocolClient> client);
+
+  Response Enable();
+  Response Disable();
+
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(SecurityHandler);
+};
+
+}  // namespace security
+}  // namespace devtools
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SECURITY_HANDLER_H_
diff --git a/content/browser/devtools/protocol/service_worker_handler.cc b/content/browser/devtools/protocol/service_worker_handler.cc
index 907d8a5f..de97cc8 100644
--- a/content/browser/devtools/protocol/service_worker_handler.cc
+++ b/content/browser/devtools/protocol/service_worker_handler.cc
@@ -397,6 +397,20 @@
   return Response::OK();
 }
 
+Response ServiceWorkerHandler::GetTargetInfo(DevToolsCommandId command_id,
+                                             const std::string& target_id) {
+  return Response::InternalError("Not implemented yet");
+}
+
+Response ServiceWorkerHandler::ActivateTarget(const std::string& target_id) {
+  scoped_refptr<DevToolsAgentHost> agent_host(
+      DevToolsAgentHost::GetForId(target_id));
+  if (!agent_host)
+    return Response::InvalidParams("targetId");
+  agent_host->Activate();
+  return Response::OK();
+}
+
 void ServiceWorkerHandler::OpenNewDevToolsWindow(int process_id,
                                                  int devtools_agent_route_id) {
   scoped_refptr<DevToolsAgentHostImpl> agent_host(
diff --git a/content/browser/devtools/protocol/service_worker_handler.h b/content/browser/devtools/protocol/service_worker_handler.h
index 629fff0..5c7c1ca 100644
--- a/content/browser/devtools/protocol/service_worker_handler.h
+++ b/content/browser/devtools/protocol/service_worker_handler.h
@@ -59,6 +59,9 @@
   Response DeliverPushMessage(const std::string& origin,
                               const std::string& registration_id,
                               const std::string& data);
+  Response GetTargetInfo(DevToolsCommandId command_id,
+                         const std::string& target_id);
+  Response ActivateTarget(const std::string& target_id);
 
   // WorkerDevToolsManager::Observer implementation.
   void WorkerCreated(ServiceWorkerDevToolsAgentHost* host) override;
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
index 4ba32ed..c4becb1 100644
--- a/content/browser/devtools/protocol/tracing_handler.cc
+++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -47,7 +47,6 @@
 
 TracingHandler::TracingHandler(TracingHandler::Target target)
     : target_(target),
-      is_recording_(false),
       weak_factory_(this) {
 }
 
@@ -59,7 +58,7 @@
 }
 
 void TracingHandler::Detached() {
-  if (is_recording_)
+  if (IsRecording())
     DisableRecording(true);
 }
 
@@ -83,10 +82,9 @@
                                const std::string* categories,
                                const std::string* options,
                                const double* buffer_usage_reporting_interval) {
-  if (is_recording_)
+  if (IsRecording())
     return Response::InternalError("Tracing is already started");
 
-  is_recording_ = true;
   base::trace_event::TraceConfig trace_config(
       categories ? *categories : std::string(),
       options ? *options : std::string());
@@ -111,7 +109,7 @@
 }
 
 Response TracingHandler::End(DevToolsCommandId command_id) {
-  if (!is_recording_)
+  if (!IsRecording())
     return Response::InternalError("Tracing is not started");
 
   DisableRecording(false);
@@ -171,12 +169,15 @@
 }
 
 void TracingHandler::DisableRecording(bool abort) {
-  is_recording_ = false;
   buffer_usage_poll_timer_.reset();
   TracingController::GetInstance()->DisableRecording(
       abort ? nullptr : new DevToolsTraceSinkProxy(weak_factory_.GetWeakPtr()));
 }
 
+bool TracingHandler::IsRecording() const {
+  return TracingController::GetInstance()->IsRecording();
+}
+
 }  // namespace tracing
 }  // namespace devtools
 }  // namespace content
diff --git a/content/browser/devtools/protocol/tracing_handler.h b/content/browser/devtools/protocol/tracing_handler.h
index 94f40597..6bbf82b 100644
--- a/content/browser/devtools/protocol/tracing_handler.h
+++ b/content/browser/devtools/protocol/tracing_handler.h
@@ -54,9 +54,10 @@
 
   void DisableRecording(bool abort);
 
+  bool IsRecording() const;
+
   scoped_ptr<base::Timer> buffer_usage_poll_timer_;
   Target target_;
-  bool is_recording_;
 
   scoped_ptr<Client> client_;
   base::WeakPtrFactory<TracingHandler> weak_factory_;
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index c3e2ec9c..2872ef9 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -598,7 +598,8 @@
   dom_handler_->SetRenderFrameHost(host);
   if (emulation_handler_)
     emulation_handler_->SetRenderFrameHost(host);
-  input_handler_->SetRenderWidgetHost(host->GetRenderWidgetHost());
+  input_handler_->SetRenderWidgetHost(
+      host ? host->GetRenderWidgetHost() : nullptr);
   inspector_handler_->SetRenderFrameHost(host);
   network_handler_->SetRenderFrameHost(host);
   if (page_handler_)
diff --git a/content/browser/download/download_stats.cc b/content/browser/download/download_stats.cc
index f8b92bea..1dec4d66 100644
--- a/content/browser/download/download_stats.cc
+++ b/content/browser/download/download_stats.cc
@@ -344,13 +344,13 @@
   download_len /= 1024;  // In Kilobytes
   static const int kBuckets = 50;
 
-  if (LowerCaseEqualsASCII(accepts_ranges, "none")) {
+  if (base::LowerCaseEqualsASCII(accepts_ranges, "none")) {
     UMA_HISTOGRAM_CUSTOM_COUNTS("Download.AcceptRangesNone.KBytes",
                                 download_len,
                                 1,
                                 max,
                                 kBuckets);
-  } else if (LowerCaseEqualsASCII(accepts_ranges, "bytes")) {
+  } else if (base::LowerCaseEqualsASCII(accepts_ranges, "bytes")) {
     UMA_HISTOGRAM_CUSTOM_COUNTS("Download.AcceptRangesBytes.KBytes",
                                 download_len,
                                 1,
@@ -467,14 +467,14 @@
 
   // Do partial matches.
   if (download_content == DOWNLOAD_CONTENT_UNRECOGNIZED) {
-    if (StartsWithASCII(mime_type_string, "text/", true)) {
+    if (base::StartsWithASCII(mime_type_string, "text/", true)) {
       download_content = DOWNLOAD_CONTENT_TEXT;
-    } else if (StartsWithASCII(mime_type_string, "image/", true)) {
+    } else if (base::StartsWithASCII(mime_type_string, "image/", true)) {
       download_content = DOWNLOAD_CONTENT_IMAGE;
       RecordDownloadImageType(mime_type_string);
-    } else if (StartsWithASCII(mime_type_string, "audio/", true)) {
+    } else if (base::StartsWithASCII(mime_type_string, "audio/", true)) {
       download_content = DOWNLOAD_CONTENT_AUDIO;
-    } else if (StartsWithASCII(mime_type_string, "video/", true)) {
+    } else if (base::StartsWithASCII(mime_type_string, "video/", true)) {
       download_content = DOWNLOAD_CONTENT_VIDEO;
     }
   }
diff --git a/content/browser/fileapi/OWNERS b/content/browser/fileapi/OWNERS
index 43601cc..7c932798 100644
--- a/content/browser/fileapi/OWNERS
+++ b/content/browser/fileapi/OWNERS
@@ -1,4 +1,3 @@
-kinuko@chromium.org
 michaeln@chromium.org
 jianli@chromium.org
 tzik@chromium.org
diff --git a/content/browser/fileapi/fileapi_message_filter.cc b/content/browser/fileapi/fileapi_message_filter.cc
index 9c10e43b..bcd2ce6 100644
--- a/content/browser/fileapi/fileapi_message_filter.cc
+++ b/content/browser/fileapi/fileapi_message_filter.cc
@@ -598,8 +598,8 @@
     const GURL& url, const std::string& content_type) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   // Only an internal Blob URL is expected here. See the BlobURL of the Blink.
-  if (!StartsWithASCII(
-          url.path(), "blobinternal%3A///", true /* case_sensitive */)) {
+  if (!base::StartsWithASCII(url.path(), "blobinternal%3A///",
+                             true /* case_sensitive */)) {
     NOTREACHED() << "Malformed Stream URL: " << url.spec();
     bad_message::ReceivedBadMessage(this,
                                     bad_message::FAMF_MALFORMED_STREAM_URL);
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc
index dbc4128..a27d7d2 100644
--- a/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -11,6 +11,7 @@
 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "content/common/frame_messages.h"
 #include "content/common/gpu/gpu_messages.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -142,6 +143,13 @@
   return child_frame_rect_;
 }
 
+void CrossProcessFrameConnector::GetScreenInfo(blink::WebScreenInfo* results) {
+  RenderWidgetHostView* rwhv =
+      frame_proxy_in_parent_renderer_->GetRenderWidgetHostView();
+  if (rwhv)
+    static_cast<RenderWidgetHostViewBase*>(rwhv)->GetScreenInfo(results);
+}
+
 void CrossProcessFrameConnector::OnForwardInputEvent(
     const blink::WebInputEvent* event) {
   if (!view_)
diff --git a/content/browser/frame_host/cross_process_frame_connector.h b/content/browser/frame_host/cross_process_frame_connector.h
index fd0dc53..aa5b35a7 100644
--- a/content/browser/frame_host/cross_process_frame_connector.h
+++ b/content/browser/frame_host/cross_process_frame_connector.h
@@ -11,6 +11,7 @@
 
 namespace blink {
 class WebInputEvent;
+struct WebScreenInfo;
 }
 
 namespace cc {
@@ -93,6 +94,7 @@
                                     const cc::SurfaceSequence& sequence);
 
   gfx::Rect ChildFrameRect();
+  void GetScreenInfo(blink::WebScreenInfo* results);
 
  private:
   // Handlers for messages received from the parent frame.
diff --git a/content/browser/frame_host/frame_mojo_shell.cc b/content/browser/frame_host/frame_mojo_shell.cc
new file mode 100644
index 0000000..6823931e
--- /dev/null
+++ b/content/browser/frame_host/frame_mojo_shell.cc
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/frame_host/frame_mojo_shell.h"
+
+#include "content/browser/mojo/mojo_shell_context.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/site_instance.h"
+
+namespace content {
+
+FrameMojoShell::FrameMojoShell(RenderFrameHost* frame_host)
+    : frame_host_(frame_host) {
+}
+
+FrameMojoShell::~FrameMojoShell() {
+}
+
+void FrameMojoShell::BindRequest(
+    mojo::InterfaceRequest<mojo::Shell> shell_request) {
+  bindings_.AddBinding(this, shell_request.Pass());
+}
+
+void FrameMojoShell::ConnectToApplication(
+    mojo::URLRequestPtr application_url,
+    mojo::InterfaceRequest<mojo::ServiceProvider> services,
+    mojo::ServiceProviderPtr exposed_services) {
+  MojoShellContext::ConnectToApplication(
+      GURL(application_url->url), frame_host_->GetSiteInstance()->GetSiteURL(),
+      services.Pass());
+}
+
+void FrameMojoShell::QuitApplication() {
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/frame_mojo_shell.h b/content/browser/frame_host/frame_mojo_shell.h
new file mode 100644
index 0000000..3c209d2
--- /dev/null
+++ b/content/browser/frame_host/frame_mojo_shell.h
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_FRAME_HOST_FRAME_MOJO_SHELL_H_
+#define CONTENT_BROWSER_FRAME_HOST_FRAME_MOJO_SHELL_H_
+
+#include "base/macros.h"
+#include "mojo/application/public/interfaces/shell.mojom.h"
+#include "mojo/common/weak_binding_set.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+
+namespace content {
+
+class RenderFrameHost;
+
+// This provides the |mojo::Shell| service interface to each frame's
+// ServiceRegistry, giving frames the ability to connect to Mojo applications.
+class FrameMojoShell : public mojo::Shell {
+ public:
+  explicit FrameMojoShell(RenderFrameHost* frame_host);
+  ~FrameMojoShell() override;
+
+  void BindRequest(mojo::InterfaceRequest<mojo::Shell> shell_request);
+
+ private:
+  // mojo::Shell:
+  void ConnectToApplication(
+      mojo::URLRequestPtr application_url,
+      mojo::InterfaceRequest<mojo::ServiceProvider> services,
+      mojo::ServiceProviderPtr exposed_services) override;
+  void QuitApplication() override;
+
+  RenderFrameHost* frame_host_;
+  mojo::WeakBindingSet<mojo::Shell> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameMojoShell);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FRAME_HOST_FRAME_MOJO_SHELL_H_
diff --git a/content/browser/frame_host/frame_tree_browsertest.cc b/content/browser/frame_host/frame_tree_browsertest.cc
index c013d6a..7b37ccf 100644
--- a/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/content/browser/frame_host/frame_tree_browsertest.cc
@@ -283,6 +283,37 @@
             blink::WebSandboxFlags::All);
 }
 
+// Ensure that a popup opened from a subframe sets its opener to the subframe's
+// FrameTreeNode, and that the opener is cleared if the subframe is destroyed.
+IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SubframeOpenerSetForNewWindow) {
+  GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+
+  // Open a new window from a subframe.
+  ShellAddedObserver new_shell_observer;
+  GURL popup_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
+  EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
+                            "window.open('" + popup_url.spec() + "');"));
+  Shell* new_shell = new_shell_observer.GetShell();
+  WebContents* new_contents = new_shell->web_contents();
+  WaitForLoadStop(new_contents);
+
+  // Check that the new window's opener points to the correct subframe on
+  // original window.
+  FrameTreeNode* popup_root =
+      static_cast<WebContentsImpl*>(new_contents)->GetFrameTree()->root();
+  EXPECT_EQ(root->child_at(0), popup_root->opener());
+
+  // Close the original window.  This should clear the new window's opener.
+  shell()->Close();
+  EXPECT_EQ(nullptr, popup_root->opener());
+}
+
 class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
  public:
   CrossProcessFrameTreeBrowserTest() {}
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
index 08254c9..b553503b 100644
--- a/content/browser/frame_host/frame_tree_node.cc
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -37,6 +37,24 @@
 
 }  // namespace
 
+// This observer watches the opener of its owner FrameTreeNode and clears the
+// owner's opener if the opener is destroyed.
+class FrameTreeNode::OpenerDestroyedObserver : public FrameTreeNode::Observer {
+ public:
+  OpenerDestroyedObserver(FrameTreeNode* owner) : owner_(owner) {}
+
+  // FrameTreeNode::Observer
+  void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
+    CHECK_EQ(owner_->opener(), node);
+    owner_->SetOpener(nullptr);
+  }
+
+ private:
+  FrameTreeNode* owner_;
+
+  DISALLOW_COPY_AND_ASSIGN(OpenerDestroyedObserver);
+};
+
 int FrameTreeNode::next_frame_tree_node_id_ = 1;
 
 // static
@@ -65,6 +83,8 @@
                       manager_delegate),
       frame_tree_node_id_(next_frame_tree_node_id_++),
       parent_(NULL),
+      opener_(nullptr),
+      opener_observer_(nullptr),
       replication_state_(scope, name, sandbox_flags),
       // Effective sandbox flags also need to be set, since initial sandbox
       // flags should apply to the initial empty document in the frame.
@@ -78,10 +98,22 @@
 
 FrameTreeNode::~FrameTreeNode() {
   frame_tree_->FrameRemoved(this);
+  FOR_EACH_OBSERVER(Observer, observers_, OnFrameTreeNodeDestroyed(this));
+
+  if (opener_)
+    opener_->RemoveObserver(opener_observer_.get());
 
   g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
 }
 
+void FrameTreeNode::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void FrameTreeNode::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 bool FrameTreeNode::IsMainFrame() const {
   return frame_tree_->root() == this;
 }
@@ -139,6 +171,21 @@
   old_children.clear();  // May notify observers.
 }
 
+void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
+  if (opener_) {
+    opener_->RemoveObserver(opener_observer_.get());
+    opener_observer_.reset();
+  }
+
+  opener_ = opener;
+
+  if (opener_) {
+    if (!opener_observer_)
+      opener_observer_ = make_scoped_ptr(new OpenerDestroyedObserver(this));
+    opener_->AddObserver(opener_observer_.get());
+  }
+}
+
 void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) {
   if (!origin.IsSameAs(replication_state_.origin))
     render_manager_.OnDidUpdateOrigin(origin);
diff --git a/content/browser/frame_host/frame_tree_node.h b/content/browser/frame_host/frame_tree_node.h
index 21fbf27..19f87a35 100644
--- a/content/browser/frame_host/frame_tree_node.h
+++ b/content/browser/frame_host/frame_tree_node.h
@@ -31,6 +31,14 @@
 // are frame-specific (as opposed to page-specific).
 class CONTENT_EXPORT FrameTreeNode {
  public:
+  class Observer {
+   public:
+    // Invoked when a FrameTreeNode is being destroyed.
+    virtual void OnFrameTreeNodeDestroyed(FrameTreeNode* node) {}
+
+    virtual ~Observer() {}
+  };
+
   // Returns the FrameTreeNode with the given global |frame_tree_node_id|,
   // regardless of which FrameTree it is in.
   static FrameTreeNode* GloballyFindByID(int frame_tree_node_id);
@@ -47,6 +55,9 @@
 
   ~FrameTreeNode();
 
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
   bool IsMainFrame() const;
 
   void AddChild(scoped_ptr<FrameTreeNode> child,
@@ -83,6 +94,13 @@
 
   FrameTreeNode* parent() const { return parent_; }
 
+  FrameTreeNode* opener() const { return opener_; }
+
+  // Assigns a new opener for this node and, if |opener| is non-null, registers
+  // an observer that will clear this node's opener if |opener| is ever
+  // destroyed.
+  void SetOpener(FrameTreeNode* opener);
+
   FrameTreeNode* child_at(size_t index) const {
     return children_[index];
   }
@@ -172,6 +190,8 @@
   void DidChangeLoadProgress(double load_progress);
 
  private:
+  class OpenerDestroyedObserver;
+
   void set_parent(FrameTreeNode* parent) { parent_ = parent; }
 
   // The next available browser-global FrameTreeNode ID.
@@ -198,6 +218,18 @@
   // not yet been attached to the frame tree.
   FrameTreeNode* parent_;
 
+  // The frame that opened this frame, if any.  Will be set to null if the
+  // opener is closed, or if this frame disowns its opener by setting its
+  // window.opener to null.
+  FrameTreeNode* opener_;
+
+  // An observer that clears this node's |opener_| if the opener is destroyed.
+  // This observer is added to the |opener_|'s observer list when the |opener_|
+  // is set to a non-null node, and it is removed from that list when |opener_|
+  // changes or when this node is destroyed.  It is also cleared if |opener_|
+  // is disowned.
+  scoped_ptr<OpenerDestroyedObserver> opener_observer_;
+
   // The immediate children of this specific frame.
   ScopedVector<FrameTreeNode> children_;
 
@@ -229,6 +261,9 @@
   // be reset and a RenderFrameHost will be responsible for the navigation.
   scoped_ptr<NavigationRequest> navigation_request_;
 
+  // List of objects observing this FrameTreeNode.
+  base::ObserverList<Observer> observers_;
+
   DISALLOW_COPY_AND_ASSIGN(FrameTreeNode);
 };
 
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 3565d33..82fb779d 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -814,8 +814,10 @@
 
 // Verify that navigations for NAVIGATION_TYPE_NEW_SUBFRAME and
 // NAVIGATION_TYPE_AUTO_SUBFRAME are properly classified.
-IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
-                       NavigationTypeClassification_NewAndAutoSubframe) {
+// TODO(creis): Re-enable this test when https://crbug.com/498559 is fixed.
+IN_PROC_BROWSER_TEST_F(
+    NavigationControllerBrowserTest,
+    DISABLED_NavigationTypeClassification_NewAndAutoSubframe) {
   GURL main_url(embedded_test_server()->GetURL(
       "/navigation_controller/page_with_iframe.html"));
   NavigateToURL(shell(), main_url);
@@ -829,10 +831,20 @@
   ASSERT_NE(nullptr, root->child_at(0));
 
   {
+    // Initial load.
+    LoadCommittedCapturer capturer(root->child_at(0));
+    GURL frame_url(embedded_test_server()->GetURL(
+        "/navigation_controller/simple_page_1.html"));
+    NavigateFrameToURL(root->child_at(0), frame_url);
+    capturer.Wait();
+    EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
+  }
+
+  {
     // Simple load.
     FrameNavigateParamsCapturer capturer(root->child_at(0));
     GURL frame_url(embedded_test_server()->GetURL(
-        "/navigation_controller/simple_page_1.html"));
+        "/navigation_controller/simple_page_2.html"));
     NavigateFrameToURL(root->child_at(0), frame_url);
     capturer.Wait();
     EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h
index d617b5f..09bb846 100644
--- a/content/browser/frame_host/render_frame_host_delegate.h
+++ b/content/browser/frame_host/render_frame_host_delegate.h
@@ -90,10 +90,6 @@
   virtual void DidChangeName(RenderFrameHost* render_frame_host,
                              const std::string& name) {}
 
-  // The frame set its opener to null, disowning it for the lifetime of the
-  // window. Only called for the top-level frame.
-  virtual void DidDisownOpener(RenderFrameHost* render_frame_host) {}
-
   // The onload handler in the frame has completed. Only called for the top-
   // level frame.
   virtual void DocumentOnLoadCompleted(RenderFrameHost* render_frame_host) {}
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 0c9bcb9e..52db3bd 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -19,6 +19,7 @@
 #include "content/browser/frame_host/cross_process_frame_connector.h"
 #include "content/browser/frame_host/cross_site_transferring_request.h"
 #include "content/browser/frame_host/frame_accessibility.h"
+#include "content/browser/frame_host/frame_mojo_shell.h"
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/navigation_request.h"
@@ -1212,9 +1213,23 @@
 }
 
 void RenderFrameHostImpl::OnDidDisownOpener() {
-  // This message is only sent for top-level frames. TODO(avi): when frame tree
-  // mirroring works correctly, add a check here to enforce it.
-  delegate_->DidDisownOpener(this);
+  // This message is only sent for top-level frames for now.
+  // TODO(alexmos):  This should eventually support subframe openers as well,
+  // and it should allow openers to be updated to another frame (which can
+  // happen via window.open('','framename')) in addition to being disowned.
+
+  // No action is necessary if the opener has already been cleared.
+  if (!frame_tree_node_->opener())
+    return;
+
+  // Clear our opener so that future cross-process navigations don't have an
+  // opener assigned.
+  frame_tree_node_->SetOpener(nullptr);
+
+  // Notify all other RenderFrameHosts and RenderFrameProxies for this frame.
+  // This is important in case we go back to them, or if another window in
+  // those processes tries to access window.opener.
+  frame_tree_node_->render_manager()->DidDisownOpener(this);
 }
 
 void RenderFrameHostImpl::OnDidChangeName(const std::string& name) {
@@ -1549,6 +1564,12 @@
       base::Bind(&CreateMediaRendererService));
 #endif
 
+  if (!frame_mojo_shell_)
+    frame_mojo_shell_.reset(new FrameMojoShell(this));
+
+  GetServiceRegistry()->AddService<mojo::Shell>(base::Bind(
+      &FrameMojoShell::BindRequest, base::Unretained(frame_mojo_shell_.get())));
+
   GetContentClient()->browser()->OverrideRenderFrameMojoServices(
       GetServiceRegistry(), this);
 }
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 60764c6..1d01885 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -54,6 +54,7 @@
 
 class CrossProcessFrameConnector;
 class CrossSiteTransferringRequest;
+class FrameMojoShell;
 class FrameTree;
 class FrameTreeNode;
 class PermissionServiceContext;
@@ -724,6 +725,9 @@
   // Context shared for each PermissionService instance created for this RFH.
   scoped_ptr<PermissionServiceContext> permission_service_context_;
 
+  // The frame's Mojo Shell service.
+  scoped_ptr<FrameMojoShell> frame_mojo_shell_;
+
   // NOTE: This must be the last member.
   base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
 
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index f0f5808..0a27c9e 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -102,6 +102,11 @@
       site_instance_.get());
 }
 
+RenderWidgetHostView* RenderFrameProxyHost::GetRenderWidgetHostView() {
+  return frame_tree_node_->parent()->render_manager()
+      ->GetRenderWidgetHostView();
+}
+
 void RenderFrameProxyHost::TakeFrameHostOwnership(
     scoped_ptr<RenderFrameHostImpl> render_frame_host) {
   CHECK(render_frame_host_ == nullptr);
diff --git a/content/browser/frame_host/render_frame_proxy_host.h b/content/browser/frame_host/render_frame_proxy_host.h
index c297c043..58a741bf 100644
--- a/content/browser/frame_host/render_frame_proxy_host.h
+++ b/content/browser/frame_host/render_frame_proxy_host.h
@@ -90,6 +90,7 @@
     return render_frame_host_.get();
   }
   RenderViewHostImpl* GetRenderViewHost();
+  RenderWidgetHostView* GetRenderWidgetHostView();
 
   void TakeFrameHostOwnership(
       scoped_ptr<RenderFrameHostImpl> render_frame_host);
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc
index 5b17009..8be87ea5 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -27,7 +27,7 @@
       last_output_surface_id_(0),
       current_surface_scale_factor_(1.f),
       ack_pending_count_(0),
-      frame_connector_(NULL),
+      frame_connector_(nullptr),
       weak_factory_(this) {
   if (use_surfaces_)
     id_allocator_ = CreateSurfaceIdAllocator();
@@ -288,6 +288,9 @@
 
 void RenderWidgetHostViewChildFrame::GetScreenInfo(
     blink::WebScreenInfo* results) {
+  if (!frame_connector_)
+    return;
+  frame_connector_->GetScreenInfo(results);
 }
 
 gfx::Rect RenderWidgetHostViewChildFrame::GetBoundsInRootWindow() {
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc
new file mode 100644
index 0000000..3e36908
--- /dev/null
+++ b/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc
@@ -0,0 +1,76 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
+#include "content/test/test_content_browser_client.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace content {
+
+class RenderWidgetHostViewChildFrameTest : public ContentBrowserTest {
+ public:
+  RenderWidgetHostViewChildFrameTest() {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(switches::kSitePerProcess);
+  }
+
+  void SetUpOnMainThread() override {
+    host_resolver()->AddRule("*", "127.0.0.1");
+    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+    SetupCrossSiteRedirector(embedded_test_server());
+  }
+
+  void CheckScreenWidth(RenderFrameHost* render_frame_host) {
+    int width;
+    ExecuteScriptAndGetValue(render_frame_host, "window.screen.width")
+        ->GetAsInteger(&width);
+    EXPECT_EQ(expected_screen_width_, width);
+  }
+
+  void set_expected_screen_width(int width) {
+    expected_screen_width_ = width;
+  }
+
+ private:
+  int expected_screen_width_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewChildFrameTest);
+};
+
+// Tests that the screen is properly reflected for RWHVChildFrame.
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameTest, Screen) {
+  GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
+  NavigateToURL(shell(), main_url);
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()->root();
+
+  // Load cross-site page into iframe.
+  GURL cross_site_url(
+      embedded_test_server()->GetURL("foo.com", "/title2.html"));
+  NavigateFrameToURL(root->child_at(0), cross_site_url);
+
+  int main_frame_screen_width = 0;
+  ExecuteScriptAndGetValue(shell()->web_contents()->GetMainFrame(),
+      "window.screen.width")->GetAsInteger(&main_frame_screen_width);
+  set_expected_screen_width(main_frame_screen_width);
+  EXPECT_FALSE(main_frame_screen_width == 0);
+
+  shell()->web_contents()->ForEachFrame(
+      base::Bind(&RenderWidgetHostViewChildFrameTest::CheckScreenWidth, this));
+}
+
+}  // namespace content
diff --git a/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc b/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
index 26f2913..7470d4f 100644
--- a/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_linux.cc
@@ -42,7 +42,7 @@
     return false;
 
   static const char kJoystickRoot[] = "/dev/input/js";
-  bool is_gamepad = StartsWithASCII(node_path, kJoystickRoot, true);
+  bool is_gamepad = base::StartsWithASCII(node_path, kJoystickRoot, true);
   if (!is_gamepad)
     return false;
 
diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
index 4d12ccbd..b6162ba 100644
--- a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
+++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
@@ -165,7 +165,8 @@
       new_id, size, format, usage, child_client_id, 0,
       base::Bind(&BrowserGpuMemoryBufferManager::
                      GpuMemoryBufferAllocatedForChildProcess,
-                 weak_ptr_factory_.GetWeakPtr(), child_client_id, callback));
+                 weak_ptr_factory_.GetWeakPtr(), new_id, child_client_id,
+                 callback));
 }
 
 gfx::GpuMemoryBuffer*
@@ -297,12 +298,9 @@
 
   DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
   request->result = GpuMemoryBufferImpl::CreateFromHandle(
-      handle,
-      request->size,
-      request->format,
+      handle, request->size, request->format, request->usage,
       base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 handle.id,
+                 weak_ptr_factory_.GetWeakPtr(), handle.id,
                  request->client_id));
   request->event.Signal();
 }
@@ -317,6 +315,7 @@
 }
 
 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
+    gfx::GpuMemoryBufferId id,
     int child_client_id,
     const AllocationCallback& callback,
     const gfx::GpuMemoryBufferHandle& handle) {
@@ -337,19 +336,21 @@
 
   BufferMap& buffers = client_it->second;
 
-  BufferMap::iterator buffer_it = buffers.find(handle.id);
+  BufferMap::iterator buffer_it = buffers.find(id);
   DCHECK(buffer_it != buffers.end());
   DCHECK_EQ(buffer_it->second.type, gfx::EMPTY_BUFFER);
 
-  if (handle.is_null()) {
+  // If the handle isn't valid, that means that the GPU process crashed or is
+  // misbehaving so we remove the buffer entry and run the allocation callback
+  // with an empty handle to indicate failure.
+  bool valid_handle = !handle.is_null() && handle.id == id &&
+                      handle.type != gfx::SHARED_MEMORY_BUFFER;
+  if (!valid_handle) {
     buffers.erase(buffer_it);
     callback.Run(gfx::GpuMemoryBufferHandle());
     return;
   }
 
-  // The factory should never return a shared memory backed buffer.
-  DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
-
   // Store the type of this buffer so it can be cleaned up if the child
   // process is removed.
   buffer_it->second.type = handle.type;
diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.h b/content/browser/gpu/browser_gpu_memory_buffer_manager.h
index 74ba943..d549029a 100644
--- a/content/browser/gpu/browser_gpu_memory_buffer_manager.h
+++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.h
@@ -89,6 +89,7 @@
                               int client_id,
                               uint32 sync_point);
   void GpuMemoryBufferAllocatedForChildProcess(
+      gfx::GpuMemoryBufferId id,
       int child_client_id,
       const AllocationCallback& callback,
       const gfx::GpuMemoryBufferHandle& handle);
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 2e46bda..3da40a8be 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -29,7 +29,6 @@
 const char* kGpuCompositingFeatureName = "gpu_compositing";
 const char* kWebGLFeatureName = "webgl";
 const char* kRasterizationFeatureName = "rasterization";
-const char* kThreadedRasterizationFeatureName = "threaded_rasterization";
 const char* kMultipleRasterThreadsFeatureName = "multiple_raster_threads";
 
 const int kMinRasterThreads = 1;
@@ -145,14 +144,6 @@
           true
       },
       {
-          kThreadedRasterizationFeatureName,
-          false,
-          !IsImplSidePaintingEnabled(),
-          "Threaded rasterization has not been enabled or"
-          " is not supported by the current system.",
-          false
-      },
-      {
           kMultipleRasterThreadsFeatureName,
           false,
           NumberOfRendererRasterThreads() == 1,
@@ -189,16 +180,16 @@
   return enabled;
 }
 
-bool IsImplSidePaintingEnabled() {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kDisableImplSidePainting))
-    return false;
-  return true;
-}
-
 int NumberOfRendererRasterThreads() {
-  int num_raster_threads = base::SysInfo::NumberOfProcessors() / 2;
+  int num_processors = base::SysInfo::NumberOfProcessors();
+
+#if defined(OS_ANDROID)
+  // Android may report 6 to 8 CPUs for big.LITTLE configurations.
+  // Limit the number of raster threads based on maximum of 4 big cores.
+  num_processors = std::min(num_processors, 4);
+#endif
+
+  int num_raster_threads = num_processors / 2;
 
   // Async uploads is used when neither zero-copy nor one-copy is enabled and
   // it uses its own thread, so reduce the number of raster threads when async
@@ -230,15 +221,7 @@
 
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kEnableOneCopy))
-    return true;
-  if (command_line.HasSwitch(switches::kDisableOneCopy))
-    return false;
-
-#if defined(OS_ANDROID)
-  return false;
-#endif
-  return true;
+  return !command_line.HasSwitch(switches::kDisableOneCopy);
 }
 
 bool IsZeroCopyUploadEnabled() {
@@ -259,9 +242,6 @@
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
 
-  if (!IsImplSidePaintingEnabled())
-    return false;
-
   if (command_line.HasSwitch(switches::kDisableGpuRasterization))
     return false;
   else if (command_line.HasSwitch(switches::kEnableGpuRasterization))
@@ -283,10 +263,6 @@
 bool IsForceGpuRasterizationEnabled() {
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-
-  if (!IsImplSidePaintingEnabled())
-    return false;
-
   return command_line.HasSwitch(switches::kForceGpuRasterization);
 }
 
@@ -350,8 +326,6 @@
         status += "_software";
       else
         status += "_off";
-      if (gpu_feature_info.name == kThreadedRasterizationFeatureName)
-        status += "_ok";
     } else if (gpu_feature_info.blocked ||
                gpu_access_blocked) {
       status = "unavailable";
@@ -374,8 +348,7 @@
         if (command_line.HasSwitch(switches::kNumRasterThreads))
           status += "_force";
       }
-      if (gpu_feature_info.name == kThreadedRasterizationFeatureName ||
-          gpu_feature_info.name == kMultipleRasterThreadsFeatureName)
+      if (gpu_feature_info.name == kMultipleRasterThreadsFeatureName)
         status += "_on";
     }
     if (gpu_feature_info.name == kWebGLFeatureName &&
diff --git a/content/browser/gpu/compositor_util.h b/content/browser/gpu/compositor_util.h
index 1475e6b..fab9099 100644
--- a/content/browser/gpu/compositor_util.h
+++ b/content/browser/gpu/compositor_util.h
@@ -20,10 +20,6 @@
 // Returns true if delegated-renderer is on (via flags, or platform default).
 CONTENT_EXPORT bool IsDelegatedRendererEnabled();
 
-// Returns true if impl-side painting is on (via flags, or platform default)
-// for the renderer.
-CONTENT_EXPORT bool IsImplSidePaintingEnabled();
-
 // Returns true if one-copy uploads is on (via flags, or platform default).
 // Only one of one-copy and zero-copy can be enabled at a time.
 CONTENT_EXPORT bool IsOneCopyUploadEnabled();
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index bc80323..64769850 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -45,6 +45,10 @@
 #include "ui/events/latency_info.h"
 #include "ui/gl/gl_switches.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
 #include "content/common/sandbox_win.h"
@@ -1066,6 +1070,9 @@
     gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
 
     std::string in_str = GetContentClient()->GetProduct() + "-" +
+#if defined(OS_ANDROID)
+        base::android::BuildInfo::GetInstance()->android_build_fp() + "-" +
+#endif
         info.gl_vendor + "-" + info.gl_renderer + "-" +
         info.driver_version + "-" + info.driver_vendor;
 
diff --git a/content/browser/in_process_io_surface_manager_mac.cc b/content/browser/in_process_io_surface_manager_mac.cc
new file mode 100644
index 0000000..ca387859
--- /dev/null
+++ b/content/browser/in_process_io_surface_manager_mac.cc
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/in_process_io_surface_manager_mac.h"
+
+#include "base/logging.h"
+
+namespace content {
+
+// static
+InProcessIOSurfaceManager* InProcessIOSurfaceManager::GetInstance() {
+  return Singleton<InProcessIOSurfaceManager,
+                   LeakySingletonTraits<InProcessIOSurfaceManager>>::get();
+}
+
+bool InProcessIOSurfaceManager::RegisterIOSurface(int io_surface_id,
+                                                  int client_id,
+                                                  IOSurfaceRef io_surface) {
+  base::AutoLock lock(lock_);
+
+  DCHECK(io_surfaces_.find(io_surface_id) == io_surfaces_.end());
+  io_surfaces_.add(io_surface_id,
+                   make_scoped_ptr(new base::mac::ScopedMachSendRight(
+                       IOSurfaceCreateMachPort(io_surface))));
+  return true;
+}
+
+void InProcessIOSurfaceManager::UnregisterIOSurface(int io_surface_id,
+                                                    int client_id) {
+  base::AutoLock lock(lock_);
+
+  DCHECK(io_surfaces_.find(io_surface_id) != io_surfaces_.end());
+  io_surfaces_.erase(io_surface_id);
+}
+
+IOSurfaceRef InProcessIOSurfaceManager::AcquireIOSurface(int io_surface_id) {
+  base::AutoLock lock(lock_);
+
+  DCHECK(io_surfaces_.find(io_surface_id) != io_surfaces_.end());
+  return IOSurfaceLookupFromMachPort(io_surfaces_.get(io_surface_id)->get());
+}
+
+InProcessIOSurfaceManager::InProcessIOSurfaceManager() {
+}
+
+InProcessIOSurfaceManager::~InProcessIOSurfaceManager() {
+}
+
+}  // namespace content
diff --git a/content/browser/in_process_io_surface_manager_mac.h b/content/browser/in_process_io_surface_manager_mac.h
new file mode 100644
index 0000000..1ace534
--- /dev/null
+++ b/content/browser/in_process_io_surface_manager_mac.h
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_IN_PROCESS_IO_SURFACE_MANAGER_MAC_H_
+#define CONTENT_BROWSER_IN_PROCESS_IO_SURFACE_MANAGER_MAC_H_
+
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+#include "content/common/content_export.h"
+#include "content/common/mac/io_surface_manager.h"
+
+namespace content {
+
+class CONTENT_EXPORT InProcessIOSurfaceManager : public IOSurfaceManager {
+ public:
+  static InProcessIOSurfaceManager* GetInstance();
+
+  // Overridden from IOSurfaceManager:
+  bool RegisterIOSurface(int io_surface_id,
+                         int client_id,
+                         IOSurfaceRef io_surface) override;
+  void UnregisterIOSurface(int io_surface_id, int client_id) override;
+  IOSurfaceRef AcquireIOSurface(int io_surface_id) override;
+
+ private:
+  friend struct DefaultSingletonTraits<InProcessIOSurfaceManager>;
+
+  InProcessIOSurfaceManager();
+  ~InProcessIOSurfaceManager() override;
+
+  using IOSurfaceMap =
+      base::ScopedPtrHashMap<int, scoped_ptr<base::mac::ScopedMachSendRight>>;
+  IOSurfaceMap io_surfaces_;
+  base::Lock lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(InProcessIOSurfaceManager);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_IN_PROCESS_IO_SURFACE_MANAGER_MAC_H_
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index 58d0253..87bc8838 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -3174,6 +3174,20 @@
                                              const IndexedDBKey* primary_key,
                                              IteratorState next_state,
                                              leveldb::Status* s) {
+  DCHECK(!key || next_state == SEEK);
+
+  if (cursor_options_.forward)
+    return ContinueNext(key, primary_key, next_state, s);
+  else
+    return ContinuePrevious(key, primary_key, next_state, s);
+}
+
+bool IndexedDBBackingStore::Cursor::ContinueNext(
+    const IndexedDBKey* key,
+    const IndexedDBKey* primary_key,
+    IteratorState next_state,
+    leveldb::Status* s) {
+  DCHECK(cursor_options_.forward);
   DCHECK(!key || key->IsValid());
   DCHECK(!primary_key || primary_key->IsValid());
   *s = leveldb::Status::OK();
@@ -3181,62 +3195,37 @@
   // TODO(alecflett): avoid a copy here?
   IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey();
 
-  // When iterating with PrevNoDuplicate, spec requires that the
-  // value we yield for each key is the first duplicate in forwards
-  // order.
-  IndexedDBKey last_duplicate_key;
-
-  bool forward = cursor_options_.forward;
-  bool first_iteration_forward = forward;
-  bool flipped = false;
+  // Optimization: if seeking to a particular key (or key and primary key),
+  // skip the cursor forward rather than iterating it.
+  if (next_state == SEEK && key) {
+    std::string leveldb_key =
+        primary_key ? EncodeKey(*key, *primary_key) : EncodeKey(*key);
+    *s = iterator_->Seek(leveldb_key);
+    if (!s->ok())
+      return false;
+    // Cursor is at the next value already; don't advance it again below.
+    next_state = READY;
+  }
 
   for (;;) {
+    // Only advance the cursor if it was not set to position already,
+    // either because it is newly opened (and positioned at start of range)
+    // or skipped forward by continue with a specific key.
     if (next_state == SEEK) {
-      // TODO(jsbell): Optimize seeking for reverse cursors as well.
-      if (first_iteration_forward && key) {
-        first_iteration_forward = false;
-        std::string leveldb_key;
-        if (primary_key) {
-          leveldb_key = EncodeKey(*key, *primary_key);
-        } else {
-          leveldb_key = EncodeKey(*key);
-        }
-        *s = iterator_->Seek(leveldb_key);
-      } else if (forward) {
-        *s = iterator_->Next();
-      } else {
-        *s = iterator_->Prev();
-      }
+      *s = iterator_->Next();
       if (!s->ok())
         return false;
     } else {
-      next_state = SEEK;  // for subsequent iterations
+      next_state = SEEK;
     }
 
-    if (!iterator_->IsValid()) {
-      if (!forward && last_duplicate_key.IsValid()) {
-        // We need to walk forward because we hit the end of
-        // the data.
-        forward = true;
-        flipped = true;
-        continue;
-      }
-
+    // TODO(jsbell): Can we DCHECK iterator_->IsValid() up top?
+    // Fail if we've run out of data or gone past the cursor's bounds.
+    if (!iterator_->IsValid() || IsPastBounds())
       return false;
-    }
 
-    if (IsPastBounds()) {
-      if (!forward && last_duplicate_key.IsValid()) {
-        // We need to walk forward because now we're beyond the
-        // bounds defined by the cursor.
-        forward = true;
-        flipped = true;
-        continue;
-      }
-
-      return false;
-    }
-
+    // TODO(jsbell): Document why this might be false. When do we ever not
+    // seek into the range before starting cursor iteration?
     if (!HaveEnteredRange())
       continue;
 
@@ -3248,52 +3237,157 @@
       continue;
     }
 
+    // If seeking to a key (or key and primary key), continue until found.
+    // TODO(jsbell): Given the Seek() optimization above, this should
+    // not be necessary. Verify and remove.
     if (key) {
-      if (forward) {
-        if (primary_key && current_key_->Equals(*key) &&
-            this->primary_key().IsLessThan(*primary_key))
-          continue;
-        if (!flipped && current_key_->IsLessThan(*key))
-          continue;
-      } else {
-        if (primary_key && key->Equals(*current_key_) &&
-            primary_key->IsLessThan(this->primary_key()))
-          continue;
-        if (key->IsLessThan(*current_key_))
-          continue;
-      }
+      if (primary_key && current_key_->Equals(*key) &&
+          this->primary_key().IsLessThan(*primary_key))
+        continue;
+      if (current_key_->IsLessThan(*key))
+        continue;
     }
 
-    if (cursor_options_.unique) {
-      if (previous_key.IsValid() && current_key_->Equals(previous_key)) {
-        // We should never be able to walk forward all the way
-        // to the previous key.
-        DCHECK(!last_duplicate_key.IsValid());
-        continue;
-      }
+    // Cursor is now positioned at a non-stale record in range.
 
-      if (!forward) {
-        if (!last_duplicate_key.IsValid()) {
-          last_duplicate_key = *current_key_;
-          continue;
-        }
-
-        // We need to walk forward because we hit the boundary
-        // between key ranges.
-        if (!last_duplicate_key.Equals(*current_key_)) {
-          forward = true;
-          flipped = true;
-          continue;
-        }
-
-        continue;
-      }
+    // "Unique" cursors should continue seeking until a new key value is seen.
+    if (cursor_options_.unique && previous_key.IsValid() &&
+        current_key_->Equals(previous_key)) {
+      continue;
     }
+
     break;
   }
 
+  return true;
+}
+
+bool IndexedDBBackingStore::Cursor::ContinuePrevious(
+    const IndexedDBKey* key,
+    const IndexedDBKey* primary_key,
+    IteratorState next_state,
+    leveldb::Status* s) {
+  DCHECK(!cursor_options_.forward);
+  DCHECK(!key || key->IsValid());
+  DCHECK(!primary_key || primary_key->IsValid());
+  *s = leveldb::Status::OK();
+
+  // TODO(alecflett): avoid a copy here?
+  IndexedDBKey previous_key = current_key_ ? *current_key_ : IndexedDBKey();
+
+  // When iterating with PrevNoDuplicate, spec requires that the value we
+  // yield for each key is the *first* duplicate in forwards order. We do this
+  // by remembering the *last* duplicate seen (implicitly, the first value
+  // seen with a new key), continuing until another new key is seen, then
+  // reversing until we find a key equal to the *last* duplicate.
+  IndexedDBKey last_duplicate_key;
+  bool find_first_duplicate = false;
+
+  // TODO(jsbell): Optimize continuing to a specific key (or key and primary
+  // key) for reverse cursors as well. See Seek() optimization at the start
+  // of ContinueNext() for an example.
+
+  for (;;) {
+    if (next_state == SEEK) {
+      *s = iterator_->Prev();
+      if (!s->ok())
+        return false;
+    } else {
+      next_state = SEEK;  // for subsequent iterations
+    }
+
+    // If we've run out of data or gone past the cursor's bounds.
+    if (!iterator_->IsValid() || IsPastBounds()) {
+      if (last_duplicate_key.IsValid()) {
+        // Walk the cursor forward to the first duplicate.
+        find_first_duplicate = true;
+        break;
+      }
+
+      return false;
+    }
+
+    // TODO(jsbell): Document why this might be false. When do we ever not
+    // seek into the range before starting cursor iteration?
+    if (!HaveEnteredRange())
+      continue;
+
+    // The row may not load because there's a stale entry in the
+    // index. If no error then not fatal.
+    if (!LoadCurrentRow(s)) {
+      if (!s->ok())
+        return false;
+      continue;
+    }
+
+    // If seeking to a key (or key and primary key), continue until found.
+    // TODO(jsbell): If Seek() optimization is added above, remove this.
+    if (key) {
+      if (primary_key && key->Equals(*current_key_) &&
+          primary_key->IsLessThan(this->primary_key()))
+        continue;
+      if (key->IsLessThan(*current_key_))
+        continue;
+    }
+
+    // Cursor is now positioned at a non-stale record in range.
+
+    if (cursor_options_.unique) {
+      // If entry is a duplicate, keep going. Although the cursor should be
+      // positioned at the first duplicate already, new duplicates may have
+      // been inserted since the cursor was last iterated, and should be
+      // skipped to maintain "unique" iteration.
+      if (previous_key.IsValid() && current_key_->Equals(previous_key))
+        continue;
+
+      // If we've found a new key, remember it and keep going.
+      if (!last_duplicate_key.IsValid()) {
+        last_duplicate_key = *current_key_;
+        continue;
+      }
+
+      // If we're still seeing duplicates, keep going.
+      if (last_duplicate_key.Equals(*current_key_))
+        continue;
+
+      // Walk the cursor forward to the first duplicate.
+      find_first_duplicate = true;
+    }
+
+    break;
+  }
+
+  // TODO(jsbell): Rather than iterating, stash the last leveldb key of the
+  // last plausible result, then Seek() the cursor directly to that and
+  // LoadCurrentRow().
+
+  if (find_first_duplicate) {
+    DCHECK_EQ(next_state, SEEK);
+    DCHECK(cursor_options_.unique);
+    for (;;) {
+      *s = iterator_->Next();
+      if (!s->ok() || !iterator_->IsValid() || IsPastBounds())
+        return false;
+
+      // TODO(jsbell): Document why this might be false. When do we ever not
+      // seek into the range before starting cursor iteration?
+      if (!HaveEnteredRange())
+        continue;
+
+      // The row may not load because there's a stale entry in the
+      // index. If no error then not fatal.
+      if (!LoadCurrentRow(s)) {
+        if (!s->ok())
+          return false;
+        continue;
+      }
+
+      break;
+    }
+  }
+
   DCHECK(!last_duplicate_key.IsValid() ||
-         (forward && last_duplicate_key.Equals(*current_key_)));
+         (find_first_duplicate && last_duplicate_key.Equals(*current_key_)));
   return true;
 }
 
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h
index 7b11a600..31f21320 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -338,6 +338,19 @@
     IndexedDBBackingStore::RecordIdentifier record_identifier_;
 
    private:
+    // For cursors with direction Next or NextNoDuplicate.
+    bool ContinueNext(const IndexedDBKey* key,
+                      const IndexedDBKey* primary_key,
+                      IteratorState state,
+                      leveldb::Status*);
+    // For cursors with direction Prev or PrevNoDuplicate.
+    // The PrevNoDuplicate case has additional complexity of not
+    // being symmetric with NextNoDuplicate.
+    bool ContinuePrevious(const IndexedDBKey* key,
+                          const IndexedDBKey* primary_key,
+                          IteratorState state,
+                          leveldb::Status*);
+
     DISALLOW_COPY_AND_ASSIGN(Cursor);
   };
 
diff --git a/content/browser/loader/buffered_resource_handler.cc b/content/browser/loader/buffered_resource_handler.cc
index a160eed..5a18072 100644
--- a/content/browser/loader/buffered_resource_handler.cc
+++ b/content/browser/loader/buffered_resource_handler.cc
@@ -259,7 +259,7 @@
                                      &content_type_options);
 
   bool sniffing_blocked =
-      LowerCaseEqualsASCII(content_type_options, "nosniff");
+      base::LowerCaseEqualsASCII(content_type_options, "nosniff");
   bool we_would_like_to_sniff =
       net::ShouldSniffMimeType(request()->url(), mime_type);
 
diff --git a/content/browser/loader/resource_dispatcher_host_browsertest.cc b/content/browser/loader/resource_dispatcher_host_browsertest.cc
index bb333a5..0fa2733 100644
--- a/content/browser/loader/resource_dispatcher_host_browsertest.cc
+++ b/content/browser/loader/resource_dispatcher_host_browsertest.cc
@@ -103,7 +103,7 @@
   GURL url(embedded_test_server()->GetURL("/dynamic1.html"));
   base::string16 title;
   ASSERT_TRUE(GetPopupTitle(url, &title));
-  EXPECT_TRUE(StartsWith(title, ASCIIToUTF16("My Popup Title"), true))
+  EXPECT_TRUE(base::StartsWith(title, ASCIIToUTF16("My Popup Title"), true))
       << "Actual title: " << title;
 }
 
@@ -115,7 +115,7 @@
   GURL url(embedded_test_server()->GetURL("/dynamic2.html"));
   base::string16 title;
   ASSERT_TRUE(GetPopupTitle(url, &title));
-  EXPECT_TRUE(StartsWith(title, ASCIIToUTF16("My Dynamic Title"), true))
+  EXPECT_TRUE(base::StartsWith(title, ASCIIToUTF16("My Dynamic Title"), true))
       << "Actual title: " << title;
 }
 
@@ -266,7 +266,7 @@
 scoped_ptr<net::test_server::HttpResponse> NoContentResponseHandler(
     const std::string& path,
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(path, request.relative_url, true))
+  if (!base::StartsWithASCII(path, request.relative_url, true))
     return scoped_ptr<net::test_server::HttpResponse>();
 
   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
@@ -443,7 +443,7 @@
 scoped_ptr<net::test_server::HttpResponse> HandleRedirectRequest(
     const std::string& request_path,
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(request.relative_url, request_path, true))
+  if (!base::StartsWithASCII(request.relative_url, request_path, true))
     return scoped_ptr<net::test_server::HttpResponse>();
 
   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index baaf2f9..c69bcdb 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -2352,11 +2352,6 @@
 
   ChildProcessSecurityPolicyImpl* policy =
       ChildProcessSecurityPolicyImpl::GetInstance();
-  if (!policy->CanSendCookiesForOrigin(child_id, request_data.url)) {
-    load_flags |= (net::LOAD_DO_NOT_SEND_COOKIES |
-                   net::LOAD_DO_NOT_SEND_AUTH_DATA |
-                   net::LOAD_DO_NOT_SAVE_COOKIES);
-  }
 
   // Raw headers are sensitive, as they include Cookie/Set-Cookie, so only
   // allow requesting them if requester has ReadRawCookies permission.
diff --git a/content/browser/manifest/manifest_browsertest.cc b/content/browser/manifest/manifest_browsertest.cc
index 490e704..0393710 100644
--- a/content/browser/manifest/manifest_browsertest.cc
+++ b/content/browser/manifest/manifest_browsertest.cc
@@ -476,7 +476,7 @@
 
   // The custom embedded test server will fill the name field with the cookie
   // content.
-  EXPECT_TRUE(EqualsASCII(manifest().name.string(), "foobar"));
+  EXPECT_TRUE(base::EqualsASCII(manifest().name.string(), "foobar"));
 }
 
 namespace {
@@ -532,7 +532,7 @@
 
   // The custom embedded test server will fill set the name to 'no cookies' if
   // it did not find cookies.
-  EXPECT_TRUE(EqualsASCII(manifest().name.string(), "no cookies"));
+  EXPECT_TRUE(base::EqualsASCII(manifest().name.string(), "no cookies"));
 }
 
 } // namespace content
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc
index c77ead0..32e2c04 100644
--- a/content/browser/media/android/browser_media_player_manager.cc
+++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -335,19 +335,6 @@
   return NULL;
 }
 
-void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
-  if (fullscreen_player_id_ == player_id)
-    return;
-
-  if (fullscreen_player_id_ != kInvalidMediaPlayerId) {
-    // TODO(qinmin): Determine the correct error code we should report to WMPA.
-    OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE);
-    return;
-  }
-
-  Send(new MediaPlayerMsg_RequestFullscreen(RoutingID(), player_id));
-}
-
 bool BrowserMediaPlayerManager::RequestPlay(int player_id) {
   MediaPlayerAndroid* player = GetPlayer(player_id);
   DCHECK(player);
diff --git a/content/browser/media/android/browser_media_player_manager.h b/content/browser/media/android/browser_media_player_manager.h
index 8a8d5e6..4f8c128 100644
--- a/content/browser/media/android/browser_media_player_manager.h
+++ b/content/browser/media/android/browser_media_player_manager.h
@@ -98,7 +98,6 @@
   media::MediaUrlInterceptor* GetMediaUrlInterceptor() override;
   media::MediaPlayerAndroid* GetFullscreenPlayer() override;
   media::MediaPlayerAndroid* GetPlayer(int player_id) override;
-  void RequestFullScreen(int player_id) override;
   bool RequestPlay(int player_id) override;
 #if defined(VIDEO_HOLE)
   void AttachExternalVideoSurface(int player_id, jobject surface);
diff --git a/content/browser/media/capture/aura_window_capture_machine.cc b/content/browser/media/capture/aura_window_capture_machine.cc
index b17f31d..1546f653 100644
--- a/content/browser/media/capture/aura_window_capture_machine.cc
+++ b/content/browser/media/capture/aura_window_capture_machine.cc
@@ -288,11 +288,12 @@
     if (!texture_mailbox.IsTexture())
       return false;
     video_frame = media::VideoFrame::WrapNativeTexture(
+        media::VideoFrame::ARGB,
         gpu::MailboxHolder(texture_mailbox.mailbox(), texture_mailbox.target(),
                            texture_mailbox.sync_point()),
         base::Bind(&RunSingleReleaseCallback, base::Passed(&release_callback)),
         result->size(), gfx::Rect(result->size()), result->size(),
-        base::TimeDelta(), false /* allow_overlay */, true /* has_alpha */);
+        base::TimeDelta());
     capture_frame_cb.Run(video_frame, start_time, true);
     return true;
   } else {
diff --git a/content/browser/media/capture/video_capture_oracle.cc b/content/browser/media/capture/video_capture_oracle.cc
index 9157d8ce..0632ef131 100644
--- a/content/browser/media/capture/video_capture_oracle.cc
+++ b/content/browser/media/capture/video_capture_oracle.cc
@@ -38,7 +38,8 @@
 
 VideoCaptureOracle::VideoCaptureOracle(base::TimeDelta min_capture_period)
     : next_frame_number_(0),
-      last_delivered_frame_number_(-1),
+      last_successfully_delivered_frame_number_(-1),
+      num_frames_pending_(0),
       smoothing_sampler_(min_capture_period,
                          kNumRedundantCapturesOfStaticContent),
       content_sampler_(min_capture_period) {
@@ -80,7 +81,7 @@
     case kTimerPoll:
       // While the timer is firing, only allow a sampling if there are none
       // currently in-progress.
-      if (last_delivered_frame_number_ == (next_frame_number_ - 1)) {
+      if (num_frames_pending_ == 0) {
         should_sample = smoothing_sampler_.IsOverdueForSamplingAt(event_time);
         if (should_sample)
           duration_of_next_frame_ = smoothing_sampler_.min_capture_period();
@@ -98,28 +99,32 @@
 int VideoCaptureOracle::RecordCapture() {
   smoothing_sampler_.RecordSample();
   content_sampler_.RecordSample(GetFrameTimestamp(next_frame_number_));
+  num_frames_pending_++;
   return next_frame_number_++;
 }
 
 bool VideoCaptureOracle::CompleteCapture(int frame_number,
                                          bool capture_was_successful,
                                          base::TimeTicks* frame_timestamp) {
-  // Drop frame if previous frame number is higher.
-  if (last_delivered_frame_number_ > frame_number) {
+  num_frames_pending_--;
+
+  // Drop frame if previously delivered frame number is higher.
+  if (last_successfully_delivered_frame_number_ > frame_number) {
     LOG_IF(WARNING, capture_was_successful)
         << "Out of order frame delivery detected (have #" << frame_number
-        << ", last was #" << last_delivered_frame_number_
+        << ", last was #" << last_successfully_delivered_frame_number_
         << ").  Dropping frame.";
     return false;
   }
-  DCHECK_NE(last_delivered_frame_number_, frame_number);
-  last_delivered_frame_number_ = frame_number;
 
   if (!capture_was_successful) {
     VLOG(2) << "Capture of frame #" << frame_number << " was not successful.";
     return false;
   }
 
+  DCHECK_NE(last_successfully_delivered_frame_number_, frame_number);
+  last_successfully_delivered_frame_number_ = frame_number;
+
   *frame_timestamp = GetFrameTimestamp(frame_number);
 
   // If enabled, log a measurement of how this frame timestamp has incremented
diff --git a/content/browser/media/capture/video_capture_oracle.h b/content/browser/media/capture/video_capture_oracle.h
index 5bb1dd0..db8ae41 100644
--- a/content/browser/media/capture/video_capture_oracle.h
+++ b/content/browser/media/capture/video_capture_oracle.h
@@ -85,8 +85,11 @@
   // returned false.
   base::TimeDelta duration_of_next_frame_;
 
-  // Stores the frame number from the last delivered frame.
-  int last_delivered_frame_number_;
+  // Stores the frame number from the last successfully delivered frame.
+  int last_successfully_delivered_frame_number_;
+
+  // Stores the number of pending frame captures.
+  int num_frames_pending_;
 
   // These track present/paint history and propose whether to sample each event
   // for capture.  |smoothing_sampler_| uses a "works for all" heuristic, while
diff --git a/content/browser/media/capture/video_capture_oracle_unittest.cc b/content/browser/media/capture/video_capture_oracle_unittest.cc
index 2d949508..4943ee3 100644
--- a/content/browser/media/capture/video_capture_oracle_unittest.cc
+++ b/content/browser/media/capture/video_capture_oracle_unittest.cc
@@ -52,9 +52,9 @@
   }
 }
 
-// Tests that VideoCaptureOracle is enforcing the requirement that captured
-// frames are delivered in order.  Otherwise, downstream consumers could be
-// tripped-up by out-of-order frames or frame timestamps.
+// Tests that VideoCaptureOracle is enforcing the requirement that
+// successfully captured frames are delivered in order.  Otherwise, downstream
+// consumers could be tripped-up by out-of-order frames or frame timestamps.
 TEST(VideoCaptureOracleTest, EnforcesFramesDeliveredInOrder) {
   const base::TimeDelta min_capture_period =
       base::TimeDelta::FromSeconds(1) / 30;
@@ -93,7 +93,8 @@
     }
   }
 
-  // Pipelined scenario with out-of-order delivery attempts rejected.
+  // Pipelined scenario with successful out-of-order delivery attempts
+  // rejected.
   for (int i = 0; i < 50; ++i) {
     const int num_in_flight = 1 + i % 3;
     for (int j = 0; j < num_in_flight; ++j) {
@@ -109,6 +110,26 @@
           oracle.CompleteCapture(last_frame_number - j, true, &ignored));
     }
   }
+
+  // Pipelined scenario with successful delivery attempts accepted after an
+  // unsuccessful out of order delivery attempt.
+  for (int i = 0; i < 50; ++i) {
+    const int num_in_flight = 1 + i % 3;
+    for (int j = 0; j < num_in_flight; ++j) {
+      t += event_increment;
+      ASSERT_TRUE(oracle.ObserveEventAndDecideCapture(
+          VideoCaptureOracle::kCompositorUpdate,
+          damage_rect, t));
+      last_frame_number = oracle.RecordCapture();
+    }
+    // Report the last frame as an out of order failure.
+    ASSERT_FALSE(oracle.CompleteCapture(last_frame_number, false, &ignored));
+    for (int j = 1; j < num_in_flight - 1; ++j) {
+      ASSERT_TRUE(
+          oracle.CompleteCapture(last_frame_number - j, true, &ignored));
+    }
+
+  }
 }
 
 // Tests that VideoCaptureOracle transitions between using its two samplers in a
diff --git a/content/browser/media/capture/web_contents_capture_util.cc b/content/browser/media/capture/web_contents_capture_util.cc
index e1c5d52..d81690b 100644
--- a/content/browser/media/capture/web_contents_capture_util.cc
+++ b/content/browser/media/capture/web_contents_capture_util.cc
@@ -22,7 +22,7 @@
     int* render_process_id,
     int* main_render_frame_id) {
   static const char kDeviceScheme[] = "web-contents-media-stream://";
-  if (!StartsWithASCII(device_id_param, kDeviceScheme, true))
+  if (!base::StartsWithASCII(device_id_param, kDeviceScheme, true))
     return false;
 
   const std::string device_id = device_id_param.substr(
diff --git a/content/browser/media/media_internals.cc b/content/browser/media/media_internals.cc
index 7f4d62e..d622820a 100644
--- a/content/browser/media/media_internals.cc
+++ b/content/browser/media/media_internals.cc
@@ -9,8 +9,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_frame_host.h"
@@ -104,6 +102,8 @@
   void OnClosed(int component_id) override;
   void OnError(int component_id) override;
   void OnSetVolume(int component_id, double volume) override;
+  void OnSwitchOutputDevice(int component_id,
+                            const std::string& device_id) override;
 
   // Called by MediaInternals to update the WebContents title for a stream.
   void SendWebContentsTitle(int component_id,
@@ -189,6 +189,16 @@
                                        kAudioLogUpdateFunction, &dict);
 }
 
+void AudioLogImpl::OnSwitchOutputDevice(int component_id,
+                                        const std::string& device_id) {
+  base::DictionaryValue dict;
+  StoreComponentMetadata(component_id, &dict);
+  dict.SetString("device_id", device_id);
+  media_internals_->SendAudioLogUpdate(MediaInternals::UPDATE_IF_EXISTS,
+                                       FormatCacheKey(component_id),
+                                       kAudioLogUpdateFunction, &dict);
+}
+
 void AudioLogImpl::SendWebContentsTitle(int component_id,
                                         int render_process_id,
                                         int render_frame_id) {
@@ -249,22 +259,19 @@
   dict->SetInteger("component_type", component_);
 }
 
-class MediaInternals::MediaInternalsUMAHandler : public NotificationObserver {
+// This class lives on the browser UI thread.
+class MediaInternals::MediaInternalsUMAHandler {
  public:
   MediaInternalsUMAHandler();
 
-  // NotificationObserver implementation.
-  void Observe(int type,
-               const NotificationSource& source,
-               const NotificationDetails& details) override;
-
-  // Reports the pipeline status to UMA for every player
-  // associated with the renderer process and then deletes the player state.
-  void LogAndClearPlayersInRenderer(int render_process_id);
+  // Called when a render process is terminated. Reports the pipeline status to
+  // UMA for every player associated with the renderer process and then deletes
+  // the player state.
+  void OnProcessTerminated(int render_process_id);
 
   // Helper function to save the event payload to RendererPlayerMap.
-  void SavePlayerState(const media::MediaLogEvent& event,
-                       int render_process_id);
+  void SavePlayerState(int render_process_id,
+                       const media::MediaLogEvent& event);
 
  private:
   struct PipelineInfo {
@@ -290,48 +297,25 @@
   // Helper to generate PipelineStatus UMA name for AudioVideo streams.
   std::string GetUMANameForAVStream(const PipelineInfo& player_info);
 
-  // Key is playerid
+  // Key is player id.
   typedef std::map<int, PipelineInfo> PlayerInfoMap;
 
-  // Key is renderer id
+  // Key is renderer id.
   typedef std::map<int, PlayerInfoMap> RendererPlayerMap;
 
-  // Stores player information per renderer
+  // Stores player information per renderer.
   RendererPlayerMap renderer_info_;
 
-  NotificationRegistrar registrar_;
-
   DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler);
 };
 
 MediaInternals::MediaInternalsUMAHandler::MediaInternalsUMAHandler() {
-  registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
-                 NotificationService::AllBrowserContextsAndSources());
-}
-
-void MediaInternals::MediaInternalsUMAHandler::Observe(
-    int type,
-    const NotificationSource& source,
-    const NotificationDetails& details) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
-  RenderProcessHost* process = Source<RenderProcessHost>(source).ptr();
-
-  // Post the task to the IO thread to avoid race in updating renderer_info_ map
-  // by both SavePlayerState & LogAndClearPlayersInRenderer from different
-  // threads.
-  // Using base::Unretained() on MediaInternalsUMAHandler is safe since
-  // it is owned by MediaInternals and share the same lifetime
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&MediaInternalsUMAHandler::LogAndClearPlayersInRenderer,
-                 base::Unretained(this), process->GetID()));
 }
 
 void MediaInternals::MediaInternalsUMAHandler::SavePlayerState(
-    const media::MediaLogEvent& event,
-    int render_process_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    int render_process_id,
+    const media::MediaLogEvent& event) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   PlayerInfoMap& player_info = renderer_info_[render_process_id];
   switch (event.type) {
     case media::MediaLogEvent::PIPELINE_ERROR: {
@@ -379,7 +363,7 @@
 
 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream(
     const PipelineInfo& player_info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   static const char kPipelineUmaPrefix[] = "Media.PipelineStatus.AudioVideo.";
   std::string uma_name = kPipelineUmaPrefix;
   if (player_info.video_codec_name == "vp8") {
@@ -411,7 +395,7 @@
 
 void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus(
     const PipelineInfo& player_info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (player_info.has_video && player_info.has_audio) {
     base::LinearHistogram::FactoryGet(
         GetUMANameForAVStream(player_info), 1, media::PIPELINE_STATUS_MAX,
@@ -439,9 +423,10 @@
   }
 }
 
-void MediaInternals::MediaInternalsUMAHandler::LogAndClearPlayersInRenderer(
+void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated(
     int render_process_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
   auto players_it = renderer_info_.find(render_process_id);
   if (players_it == renderer_info_.end())
     return;
@@ -450,6 +435,7 @@
     ReportUMAForPipelineStatus(it->second);
     players_it->second.erase(it++);
   }
+  renderer_info_.erase(players_it);
 }
 
 MediaInternals* MediaInternals::GetInstance() {
@@ -460,44 +446,72 @@
     : can_update_(false),
       owner_ids_(),
       uma_handler_(new MediaInternalsUMAHandler()) {
+  registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+                 NotificationService::AllBrowserContextsAndSources());
 }
 
 MediaInternals::~MediaInternals() {}
 
+void MediaInternals::Observe(int type,
+                             const NotificationSource& source,
+                             const NotificationDetails& details) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
+  RenderProcessHost* process = Source<RenderProcessHost>(source).ptr();
+
+  uma_handler_->OnProcessTerminated(process->GetID());
+  pending_events_map_.erase(process->GetID());
+}
+
+// Converts the |event| to a |update|. Returns whether the conversion succeeded.
+static bool ConvertEventToUpdate(int render_process_id,
+                                 const media::MediaLogEvent& event,
+                                 base::string16* update) {
+  DCHECK(update);
+
+  base::DictionaryValue dict;
+  dict.SetInteger("renderer", render_process_id);
+  dict.SetInteger("player", event.id);
+  dict.SetString("type", media::MediaLog::EventTypeToString(event.type));
+
+  // TODO(dalecurtis): This is technically not correct.  TimeTicks "can't" be
+  // converted to to a human readable time format.  See base/time/time.h.
+  const double ticks = event.time.ToInternalValue();
+  const double ticks_millis = ticks / base::Time::kMicrosecondsPerMillisecond;
+  dict.SetDouble("ticksMillis", ticks_millis);
+
+  // Convert PipelineStatus to human readable string
+  if (event.type == media::MediaLogEvent::PIPELINE_ERROR) {
+    int status;
+    if (!event.params.GetInteger("pipeline_error", &status) ||
+        status < static_cast<int>(media::PIPELINE_OK) ||
+        status > static_cast<int>(media::PIPELINE_STATUS_MAX)) {
+      return false;
+    }
+    media::PipelineStatus error = static_cast<media::PipelineStatus>(status);
+    dict.SetString("params.pipeline_error",
+                   media::MediaLog::PipelineStatusToString(error));
+  } else {
+    dict.Set("params", event.params.DeepCopy());
+  }
+
+  *update = SerializeUpdate("media.onMediaEvent", &dict);
+  return true;
+}
+
 void MediaInternals::OnMediaEvents(
     int render_process_id, const std::vector<media::MediaLogEvent>& events) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Notify observers that |event| has occurred.
-  for (auto event = events.begin(); event != events.end(); ++event) {
-    base::DictionaryValue dict;
-    dict.SetInteger("renderer", render_process_id);
-    dict.SetInteger("player", event->id);
-    dict.SetString("type", media::MediaLog::EventTypeToString(event->type));
-
-    // TODO(dalecurtis): This is technically not correct.  TimeTicks "can't" be
-    // converted to to a human readable time format.  See base/time/time.h.
-    const double ticks = event->time.ToInternalValue();
-    const double ticks_millis = ticks / base::Time::kMicrosecondsPerMillisecond;
-    dict.SetDouble("ticksMillis", ticks_millis);
-
-    // Convert PipelineStatus to human readable string
-    if (event->type == media::MediaLogEvent::PIPELINE_ERROR) {
-      int status;
-      if (!event->params.GetInteger("pipeline_error", &status) ||
-          status < static_cast<int>(media::PIPELINE_OK) ||
-          status > static_cast<int>(media::PIPELINE_STATUS_MAX)) {
-        continue;
-      }
-      media::PipelineStatus error = static_cast<media::PipelineStatus>(status);
-      dict.SetString("params.pipeline_error",
-                     media::MediaLog::PipelineStatusToString(error));
-    } else {
-      dict.Set("params", event->params.DeepCopy());
+  for (const auto& event : events) {
+    if (CanUpdate()) {
+      base::string16 update;
+      if (ConvertEventToUpdate(render_process_id, event, &update))
+        SendUpdate(update);
     }
 
-    if (CanUpdate())
-      SendUpdate(SerializeUpdate("media.onMediaEvent", &dict));
-    uma_handler_->SavePlayerState(*event, render_process_id);
+    SaveEvent(render_process_id, event);
+    uma_handler_->SavePlayerState(render_process_id, event);
   }
 }
 
@@ -527,6 +541,19 @@
   return can_update_;
 }
 
+void MediaInternals::SendHistoricalMediaEvents() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  for (const auto& pending_events : pending_events_map_) {
+    for (const auto& event : pending_events.second) {
+      base::string16 update;
+      if (ConvertEventToUpdate(pending_events.first, event, &update))
+        SendUpdate(update);
+    }
+  }
+  // Do not clear the map/list here so that refreshing the UI or opening a
+  // second UI still works nicely!
+}
+
 void MediaInternals::SendAudioStreamData() {
   base::string16 audio_stream_update;
   {
@@ -601,6 +628,28 @@
     update_callbacks_[i].Run(update);
 }
 
+void MediaInternals::SaveEvent(int process_id,
+                               const media::MediaLogEvent& event) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  // Max number of saved updates allowed for one process.
+  const size_t kMaxNumEvents = 128;
+
+  // Do not save instantaneous events that happen frequently and have little
+  // value in the future.
+  if (event.type == media::MediaLogEvent::NETWORK_ACTIVITY_SET ||
+      event.type == media::MediaLogEvent::BUFFERED_EXTENTS_CHANGED) {
+    return;
+  }
+
+  auto& pending_events = pending_events_map_[process_id];
+  // TODO(xhwang): Notify user that some old logs could have been truncated.
+  // See http://crbug.com/498520
+  if (pending_events.size() >= kMaxNumEvents)
+    pending_events.pop_front();
+  pending_events.push_back(event);
+}
+
 void MediaInternals::SendAudioLogUpdate(AudioLogUpdateType type,
                                         const std::string& cache_key,
                                         const std::string& function,
diff --git a/content/browser/media/media_internals.h b/content/browser/media/media_internals.h
index 72efdd6b..fed457a 100644
--- a/content/browser/media/media_internals.h
+++ b/content/browser/media/media_internals.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_BROWSER_MEDIA_MEDIA_INTERNALS_H_
 #define CONTENT_BROWSER_MEDIA_MEDIA_INTERNALS_H_
 
+#include <list>
+#include <map>
 #include <string>
 #include <vector>
 
@@ -15,6 +17,8 @@
 #include "base/synchronization/lock.h"
 #include "base/values.h"
 #include "content/common/content_export.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "media/audio/audio_logging.h"
 #include "media/base/media_log.h"
 #include "media/video/capture/video_capture_device_info.h"
@@ -28,7 +32,8 @@
 
 // This class stores information about currently active media.
 class CONTENT_EXPORT MediaInternals
-    : NON_EXPORTED_BASE(public media::AudioLogFactory) {
+    : NON_EXPORTED_BASE(public media::AudioLogFactory),
+      public NotificationObserver {
  public:
   // Called with the update string.
   typedef base::Callback<void(const base::string16&)> UpdateCallback;
@@ -37,6 +42,11 @@
 
   ~MediaInternals() override;
 
+  // NotificationObserver implementation.
+  void Observe(int type,
+               const NotificationSource& source,
+               const NotificationDetails& details) override;
+
   // Called when a MediaEvent occurs.
   void OnMediaEvents(int render_process_id,
                      const std::vector<media::MediaLogEvent>& events);
@@ -50,6 +60,9 @@
   // thread.
   bool CanUpdate();
 
+  // Replay all saved media events.
+  void SendHistoricalMediaEvents();
+
   // Sends all audio cached data to each registered UpdateCallback.
   void SendAudioStreamData();
 
@@ -80,12 +93,21 @@
   friend class MediaInternalsTest;
   friend struct base::DefaultLazyInstanceTraits<MediaInternals>;
 
+  // Pending events for a particular process.
+  using PendingEvents = std::list<media::MediaLogEvent>;
+
+  // The maps between process ID and PendingEvents.
+  using PendingEventsMap = std::map<int, PendingEvents>;
+
   MediaInternals();
 
   // Sends |update| to each registered UpdateCallback.  Safe to call from any
   // thread, but will forward to the IO thread.
   void SendUpdate(const base::string16& update);
 
+  // Saves |event| so that it can be sent later in SendHistoricalMediaEvents().
+  void SaveEvent(int process_id, const media::MediaLogEvent& event);
+
   // Caches |value| under |cache_key| so that future SendAudioLogUpdate() calls
   // will include the current data.  Calls JavaScript |function|(|value|) for
   // each registered UpdateCallback.
@@ -102,10 +124,13 @@
 
   // Must only be accessed on the UI thread.
   std::vector<UpdateCallback> update_callbacks_;
+  PendingEventsMap pending_events_map_;
 
   // Must only be accessed on the IO thread.
   base::ListValue video_capture_capabilities_cached_data_;
 
+  NotificationRegistrar registrar_;
+
   // All variables below must be accessed under |lock_|.
   base::Lock lock_;
   bool can_update_;
diff --git a/content/browser/media/media_internals_proxy.cc b/content/browser/media/media_internals_proxy.cc
index 771d5f7..6e338ed 100644
--- a/content/browser/media/media_internals_proxy.cc
+++ b/content/browser/media/media_internals_proxy.cc
@@ -69,7 +69,9 @@
 void MediaInternalsProxy::GetEverything() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  // Ask MediaInternals for all its data.
+  MediaInternals::GetInstance()->SendHistoricalMediaEvents();
+
+  // Ask MediaInternals for its data on IO thread.
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::Bind(&MediaInternalsProxy::GetEverythingOnIOThread, this));
@@ -136,6 +138,7 @@
 
 void MediaInternalsProxy::GetEverythingOnIOThread() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  // TODO(xhwang): Investigate whether we can update on UI thread directly.
   MediaInternals::GetInstance()->SendAudioStreamData();
   MediaInternals::GetInstance()->SendVideoCaptureDeviceCapabilities();
 }
diff --git a/content/browser/mojo/mojo_app_connection_impl.cc b/content/browser/mojo/mojo_app_connection_impl.cc
index d643bbf..4f567d9 100644
--- a/content/browser/mojo/mojo_app_connection_impl.cc
+++ b/content/browser/mojo/mojo_app_connection_impl.cc
@@ -8,12 +8,20 @@
 
 namespace content {
 
-scoped_ptr<MojoAppConnection> MojoAppConnection::Create(const GURL& url) {
-  return scoped_ptr<MojoAppConnection>(new MojoAppConnectionImpl(url));
+const char kBrowserMojoAppUrl[] = "system:content_browser";
+
+// static
+scoped_ptr<MojoAppConnection> MojoAppConnection::Create(
+    const GURL& url,
+    const GURL& requestor_url) {
+  return scoped_ptr<MojoAppConnection>(
+      new MojoAppConnectionImpl(url, requestor_url));
 }
 
-MojoAppConnectionImpl::MojoAppConnectionImpl(const GURL& url) {
-  MojoShellContext::ConnectToApplication(url, mojo::GetProxy(&services_));
+MojoAppConnectionImpl::MojoAppConnectionImpl(const GURL& url,
+                                             const GURL& requestor_url) {
+  MojoShellContext::ConnectToApplication(url, requestor_url,
+                                         mojo::GetProxy(&services_));
 }
 
 MojoAppConnectionImpl::~MojoAppConnectionImpl() {
diff --git a/content/browser/mojo/mojo_app_connection_impl.h b/content/browser/mojo/mojo_app_connection_impl.h
index 4628acc..6fc4ea3 100644
--- a/content/browser/mojo/mojo_app_connection_impl.h
+++ b/content/browser/mojo/mojo_app_connection_impl.h
@@ -16,7 +16,7 @@
 // Implementation of the app connection mechanism provided to browser code.
 class MojoAppConnectionImpl : public MojoAppConnection {
  public:
-  explicit MojoAppConnectionImpl(const GURL& url);
+  MojoAppConnectionImpl(const GURL& url, const GURL& requestor_url);
   ~MojoAppConnectionImpl() override;
 
  private:
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc
index 49e66a9..7541a0e3 100644
--- a/content/browser/mojo/mojo_shell_context.cc
+++ b/content/browser/mojo/mojo_shell_context.cc
@@ -28,10 +28,6 @@
 
 namespace {
 
-// Virtual app URL to use as the requestor identity when connecting from browser
-// code to a Mojo app via the shell proxy.
-const char kBrowserAppUrl[] = "system:content_browser";
-
 // An extra set of apps to register on initialization, if set by a test.
 const MojoShellContext::StaticApplicationMap* g_applications_for_test;
 
@@ -88,17 +84,19 @@
 
   void ConnectToApplication(
       const GURL& url,
+      const GURL& requestor_url,
       mojo::InterfaceRequest<mojo::ServiceProvider> request) {
     if (task_runner_ == base::ThreadTaskRunnerHandle::Get()) {
       if (shell_context_)
-        shell_context_->ConnectToApplicationOnOwnThread(url, request.Pass());
+        shell_context_->ConnectToApplicationOnOwnThread(url, requestor_url,
+                                                        request.Pass());
     } else {
       // |shell_context_| outlives the main MessageLoop, so it's safe for it to
       // be unretained here.
       task_runner_->PostTask(
           FROM_HERE,
           base::Bind(&MojoShellContext::ConnectToApplicationOnOwnThread,
-                     base::Unretained(shell_context_), url,
+                     base::Unretained(shell_context_), url, requestor_url,
                      base::Passed(&request)));
     }
   }
@@ -147,17 +145,19 @@
 // static
 void MojoShellContext::ConnectToApplication(
     const GURL& url,
+    const GURL& requestor_url,
     mojo::InterfaceRequest<mojo::ServiceProvider> request) {
-  proxy_.Get()->ConnectToApplication(url, request.Pass());
+  proxy_.Get()->ConnectToApplication(url, requestor_url, request.Pass());
 }
 
 void MojoShellContext::ConnectToApplicationOnOwnThread(
     const GURL& url,
+    const GURL& requestor_url,
     mojo::InterfaceRequest<mojo::ServiceProvider> request) {
   mojo::URLRequestPtr url_request = mojo::URLRequest::New();
   url_request->url = mojo::String::From(url);
   application_manager_->ConnectToApplication(
-      url_request.Pass(), GURL(kBrowserAppUrl), request.Pass(),
+      url_request.Pass(), requestor_url, request.Pass(),
       mojo::ServiceProviderPtr(), base::Bind(&base::DoNothing));
 }
 
diff --git a/content/browser/mojo/mojo_shell_context.h b/content/browser/mojo/mojo_shell_context.h
index b0ac5b16..ab0207b 100644
--- a/content/browser/mojo/mojo_shell_context.h
+++ b/content/browser/mojo/mojo_shell_context.h
@@ -36,9 +36,11 @@
 
   // Connects an application at |url| and gets a handle to its exposed services.
   // This is only intended for use in browser code that's not part of some Mojo
-  // application. May be called from any thread.
+  // application. May be called from any thread. |requestor_url| is given to
+  // the target application as the requestor's URL upon connection.
   static void ConnectToApplication(
       const GURL& url,
+      const GURL& requestor_url,
       mojo::InterfaceRequest<mojo::ServiceProvider> request);
 
   static void SetApplicationsForTest(const StaticApplicationMap* apps);
@@ -49,6 +51,7 @@
 
   void ConnectToApplicationOnOwnThread(
       const GURL& url,
+      const GURL& requestor_url,
       mojo::InterfaceRequest<mojo::ServiceProvider> request);
 
   // mojo::shell::ApplicationManager::Delegate:
diff --git a/content/browser/mojo_shell_browsertest.cc b/content/browser/mojo_shell_browsertest.cc
index 3dcde732..b291961 100644
--- a/content/browser/mojo_shell_browsertest.cc
+++ b/content/browser/mojo_shell_browsertest.cc
@@ -35,7 +35,8 @@
 };
 
 IN_PROC_BROWSER_TEST_F(MojoShellTest, TestBrowserConnection) {
-  auto test_app = MojoAppConnection::Create(GURL(kInProcessTestMojoAppUrl));
+  auto test_app = MojoAppConnection::Create(GURL(kInProcessTestMojoAppUrl),
+                                            GURL(kBrowserMojoAppUrl));
   TestMojoServicePtr test_service;
   test_app->ConnectToService(&test_service);
 
@@ -48,7 +49,8 @@
   // With no loader registered at this URL, the shell should spawn a utility
   // process and connect us to it. content_shell's utility process always hosts
   // a TestMojoApp at |kTestMojoAppUrl|.
-  auto test_app = MojoAppConnection::Create(GURL(kTestMojoAppUrl));
+  auto test_app = MojoAppConnection::Create(GURL(kTestMojoAppUrl),
+                                            GURL(kBrowserMojoAppUrl));
   TestMojoServicePtr test_service;
   test_app->ConnectToService(&test_service);
 
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.cc b/content/browser/notifications/notification_event_dispatcher_impl.cc
index b135177f..1f72416a 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -52,6 +52,7 @@
     case SERVICE_WORKER_ERROR_TIMEOUT:
     case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
     case SERVICE_WORKER_ERROR_DISK_CACHE:
+    case SERVICE_WORKER_ERROR_REDUNDANT:
     case SERVICE_WORKER_ERROR_MAX_VALUE:
       status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
       break;
@@ -105,6 +106,7 @@
     case SERVICE_WORKER_ERROR_TIMEOUT:
     case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
     case SERVICE_WORKER_ERROR_DISK_CACHE:
+    case SERVICE_WORKER_ERROR_REDUNDANT:
     case SERVICE_WORKER_ERROR_MAX_VALUE:
       status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
       break;
diff --git a/content/browser/presentation/presentation_service_impl.cc b/content/browser/presentation/presentation_service_impl.cc
index 916dded..a3299c78 100644
--- a/content/browser/presentation/presentation_service_impl.cc
+++ b/content/browser/presentation/presentation_service_impl.cc
@@ -53,35 +53,50 @@
     presentation::SessionMessagePtr input) {
   DCHECK(!input.is_null());
   scoped_ptr<content::PresentationSessionMessage> output;
-  if (input->type == presentation::PresentationMessageType::
-                     PRESENTATION_MESSAGE_TYPE_TEXT) {
-    DCHECK(!input->message.is_null());
-    DCHECK(input->data.is_null());
-    // Return null PresentationSessionMessage if size exceeds.
-    if (input->message.size() > content::kMaxPresentationSessionMessageSize)
+  switch (input->type) {
+    case presentation::PresentationMessageType::
+        PRESENTATION_MESSAGE_TYPE_TEXT: {
+      DCHECK(!input->message.is_null());
+      DCHECK(input->data.is_null());
+      // Return null PresentationSessionMessage if size exceeds.
+      if (input->message.size() > content::kMaxPresentationSessionMessageSize)
+        return output.Pass();
+
+      output = content::PresentationSessionMessage::CreateStringMessage(
+          input->presentation_url, input->presentation_id,
+          make_scoped_ptr(new std::string));
+      input->message.Swap(output->message.get());
       return output.Pass();
+    }
+    case presentation::PresentationMessageType::
+        PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER: {
+      DCHECK(!input->data.is_null());
+      DCHECK(input->message.is_null());
+      if (input->data.size() > content::kMaxPresentationSessionMessageSize)
+        return output.Pass();
 
-    output = content::PresentationSessionMessage::CreateStringMessage(
-        input->presentation_url,
-        input->presentation_id,
-        make_scoped_ptr(new std::string));
-    input->message.Swap(output->message.get());
-
-  } else if (input->type == presentation::PresentationMessageType::
-              PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER) {
-    DCHECK(!input->data.is_null());
-    DCHECK(input->message.is_null());
-    // Return null PresentationSessionMessage if size exceeds.
-    if (input->data.size() > content::kMaxPresentationSessionMessageSize)
+      output = content::PresentationSessionMessage::CreateArrayBufferMessage(
+          input->presentation_url, input->presentation_id,
+          make_scoped_ptr(new std::vector<uint8_t>));
+      input->data.Swap(output->data.get());
       return output.Pass();
+    }
+    case presentation::PresentationMessageType::
+        PRESENTATION_MESSAGE_TYPE_BLOB: {
+      DCHECK(!input->data.is_null());
+      DCHECK(input->message.is_null());
+      if (input->data.size() > content::kMaxPresentationSessionMessageSize)
+        return output.Pass();
 
-    output = content::PresentationSessionMessage::CreateBinaryMessage(
-        input->presentation_url,
-        input->presentation_id,
-        make_scoped_ptr(new std::vector<uint8_t>));
-    input->data.Swap(output->data.get());
+      output = content::PresentationSessionMessage::CreateBlobMessage(
+          input->presentation_url, input->presentation_id,
+          make_scoped_ptr(new std::vector<uint8_t>));
+      input->data.Swap(output->data.get());
+      return output.Pass();
+    }
   }
 
+  NOTREACHED() << "Invalid presentation message type " << input->type;
   return output.Pass();
 }
 
diff --git a/content/browser/presentation/presentation_service_impl_unittest.cc b/content/browser/presentation/presentation_service_impl_unittest.cc
index 81a2dba..7e329df 100644
--- a/content/browser/presentation/presentation_service_impl_unittest.cc
+++ b/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -305,7 +305,7 @@
             presentation_url, presentation_id,
             scoped_ptr<std::string>(new std::string(text_msg))));
     messages->push_back(
-        content::PresentationSessionMessage::CreateBinaryMessage(
+        content::PresentationSessionMessage::CreateArrayBufferMessage(
             presentation_url, presentation_id,
             scoped_ptr<std::vector<uint8_t>>(
                 new std::vector<uint8_t>(binary_data))));
@@ -740,6 +740,7 @@
   EXPECT_EQ(presentation_url, test_message->presentation_url);
   EXPECT_EQ(presentation_id, test_message->presentation_id);
   EXPECT_TRUE(test_message->is_binary());
+  EXPECT_EQ(PresentationMessageType::ARRAY_BUFFER, test_message->type);
   EXPECT_FALSE(test_message->message);
   EXPECT_EQ(data.size(), test_message->data.get()->size());
   EXPECT_TRUE(test_message->data.get()->size() <=
@@ -790,6 +791,50 @@
   SaveQuitClosureAndRunLoop();
 }
 
+TEST_F(PresentationServiceImplTest, SendBlobData) {
+  std::string presentation_url("http://foo.com/index.html");
+  std::string presentation_id("presentationId");
+  const uint8 buffer[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
+  std::vector<uint8> data;
+  data.assign(buffer, buffer + sizeof(buffer));
+
+  presentation::SessionMessagePtr message_request(
+      presentation::SessionMessage::New());
+  message_request->presentation_url = presentation_url;
+  message_request->presentation_id = presentation_id;
+  message_request->type =
+      presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_BLOB;
+  message_request->data = mojo::Array<uint8>::From(data);
+  service_ptr_->SendSessionMessage(
+      message_request.Pass(),
+      base::Bind(&PresentationServiceImplTest::ExpectSendMessageMojoCallback,
+                 base::Unretained(this)));
+
+  base::RunLoop run_loop;
+  base::Closure send_message_cb;
+  PresentationSessionMessage* test_message = nullptr;
+  EXPECT_CALL(mock_delegate_, SendMessageRawPtr(_, _, _, _))
+      .WillOnce(DoAll(
+          InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit),
+          SaveArg<2>(&test_message),
+          SaveArg<3>(&send_message_cb)));
+  run_loop.Run();
+
+  EXPECT_TRUE(test_message);
+  EXPECT_EQ(presentation_url, test_message->presentation_url);
+  EXPECT_EQ(presentation_id, test_message->presentation_id);
+  EXPECT_TRUE(test_message->is_binary());
+  EXPECT_EQ(PresentationMessageType::BLOB, test_message->type);
+  EXPECT_FALSE(test_message->message);
+  EXPECT_EQ(data.size(), test_message->data.get()->size());
+  EXPECT_TRUE(test_message->data.get()->size() <=
+              kMaxPresentationSessionMessageSize);
+  EXPECT_EQ(0, memcmp(buffer, &(*test_message->data.get())[0], sizeof(buffer)));
+  delete test_message;
+  send_message_cb.Run();
+  SaveQuitClosureAndRunLoop();
+}
+
 TEST_F(PresentationServiceImplTest, MaxPendingStartSessionRequests) {
   const char* presentation_url = "http://fooUrl%d";
   const char* presentation_id = "presentationId%d";
diff --git a/content/browser/push_messaging/push_messaging_message_filter.cc b/content/browser/push_messaging/push_messaging_message_filter.cc
index 4732280..d7b791a 100644
--- a/content/browser/push_messaging/push_messaging_message_filter.cc
+++ b/content/browser/push_messaging/push_messaging_message_filter.cc
@@ -568,6 +568,7 @@
     case SERVICE_WORKER_ERROR_TIMEOUT:
     case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
     case SERVICE_WORKER_ERROR_DISK_CACHE:
+    case SERVICE_WORKER_ERROR_REDUNDANT:
     case SERVICE_WORKER_ERROR_MAX_VALUE:
       NOTREACHED() << "Got unexpected error code: " << service_worker_status
                    << " " << ServiceWorkerStatusToString(service_worker_status);
@@ -745,6 +746,7 @@
     case SERVICE_WORKER_ERROR_TIMEOUT:
     case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
     case SERVICE_WORKER_ERROR_DISK_CACHE:
+    case SERVICE_WORKER_ERROR_REDUNDANT:
     case SERVICE_WORKER_ERROR_MAX_VALUE:
       NOTREACHED() << "Got unexpected error code: " << service_worker_status
                    << " " << ServiceWorkerStatusToString(service_worker_status);
diff --git a/content/browser/push_messaging/push_messaging_router.cc b/content/browser/push_messaging/push_messaging_router.cc
index f5d75f2..94510a08 100644
--- a/content/browser/push_messaging/push_messaging_router.cc
+++ b/content/browser/push_messaging/push_messaging_router.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/push_messaging/push_messaging_router.h"
 
+#include <string>
+
 #include "base/bind.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_registration.h"
@@ -137,6 +139,7 @@
     case SERVICE_WORKER_ERROR_TIMEOUT:
     case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
     case SERVICE_WORKER_ERROR_DISK_CACHE:
+    case SERVICE_WORKER_ERROR_REDUNDANT:
       delivery_status = PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR;
       break;
     case SERVICE_WORKER_ERROR_EXISTS:
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 4a12052..87d48eb 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -74,15 +74,15 @@
  public:
   OutputSurfaceWithoutParent(
       const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
-      base::WeakPtr<CompositorImpl> compositor_impl)
+      const base::Callback<void(gpu::Capabilities)>&
+          populate_gpu_capabilities_callback)
       : cc::OutputSurface(context_provider),
+        populate_gpu_capabilities_callback_(populate_gpu_capabilities_callback),
         swap_buffers_completion_callback_(
             base::Bind(&OutputSurfaceWithoutParent::OnSwapBuffersCompleted,
                        base::Unretained(this))) {
     capabilities_.adjust_deadline_for_parent = false;
     capabilities_.max_frames_pending = 2;
-    compositor_impl_ = compositor_impl;
-    main_thread_ = base::ThreadTaskRunnerHandle::Get();
   }
 
   void SwapBuffers(cc::CompositorFrame* frame) override {
@@ -100,11 +100,8 @@
     GetCommandBufferProxy()->SetSwapBuffersCompletionCallback(
         swap_buffers_completion_callback_.callback());
 
-    main_thread_->PostTask(
-        FROM_HERE,
-        base::Bind(&CompositorImpl::PopulateGpuCapabilities,
-                   compositor_impl_,
-                   context_provider_->ContextCapabilities().gpu));
+    populate_gpu_capabilities_callback_.Run(
+        context_provider_->ContextCapabilities().gpu);
 
     return true;
   }
@@ -126,12 +123,10 @@
     OutputSurface::OnSwapBuffersComplete();
   }
 
+  base::Callback<void(gpu::Capabilities)> populate_gpu_capabilities_callback_;
   base::CancelableCallback<void(const std::vector<ui::LatencyInfo>&,
                                 gfx::SwapResult)>
       swap_buffers_completion_callback_;
-
-  scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
-  base::WeakPtr<CompositorImpl> compositor_impl_;
 };
 
 static bool g_initialized = false;
@@ -648,8 +643,9 @@
   DCHECK(context_provider.get());
 
   scoped_ptr<cc::OutputSurface> real_output_surface(
-      new OutputSurfaceWithoutParent(context_provider,
-                                     weak_factory_.GetWeakPtr()));
+      new OutputSurfaceWithoutParent(
+          context_provider, base::Bind(&CompositorImpl::PopulateGpuCapabilities,
+                                       base::Unretained(this))));
 
   cc::SurfaceManager* manager = GetSurfaceManager();
   if (manager) {
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc b/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
index ba187b0..8bcda99 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
@@ -7,6 +7,7 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
 #include "content/browser/renderer_host/ui_events_helper.h"
+#include "third_party/WebKit/public/platform/WebScreenInfo.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/events/event_processor.h"
@@ -21,12 +22,21 @@
 SyntheticGestureTargetAura::SyntheticGestureTargetAura(
     RenderWidgetHostImpl* host)
     : SyntheticGestureTargetBase(host) {
+  blink::WebScreenInfo screenInfo;
+  host->GetWebScreenInfo(&screenInfo);
+  device_scale_factor_ = screenInfo.deviceScaleFactor;
 }
 
 void SyntheticGestureTargetAura::DispatchWebTouchEventToPlatform(
     const WebTouchEvent& web_touch,
     const ui::LatencyInfo& latency_info) {
   TouchEventWithLatencyInfo touch_with_latency(web_touch, latency_info);
+  for (size_t i = 0; i < touch_with_latency.event.touchesLength; i++) {
+    touch_with_latency.event.touches[i].position.x *= device_scale_factor_;
+    touch_with_latency.event.touches[i].position.y *= device_scale_factor_;
+    touch_with_latency.event.touches[i].radiusX *= device_scale_factor_;
+    touch_with_latency.event.touches[i].radiusY *= device_scale_factor_;
+  }
   ScopedVector<ui::TouchEvent> events;
   bool conversion_success = MakeUITouchEventsFromWebTouchEvents(
       touch_with_latency, &events, LOCAL_COORDINATES);
@@ -47,7 +57,8 @@
 void SyntheticGestureTargetAura::DispatchWebMouseWheelEventToPlatform(
       const blink::WebMouseWheelEvent& web_wheel,
       const ui::LatencyInfo&) {
-  gfx::Point location(web_wheel.x, web_wheel.y);
+  gfx::PointF location(web_wheel.x * device_scale_factor_,
+                       web_wheel.y * device_scale_factor_);
   ui::MouseEvent mouse_event(ui::ET_MOUSEWHEEL, location, location,
                              ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
   ui::MouseWheelEvent wheel_event(
@@ -115,7 +126,8 @@
 void SyntheticGestureTargetAura::DispatchWebMouseEventToPlatform(
       const blink::WebMouseEvent& web_mouse,
       const ui::LatencyInfo& latency_info) {
-  gfx::Point location(web_mouse.x, web_mouse.y);
+  gfx::PointF location(web_mouse.x * device_scale_factor_,
+                       web_mouse.y * device_scale_factor_);
   ui::EventType event_type = WebMouseEventTypeToEventType(web_mouse.type);
   int flags = WebMouseEventButtonToFlags(web_mouse.button);
   ui::MouseEvent mouse_event(event_type, location, location,
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_aura.h b/content/browser/renderer_host/input/synthetic_gesture_target_aura.h
index 53f0672..42303f2 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_aura.h
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_aura.h
@@ -47,6 +47,13 @@
  private:
   aura::Window* GetWindow() const;
 
+  // Synthetic located event's location and touch event's radius are in DIP and
+  // aura event dispatcher assumes input event is in device pixel and will apply
+  // device scale factor to convert the input to DIP. So we need to use
+  // device_scale_factor to convert the input event from DIP to device pixel
+  // before dispatching it into platform.
+  float device_scale_factor_;
+
   DISALLOW_COPY_AND_ASSIGN(SyntheticGestureTargetAura);
 };
 
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc
index 15dd9e6..2692f74 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc
@@ -469,7 +469,7 @@
   LogMessage(stream_id, err_msg, true);
 
   Send(new AudioInputMsg_NotifyStreamStateChanged(
-      stream_id, media::AudioInputIPCDelegate::kError));
+      stream_id, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR));
 }
 
 void AudioInputRendererHost::DeleteEntries() {
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc
index 5f140ac..dddeee2 100644
--- a/content/browser/renderer_host/media/audio_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -10,7 +10,9 @@
 #include "base/memory/shared_memory.h"
 #include "base/metrics/histogram.h"
 #include "base/process/process.h"
+#include "content/browser/bad_message.h"
 #include "content/browser/browser_main_loop.h"
+#include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/media/audio_stream_monitor.h"
 #include "content/browser/media/capture/audio_mirroring_manager.h"
@@ -18,13 +20,16 @@
 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
 #include "content/browser/renderer_host/media/audio_sync_reader.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/common/media/audio_messages.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/media_device_id.h"
 #include "content/public/browser/media_observer.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/common/content_switches.h"
+#include "media/audio/audio_device_name.h"
 #include "media/audio/audio_manager_base.h"
 #include "media/base/audio_bus.h"
 #include "media/base/limits.h"
@@ -146,7 +151,8 @@
     media::AudioManager* audio_manager,
     AudioMirroringManager* mirroring_manager,
     MediaInternals* media_internals,
-    MediaStreamManager* media_stream_manager)
+    MediaStreamManager* media_stream_manager,
+    const ResourceContext::SaltCallback& salt_callback)
     : BrowserMessageFilter(AudioMsgStart),
       render_process_id_(render_process_id),
       audio_manager_(audio_manager),
@@ -154,7 +160,8 @@
       audio_log_(media_internals->CreateAudioLog(
           media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
       media_stream_manager_(media_stream_manager),
-      num_playing_streams_(0) {
+      num_playing_streams_(0),
+      salt_callback_(salt_callback) {
   DCHECK(audio_manager_);
   DCHECK(media_stream_manager_);
 }
@@ -269,8 +276,8 @@
 
   Send(new AudioMsg_NotifyStreamStateChanged(
       stream_id,
-      is_playing ? media::AudioOutputIPCDelegate::kPlaying
-                 : media::AudioOutputIPCDelegate::kPaused));
+      is_playing ? media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING
+                 : media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED));
 
   if (is_playing) {
     AudioStreamMonitor::StartMonitoringStream(
@@ -310,6 +317,7 @@
     IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
     IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
     IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
+    IPC_MESSAGE_HANDLER(AudioHostMsg_SwitchOutputDevice, OnSwitchOutputDevice)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -422,9 +430,158 @@
   audio_log_->OnSetVolume(stream_id, volume);
 }
 
+void AudioRendererHost::OnSwitchOutputDevice(int stream_id,
+                                             int render_frame_id,
+                                             const std::string& device_id,
+                                             const GURL& security_origin,
+                                             int request_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DVLOG(1) << "AudioRendererHost@" << this
+           << "::OnSwitchOutputDevice(stream_id=" << stream_id
+           << ", render_frame_id=" << render_frame_id
+           << ", device_id=" << device_id
+           << ", security_origin=" << security_origin
+           << ", request_id=" << request_id << ")";
+  if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
+          render_process_id_, security_origin)) {
+    content::bad_message::ReceivedBadMessage(this,
+                                             bad_message::ARH_UNAUTHORIZED_URL);
+    return;
+  }
+
+  if (device_id.empty()) {
+    DVLOG(1) << __FUNCTION__ << ": default output device requested. "
+             << "No permissions check or device translation/validation needed.";
+    DoSwitchOutputDevice(stream_id, device_id, request_id);
+  } else {
+    // Check that MediaStream device permissions have been granted,
+    // hence the use of a MediaStreamUIProxy.
+    scoped_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
+
+    // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
+    // because MediaStreamUIProxy::CheckAccess does not currently support
+    // MEDIA_DEVICE_AUDIO_OUTPUT.
+    // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes
+    // available. http://crbug.com/498675
+    ui_proxy->CheckAccess(
+        security_origin, MEDIA_DEVICE_AUDIO_CAPTURE,
+        render_process_id_, render_frame_id,
+        base::Bind(&AudioRendererHost::OutputDeviceAccessChecked, this,
+                   base::Passed(&ui_proxy), stream_id, device_id,
+                   security_origin, render_frame_id, request_id));
+  }
+}
+
+void AudioRendererHost::OutputDeviceAccessChecked(
+    scoped_ptr<MediaStreamUIProxy> ui_proxy,
+    int stream_id,
+    const std::string& device_id,
+    const GURL& security_origin,
+    int render_frame_id,
+    int request_id,
+    bool have_access) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DVLOG(1) << __FUNCTION__;
+  if (!have_access) {
+    DVLOG(0) << __FUNCTION__
+             << ": Have no access to media devices. Not switching device.";
+    Send(new AudioMsg_NotifyOutputDeviceSwitched(
+        stream_id, request_id,
+        media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED));
+    return;
+  }
+
+  scoped_refptr<base::SingleThreadTaskRunner> audio_worker_runner =
+      AudioManager::Get()->GetWorkerTaskRunner();
+  audio_worker_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&AudioRendererHost::StartTranslateOutputDeviceName, this,
+                 stream_id, device_id, security_origin, request_id));
+}
+
+void AudioRendererHost::StartTranslateOutputDeviceName(
+    int stream_id,
+    const std::string& device_id,
+    const GURL& security_origin,
+    int request_id) {
+  DCHECK(AudioManager::Get()->GetWorkerTaskRunner()->BelongsToCurrentThread());
+  DCHECK(!device_id.empty());
+  DVLOG(1) << __FUNCTION__;
+
+  media::AudioDeviceNames* device_names(new media::AudioDeviceNames);
+  AudioManager::Get()->GetAudioOutputDeviceNames(device_names);
+
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&AudioRendererHost::FinishTranslateOutputDeviceName, this,
+                 stream_id, device_id, security_origin, request_id,
+                 base::Owned(device_names)));
+}
+
+void AudioRendererHost::FinishTranslateOutputDeviceName(
+    int stream_id,
+    const std::string& device_id,
+    const GURL& security_origin,
+    int request_id,
+    media::AudioDeviceNames* device_names) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(!device_id.empty());
+  DVLOG(1) << __FUNCTION__;
+
+  std::string raw_device_id;
+  // Process the enumeration here because |salt_callback_| can run
+  // only on the IO thread
+  for (const auto& device_name : *device_names) {
+    const std::string candidate_device_id = content::GetHMACForMediaDeviceID(
+        salt_callback_, security_origin, device_name.unique_id);
+    if (candidate_device_id == device_id) {
+      DVLOG(1) << "Requested device " << device_name.unique_id << " - "
+               << device_name.device_name;
+      raw_device_id = device_name.unique_id;
+    }
+  }
+
+  if (raw_device_id.empty()) {
+    DVLOG(1) << "Requested device " << device_id << " could not be found.";
+    Send(new AudioMsg_NotifyOutputDeviceSwitched(
+        stream_id, request_id,
+        media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_FOUND));
+    return;
+  }
+
+  DoSwitchOutputDevice(stream_id, raw_device_id, request_id);
+}
+
+void AudioRendererHost::DoSwitchOutputDevice(int stream_id,
+                                             const std::string& raw_device_id,
+                                             int request_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << raw_device_id << ", "
+           << request_id << ")";
+  AudioEntry* entry = LookupById(stream_id);
+  if (!entry) {
+    Send(new AudioMsg_NotifyOutputDeviceSwitched(
+        stream_id, request_id,
+        media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE));
+    return;
+  }
+
+  entry->controller()->SwitchOutputDevice(
+      raw_device_id, base::Bind(&AudioRendererHost::DoOutputDeviceSwitched,
+                                this, stream_id, request_id));
+  audio_log_->OnSwitchOutputDevice(entry->stream_id(), raw_device_id);
+}
+
+void AudioRendererHost::DoOutputDeviceSwitched(int stream_id, int request_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << request_id << ")";
+  Send(new AudioMsg_NotifyOutputDeviceSwitched(
+      stream_id, request_id, media::SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS));
+}
+
 void AudioRendererHost::SendErrorMessage(int stream_id) {
   Send(new AudioMsg_NotifyStreamStateChanged(
-      stream_id, media::AudioOutputIPCDelegate::kError));
+      stream_id, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR));
 }
 
 void AudioRendererHost::OnCloseStream(int stream_id) {
@@ -439,8 +596,6 @@
   audio_entries_.erase(i);
 
   media::AudioOutputController* const controller = entry->controller();
-  if (mirroring_manager_)
-    mirroring_manager_->RemoveDiverter(controller);
   controller->Close(
       base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry)));
   audio_log_->OnClosed(stream_id);
@@ -448,6 +603,15 @@
 
 void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  // De-register the controller from the AudioMirroringManager now that the
+  // controller has closed the AudioOutputStream and shut itself down.  This
+  // ensures that calling RemoveDiverter() here won't trigger the controller to
+  // re-start the default AudioOutputStream and cause a brief audio blip to come
+  // out the user's speakers.  http://crbug.com/474432
+  if (mirroring_manager_)
+    mirroring_manager_->RemoveDiverter(entry->controller());
+
   AudioStreamMonitor::StopMonitoringStream(
       render_process_id_, entry->render_frame_id(), entry->stream_id());
   UpdateNumPlayingStreams(entry.get(), false);
diff --git a/content/browser/renderer_host/media/audio_renderer_host.h b/content/browser/renderer_host/media/audio_renderer_host.h
index 69d3ea1..ed89e93d 100644
--- a/content/browser/renderer_host/media/audio_renderer_host.h
+++ b/content/browser/renderer_host/media/audio_renderer_host.h
@@ -38,6 +38,7 @@
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_AUDIO_RENDERER_HOST_H_
 
 #include <map>
+#include <string>
 
 #include "base/atomic_ref_count.h"
 #include "base/gtest_prod_util.h"
@@ -49,10 +50,12 @@
 #include "content/public/browser/browser_message_filter.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/resource_context.h"
 #include "media/audio/audio_io.h"
 #include "media/audio/audio_logging.h"
 #include "media/audio/audio_output_controller.h"
 #include "media/audio/simple_sources.h"
+#include "url/gurl.h"
 
 namespace media {
 class AudioManager;
@@ -64,6 +67,7 @@
 class AudioMirroringManager;
 class MediaInternals;
 class MediaStreamManager;
+class MediaStreamUIProxy;
 class ResourceContext;
 
 class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
@@ -73,7 +77,8 @@
                     media::AudioManager* audio_manager,
                     AudioMirroringManager* mirroring_manager,
                     MediaInternals* media_internals,
-                    MediaStreamManager* media_stream_manager);
+                    MediaStreamManager* media_stream_manager,
+                    const ResourceContext::SaltCallback& salt_callback);
 
   // Calls |callback| with the list of AudioOutputControllers for this object.
   void GetOutputControllers(
@@ -135,6 +140,38 @@
   // Set the volume of the audio stream referenced by |stream_id|.
   void OnSetVolume(int stream_id, double volume);
 
+  // Set the output device of the audio stream referenced by |stream_id|.
+  void OnSwitchOutputDevice(int stream_id,
+                            int render_frame_id,
+                            const std::string& device_id,
+                            const GURL& security_origin,
+                            int request_id);
+
+  void OutputDeviceAccessChecked(scoped_ptr<MediaStreamUIProxy> ui_proxy,
+                                 int stream_id,
+                                 const std::string& device_id,
+                                 const GURL& security_origin,
+                                 int render_frame_id,
+                                 int request_id,
+                                 bool have_access);
+
+  void StartTranslateOutputDeviceName(int stream_id,
+                                      const std::string& device_id,
+                                      const GURL& security_origin,
+                                      int request_id);
+
+  void FinishTranslateOutputDeviceName(int stream_id,
+                                       const std::string& device_id,
+                                       const GURL& security_origin,
+                                       int request_id,
+                                       media::AudioDeviceNames*);
+
+  void DoSwitchOutputDevice(int stream_id,
+                            const std::string& raw_device_id,
+                            int request_id);
+
+  void DoOutputDeviceSwitched(int stream_id, int request_id);
+
   // Complete the process of creating an audio stream. This will set up the
   // shared memory or shared socket in low latency mode and send the
   // NotifyStreamCreated message to the peer.
@@ -163,6 +200,9 @@
   // ResourceScheduler when the renderer starts or stops playing an audiostream.
   void UpdateNumPlayingStreams(AudioEntry* entry, bool is_playing);
 
+  // Checks that the renderer process supplies a URL it is allowed to use
+  bool IsURLAllowed(const GURL& url);
+
   // ID of the RenderProcessHost that owns this instance.
   const int render_process_id_;
 
@@ -179,6 +219,9 @@
   // The number of streams in the playing state.
   base::AtomicRefCount num_playing_streams_;
 
+  // Salt required to translate renderer device IDs to raw device IDs
+  ResourceContext::SaltCallback salt_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(AudioRendererHost);
 };
 
diff --git a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
index c50430e..3986720 100644
--- a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
+++ b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
@@ -31,6 +31,11 @@
 const int kRenderProcessId = 1;
 const int kRenderFrameId = 5;
 const int kStreamId = 50;
+const int kBadStreamId = 99;
+const int kSwitchOutputDeviceRequestId = 1;
+const GURL kSecurityOrigin("http://localhost");
+const std::string kDefaultDeviceID = "";
+const std::string kBadDeviceID = "bad-device-id";
 }  // namespace
 
 namespace content {
@@ -55,12 +60,14 @@
   MockAudioRendererHost(media::AudioManager* audio_manager,
                         AudioMirroringManager* mirroring_manager,
                         MediaInternals* media_internals,
-                        MediaStreamManager* media_stream_manager)
+                        MediaStreamManager* media_stream_manager,
+                        const ResourceContext::SaltCallback& salt_callback)
       : AudioRendererHost(kRenderProcessId,
                           audio_manager,
                           mirroring_manager,
                           media_internals,
-                          media_stream_manager),
+                          media_stream_manager,
+                          salt_callback),
         shared_memory_length_(0) {}
 
   // A list of mock methods.
@@ -68,6 +75,10 @@
   MOCK_METHOD1(OnStreamPlaying, void(int stream_id));
   MOCK_METHOD1(OnStreamPaused, void(int stream_id));
   MOCK_METHOD1(OnStreamError, void(int stream_id));
+  MOCK_METHOD3(OnOutputDeviceSwitched,
+               void(int stream_id,
+                    int request_id,
+                    media::SwitchOutputDeviceResult result));
 
  private:
   virtual ~MockAudioRendererHost() {
@@ -89,6 +100,8 @@
                           OnNotifyStreamCreated)
       IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged,
                           OnNotifyStreamStateChanged)
+      IPC_MESSAGE_HANDLER(AudioMsg_NotifyOutputDeviceSwitched,
+                          OnNotifyOutputDeviceSwitched)
       IPC_MESSAGE_UNHANDLED(handled = false)
     IPC_END_MESSAGE_MAP()
     EXPECT_TRUE(handled);
@@ -116,15 +129,15 @@
   }
 
   void OnNotifyStreamStateChanged(int stream_id,
-                                  media::AudioOutputIPCDelegate::State state) {
+                                  media::AudioOutputIPCDelegateState state) {
     switch (state) {
-      case media::AudioOutputIPCDelegate::kPlaying:
+      case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING:
         OnStreamPlaying(stream_id);
         break;
-      case media::AudioOutputIPCDelegate::kPaused:
+      case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED:
         OnStreamPaused(stream_id);
         break;
-      case media::AudioOutputIPCDelegate::kError:
+      case media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR:
         OnStreamError(stream_id);
         break;
       default:
@@ -133,6 +146,23 @@
     }
   }
 
+  void OnNotifyOutputDeviceSwitched(int stream_id,
+                                    int request_id,
+                                    media::SwitchOutputDeviceResult result) {
+    switch (result) {
+      case media::SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS:
+      case media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_FOUND:
+      case media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED:
+      case media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE:
+      case media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_SUPPORTED:
+        OnOutputDeviceSwitched(stream_id, request_id, result);
+        break;
+      default:
+        FAIL() << "Unknown SwitchOutputDevice result";
+        break;
+    }
+  }
+
   scoped_ptr<base::SharedMemory> shared_memory_;
   scoped_ptr<base::SyncSocket> sync_socket_;
   uint32 shared_memory_length_;
@@ -140,6 +170,16 @@
   DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost);
 };
 
+namespace {
+std::string ReturnMockSalt() {
+  return std::string();
+}
+
+ResourceContext::SaltCallback GetMockSaltCallback() {
+  return base::Bind(&ReturnMockSalt);
+}
+}
+
 class AudioRendererHostTest : public testing::Test {
  public:
   AudioRendererHostTest() {
@@ -147,10 +187,10 @@
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kUseFakeDeviceForMediaStream);
     media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
-    host_ = new MockAudioRendererHost(audio_manager_.get(),
-                                      &mirroring_manager_,
+    host_ = new MockAudioRendererHost(audio_manager_.get(), &mirroring_manager_,
                                       MediaInternals::GetInstance(),
-                                      media_stream_manager_.get());
+                                      media_stream_manager_.get(),
+                                      GetMockSaltCallback());
 
     // Simulate IPC channel connected.
     host_->set_peer_process_for_testing(base::Process::Current());
@@ -230,6 +270,17 @@
     SyncWithAudioThread();
   }
 
+  void SwitchOutputDevice(int stream_id,
+                          std::string device_id,
+                          media::SwitchOutputDeviceResult expected_result) {
+    EXPECT_CALL(*host_.get(),
+                OnOutputDeviceSwitched(stream_id, kSwitchOutputDeviceRequestId,
+                                       expected_result));
+    host_->OnSwitchOutputDevice(stream_id, kRenderFrameId, device_id,
+                                kSecurityOrigin, kSwitchOutputDeviceRequestId);
+    SyncWithAudioThread();
+  }
+
   void SimulateError() {
     EXPECT_EQ(1u, host_->audio_entries_.size())
         << "Calls Create() before calling this method";
@@ -301,6 +352,27 @@
   Close();
 }
 
+TEST_F(AudioRendererHostTest, SwitchOutputDevice) {
+  Create(false);
+  SwitchOutputDevice(kStreamId, kDefaultDeviceID,
+                     media::SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS);
+  Close();
+}
+
+TEST_F(AudioRendererHostTest, SwitchOutputDeviceNotAuthorized) {
+  Create(false);
+  SwitchOutputDevice(kStreamId, kBadDeviceID,
+                     media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED);
+  Close();
+}
+
+TEST_F(AudioRendererHostTest, SwitchOutputDeviceNoStream) {
+  Create(false);
+  SwitchOutputDevice(kBadStreamId, kDefaultDeviceID,
+                     media::SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE);
+  Close();
+}
+
 // Simulate the case where a stream is not properly closed.
 TEST_F(AudioRendererHostTest, CreatePlayAndShutdown) {
   Create(false);
diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
index 4dbec58..bbdc0965 100644
--- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -155,8 +155,8 @@
       const media::VideoFrame::ReleaseMailboxCB& release_cb,
       gfx::Size dimensions) {
     return media::VideoFrame::WrapNativeTexture(
-        holder, release_cb, dimensions, gfx::Rect(dimensions), dimensions,
-        base::TimeDelta(), false /* allow_overlay */, true /* has_alpha */);
+        media::VideoFrame::ARGB, holder, release_cb, dimensions,
+        gfx::Rect(dimensions), dimensions, base::TimeDelta());
   }
 
   TestBrowserThreadBundle bundle_;
diff --git a/content/browser/renderer_host/media/video_capture_device_client.cc b/content/browser/renderer_host/media/video_capture_device_client.cc
index b739aca..465c0c7 100644
--- a/content/browser/renderer_host/media/video_capture_device_client.cc
+++ b/content/browser/renderer_host/media/video_capture_device_client.cc
@@ -28,6 +28,7 @@
 
 using media::VideoCaptureFormat;
 using media::VideoFrame;
+using media::VideoFrameMetadata;
 
 namespace content {
 
@@ -559,14 +560,15 @@
 
   scoped_refptr<media::VideoFrame> video_frame =
       media::VideoFrame::WrapNativeTexture(
+          media::VideoFrame::ARGB,
           mailbox_holder,
           media::BindToCurrentLoop(base::Bind(
               &VideoCaptureDeviceClient::TextureWrapHelper::ReleaseCallback,
               this, image_id, texture_id)),
           frame_format.frame_size, gfx::Rect(frame_format.frame_size),
-          frame_format.frame_size, base::TimeDelta(), true /* allow_overlay */,
-          true /* has_alpha */);
-  video_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
+          frame_format.frame_size, base::TimeDelta());
+  video_frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
+  video_frame->metadata()->SetDouble(VideoFrameMetadata::FRAME_RATE,
                                      frame_format.frame_rate);
 
   BrowserThread::PostTask(
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 8e96da0..c581a7a 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
 #include "base/threading/worker_pool.h"
+#include "content/browser/bad_message.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
@@ -444,6 +445,12 @@
   BrowserThread::DeleteOnIOThread::Destruct(this);
 }
 
+void RenderMessageFilter::OverrideThreadForMessage(const IPC::Message& message,
+                                                   BrowserThread::ID* thread) {
+  if (message.type() == ViewHostMsg_MediaLogEvents::ID)
+    *thread = BrowserThread::UI;
+}
+
 base::TaskRunner* RenderMessageFilter::OverrideTaskRunnerForMessage(
     const IPC::Message& message) {
 #if defined(OS_WIN)
@@ -495,6 +502,7 @@
           resource_context_,
           render_process_id_,
           params.opener_id,
+          params.opener_render_frame_id,
           &no_javascript_access);
 
   if (!can_create_window) {
@@ -558,8 +566,11 @@
                                       const std::string& cookie) {
   ChildProcessSecurityPolicyImpl* policy =
       ChildProcessSecurityPolicyImpl::GetInstance();
-  if (!policy->CanAccessCookiesForOrigin(render_process_id_, url))
+  if (!policy->CanAccessCookiesForOrigin(render_process_id_, url)) {
+    bad_message::ReceivedBadMessage(this,
+                                    bad_message::RMF_SET_COOKIE_BAD_ORIGIN);
     return;
+  }
 
   net::CookieOptions options;
   if (GetContentClient()->browser()->AllowSetCookie(
@@ -579,7 +590,9 @@
   ChildProcessSecurityPolicyImpl* policy =
       ChildProcessSecurityPolicyImpl::GetInstance();
   if (!policy->CanAccessCookiesForOrigin(render_process_id_, url)) {
-    SendGetCookiesResponse(reply_msg, std::string());
+    bad_message::ReceivedBadMessage(this,
+                                    bad_message::RMF_GET_COOKIES_BAD_ORIGIN);
+    delete reply_msg;
     return;
   }
 
@@ -1048,6 +1061,9 @@
 
 void RenderMessageFilter::OnMediaLogEvents(
     const std::vector<media::MediaLogEvent>& events) {
+  // OnMediaLogEvents() is always dispatched to the UI thread for handling.
+  // See OverrideThreadForMessage().
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (media_internals_)
     media_internals_->OnMediaEvents(render_process_id_, events);
 }
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 5af31aea..0976637a 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -107,6 +107,8 @@
   // BrowserMessageFilter methods:
   bool OnMessageReceived(const IPC::Message& message) override;
   void OnDestruct() const override;
+  void OverrideThreadForMessage(const IPC::Message& message,
+                                BrowserThread::ID* thread) override;
   base::TaskRunner* OverrideTaskRunnerForMessage(
       const IPC::Message& message) override;
 
diff --git a/content/browser/renderer_host/render_message_filter_browsertest.cc b/content/browser/renderer_host/render_message_filter_browsertest.cc
new file mode 100644
index 0000000..f6ae7ae
--- /dev/null
+++ b/content/browser/renderer_host/render_message_filter_browsertest.cc
@@ -0,0 +1,178 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "content/browser/frame_host/frame_tree.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/frame_messages.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
+#include "ipc/ipc_security_test_util.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+std::string GetCookieFromJS(RenderFrameHost* frame) {
+  std::string cookie;
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      frame, "window.domAutomationController.send(document.cookie);", &cookie));
+  return cookie;
+}
+
+}  // namespace
+
+using RenderMessageFilterBrowserTest = ContentBrowserTest;
+
+// Exercises basic cookie operations via javascript, including an http page
+// interacting with secure cookies.
+IN_PROC_BROWSER_TEST_F(RenderMessageFilterBrowserTest, Cookies) {
+  host_resolver()->AddRule("*", "127.0.0.1");
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  SetupCrossSiteRedirector(embedded_test_server());
+
+  net::SpawnedTestServer https_server(
+      net::SpawnedTestServer::TYPE_HTTPS, net::SpawnedTestServer::kLocalhost,
+      base::FilePath(FILE_PATH_LITERAL("content/test/data")));
+  ASSERT_TRUE(https_server.Start());
+
+  // The server sends a HttpOnly cookie. The RenderMessageFilter should never
+  // allow this to be sent to any renderer process.
+  GURL https_url = https_server.GetURL("set-cookie?notforjs=1;HttpOnly");
+  GURL http_url = embedded_test_server()->GetURL("/frame_with_load_event.html");
+
+  Shell* shell2 = CreateBrowser();
+  NavigateToURL(shell(), http_url);
+  NavigateToURL(shell2, https_url);
+
+  WebContentsImpl* web_contents_https =
+      static_cast<WebContentsImpl*>(shell2->web_contents());
+  WebContentsImpl* web_contents_http =
+      static_cast<WebContentsImpl*>(shell()->web_contents());
+  EXPECT_EQ("http://127.0.0.1/",
+            web_contents_http->GetSiteInstance()->GetSiteURL().spec());
+  EXPECT_EQ("https://127.0.0.1/",
+            web_contents_https->GetSiteInstance()->GetSiteURL().spec());
+
+  EXPECT_NE(web_contents_http->GetSiteInstance()->GetProcess(),
+            web_contents_https->GetSiteInstance()->GetProcess());
+
+  EXPECT_EQ("", GetCookieFromJS(web_contents_https->GetMainFrame()));
+  EXPECT_EQ("", GetCookieFromJS(web_contents_http->GetMainFrame()));
+
+  // Non-TLS page writes secure cookie.
+  EXPECT_TRUE(ExecuteScript(web_contents_http->GetMainFrame(),
+                            "document.cookie = 'A=1; secure;';"));
+  EXPECT_EQ("A=1", GetCookieFromJS(web_contents_https->GetMainFrame()));
+  EXPECT_EQ("", GetCookieFromJS(web_contents_http->GetMainFrame()));
+
+  // TLS page writes not-secure cookie.
+  EXPECT_TRUE(ExecuteScript(web_contents_http->GetMainFrame(),
+                            "document.cookie = 'B=2';"));
+  EXPECT_EQ("A=1; B=2", GetCookieFromJS(web_contents_https->GetMainFrame()));
+  EXPECT_EQ("B=2", GetCookieFromJS(web_contents_http->GetMainFrame()));
+
+  // Non-TLS page writes secure cookie.
+  EXPECT_TRUE(ExecuteScript(web_contents_https->GetMainFrame(),
+                            "document.cookie = 'C=3;secure;';"));
+  EXPECT_EQ("A=1; B=2; C=3",
+            GetCookieFromJS(web_contents_https->GetMainFrame()));
+  EXPECT_EQ("B=2", GetCookieFromJS(web_contents_http->GetMainFrame()));
+
+  // TLS page writes not-secure cookie.
+  EXPECT_TRUE(ExecuteScript(web_contents_https->GetMainFrame(),
+                            "document.cookie = 'D=4';"));
+  EXPECT_EQ("A=1; B=2; C=3; D=4",
+            GetCookieFromJS(web_contents_https->GetMainFrame()));
+  EXPECT_EQ("B=2; D=4", GetCookieFromJS(web_contents_http->GetMainFrame()));
+}
+
+// The RenderMessageFilter will kill processes when they access the cookies of
+// sites other than the site the process is dedicated to, under site isolation.
+IN_PROC_BROWSER_TEST_F(RenderMessageFilterBrowserTest,
+                       CrossSiteCookieSecurityEnforcement) {
+  // The code under test is only active under site isolation.
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
+
+  host_resolver()->AddRule("*", "127.0.0.1");
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  SetupCrossSiteRedirector(embedded_test_server());
+  NavigateToURL(shell(),
+                embedded_test_server()->GetURL("/frame_with_load_event.html"));
+
+  WebContentsImpl* tab = static_cast<WebContentsImpl*>(shell()->web_contents());
+
+  // The iframe on the http page should get its own process.
+  FrameTreeVisualizer v;
+  EXPECT_EQ(
+      " Site A ------------ proxies for B\n"
+      "   +--Site B ------- proxies for A\n"
+      "Where A = http://127.0.0.1/\n"
+      "      B = http://baz.com/",
+      v.DepictFrameTree(tab->GetFrameTree()->root()));
+
+  RenderFrameHost* main_frame = tab->GetMainFrame();
+  RenderFrameHost* iframe =
+      tab->GetFrameTree()->root()->child_at(0)->current_frame_host();
+
+  EXPECT_NE(iframe->GetProcess(), main_frame->GetProcess());
+
+  // Try to get cross-site cookies from the subframe's process and wait for it
+  // to be killed.
+  std::string response;
+  FrameHostMsg_GetCookies illegal_get_cookies(
+      iframe->GetRoutingID(), GURL("http://127.0.0.1/"),
+      GURL("http://127.0.0.1/"), &response);
+
+  RenderProcessHostWatcher iframe_killed(
+      iframe->GetProcess(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+
+  IPC::IpcSecurityTestUtil::PwnMessageReceived(
+      iframe->GetProcess()->GetChannel(), illegal_get_cookies);
+
+  iframe_killed.Wait();
+
+  EXPECT_EQ(
+      " Site A ------------ proxies for B\n"
+      "   +--Site B ------- proxies for A\n"
+      "Where A = http://127.0.0.1/\n"
+      "      B = http://baz.com/ (no process)",
+      v.DepictFrameTree(tab->GetFrameTree()->root()));
+
+  // Now set a cross-site cookie from the main frame's process and wait for it
+  // to be killed.
+  RenderProcessHostWatcher main_frame_killed(
+      tab->GetMainFrame()->GetProcess(),
+      RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+  FrameHostMsg_SetCookie illegal_set_cookie(tab->GetMainFrame()->GetRoutingID(),
+                                            GURL("https://baz.com/"),
+                                            GURL("https://baz.com/"), "pwn=ed");
+  IPC::IpcSecurityTestUtil::PwnMessageReceived(
+      tab->GetMainFrame()->GetProcess()->GetChannel(), illegal_set_cookie);
+
+  main_frame_killed.Wait();
+
+  EXPECT_EQ(
+      " Site A\n"
+      "Where A = http://127.0.0.1/ (no process)",
+      v.DepictFrameTree(tab->GetFrameTree()->root()));
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index d4da1d4..db5ea5d 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -795,7 +795,8 @@
       audio_manager,
       AudioMirroringManager::GetInstance(),
       media_internals,
-      media_stream_manager);
+      media_stream_manager,
+      browser_context->GetResourceContext()->GetMediaDeviceIDSalt());
   AddFilter(audio_renderer_host_.get());
   AddFilter(
       new MidiHost(GetID(), BrowserMainLoop::GetInstance()->midi_manager()));
@@ -1112,13 +1113,9 @@
   if (IsDelegatedRendererEnabled())
     command_line->AppendSwitch(switches::kEnableDelegatedRenderer);
 
-  if (IsImplSidePaintingEnabled()) {
-    command_line->AppendSwitchASCII(
-        switches::kNumRasterThreads,
-        base::IntToString(NumberOfRendererRasterThreads()));
-  } else {
-    command_line->AppendSwitch(switches::kDisableImplSidePainting);
-  }
+  command_line->AppendSwitchASCII(
+      switches::kNumRasterThreads,
+      base::IntToString(NumberOfRendererRasterThreads()));
 
   if (IsGpuRasterizationEnabled())
     command_line->AppendSwitch(switches::kEnableGpuRasterization);
@@ -1261,7 +1258,6 @@
     switches::kEnableBrowserSideNavigation,
     switches::kEnableCompositorAnimationTimelines,
     switches::kEnableCredentialManagerAPI,
-    switches::kEnableDeferredImageDecoding,
     switches::kEnableDelayAgnosticAec,
     switches::kEnableDisplayList2dCanvas,
     switches::kEnableDistanceFieldText,
@@ -1292,13 +1288,13 @@
     switches::kEnableSmoothScrolling,
     switches::kEnableStaleWhileRevalidate,
     switches::kEnableStatsTable,
-    switches::kEnableStrictSiteIsolation,
     switches::kEnableThreadedCompositing,
     switches::kEnableTouchDragDrop,
     switches::kEnableTouchEditing,
     switches::kEnableUnsafeES3APIs,
     switches::kEnableViewport,
     switches::kEnableViewportMeta,
+    switches::kInvertViewportScrollOrder,
     switches::kEnableVtune,
     switches::kEnableWebBluetooth,
     switches::kEnableWebGLDraftExtensions,
@@ -1414,11 +1410,6 @@
     renderer_cmd->AppendSwitch(switches::kDisableDatabases);
   }
 
-  // Enforce the extra command line flags for impl-side painting.
-  if (IsImplSidePaintingEnabled() &&
-      !browser_cmd.HasSwitch(switches::kEnableDeferredImageDecoding))
-    renderer_cmd->AppendSwitch(switches::kEnableDeferredImageDecoding);
-
   // Add kWaitForDebugger to let renderer process wait for a debugger.
   if (browser_cmd.HasSwitch(switches::kWaitForDebuggerChildren)) {
     // Look to pass-on the kWaitForDebugger flag.
@@ -1942,16 +1933,14 @@
 // static
 bool RenderProcessHost::ShouldTryToUseExistingProcessHost(
     BrowserContext* browser_context, const GURL& url) {
-  // Experimental:
-  // If --enable-strict-site-isolation or --site-per-process is enabled, do not
-  // try to reuse renderer processes when over the limit.  (We could allow pages
-  // from the same site to share, if we knew what the given process was
-  // dedicated to.  Allowing no sharing is simpler for now.)  This may cause
-  // resource exhaustion issues if too many sites are open at once.
+  // If --site-per-process is enabled, do not try to reuse renderer processes
+  // when over the limit.  (We could allow pages from the same site to share, if
+  // we knew what the given process was dedicated to.  Allowing no sharing is
+  // simpler for now.)  This may cause resource exhaustion issues if too many
+  // sites are open at once.
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kEnableStrictSiteIsolation) ||
-      command_line.HasSwitch(switches::kSitePerProcess))
+  if (command_line.HasSwitch(switches::kSitePerProcess))
     return false;
 
   if (run_renderer_in_process())
@@ -2262,7 +2251,7 @@
   // absence of field trials to get coverage on the perf waterfall.
   base::FieldTrial* trial =
       base::FieldTrialList::Find("BackgroundRendererProcesses");
-  if (!trial || !StartsWithASCII(trial->group_name(), "Disallow", true)) {
+  if (!trial || !base::StartsWithASCII(trial->group_name(), "Disallow", true)) {
     child_process_launcher_->SetProcessBackgrounded(backgrounded);
   }
 #else
diff --git a/content/browser/renderer_host/render_process_host_unittest.cc b/content/browser/renderer_host/render_process_host_unittest.cc
index e25c53c..83aa6b2 100644
--- a/content/browser/renderer_host/render_process_host_unittest.cc
+++ b/content/browser/renderer_host/render_process_host_unittest.cc
@@ -33,13 +33,11 @@
 
 #if !defined(OS_ANDROID)
 TEST_F(RenderProcessHostUnitTest, RendererProcessLimit) {
-  // This test shouldn't run with --site-per-process or
-  // --enable-strict-site-isolation modes, since they don't allow renderer
-  // process reuse, which this test explicitly exercises.
+  // This test shouldn't run with --site-per-process mode, which prohibits
+  // the renderer process reuse this test explicitly exercises.
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kSitePerProcess) ||
-      command_line.HasSwitch(switches::kEnableStrictSiteIsolation))
+  if (command_line.HasSwitch(switches::kSitePerProcess))
     return;
 
   // Disable any overrides.
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 3495a15..a64475823 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -431,13 +431,14 @@
   prefs.accelerated_2d_canvas_msaa_sample_count =
       atoi(command_line.GetSwitchValueASCII(
       switches::kAcceleratedCanvas2dMSAASampleCount).c_str());
-  // Text blobs rely on impl-side painting for proper LCD handling.
-  prefs.text_blobs_enabled = command_line.HasSwitch(switches::kForceTextBlobs)
-      || (content::IsImplSidePaintingEnabled() &&
-          !command_line.HasSwitch(switches::kDisableTextBlobs));
+  prefs.text_blobs_enabled =
+      command_line.HasSwitch(switches::kForceTextBlobs) ||
+      !command_line.HasSwitch(switches::kDisableTextBlobs);
 
   prefs.pinch_overlay_scrollbar_thickness = 10;
   prefs.use_solid_color_scrollbars = ui::IsOverlayScrollbarEnabled();
+  prefs.invert_viewport_scroll_order =
+      command_line.HasSwitch(switches::kInvertViewportScrollOrder);
 
 #if defined(OS_ANDROID)
   // On Android, user gestures are normally required, unless that requirement
@@ -506,10 +507,6 @@
   prefs.main_frame_resizes_are_orientation_changes =
       command_line.HasSwitch(switches::kMainFrameResizesAreOrientationChanges);
 
-  prefs.deferred_image_decoding_enabled =
-      command_line.HasSwitch(switches::kEnableDeferredImageDecoding) ||
-      content::IsImplSidePaintingEnabled();
-
   prefs.image_color_profiles_enabled =
       command_line.HasSwitch(switches::kEnableImageColorProfiles);
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index b8b7f3e..5483d015 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -829,6 +829,8 @@
         window_->GetBoundsInRootWindow());
   }
 #endif
+  if (!in_shutdown_)
+    host_->SendScreenRects();
 }
 
 void RenderWidgetHostViewAura::ParentHierarchyChanged() {
@@ -2455,7 +2457,7 @@
   aura::Window* root_window = window_->GetRootWindow();
   if (!root_window)
     return NULL;
-  return root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
+  return root_window->GetHost()->GetInputMethod();
 }
 
 void RenderWidgetHostViewAura::Shutdown() {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 5af7f4ca..00eda4c 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -815,6 +815,67 @@
   aura::client::SetScreenPositionClient(root, NULL);
 }
 
+// Checks that moving parent sends new screen bounds.
+TEST_F(RenderWidgetHostViewAuraTest, ParentMovementUpdatesScreenRect) {
+  view_->InitAsChild(NULL);
+
+  aura::Window* root = parent_view_->GetNativeView()->GetRootWindow();
+
+  aura::test::TestWindowDelegate delegate1, delegate2;
+  scoped_ptr<aura::Window> parent1(new aura::Window(&delegate1));
+  parent1->Init(ui::LAYER_TEXTURED);
+  parent1->Show();
+  scoped_ptr<aura::Window> parent2(new aura::Window(&delegate2));
+  parent2->Init(ui::LAYER_TEXTURED);
+  parent2->Show();
+
+  root->AddChild(parent1.get());
+  parent1->AddChild(parent2.get());
+  parent2->AddChild(view_->GetNativeView());
+
+  root->SetBounds(gfx::Rect(0, 0, 400, 400));
+  parent1->SetBounds(gfx::Rect(1, 1, 300, 300));
+  parent2->SetBounds(gfx::Rect(2, 2, 200, 200));
+  view_->SetBounds(gfx::Rect(3, 3, 100, 100));
+  // view_ will be destroyed when parent is destroyed.
+  view_ = NULL;
+
+  // Flush the state after initial setup is done.
+  widget_host_->OnMessageReceived(
+      ViewHostMsg_UpdateScreenRects_ACK(widget_host_->GetRoutingID()));
+  widget_host_->OnMessageReceived(
+      ViewHostMsg_UpdateScreenRects_ACK(widget_host_->GetRoutingID()));
+  sink_->ClearMessages();
+
+  // Move parents.
+  parent2->SetBounds(gfx::Rect(20, 20, 200, 200));
+  ASSERT_EQ(1U, sink_->message_count());
+  const IPC::Message* msg = sink_->GetMessageAt(0);
+  ASSERT_EQ(ViewMsg_UpdateScreenRects::ID, msg->type());
+  ViewMsg_UpdateScreenRects::Param params;
+  ViewMsg_UpdateScreenRects::Read(msg, &params);
+  EXPECT_EQ(gfx::Rect(24, 24, 100, 100), base::get<0>(params));
+  EXPECT_EQ(gfx::Rect(1, 1, 300, 300), base::get<1>(params));
+  sink_->ClearMessages();
+  widget_host_->OnMessageReceived(
+      ViewHostMsg_UpdateScreenRects_ACK(widget_host_->GetRoutingID()));
+  // There should not be any pending update.
+  EXPECT_EQ(0U, sink_->message_count());
+
+  parent1->SetBounds(gfx::Rect(10, 10, 300, 300));
+  ASSERT_EQ(1U, sink_->message_count());
+  msg = sink_->GetMessageAt(0);
+  ASSERT_EQ(ViewMsg_UpdateScreenRects::ID, msg->type());
+  ViewMsg_UpdateScreenRects::Read(msg, &params);
+  EXPECT_EQ(gfx::Rect(33, 33, 100, 100), base::get<0>(params));
+  EXPECT_EQ(gfx::Rect(10, 10, 300, 300), base::get<1>(params));
+  sink_->ClearMessages();
+  widget_host_->OnMessageReceived(
+      ViewHostMsg_UpdateScreenRects_ACK(widget_host_->GetRoutingID()));
+  // There should not be any pending update.
+  EXPECT_EQ(0U, sink_->message_count());
+}
+
 // Checks that a fullscreen view is destroyed when it loses the focus.
 TEST_F(RenderWidgetHostViewAuraTest, DestroyFullscreenOnBlur) {
   view_->InitAsFullscreen(parent_view_);
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index c53d246..21266f1 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -19,7 +19,7 @@
 #include "content/public/browser/readback_types.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "ipc/ipc_listener.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
 #include "third_party/WebKit/public/web/WebPopupType.h"
 #include "third_party/WebKit/public/web/WebTextDirection.h"
 #include "ui/base/ime/text_input_mode.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_base_unittest.cc b/content/browser/renderer_host/render_widget_host_view_base_unittest.cc
index 6cc861d..8277d1f6 100644
--- a/content/browser/renderer_host/render_widget_host_view_base_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base_unittest.cc
@@ -5,7 +5,7 @@
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
 #include "ui/gfx/display.h"
 
 namespace content {
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index d2137fb..b7ca5ff0 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -20,7 +20,6 @@
 #include "base/time/time.h"
 #include "content/browser/compositor/browser_compositor_view_mac.h"
 #include "content/browser/compositor/delegated_frame_host.h"
-#include "content/browser/renderer_host/display_link_mac.h"
 #include "content/browser/renderer_host/input/mouse_wheel_rails_filter_mac.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "content/common/content_export.h"
@@ -30,6 +29,7 @@
 #include "ipc/ipc_sender.h"
 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
 #include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
+#include "ui/accelerated_widget_mac/display_link_mac.h"
 #include "ui/accelerated_widget_mac/io_surface_layer.h"
 #include "ui/base/cocoa/remote_layer_api.h"
 #import "ui/base/cocoa/tool_tip_base_view.h"
@@ -566,7 +566,7 @@
   RenderWidgetHostViewMac* fullscreen_parent_host_view_;
 
   // Display link for getting vsync info.
-  scoped_refptr<DisplayLinkMac> display_link_;
+  scoped_refptr<ui::DisplayLinkMac> display_link_;
 
   // The current VSync timebase and interval. This is zero until the first call
   // to SendVSyncParametersToRenderer(), and refreshed regularly thereafter.
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 625f041..6eb9cf4a 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -40,6 +40,7 @@
 #include "content/browser/renderer_host/render_widget_helper.h"
 #import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h"
 #import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h"
+#include "content/browser/renderer_host/render_widget_resize_helper.h"
 #import "content/browser/renderer_host/text_input_client_mac.h"
 #include "content/common/accessibility_messages.h"
 #include "content/common/edit_command.h"
@@ -827,7 +828,7 @@
   NSNumber* screen_number = [screen_description objectForKey:@"NSScreenNumber"];
   CGDirectDisplayID display_id = [screen_number unsignedIntValue];
 
-  display_link_ = DisplayLinkMac::GetForDisplay(display_id);
+  display_link_ = ui::DisplayLinkMac::GetForDisplay(display_id);
   if (!display_link_.get()) {
     // Note that on some headless systems, the display link will fail to be
     // created, so this should not be a fatal error.
@@ -2980,7 +2981,7 @@
     // We ignore commands that insert characters, because this was causing
     // strange behavior (e.g. tab always inserted a tab rather than moving to
     // the next field on the page).
-    if (!StartsWithASCII(command, "insert", false))
+    if (!base::StartsWithASCII(command, "insert", false))
       editCommands_.push_back(EditCommand(command, ""));
   } else {
     RenderWidgetHostImpl* rwh = renderWidgetHostView_->render_widget_host_;
diff --git a/content/browser/resources/gpu/info_view.js b/content/browser/resources/gpu/info_view.js
index 40810054..20c6b8e 100644
--- a/content/browser/resources/gpu/info_view.js
+++ b/content/browser/resources/gpu/info_view.js
@@ -93,7 +93,6 @@
         'video_encode': 'Video Encode',
         'panel_fitting': 'Panel Fitting',
         'rasterization': 'Rasterization',
-        'threaded_rasterization': 'Threaded Rasterization',
         'multiple_raster_threads': 'Multiple Raster Threads',
       };
 
diff --git a/content/browser/resources/media/client_renderer.js b/content/browser/resources/media/client_renderer.js
index a631cbe..ccee09e 100644
--- a/content/browser/resources/media/client_renderer.js
+++ b/content/browser/resources/media/client_renderer.js
@@ -137,11 +137,17 @@
     },
 
     /**
-     * Called when a playre is removed from the collection.
+     * Called when a player is removed from the collection.
      * @param players The entire map of id -> player.
-     * @param player_added The player that was removed.
+     * @param playerRemoved The player that was removed.
      */
     playerRemoved: function(players, playerRemoved) {
+      if (playerRemoved === this.selectedPlayer) {
+        removeChildren(this.playerPropertiesTable);
+        removeChildren(this.logTable);
+        removeChildren(this.graphElement);
+        document.body.classList.add(ClientRenderer.Css_.NO_PLAYERS_SELECTED);
+      }
       this.redrawPlayerList_(players);
     },
 
diff --git a/content/browser/resources/media/main.js b/content/browser/resources/media/main.js
index 7045197..5ca4bed 100644
--- a/content/browser/resources/media/main.js
+++ b/content/browser/resources/media/main.js
@@ -176,7 +176,7 @@
 
     if (propertyCount === 0) {
       manager.updatePlayerInfo(
-          source, event.ticksMillis, 'EVENT', event.type);
+          source, event.ticksMillis, 'event', event.type);
     }
   };
 
diff --git a/content/browser/resources/media/manager.js b/content/browser/resources/media/manager.js
index 5508c66c..b335349f 100644
--- a/content/browser/resources/media/manager.js
+++ b/content/browser/resources/media/manager.js
@@ -73,8 +73,9 @@
      * @param id The ID of the player to remove.
      */
     removePlayer: function(id) {
+      var playerRemoved = this.players_[id];
       delete this.players_[id];
-      this.clientRenderer_.playerRemoved(this.players_, this.players_[id]);
+      this.clientRenderer_.playerRemoved(this.players_, playerRemoved);
     },
 
     updatePlayerInfoNoRecord: function(id, timestamp, key, value) {
diff --git a/content/browser/resources/service_worker/OWNERS b/content/browser/resources/service_worker/OWNERS
index df9c7767..4366545 100644
--- a/content/browser/resources/service_worker/OWNERS
+++ b/content/browser/resources/service_worker/OWNERS
@@ -2,6 +2,3 @@
 horo@chromium.org
 falken@chromium.org
 nhiroki@chromium.org
-
-# may not be available
-kinuko@chromium.org
diff --git a/content/browser/screen_orientation/screen_orientation_delegate_android.h b/content/browser/screen_orientation/screen_orientation_delegate_android.h
index 75582094..36886ddc 100644
--- a/content/browser/screen_orientation/screen_orientation_delegate_android.h
+++ b/content/browser/screen_orientation/screen_orientation_delegate_android.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "content/public/browser/screen_orientation_delegate.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 
 namespace content {
 
diff --git a/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h b/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h
index 29bc534..1b90f77 100644
--- a/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h
+++ b/content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h
@@ -7,8 +7,8 @@
 
 #include "content/public/browser/screen_orientation_dispatcher_host.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "third_party/WebKit/public/platform/WebLockOrientationError.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationError.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 
 namespace content {
 
diff --git a/content/browser/service_worker/OWNERS b/content/browser/service_worker/OWNERS
index c84704d..61321a28 100644
--- a/content/browser/service_worker/OWNERS
+++ b/content/browser/service_worker/OWNERS
@@ -2,6 +2,3 @@
 falken@chromium.org
 horo@chromium.org
 nhiroki@chromium.org
-
-# may not be available
-kinuko@chromium.org
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index 3e512c1a..eeaf4c4b 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -7,8 +7,11 @@
 #include <map>
 #include <string>
 
+#include "base/atomic_sequence_num.h"
 #include "base/bind.h"
+#include "base/memory/scoped_vector.h"
 #include "base/thread_task_runner_handle.h"
+#include "content/browser/message_port_message_filter.h"
 #include "content/browser/service_worker/embedded_worker_instance.h"
 #include "content/browser/service_worker/embedded_worker_registry.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
@@ -19,6 +22,24 @@
 
 namespace content {
 
+class MockMessagePortMessageFilter : public MessagePortMessageFilter {
+ public:
+  MockMessagePortMessageFilter()
+      : MessagePortMessageFilter(
+            base::Bind(&base::AtomicSequenceNumber::GetNext,
+                       base::Unretained(&next_routing_id_))) {}
+
+  bool Send(IPC::Message* message) override {
+    message_queue_.push_back(message);
+    return true;
+  }
+
+ private:
+  ~MockMessagePortMessageFilter() override {}
+  base::AtomicSequenceNumber next_routing_id_;
+  ScopedVector<IPC::Message> message_queue_;
+};
+
 EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
     const base::FilePath& user_data_directory,
     int mock_render_process_id)
@@ -35,7 +56,8 @@
                          NULL,
                          NULL);
   wrapper_->process_manager()->SetProcessIdForTest(mock_render_process_id);
-  registry()->AddChildProcessSender(mock_render_process_id, this, nullptr);
+  registry()->AddChildProcessSender(mock_render_process_id, this,
+                                    NewMessagePortMessageFilter());
 }
 
 EmbeddedWorkerTestHelper::~EmbeddedWorkerTestHelper() {
@@ -46,7 +68,8 @@
 void EmbeddedWorkerTestHelper::SimulateAddProcessToPattern(
     const GURL& pattern,
     int process_id) {
-  registry()->AddChildProcessSender(process_id, this, nullptr);
+  registry()->AddChildProcessSender(process_id, this,
+                                    NewMessagePortMessageFilter());
   wrapper_->process_manager()->AddProcessReferenceToPattern(
       pattern, process_id);
 }
@@ -330,4 +353,12 @@
   return context()->embedded_worker_registry();
 }
 
+MessagePortMessageFilter*
+EmbeddedWorkerTestHelper::NewMessagePortMessageFilter() {
+  scoped_refptr<MessagePortMessageFilter> filter(
+      new MockMessagePortMessageFilter);
+  message_port_message_filters_.push_back(filter);
+  return filter.get();
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index 50df4c01..6375e83 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -21,6 +21,7 @@
 
 class EmbeddedWorkerRegistry;
 class EmbeddedWorkerTestHelper;
+class MessagePortMessageFilter;
 class ServiceWorkerContextCore;
 class ServiceWorkerContextWrapper;
 struct ServiceWorkerFetchRequest;
@@ -124,6 +125,8 @@
   void OnFetchEventStub(int request_id,
                         const ServiceWorkerFetchRequest& request);
 
+  MessagePortMessageFilter* NewMessagePortMessageFilter();
+
   scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
 
   IPC::TestSink sink_;
@@ -137,6 +140,9 @@
   // Updated each time MessageToWorker message is received.
   int current_embedded_worker_id_;
 
+  std::vector<scoped_refptr<MessagePortMessageFilter>>
+      message_port_message_filters_;
+
   base::WeakPtrFactory<EmbeddedWorkerTestHelper> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerTestHelper);
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 71cb2784..97723e1 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -794,7 +794,14 @@
   ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
 }
 
-IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartPaused_ThenResume) {
+#if defined(OS_LINUX)
+// Flaky on Linux 32-bit: http://crbug.com/498688.
+#define MAYBE_StartPaused_ThenResume DISABLED_StartPaused_ThenResume
+#else
+#define MAYBE_StartPaused_ThenResume StartPaused_ThenResume
+#endif
+IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest,
+                       MAYBE_StartPaused_ThenResume) {
   pause_mode_ = PAUSE_THEN_RESUME;
   base::RunLoop start_run_loop;
   done_closure_ = start_run_loop.QuitClosure();
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc
index fef7bcdc..d2d69342 100644
--- a/content/browser/service_worker/service_worker_context_core.cc
+++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -296,11 +296,9 @@
     return;
   }
 
-  storage()->GetAllRegistrations(base::Bind(
+  storage()->GetAllRegistrationsInfos(base::Bind(
       &ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin,
-      AsWeakPtr(),
-      callback,
-      origin));
+      AsWeakPtr(), callback, origin));
 }
 
 void ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin(
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 264c9ce5..962da53 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -339,10 +339,9 @@
         base::Bind(callback, std::vector<ServiceWorkerUsageInfo>()));
     return;
   }
-  context()->storage()->GetAllRegistrations(base::Bind(
+  context()->storage()->GetAllRegistrationsInfos(base::Bind(
       &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins,
-      this,
-      callback));
+      this, callback));
 }
 
 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
@@ -526,7 +525,7 @@
     RunSoon(base::Bind(callback, std::vector<ServiceWorkerRegistrationInfo>()));
     return;
   }
-  context_core_->storage()->GetAllRegistrations(callback);
+  context_core_->storage()->GetAllRegistrationsInfos(callback);
 }
 
 void ServiceWorkerContextWrapper::GetRegistrationUserData(
diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc
index 4da2ca7..aeac92a4 100644
--- a/content/browser/service_worker/service_worker_database.cc
+++ b/content/browser/service_worker/service_worker_database.cc
@@ -5,6 +5,7 @@
 #include "content/browser/service_worker/service_worker_database.h"
 
 #include "base/files/file_util.h"
+#include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
@@ -94,10 +95,19 @@
 
 const int64 kCurrentSchemaVersion = 2;
 
+class ServiceWorkerEnv : public leveldb_env::ChromiumEnv {
+ public:
+  ServiceWorkerEnv()
+      : ChromiumEnv("LevelDBEnv.ServiceWorker", false /* make_backup */) {}
+};
+
+base::LazyInstance<ServiceWorkerEnv>::Leaky g_service_worker_env =
+    LAZY_INSTANCE_INITIALIZER;
+
 bool RemovePrefix(const std::string& str,
                   const std::string& prefix,
                   std::string* out) {
-  if (!StartsWithASCII(str, prefix, true))
+  if (!base::StartsWithASCII(str, prefix, true))
     return false;
   if (out)
     *out = str.substr(prefix.size());
@@ -449,7 +459,8 @@
 
 ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetRegistrationsForOrigin(
     const GURL& origin,
-    std::vector<RegistrationData>* registrations) {
+    std::vector<RegistrationData>* registrations,
+    std::vector<std::vector<ResourceRecord>>* opt_resources_list) {
   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
   DCHECK(registrations->empty());
 
@@ -466,6 +477,8 @@
     if (status != STATUS_OK) {
       HandleReadResult(FROM_HERE, status);
       registrations->clear();
+      if (opt_resources_list)
+        opt_resources_list->clear();
       return status;
     }
 
@@ -477,9 +490,23 @@
     if (status != STATUS_OK) {
       HandleReadResult(FROM_HERE, status);
       registrations->clear();
+      if (opt_resources_list)
+        opt_resources_list->clear();
       return status;
     }
     registrations->push_back(registration);
+
+    if (opt_resources_list) {
+      std::vector<ResourceRecord> resources;
+      status = ReadResourceRecords(registration.version_id, &resources);
+      if (status != STATUS_OK) {
+        HandleReadResult(FROM_HERE, status);
+        registrations->clear();
+        opt_resources_list->clear();
+        return status;
+      }
+      opt_resources_list->push_back(resources);
+    }
   }
 
   HandleReadResult(FROM_HERE, status);
@@ -735,7 +762,7 @@
   // |registration_id| is the only one for |origin|.
   // TODO(nhiroki): Check the uniqueness by more efficient way.
   std::vector<RegistrationData> registrations;
-  status = GetRegistrationsForOrigin(origin, &registrations);
+  status = GetRegistrationsForOrigin(origin, &registrations, nullptr);
   if (status != STATUS_OK)
     return status;
 
@@ -952,7 +979,7 @@
     batch.Delete(CreateUniqueOriginKey(origin));
 
     std::vector<RegistrationData> registrations;
-    status = GetRegistrationsForOrigin(origin, &registrations);
+    status = GetRegistrationsForOrigin(origin, &registrations, nullptr);
     if (status != STATUS_OK)
       return status;
 
@@ -987,6 +1014,8 @@
       // In-memory database not initialized.
       return STATUS_OK;
     }
+  } else {
+    options.env = g_service_worker_env.Pointer();
   }
 
   Status status =
@@ -1023,6 +1052,8 @@
   if (use_in_memory_db) {
     env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
     options.env = env_.get();
+  } else {
+    options.env = g_service_worker_env.Pointer();
   }
 
   leveldb::DB* db = NULL;
diff --git a/content/browser/service_worker/service_worker_database.h b/content/browser/service_worker/service_worker_database.h
index 13c0ed4..a435212 100644
--- a/content/browser/service_worker/service_worker_database.h
+++ b/content/browser/service_worker/service_worker_database.h
@@ -101,7 +101,8 @@
   // successfully read or not found. Otherwise, returns an error.
   Status GetRegistrationsForOrigin(
       const GURL& origin,
-      std::vector<RegistrationData>* registrations);
+      std::vector<RegistrationData>* registrations,
+      std::vector<std::vector<ResourceRecord>>* opt_resources_list);
 
   // Reads all registrations from the database. Returns OK if successfully read
   // or not found. Otherwise, returns an error.
diff --git a/content/browser/service_worker/service_worker_database_unittest.cc b/content/browser/service_worker/service_worker_database_unittest.cc
index 84424f7..e389303 100644
--- a/content/browser/service_worker/service_worker_database_unittest.cc
+++ b/content/browser/service_worker/service_worker_database_unittest.cc
@@ -406,9 +406,12 @@
   GURL origin3("https://example.org");
 
   std::vector<RegistrationData> registrations;
+  std::vector<std::vector<Resource>> resources_list;
   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database->GetRegistrationsForOrigin(origin1, &registrations));
+            database->GetRegistrationsForOrigin(origin1, &registrations,
+                                                &resources_list));
   EXPECT_TRUE(registrations.empty());
+  EXPECT_TRUE(resources_list.empty());
 
   ServiceWorkerDatabase::RegistrationData deleted_version;
   std::vector<int64> newly_purgeable_resources;
@@ -425,6 +428,16 @@
             database->WriteRegistration(data1, resources1, &deleted_version,
                                         &newly_purgeable_resources));
 
+  registrations.clear();
+  resources_list.clear();
+  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+            database->GetRegistrationsForOrigin(origin1, &registrations,
+                                                &resources_list));
+  EXPECT_EQ(1U, registrations.size());
+  VerifyRegistrationData(data1, registrations[0]);
+  EXPECT_EQ(1U, resources_list.size());
+  VerifyResourceRecords(resources1, resources_list[0]);
+
   RegistrationData data2;
   data2.registration_id = 200;
   data2.scope = URL(origin2, "/bar");
@@ -437,6 +450,16 @@
             database->WriteRegistration(data2, resources2, &deleted_version,
                                         &newly_purgeable_resources));
 
+  registrations.clear();
+  resources_list.clear();
+  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
+            database->GetRegistrationsForOrigin(origin2, &registrations,
+                                                &resources_list));
+  EXPECT_EQ(1U, registrations.size());
+  VerifyRegistrationData(data2, registrations[0]);
+  EXPECT_EQ(1U, resources_list.size());
+  VerifyResourceRecords(resources2, resources_list[0]);
+
   RegistrationData data3;
   data3.registration_id = 300;
   data3.scope = URL(origin3, "/hoge");
@@ -463,11 +486,25 @@
                                         &newly_purgeable_resources));
 
   registrations.clear();
+  resources_list.clear();
   EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database->GetRegistrationsForOrigin(origin3, &registrations));
+            database->GetRegistrationsForOrigin(origin3, &registrations,
+                                                &resources_list));
   EXPECT_EQ(2U, registrations.size());
   VerifyRegistrationData(data3, registrations[0]);
   VerifyRegistrationData(data4, registrations[1]);
+  EXPECT_EQ(2U, resources_list.size());
+  VerifyResourceRecords(resources3, resources_list[0]);
+  VerifyResourceRecords(resources4, resources_list[1]);
+
+  // The third parameter |opt_resources_list| to GetRegistrationsForOrigin()
+  // is optional. So, nullptr should be acceptable.
+  registrations.clear();
+  EXPECT_EQ(
+      ServiceWorkerDatabase::STATUS_OK,
+      database->GetRegistrationsForOrigin(origin1, &registrations, nullptr));
+  EXPECT_EQ(1U, registrations.size());
+  VerifyRegistrationData(data1, registrations[0]);
 }
 
 TEST(ServiceWorkerDatabaseTest, GetAllRegistrations) {
@@ -1471,8 +1508,9 @@
 
   // The registrations for |origin1| should be removed.
   std::vector<RegistrationData> registrations;
-  EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
-            database->GetRegistrationsForOrigin(origin1, &registrations));
+  EXPECT_EQ(
+      ServiceWorkerDatabase::STATUS_OK,
+      database->GetRegistrationsForOrigin(origin1, &registrations, nullptr));
   EXPECT_TRUE(registrations.empty());
   GURL origin_out;
   EXPECT_EQ(
diff --git a/content/browser/service_worker/service_worker_disk_cache_migrator.cc b/content/browser/service_worker/service_worker_disk_cache_migrator.cc
index df67b78..7cac97dd 100644
--- a/content/browser/service_worker/service_worker_disk_cache_migrator.cc
+++ b/content/browser/service_worker/service_worker_disk_cache_migrator.cc
@@ -4,8 +4,12 @@
 
 #include "content/browser/service_worker/service_worker_disk_cache_migrator.h"
 
+#include "base/barrier_closure.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/task_runner_util.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -18,6 +22,25 @@
 // Disk cache entry data indices (Copied from appcache_diskcache.cc).
 enum { kResponseInfoIndex, kResponseContentIndex, kResponseMetadataIndex };
 
+#if defined(OS_ANDROID)
+ServiceWorkerStatusCode MigrateForAndroid(const base::FilePath& src_path,
+                                          const base::FilePath& dest_path) {
+  // Continue the migration regardless of the deletion result. If the migrator
+  // cannot proceed or the diskcache gets corrupted due to the failure, the
+  // storage detects it and recovers by DeleteAndStartOver.
+  base::DeleteFile(dest_path, true);
+
+  if (!base::DirectoryExists(src_path))
+    return SERVICE_WORKER_OK;
+
+  // Android has alredy used the Simple backend. Just move the existing
+  // diskcache files to a new location.
+  if (base::Move(src_path, dest_path))
+    return SERVICE_WORKER_OK;
+  return SERVICE_WORKER_ERROR_FAILED;
+}
+#endif  // defined(OS_ANDROID)
+
 }  // namespace
 
 // A task to move a cached resource from the src DiskCache to the dest
@@ -225,11 +248,15 @@
 }
 
 ServiceWorkerDiskCacheMigrator::ServiceWorkerDiskCacheMigrator(
-    ServiceWorkerDiskCache* src,
-    ServiceWorkerDiskCache* dest)
-    : src_(src), dest_(dest), weak_factory_(this) {
-  DCHECK(!src_->is_disabled());
-  DCHECK(!dest_->is_disabled());
+    const base::FilePath& src_path,
+    const base::FilePath& dest_path,
+    int max_disk_cache_size,
+    const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread)
+    : src_path_(src_path),
+      dest_path_(dest_path),
+      max_disk_cache_size_(max_disk_cache_size),
+      disk_cache_thread_(disk_cache_thread),
+      weak_factory_(this) {
 }
 
 ServiceWorkerDiskCacheMigrator::~ServiceWorkerDiskCacheMigrator() {
@@ -237,6 +264,75 @@
 
 void ServiceWorkerDiskCacheMigrator::Start(const StatusCallback& callback) {
   callback_ = callback;
+
+#if defined(OS_ANDROID)
+  PostTaskAndReplyWithResult(
+      disk_cache_thread_.get(), FROM_HERE,
+      base::Bind(&MigrateForAndroid, src_path_, dest_path_),
+      base::Bind(&ServiceWorkerDiskCacheMigrator::Complete,
+                 weak_factory_.GetWeakPtr()));
+#else
+  PostTaskAndReplyWithResult(
+      disk_cache_thread_.get(), FROM_HERE,
+      base::Bind(&base::DeleteFile, dest_path_, true),
+      base::Bind(&ServiceWorkerDiskCacheMigrator::DidDeleteDestDirectory,
+                 weak_factory_.GetWeakPtr()));
+#endif  // defined(OS_ANDROID)
+}
+
+void ServiceWorkerDiskCacheMigrator::DidDeleteDestDirectory(bool deleted) {
+  // Continue the migration regardless of the deletion result. If the migrator
+  // cannot proceed or the diskcache gets corrupted due to the failure, the
+  // storage detects it and recovers by DeleteAndStartOver.
+
+  src_ = ServiceWorkerDiskCache::CreateWithBlockFileBackend();
+  dest_ = ServiceWorkerDiskCache::CreateWithSimpleBackend();
+  bool* is_failed = new bool(false);
+
+  // This closure is called when both diskcaches are initialized.
+  base::Closure barrier_closure = base::BarrierClosure(
+      2, base::Bind(&ServiceWorkerDiskCacheMigrator::DidInitializeAllDiskCaches,
+                    weak_factory_.GetWeakPtr(), base::Owned(is_failed)));
+
+  // Initialize the src DiskCache.
+  net::CompletionCallback src_callback =
+      base::Bind(&ServiceWorkerDiskCacheMigrator::DidInitializeDiskCache,
+                 weak_factory_.GetWeakPtr(), is_failed, barrier_closure);
+  int result = src_->InitWithDiskBackend(src_path_, max_disk_cache_size_,
+                                         false /* force */, disk_cache_thread_,
+                                         src_callback);
+  if (result != net::ERR_IO_PENDING)
+    src_callback.Run(result);
+
+  // Initialize the dest DiskCache.
+  net::CompletionCallback dest_callback =
+      base::Bind(&ServiceWorkerDiskCacheMigrator::DidInitializeDiskCache,
+                 weak_factory_.GetWeakPtr(), is_failed, barrier_closure);
+  result = dest_->InitWithDiskBackend(dest_path_, max_disk_cache_size_,
+                                      false /* force */, disk_cache_thread_,
+                                      dest_callback);
+  if (result != net::ERR_IO_PENDING)
+    dest_callback.Run(result);
+}
+
+void ServiceWorkerDiskCacheMigrator::DidInitializeDiskCache(
+    bool* is_failed,
+    const base::Closure& barrier_closure,
+    int result) {
+  if (result != net::OK)
+    *is_failed = true;
+  barrier_closure.Run();
+}
+
+void ServiceWorkerDiskCacheMigrator::DidInitializeAllDiskCaches(
+    bool* is_failed) {
+  if (*is_failed) {
+    LOG(ERROR) << "Failed to initialize the diskcache";
+    Complete(SERVICE_WORKER_ERROR_FAILED);
+    return;
+  }
+
+  // Iterate through existing entries in the src DiskCache.
   iterator_ = src_->disk_cache()->CreateIterator();
   OpenNextEntry();
 }
@@ -290,9 +386,9 @@
   }
 
   InflightTaskMap::KeyType task_id = next_task_id_++;
-  pending_task_.reset(new Task(task_id, resource_id,
-                               scoped_entry->GetDataSize(kResponseContentIndex),
-                               src_, dest_, weak_factory_.GetWeakPtr()));
+  pending_task_.reset(new Task(
+      task_id, resource_id, scoped_entry->GetDataSize(kResponseContentIndex),
+      src_.get(), dest_.get(), weak_factory_.GetWeakPtr()));
   if (inflight_tasks_.size() < max_number_of_inflight_tasks_) {
     RunPendingTask();
     OpenNextEntry();
@@ -337,6 +433,9 @@
 void ServiceWorkerDiskCacheMigrator::Complete(ServiceWorkerStatusCode status) {
   DCHECK(inflight_tasks_.IsEmpty());
   // TODO(nhiroki): Add UMA for the result of migration.
+
+  src_.reset();
+  dest_.reset();
   callback_.Run(status);
 }
 
diff --git a/content/browser/service_worker/service_worker_disk_cache_migrator.h b/content/browser/service_worker/service_worker_disk_cache_migrator.h
index 283db71..08d6368 100644
--- a/content/browser/service_worker/service_worker_disk_cache_migrator.h
+++ b/content/browser/service_worker/service_worker_disk_cache_migrator.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DISK_CACHE_MIGRATOR_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DISK_CACHE_MIGRATOR_H_
+
 #include "content/browser/service_worker/service_worker_disk_cache.h"
 
 #include "base/id_map.h"
@@ -22,8 +25,11 @@
  public:
   using StatusCallback = base::Callback<void(ServiceWorkerStatusCode)>;
 
-  ServiceWorkerDiskCacheMigrator(ServiceWorkerDiskCache* src,
-                                 ServiceWorkerDiskCache* dest);
+  ServiceWorkerDiskCacheMigrator(
+      const base::FilePath& src_path,
+      const base::FilePath& dest_path,
+      int max_disk_cache_size,
+      const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread);
   ~ServiceWorkerDiskCacheMigrator();
 
   // Returns SERVICE_WORKER_OK if all resources are successfully migrated. The
@@ -31,12 +37,20 @@
   void Start(const StatusCallback& callback);
 
  private:
-  friend class ServiceWorkerDiskCacheMigratorTest;
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDiskCacheMigratorTest,
+                           ThrottleInflightTasks);
+
   class Task;
   class WrappedEntry;
 
   using InflightTaskMap = IDMap<Task, IDMapOwnPointer>;
 
+  void DidDeleteDestDirectory(bool deleted);
+  void DidInitializeDiskCache(bool* is_failed,
+                              const base::Closure& barrier_closure,
+                              int result);
+  void DidInitializeAllDiskCaches(bool* is_failed);
+
   void OpenNextEntry();
   void OnNextEntryOpened(scoped_ptr<WrappedEntry> entry, int result);
   void RunPendingTask();
@@ -51,8 +65,12 @@
   scoped_ptr<disk_cache::Backend::Iterator> iterator_;
   bool is_iterating_ = false;
 
-  ServiceWorkerDiskCache* src_;
-  ServiceWorkerDiskCache* dest_;
+  base::FilePath src_path_;
+  base::FilePath dest_path_;
+  scoped_ptr<ServiceWorkerDiskCache> src_;
+  scoped_ptr<ServiceWorkerDiskCache> dest_;
+  const int max_disk_cache_size_;
+  scoped_refptr<base::SingleThreadTaskRunner> disk_cache_thread_;
 
   InflightTaskMap::KeyType next_task_id_ = 0;
   InflightTaskMap inflight_tasks_;
@@ -67,3 +85,5 @@
 };
 
 }  // namespace content
+
+#endif  // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_DISK_CACHE_MIGRATOR_H_
diff --git a/content/browser/service_worker/service_worker_disk_cache_migrator_unittest.cc b/content/browser/service_worker/service_worker_disk_cache_migrator_unittest.cc
index 7f3f030..f1397d2 100644
--- a/content/browser/service_worker/service_worker_disk_cache_migrator_unittest.cc
+++ b/content/browser/service_worker/service_worker_disk_cache_migrator_unittest.cc
@@ -4,9 +4,12 @@
 
 #include "content/browser/service_worker/service_worker_disk_cache_migrator.h"
 
+#include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
 #include "base/thread_task_runner_handle.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_storage.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -51,29 +54,61 @@
 
   void SetUp() override {
     ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir());
-    const base::FilePath kSrcDiskCachePath =
-        user_data_directory_.path().AppendASCII("SrcCache");
-    const base::FilePath kDestDiskCachePath =
-        user_data_directory_.path().AppendASCII("DestCache");
+    scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
+        new MockServiceWorkerDatabaseTaskManager(
+            base::ThreadTaskRunnerHandle::Get()));
 
-    // Initialize the src BlockFile diskcache.
-    src_ = ServiceWorkerDiskCache::CreateWithBlockFileBackend();
-    net::TestCompletionCallback cb1;
-    src_->InitWithDiskBackend(
-        kSrcDiskCachePath, kMaxDiskCacheSize, false /* force */,
-        base::ThreadTaskRunnerHandle::Get(), cb1.callback());
-    ASSERT_EQ(net::OK, cb1.WaitForResult());
+    context_.reset(new ServiceWorkerContextCore(
+        user_data_directory_.path(), database_task_manager.Pass(),
+        base::ThreadTaskRunnerHandle::Get(), nullptr, nullptr, nullptr,
+        nullptr));
+  }
 
-    // Initialize the dest Simple diskcache.
-    dest_ = ServiceWorkerDiskCache::CreateWithSimpleBackend();
-    net::TestCompletionCallback cb2;
-    dest_->InitWithDiskBackend(
-        kDestDiskCachePath, kMaxDiskCacheSize, false /* force */,
-        base::ThreadTaskRunnerHandle::Get(), cb2.callback());
-    ASSERT_EQ(net::OK, cb2.WaitForResult());
+  void TearDown() override {
+    context_.reset();
+    base::RunLoop().RunUntilIdle();
+  }
 
-    migrator_.reset(
-        new ServiceWorkerDiskCacheMigrator(src_.get(), dest_.get()));
+  base::FilePath GetOldDiskCachePath() {
+    return user_data_directory_.path().AppendASCII("SrcCache");
+  }
+  base::FilePath GetDiskCachePath() {
+    return user_data_directory_.path().AppendASCII("DestCache");
+  }
+
+  scoped_ptr<ServiceWorkerDiskCache> CreateSrcDiskCache() {
+#if defined(OS_ANDROID)
+    // Android has already used the Simple backend.
+    scoped_ptr<ServiceWorkerDiskCache> src(
+        ServiceWorkerDiskCache::CreateWithSimpleBackend());
+#else
+    scoped_ptr<ServiceWorkerDiskCache> src(
+        ServiceWorkerDiskCache::CreateWithBlockFileBackend());
+#endif  // defined(OS_ANDROID)
+
+    net::TestCompletionCallback cb;
+    src->InitWithDiskBackend(
+        GetOldDiskCachePath(), kMaxDiskCacheSize, false /* force */,
+        base::ThreadTaskRunnerHandle::Get(), cb.callback());
+    EXPECT_EQ(net::OK, cb.WaitForResult());
+    return src.Pass();
+  }
+
+  scoped_ptr<ServiceWorkerDiskCache> CreateDestDiskCache() {
+    scoped_ptr<ServiceWorkerDiskCache> dest(
+        ServiceWorkerDiskCache::CreateWithSimpleBackend());
+    net::TestCompletionCallback cb;
+    dest->InitWithDiskBackend(
+        GetDiskCachePath(), kMaxDiskCacheSize, false /* force */,
+        base::ThreadTaskRunnerHandle::Get(), cb.callback());
+    EXPECT_EQ(net::OK, cb.WaitForResult());
+    return dest.Pass();
+  }
+
+  scoped_ptr<ServiceWorkerDiskCacheMigrator> CreateMigrator() {
+    return make_scoped_ptr(new ServiceWorkerDiskCacheMigrator(
+        GetOldDiskCachePath(), GetDiskCachePath(), kMaxDiskCacheSize,
+        base::ThreadTaskRunnerHandle::Get()));
   }
 
   bool WriteResponse(ServiceWorkerDiskCache* disk_cache,
@@ -159,29 +194,18 @@
     EXPECT_EQ(0, memcmp(expected.body.data(), body_buffer->data(), rv));
   }
 
-  void Migrate() {
-    base::RunLoop run_loop;
-    migrator_->Start(base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure()));
-    run_loop.Run();
-  }
-
   int32 GetEntryCount(ServiceWorkerDiskCache* disk_cache) {
     return disk_cache->disk_cache()->GetEntryCount();
   }
 
-  void SetMaxNumberOfInflightTasks(size_t max_number) {
-    migrator_->set_max_number_of_inflight_tasks(max_number);
-  }
-
- protected:
+ private:
   TestBrowserThreadBundle browser_thread_bundle_;
   base::ScopedTempDir user_data_directory_;
-  scoped_ptr<ServiceWorkerDiskCache> src_;
-  scoped_ptr<ServiceWorkerDiskCache> dest_;
-  scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator_;
+
+  scoped_ptr<ServiceWorkerContextCore> context_;
 };
 
-TEST_F(ServiceWorkerDiskCacheMigratorTest, Basic) {
+TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateDiskCache) {
   std::vector<ResponseData> responses;
   responses.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "Hello", ""));
   responses.push_back(ResponseData(2, "HTTP/1.1 200 OK\0\0", "Service", ""));
@@ -194,24 +218,84 @@
       20, "HTTP/1.1 200 OK\0\0", std::string(256, 'a'), std::string(128, 'b')));
 
   // Populate initial data in the src diskcache.
+  scoped_ptr<ServiceWorkerDiskCache> src(CreateSrcDiskCache());
   for (const ResponseData& response : responses) {
-    ASSERT_TRUE(WriteResponse(src_.get(), response));
-    VerifyResponse(src_.get(), response);
+    ASSERT_TRUE(WriteResponse(src.get(), response));
+    VerifyResponse(src.get(), response);
   }
-  ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src_.get()));
+  ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src.get()));
+  src.reset();
 
-  Migrate();
+  // Start the migrator.
+  base::RunLoop run_loop;
+  scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator(CreateMigrator());
+  migrator->Start(base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure()));
+  run_loop.Run();
 
   // Verify the migrated contents in the dest diskcache.
+  scoped_ptr<ServiceWorkerDiskCache> dest(CreateDestDiskCache());
   for (const ResponseData& response : responses)
-    VerifyResponse(dest_.get(), response);
-  EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest_.get()));
+    VerifyResponse(dest.get(), response);
+  EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest.get()));
 }
 
 TEST_F(ServiceWorkerDiskCacheMigratorTest, MigrateEmptyDiskCache) {
-  ASSERT_EQ(0, GetEntryCount(src_.get()));
-  Migrate();
-  EXPECT_EQ(0, GetEntryCount(dest_.get()));
+  scoped_ptr<ServiceWorkerDiskCache> src(CreateSrcDiskCache());
+  ASSERT_EQ(0, GetEntryCount(src.get()));
+  src.reset();
+
+  // Start the migrator.
+  base::RunLoop run_loop;
+  scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator(CreateMigrator());
+  migrator->Start(base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure()));
+  run_loop.Run();
+
+  scoped_ptr<ServiceWorkerDiskCache> dest(CreateDestDiskCache());
+  ASSERT_EQ(0, GetEntryCount(dest.get()));
+}
+
+// Tests that the migrator properly removes existing resources in the dest
+// diskcache before starting the migration.
+TEST_F(ServiceWorkerDiskCacheMigratorTest, RemoveExistingResourcesFromDest) {
+  std::vector<ResponseData> responses1;
+  responses1.push_back(ResponseData(1, "HTTP/1.1 200 OK\0\0", "Hello", ""));
+  responses1.push_back(ResponseData(3, "HTTP/1.1 200 OK\0\0", "World", ""));
+
+  std::vector<ResponseData> responses2;
+  responses2.push_back(ResponseData(10, "HTTP/1.1 200 OK\0\0", "Hello", ""));
+  responses2.push_back(ResponseData(11, "HTTP/1.1 200 OK\0\0", "Service", ""));
+  responses2.push_back(ResponseData(12, "HTTP/1.1 200 OK\0\0", "", "Worker"));
+
+  // Populate initial resources in the src diskcache.
+  scoped_ptr<ServiceWorkerDiskCache> src(CreateSrcDiskCache());
+  for (const ResponseData& response : responses1) {
+    ASSERT_TRUE(WriteResponse(src.get(), response));
+    VerifyResponse(src.get(), response);
+  }
+  ASSERT_EQ(static_cast<int>(responses1.size()), GetEntryCount(src.get()));
+  src.reset();
+
+  // Populate different resources in the dest diskcache in order to simulate
+  // a previous partial migration.
+  scoped_ptr<ServiceWorkerDiskCache> dest(CreateDestDiskCache());
+  for (const ResponseData& response : responses2) {
+    ASSERT_TRUE(WriteResponse(dest.get(), response));
+    VerifyResponse(dest.get(), response);
+  }
+  ASSERT_EQ(static_cast<int>(responses2.size()), GetEntryCount(dest.get()));
+  dest.reset();
+
+  // Start the migrator.
+  base::RunLoop run_loop;
+  scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator(CreateMigrator());
+  migrator->Start(base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure()));
+  run_loop.Run();
+
+  // Verify that only newly migrated resources exist in the dest diskcache.
+  dest = CreateDestDiskCache();
+  for (const ResponseData& response : responses1)
+    VerifyResponse(dest.get(), response);
+  EXPECT_EQ(static_cast<int>(responses1.size()), GetEntryCount(dest.get()));
 }
 
 TEST_F(ServiceWorkerDiskCacheMigratorTest, ThrottleInflightTasks) {
@@ -220,22 +304,29 @@
     responses.push_back(ResponseData(i, "HTTP/1.1 200 OK\0\0", "foo", "bar"));
 
   // Populate initial data in the src diskcache.
+  scoped_ptr<ServiceWorkerDiskCache> src(CreateSrcDiskCache());
   for (const ResponseData& response : responses) {
-    ASSERT_TRUE(WriteResponse(src_.get(), response));
-    VerifyResponse(src_.get(), response);
+    ASSERT_TRUE(WriteResponse(src.get(), response));
+    VerifyResponse(src.get(), response);
   }
-  ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src_.get()));
+  ASSERT_EQ(static_cast<int>(responses.size()), GetEntryCount(src.get()));
+  src.reset();
+
+  scoped_ptr<ServiceWorkerDiskCacheMigrator> migrator(CreateMigrator());
 
   // Tighten the max number of inflight tasks.
-  SetMaxNumberOfInflightTasks(2);
+  migrator->set_max_number_of_inflight_tasks(2);
 
   // Migration should hit the limit, but should successfully complete.
-  Migrate();
+  base::RunLoop run_loop;
+  migrator->Start(base::Bind(&OnDiskCacheMigrated, run_loop.QuitClosure()));
+  run_loop.Run();
 
   // Verify the migrated contents in the dest diskcache.
+  scoped_ptr<ServiceWorkerDiskCache> dest(CreateDestDiskCache());
   for (const ResponseData& response : responses)
-    VerifyResponse(dest_.get(), response);
-  EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest_.get()));
+    VerifyResponse(dest.get(), response);
+  EXPECT_EQ(static_cast<int>(responses.size()), GetEntryCount(dest.get()));
 }
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index 16fb50b..d80cd145 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -162,6 +162,8 @@
                         OnUnregisterServiceWorker)
     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistration,
                         OnGetRegistration)
+    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistrations,
+                        OnGetRegistrations)
     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetRegistrationForReady,
                         OnGetRegistrationForReady)
     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated,
@@ -439,6 +441,9 @@
     const GURL& document_url) {
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerDispatcherHost::OnGetRegistration");
+
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
   if (!GetContext()) {
     Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationError(
         thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
@@ -492,7 +497,6 @@
     return;
   }
 
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (GetContext()->storage()->IsDisabled()) {
     SendGetRegistrationError(thread_id, request_id, SERVICE_WORKER_ERROR_ABORT);
     return;
@@ -513,6 +517,75 @@
                  request_id));
 }
 
+void ServiceWorkerDispatcherHost::OnGetRegistrations(int thread_id,
+                                                     int request_id,
+                                                     int provider_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  if (!GetContext()) {
+    Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
+        thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
+        base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix) +
+            base::ASCIIToUTF16(kShutdownErrorMessage)));
+    return;
+  }
+
+  ServiceWorkerProviderHost* provider_host =
+      GetContext()->GetProviderHost(render_process_id_, provider_id);
+  if (!provider_host) {
+    bad_message::ReceivedBadMessage(
+        this, bad_message::SWDH_GET_REGISTRATIONS_NO_HOST);
+    return;
+  }
+  if (!provider_host->IsContextAlive()) {
+    Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
+        thread_id, request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
+        base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix) +
+            base::ASCIIToUTF16(kShutdownErrorMessage)));
+    return;
+  }
+
+  // TODO(jungkees): This check can be removed once crbug.com/439697 is fixed.
+  if (provider_host->document_url().is_empty()) {
+    Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
+        thread_id, request_id, WebServiceWorkerError::ErrorTypeSecurity,
+        base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix) +
+            base::ASCIIToUTF16(kNoDocumentURLErrorMessage)));
+    return;
+  }
+
+  if (!OriginCanAccessServiceWorkers(provider_host->document_url())) {
+    bad_message::ReceivedBadMessage(
+        this, bad_message::SWDH_GET_REGISTRATIONS_INVALID_ORIGIN);
+    return;
+  }
+
+  if (!GetContentClient()->browser()->AllowServiceWorker(
+          provider_host->document_url(), provider_host->topmost_frame_url(),
+          resource_context_, render_process_id_, provider_host->frame_id())) {
+    Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
+        thread_id, request_id, WebServiceWorkerError::ErrorTypeUnknown,
+        base::ASCIIToUTF16(kServiceWorkerGetRegistrationsErrorPrefix) +
+            base::ASCIIToUTF16(kUserDeniedPermissionMessage)));
+    return;
+  }
+
+  if (GetContext()->storage()->IsDisabled()) {
+    SendGetRegistrationsError(thread_id, request_id,
+                              SERVICE_WORKER_ERROR_ABORT);
+    return;
+  }
+
+  TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
+                           "ServiceWorkerDispatcherHost::GetRegistrations",
+                           request_id);
+
+  GetContext()->storage()->GetRegistrationsForOrigin(
+      provider_host->document_url().GetOrigin(),
+      base::Bind(&ServiceWorkerDispatcherHost::GetRegistrationsComplete, this,
+                 thread_id, provider_id, request_id));
+}
+
 void ServiceWorkerDispatcherHost::OnGetRegistrationForReady(
     int thread_id,
     int request_id,
@@ -972,6 +1045,43 @@
       thread_id, request_id, info, attrs));
 }
 
+void ServiceWorkerDispatcherHost::GetRegistrationsComplete(
+    int thread_id,
+    int provider_id,
+    int request_id,
+    const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
+        registrations) {
+  TRACE_EVENT_ASYNC_END0("ServiceWorker",
+                         "ServiceWorkerDispatcherHost::GetRegistrations",
+                         request_id);
+  if (!GetContext())
+    return;
+
+  ServiceWorkerProviderHost* provider_host =
+      GetContext()->GetProviderHost(render_process_id_, provider_id);
+  if (!provider_host)
+    return;  // The provider has already been destroyed.
+
+  std::vector<ServiceWorkerRegistrationObjectInfo> object_infos;
+  std::vector<ServiceWorkerVersionAttributes> version_attrs;
+
+  for (const auto& registration : registrations) {
+    DCHECK(registration.get());
+    if (!registration->is_uninstalling()) {
+      ServiceWorkerRegistrationObjectInfo object_info;
+      ServiceWorkerVersionAttributes version_attr;
+      GetRegistrationObjectInfoAndVersionAttributes(
+          provider_host->AsWeakPtr(), registration.get(), &object_info,
+          &version_attr);
+      object_infos.push_back(object_info);
+      version_attrs.push_back(version_attr);
+    }
+  }
+
+  Send(new ServiceWorkerMsg_DidGetRegistrations(thread_id, request_id,
+                                                object_infos, version_attrs));
+}
+
 void ServiceWorkerDispatcherHost::GetRegistrationForReadyComplete(
     int thread_id,
     int request_id,
@@ -1037,6 +1147,20 @@
           error_message));
 }
 
+void ServiceWorkerDispatcherHost::SendGetRegistrationsError(
+    int thread_id,
+    int request_id,
+    ServiceWorkerStatusCode status) {
+  base::string16 error_message;
+  blink::WebServiceWorkerError::ErrorType error_type;
+  GetServiceWorkerRegistrationStatusResponse(status, std::string(), &error_type,
+                                             &error_message);
+  Send(new ServiceWorkerMsg_ServiceWorkerGetRegistrationsError(
+      thread_id, request_id, error_type,
+      base::ASCIIToUTF16(kServiceWorkerGetRegistrationErrorPrefix) +
+          error_message));
+}
+
 ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() {
   if (!context_wrapper_.get())
     return nullptr;
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index d121e6ba..6cca82ae1 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -29,6 +29,7 @@
 class ServiceWorkerRegistrationHandle;
 class ServiceWorkerVersion;
 struct ServiceWorkerObjectInfo;
+struct ServiceWorkerRegistrationInfo;
 struct ServiceWorkerRegistrationObjectInfo;
 struct ServiceWorkerVersionAttributes;
 struct TransferredMessagePort;
@@ -95,6 +96,7 @@
                          int request_id,
                          int provider_id,
                          const GURL& document_url);
+  void OnGetRegistrations(int thread_id, int request_id, int provider_id);
   void OnGetRegistrationForReady(int thread_id,
                                  int request_id,
                                  int provider_id);
@@ -160,6 +162,13 @@
       ServiceWorkerStatusCode status,
       const scoped_refptr<ServiceWorkerRegistration>& registration);
 
+  void GetRegistrationsComplete(
+      int thread_id,
+      int provider_id,
+      int request_id,
+      const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
+          registrations);
+
   void GetRegistrationForReadyComplete(
       int thread_id,
       int request_id,
@@ -179,6 +188,10 @@
                                 int request_id,
                                 ServiceWorkerStatusCode status);
 
+  void SendGetRegistrationsError(int thread_id,
+                                 int request_id,
+                                 ServiceWorkerStatusCode status);
+
   ServiceWorkerContextCore* GetContext();
 
   int render_process_id_;
diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index 1fdb416e..e2f2f7f6 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -129,6 +129,19 @@
     dispatcher_host_->ipc_sink()->ClearMessages();
   }
 
+  void SendGetRegistrations(int64 provider_id) {
+    dispatcher_host_->OnMessageReceived(
+        ServiceWorkerHostMsg_GetRegistrations(-1, -1, provider_id));
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void GetRegistrations(int64 provider_id, uint32 expected_message) {
+    SendGetRegistrations(provider_id);
+    EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching(
+        expected_message));
+    dispatcher_host_->ipc_sink()->ClearMessages();
+  }
+
   ServiceWorkerProviderHost* CreateServiceWorkerProviderHost(int provider_id) {
     return new ServiceWorkerProviderHost(
         kRenderProcessId, kRenderFrameId, provider_id,
@@ -177,6 +190,8 @@
   GetRegistration(kProviderId,
                   GURL("https://www.example.com/"),
                   ServiceWorkerMsg_ServiceWorkerGetRegistrationError::ID);
+  GetRegistrations(kProviderId,
+                   ServiceWorkerMsg_ServiceWorkerGetRegistrationsError::ID);
 
   SetBrowserClientForTesting(old_browser_client);
 }
@@ -494,6 +509,37 @@
                   ServiceWorkerMsg_ServiceWorkerGetRegistrationError::ID);
 }
 
+TEST_F(ServiceWorkerDispatcherHostTest, GetRegistrations_SecureOrigin) {
+  const int64 kProviderId = 99;  // Dummy value
+  scoped_ptr<ServiceWorkerProviderHost> host(
+      CreateServiceWorkerProviderHost(kProviderId));
+  host->SetDocumentUrl(GURL("https://www.example.com/foo"));
+  context()->AddProviderHost(host.Pass());
+
+  GetRegistrations(kProviderId, ServiceWorkerMsg_DidGetRegistrations::ID);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest,
+       GetRegistrations_NonSecureOriginShouldFail) {
+  const int64 kProviderId = 99;  // Dummy value
+  scoped_ptr<ServiceWorkerProviderHost> host(
+      CreateServiceWorkerProviderHost(kProviderId));
+  host->SetDocumentUrl(GURL("http://www.example.com/foo"));
+  context()->AddProviderHost(host.Pass());
+
+  SendGetRegistrations(kProviderId);
+  EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_);
+}
+
+TEST_F(ServiceWorkerDispatcherHostTest, GetRegistrations_EarlyContextDeletion) {
+  helper_->ShutdownContext();
+
+  // Let the shutdown reach the simulated IO thread.
+  base::RunLoop().RunUntilIdle();
+
+  GetRegistrations(-1, ServiceWorkerMsg_ServiceWorkerGetRegistrationsError::ID);
+}
+
 TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) {
   // Add a provider and worker.
   const int64 kProviderId = 99;  // Dummy value
diff --git a/content/browser/service_worker/service_worker_registration_status.cc b/content/browser/service_worker/service_worker_registration_status.cc
index cce28d7..65f269fd 100644
--- a/content/browser/service_worker/service_worker_registration_status.cc
+++ b/content/browser/service_worker/service_worker_registration_status.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/service_worker/service_worker_registration_status.h"
 
+#include <string>
+
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
 
@@ -30,6 +32,7 @@
     case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
     case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
     case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
+    case SERVICE_WORKER_ERROR_REDUNDANT:
       *error_type = WebServiceWorkerError::ErrorTypeInstall;
       return;
 
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc
index 4f71419..b0c59e03 100644
--- a/content/browser/service_worker/service_worker_storage.cc
+++ b/content/browser/service_worker/service_worker_storage.cc
@@ -460,38 +460,40 @@
 }
 
 void ServiceWorkerStorage::GetRegistrationsForOrigin(
-    const GURL& origin, const GetRegistrationsInfosCallback& callback) {
+    const GURL& origin,
+    const GetRegistrationsCallback& callback) {
   if (!LazyInitialize(base::Bind(
           &ServiceWorkerStorage::GetRegistrationsForOrigin,
           weak_factory_.GetWeakPtr(), origin, callback))) {
     if (state_ != INITIALIZING || !context_) {
-      RunSoon(FROM_HERE, base::Bind(
-          callback, std::vector<ServiceWorkerRegistrationInfo>()));
+      RunSoon(
+          FROM_HERE,
+          base::Bind(callback,
+                     std::vector<scoped_refptr<ServiceWorkerRegistration>>()));
     }
     return;
   }
   DCHECK_EQ(INITIALIZED, state_);
 
   RegistrationList* registrations = new RegistrationList;
+  std::vector<ResourceList>* resource_lists = new std::vector<ResourceList>;
   PostTaskAndReplyWithResult(
-      database_task_manager_->GetTaskRunner(),
-      FROM_HERE,
+      database_task_manager_->GetTaskRunner(), FROM_HERE,
       base::Bind(&ServiceWorkerDatabase::GetRegistrationsForOrigin,
-                 base::Unretained(database_.get()),
-                 origin,
-                 base::Unretained(registrations)),
+                 base::Unretained(database_.get()), origin,
+                 base::Unretained(registrations),
+                 base::Unretained(resource_lists)),
       base::Bind(&ServiceWorkerStorage::DidGetRegistrations,
-                 weak_factory_.GetWeakPtr(),
-                 callback,
-                 base::Owned(registrations),
+                 weak_factory_.GetWeakPtr(), callback,
+                 base::Owned(registrations), base::Owned(resource_lists),
                  origin));
 }
 
-void ServiceWorkerStorage::GetAllRegistrations(
+void ServiceWorkerStorage::GetAllRegistrationsInfos(
     const GetRegistrationsInfosCallback& callback) {
-  if (!LazyInitialize(base::Bind(
-          &ServiceWorkerStorage::GetAllRegistrations,
-          weak_factory_.GetWeakPtr(), callback))) {
+  if (!LazyInitialize(
+          base::Bind(&ServiceWorkerStorage::GetAllRegistrationsInfos,
+                     weak_factory_.GetWeakPtr(), callback))) {
     if (state_ != INITIALIZING || !context_) {
       RunSoon(FROM_HERE, base::Bind(
           callback, std::vector<ServiceWorkerRegistrationInfo>()));
@@ -502,16 +504,13 @@
 
   RegistrationList* registrations = new RegistrationList;
   PostTaskAndReplyWithResult(
-      database_task_manager_->GetTaskRunner(),
-      FROM_HERE,
+      database_task_manager_->GetTaskRunner(), FROM_HERE,
       base::Bind(&ServiceWorkerDatabase::GetAllRegistrations,
                  base::Unretained(database_.get()),
                  base::Unretained(registrations)),
-      base::Bind(&ServiceWorkerStorage::DidGetRegistrations,
-                 weak_factory_.GetWeakPtr(),
-                 callback,
-                 base::Owned(registrations),
-                 GURL()));
+      base::Bind(&ServiceWorkerStorage::DidGetRegistrationsInfos,
+                 weak_factory_.GetWeakPtr(), callback,
+                 base::Owned(registrations), GURL()));
 }
 
 void ServiceWorkerStorage::StoreRegistration(
@@ -1106,11 +1105,51 @@
 }
 
 void ServiceWorkerStorage::DidGetRegistrations(
-    const GetRegistrationsInfosCallback& callback,
-    RegistrationList* registrations,
+    const GetRegistrationsCallback& callback,
+    RegistrationList* registration_data_list,
+    std::vector<ResourceList>* resources_list,
     const GURL& origin_filter,
     ServiceWorkerDatabase::Status status) {
-  DCHECK(registrations);
+  DCHECK(registration_data_list);
+  DCHECK(resources_list);
+
+  if (status != ServiceWorkerDatabase::STATUS_OK &&
+      status != ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) {
+    ScheduleDeleteAndStartOver();
+    callback.Run(std::vector<scoped_refptr<ServiceWorkerRegistration>>());
+    return;
+  }
+
+  // Add all stored registrations.
+  std::set<int64> registration_ids;
+  std::vector<scoped_refptr<ServiceWorkerRegistration>> registrations;
+  size_t index = 0;
+  for (const auto& registration_data : *registration_data_list) {
+    registration_ids.insert(registration_data.registration_id);
+    registrations.push_back(GetOrCreateRegistration(
+        registration_data, resources_list->at(index++)));
+  }
+
+  // Add unstored registrations that are being installed.
+  for (RegistrationRefsById::const_iterator it =
+           installing_registrations_.begin();
+       it != installing_registrations_.end(); ++it) {
+    if ((!origin_filter.is_valid() ||
+         it->second->pattern().GetOrigin() == origin_filter) &&
+        registration_ids.insert(it->first).second) {
+      registrations.push_back((it->second).get());
+    }
+  }
+
+  callback.Run(registrations);
+}
+
+void ServiceWorkerStorage::DidGetRegistrationsInfos(
+    const GetRegistrationsInfosCallback& callback,
+    RegistrationList* registration_data_list,
+    const GURL& origin_filter,
+    ServiceWorkerDatabase::Status status) {
+  DCHECK(registration_data_list);
   if (status != ServiceWorkerDatabase::STATUS_OK &&
       status != ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) {
     ScheduleDeleteAndStartOver();
@@ -1121,7 +1160,7 @@
   // Add all stored registrations.
   std::set<int64> pushed_registrations;
   std::vector<ServiceWorkerRegistrationInfo> infos;
-  for (const auto& registration_data : *registrations) {
+  for (const auto& registration_data : *registration_data_list) {
     const bool inserted =
         pushed_registrations.insert(registration_data.registration_id).second;
     DCHECK(inserted);
@@ -1576,8 +1615,8 @@
 
   // TODO(nhiroki): Add convenient method to ServiceWorkerDatabase to check the
   // unique origin list.
-  std::vector<ServiceWorkerDatabase::RegistrationData> registrations;
-  status = database->GetRegistrationsForOrigin(origin, &registrations);
+  RegistrationList registrations;
+  status = database->GetRegistrationsForOrigin(origin, &registrations, nullptr);
   if (status != ServiceWorkerDatabase::STATUS_OK) {
     original_task_runner->PostTask(
         FROM_HERE,
@@ -1622,7 +1661,7 @@
   GURL origin = document_url.GetOrigin();
   RegistrationList registrations;
   ServiceWorkerDatabase::Status status =
-      database->GetRegistrationsForOrigin(origin, &registrations);
+      database->GetRegistrationsForOrigin(origin, &registrations, nullptr);
   if (status != ServiceWorkerDatabase::STATUS_OK) {
     original_task_runner->PostTask(
         FROM_HERE,
@@ -1659,9 +1698,9 @@
     const GURL& scope,
     const FindInDBCallback& callback) {
   GURL origin = scope.GetOrigin();
-  std::vector<ServiceWorkerDatabase::RegistrationData> registrations;
+  RegistrationList registrations;
   ServiceWorkerDatabase::Status status =
-      database->GetRegistrationsForOrigin(origin, &registrations);
+      database->GetRegistrationsForOrigin(origin, &registrations, nullptr);
   if (status != ServiceWorkerDatabase::STATUS_OK) {
     original_task_runner->PostTask(
         FROM_HERE,
diff --git a/content/browser/service_worker/service_worker_storage.h b/content/browser/service_worker/service_worker_storage.h
index 1bfa737..0b4e963 100644
--- a/content/browser/service_worker/service_worker_storage.h
+++ b/content/browser/service_worker/service_worker_storage.h
@@ -53,9 +53,11 @@
   typedef base::Callback<void(ServiceWorkerStatusCode status,
                               const scoped_refptr<ServiceWorkerRegistration>&
                                   registration)> FindRegistrationCallback;
-  typedef base::Callback<
-      void(const std::vector<ServiceWorkerRegistrationInfo>& registrations)>
-          GetRegistrationsInfosCallback;
+  typedef base::Callback<void(
+      const std::vector<scoped_refptr<ServiceWorkerRegistration>>&
+          registrations)> GetRegistrationsCallback;
+  typedef base::Callback<void(const std::vector<ServiceWorkerRegistrationInfo>&
+                                  registrations)> GetRegistrationsInfosCallback;
   typedef base::Callback<
       void(ServiceWorkerStatusCode status, bool are_equal)>
           CompareCallback;
@@ -109,13 +111,12 @@
 
   ServiceWorkerRegistration* GetUninstallingRegistration(const GURL& scope);
 
-  // Returns info about all stored and initially installing registrations for
-  // a given origin.
-  void GetRegistrationsForOrigin(
-      const GURL& origin, const GetRegistrationsInfosCallback& callback);
+  // Returns all stored registrations for a given origin.
+  void GetRegistrationsForOrigin(const GURL& origin,
+                                 const GetRegistrationsCallback& callback);
 
   // Returns info about all stored and initially installing registrations.
-  void GetAllRegistrations(const GetRegistrationsInfosCallback& callback);
+  void GetAllRegistrationsInfos(const GetRegistrationsInfosCallback& callback);
 
   // Commits |registration| with the installed but not activated |version|
   // to storage, overwritting any pre-existing registration data for the scope.
@@ -319,11 +320,15 @@
       const ServiceWorkerDatabase::RegistrationData& data,
       const ResourceList& resources,
       ServiceWorkerDatabase::Status status);
-  void DidGetRegistrations(
-      const GetRegistrationsInfosCallback& callback,
-      RegistrationList* registrations,
-      const GURL& origin_filter,
-      ServiceWorkerDatabase::Status status);
+  void DidGetRegistrations(const GetRegistrationsCallback& callback,
+                           RegistrationList* registration_data_list,
+                           std::vector<ResourceList>* resources_list,
+                           const GURL& origin_filter,
+                           ServiceWorkerDatabase::Status status);
+  void DidGetRegistrationsInfos(const GetRegistrationsInfosCallback& callback,
+                                RegistrationList* registration_data_list,
+                                const GURL& origin_filter,
+                                ServiceWorkerDatabase::Status status);
   void DidStoreRegistration(
       const StatusCallback& callback,
       const ServiceWorkerDatabase::RegistrationData& new_version,
diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc
index aa2ceb5..e6a444e3 100644
--- a/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -68,18 +68,33 @@
 
 void GetAllCallback(
     bool* was_called,
+    std::vector<scoped_refptr<ServiceWorkerRegistration>>* all_out,
+    const std::vector<scoped_refptr<ServiceWorkerRegistration>>& all) {
+  *was_called = true;
+  *all_out = all;
+}
+
+void GetAllInfosCallback(
+    bool* was_called,
     std::vector<ServiceWorkerRegistrationInfo>* all_out,
     const std::vector<ServiceWorkerRegistrationInfo>& all) {
   *was_called = true;
   *all_out = all;
 }
 
-ServiceWorkerStorage::GetRegistrationsInfosCallback
-MakeGetRegistrationsCallback(bool* was_called,
-                             std::vector<ServiceWorkerRegistrationInfo>* all) {
+ServiceWorkerStorage::GetRegistrationsCallback MakeGetRegistrationsCallback(
+    bool* was_called,
+    std::vector<scoped_refptr<ServiceWorkerRegistration>>* all) {
   return base::Bind(&GetAllCallback, was_called, all);
 }
 
+ServiceWorkerStorage::GetRegistrationsInfosCallback
+MakeGetRegistrationsInfosCallback(
+    bool* was_called,
+    std::vector<ServiceWorkerRegistrationInfo>* all) {
+  return base::Bind(&GetAllInfosCallback, was_called, all);
+}
+
 void GetUserDataCallback(
     bool* was_called,
     std::string* data_out,
@@ -329,11 +344,11 @@
     return result;
   }
 
-  void GetAllRegistrations(
+  void GetAllRegistrationsInfos(
       std::vector<ServiceWorkerRegistrationInfo>* registrations) {
     bool was_called = false;
-    storage()->GetAllRegistrations(
-        MakeGetRegistrationsCallback(&was_called, registrations));
+    storage()->GetAllRegistrationsInfos(
+        MakeGetRegistrationsInfosCallback(&was_called, registrations));
     EXPECT_FALSE(was_called);  // always async
     base::RunLoop().RunUntilIdle();
     EXPECT_TRUE(was_called);
@@ -341,11 +356,10 @@
 
   void GetRegistrationsForOrigin(
       const GURL& origin,
-      std::vector<ServiceWorkerRegistrationInfo>* registrations) {
+      std::vector<scoped_refptr<ServiceWorkerRegistration>>* registrations) {
     bool was_called = false;
     storage()->GetRegistrationsForOrigin(
-        origin,
-        MakeGetRegistrationsCallback(&was_called, registrations));
+        origin, MakeGetRegistrationsCallback(&was_called, registrations));
     EXPECT_FALSE(was_called);  // always async
     base::RunLoop().RunUntilIdle();
     EXPECT_TRUE(was_called);
@@ -579,22 +593,22 @@
   EXPECT_EQ(kResource1Size + kResource2Size,
             found_registration->resources_total_size_bytes());
   std::vector<ServiceWorkerRegistrationInfo> all_registrations;
-  GetAllRegistrations(&all_registrations);
+  GetAllRegistrationsInfos(&all_registrations);
   EXPECT_EQ(1u, all_registrations.size());
   ServiceWorkerRegistrationInfo info = all_registrations[0];
   EXPECT_EQ(kResource1Size + kResource2Size, info.stored_version_size_bytes);
   all_registrations.clear();
 
-  // Finding by origin should provide the same result iif origin is kScope.
-  std::vector<ServiceWorkerRegistrationInfo> registrations_origin;
-  GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_origin);
-  EXPECT_EQ(1u, registrations_origin.size());
-  registrations_origin.clear();
+  // Finding by origin should provide the same result if origin is kScope.
+  std::vector<scoped_refptr<ServiceWorkerRegistration>>
+      registrations_for_origin;
+  GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin);
+  EXPECT_EQ(1u, registrations_for_origin.size());
+  registrations_for_origin.clear();
 
-  GetRegistrationsForOrigin(
-      GURL("http://example.com/").GetOrigin(),
-      &registrations_origin);
-  EXPECT_TRUE(registrations_origin.empty());
+  GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
+                            &registrations_for_origin);
+  EXPECT_TRUE(registrations_for_origin.empty());
 
   found_registration = NULL;
 
@@ -685,7 +699,7 @@
   live_version->SetStatus(ServiceWorkerVersion::INSTALLING);
   live_registration->SetWaitingVersion(live_version);
 
-  // Should not be findable, including by GetAllRegistrations.
+  // Should not be findable, including by GetAllRegistrationsInfos.
   EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND,
             FindRegistrationForId(
                 kRegistrationId, kScope.GetOrigin(), &found_registration));
@@ -704,17 +718,17 @@
   EXPECT_FALSE(found_registration.get());
 
   std::vector<ServiceWorkerRegistrationInfo> all_registrations;
-  GetAllRegistrations(&all_registrations);
+  GetAllRegistrationsInfos(&all_registrations);
   EXPECT_TRUE(all_registrations.empty());
 
-  std::vector<ServiceWorkerRegistrationInfo> registrations_origin;
-  GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_origin);
-  EXPECT_TRUE(registrations_origin.empty());
+  std::vector<scoped_refptr<ServiceWorkerRegistration>>
+      registrations_for_origin;
+  GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin);
+  EXPECT_TRUE(registrations_for_origin.empty());
 
-  GetRegistrationsForOrigin(
-      GURL("http://example.com/").GetOrigin(),
-      &registrations_origin);
-  EXPECT_TRUE(registrations_origin.empty());
+  GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
+                            &registrations_for_origin);
+  EXPECT_TRUE(registrations_for_origin.empty());
 
   // Notify storage of it being installed.
   storage()->NotifyInstallingRegistration(live_registration.get());
@@ -741,19 +755,18 @@
   EXPECT_EQ(live_registration, found_registration);
   found_registration = NULL;
 
-  GetAllRegistrations(&all_registrations);
+  GetAllRegistrationsInfos(&all_registrations);
   EXPECT_EQ(1u, all_registrations.size());
   all_registrations.clear();
 
-  // Finding by origin should provide the same result iif origin is kScope.
-  GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_origin);
-  EXPECT_EQ(1u, registrations_origin.size());
-  registrations_origin.clear();
+  // Finding by origin should provide the same result if origin is kScope.
+  GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin);
+  EXPECT_EQ(1u, registrations_for_origin.size());
+  registrations_for_origin.clear();
 
-  GetRegistrationsForOrigin(
-      GURL("http://example.com/").GetOrigin(),
-      &registrations_origin);
-  EXPECT_TRUE(registrations_origin.empty());
+  GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
+                            &registrations_for_origin);
+  EXPECT_TRUE(registrations_for_origin.empty());
 
   // Notify storage of installation no longer happening.
   storage()->NotifyDoneInstallingRegistration(
@@ -777,16 +790,15 @@
             FindRegistrationForPattern(kScope, &found_registration));
   EXPECT_FALSE(found_registration.get());
 
-  GetAllRegistrations(&all_registrations);
+  GetAllRegistrationsInfos(&all_registrations);
   EXPECT_TRUE(all_registrations.empty());
 
-  GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_origin);
-  EXPECT_TRUE(registrations_origin.empty());
+  GetRegistrationsForOrigin(kScope.GetOrigin(), &registrations_for_origin);
+  EXPECT_TRUE(registrations_for_origin.empty());
 
-  GetRegistrationsForOrigin(
-      GURL("http://example.com/").GetOrigin(),
-      &registrations_origin);
-  EXPECT_TRUE(registrations_origin.empty());
+  GetRegistrationsForOrigin(GURL("http://example.com/").GetOrigin(),
+                            &registrations_for_origin);
+  EXPECT_TRUE(registrations_for_origin.empty());
 }
 
 TEST_F(ServiceWorkerStorageTest, StoreUserData) {
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc
index 17afffd..bd1abd9 100644
--- a/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -490,6 +490,9 @@
   if (status != SERVICE_WORKER_OK) {
     // TODO(falken): Add UMA and the report error to the version.
     if (is_main_resource_load_) {
+      // Using the service worker failed, so fallback to network. Detach the
+      // controller so subresource requests also skip the worker.
+      provider_host_->NotifyControllerLost();
       response_type_ = FALLBACK_TO_NETWORK;
       NotifyRestartRequired();
     } else {
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 2d709d0..302fb03 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -168,9 +168,9 @@
                                       helper_->context()->AsWeakPtr(),
                                       nullptr));
     provider_host->SetDocumentUrl(GURL("http://example.com/"));
+    registration_->SetActiveVersion(version_);
     provider_host->AssociateRegistration(registration_.get(),
                                          false /* notify_controllerchange */);
-    registration_->SetActiveVersion(version_);
 
     ChromeBlobStorageContext* chrome_blob_storage_context =
         ChromeBlobStorageContext::GetFor(browser_context_.get());
@@ -640,6 +640,10 @@
   EXPECT_EQ(200, request_->GetResponseCode());
   EXPECT_EQ("PASS", url_request_delegate_.response_data());
   EXPECT_FALSE(HasInflightRequests());
+  ServiceWorkerProviderHost* host =
+      helper_->context()->GetProviderHost(kProcessID, kProviderID);
+  ASSERT_TRUE(host);
+  EXPECT_EQ(host->controlling_version(), nullptr);
 }
 
 // TODO(horo): Remove this test when crbug.com/485900 is fixed.
diff --git a/content/browser/service_worker/service_worker_utils.cc b/content/browser/service_worker/service_worker_utils.cc
index 59748ee..7cfacceb 100644
--- a/content/browser/service_worker/service_worker_utils.cc
+++ b/content/browser/service_worker/service_worker_utils.cc
@@ -36,7 +36,7 @@
 bool ServiceWorkerUtils::ScopeMatches(const GURL& scope, const GURL& url) {
   DCHECK(!scope.has_ref());
   DCHECK(!url.has_ref());
-  return StartsWithASCII(url.spec(), scope.spec(), true);
+  return base::StartsWithASCII(url.spec(), scope.spec(), true);
 }
 
 // static
@@ -69,7 +69,7 @@
   }
 
   std::string scope_string = scope.path();
-  if (!StartsWithASCII(scope_string, max_scope_string, true)) {
+  if (!base::StartsWithASCII(scope_string, max_scope_string, true)) {
     *error_message = "The path of the provided scope ('";
     error_message->append(scope_string);
     error_message->append("') is not under the max scope allowed (");
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 9bca8eed..ff185072 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -555,11 +555,13 @@
     bool pause_after_download,
     const StatusCallback& callback) {
   if (!context_) {
+    RecordStartWorkerResult(SERVICE_WORKER_ERROR_ABORT);
     RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
     return;
   }
-  if (status_ == REDUNDANT) {
-    RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
+  if (is_redundant()) {
+    RecordStartWorkerResult(SERVICE_WORKER_ERROR_REDUNDANT);
+    RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_REDUNDANT));
     return;
   }
   prestart_status_ = status_;
@@ -643,6 +645,10 @@
     return;
   }
 
+  // TODO(kinuko): Cleanup this (and corresponding unit test) when message
+  // event becomes extendable, round-trip event. (crbug.com/498596)
+  RestartTick(&idle_time_);
+
   MessagePortMessageFilter* filter =
       embedded_worker_->message_port_message_filter();
   std::vector<int> new_routing_ids;
@@ -1703,8 +1709,8 @@
     return;
   }
   if (is_redundant()) {
-    RecordStartWorkerResult(SERVICE_WORKER_ERROR_NOT_FOUND);
-    RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
+    RecordStartWorkerResult(SERVICE_WORKER_ERROR_REDUNDANT);
+    RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_REDUNDANT));
     return;
   }
 
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index 8ec9bca..ebf14855 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/basictypes.h"
 #include "base/run_loop.h"
+#include "content/browser/message_port_service.h"
 #include "content/browser/service_worker/embedded_worker_registry.h"
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
@@ -117,6 +118,15 @@
   DISALLOW_COPY_AND_ASSIGN(MessageReceiverFromWorker);
 };
 
+void SetUpDummyMessagePort(std::vector<TransferredMessagePort>* ports) {
+  int port_id = -1;
+  MessagePortService::GetInstance()->Create(MSG_ROUTING_NONE, nullptr,
+                                            &port_id);
+  TransferredMessagePort dummy_port;
+  dummy_port.id = port_id;
+  ports->push_back(dummy_port);
+}
+
 }  // namespace
 
 class ServiceWorkerVersionTest : public testing::Test {
@@ -478,6 +488,20 @@
 
   EXPECT_EQ(SERVICE_WORKER_OK, status);
   EXPECT_LT(idle_time, version_->idle_time_);
+
+  // Dispatching a message event resets the idle time.
+  std::vector<TransferredMessagePort> ports;
+  SetUpDummyMessagePort(&ports);
+  status = SERVICE_WORKER_ERROR_FAILED;
+  version_->idle_time_ -= kOneSecond;
+  idle_time = version_->idle_time_;
+  version_->DispatchMessageEvent(base::string16(), ports,
+                                 CreateReceiverOnCurrentThread(&status));
+  base::RunLoop().RunUntilIdle();
+  MessagePortService::GetInstance()->Destroy(ports[0].id);
+
+  EXPECT_EQ(SERVICE_WORKER_OK, status);
+  EXPECT_LT(idle_time, version_->idle_time_);
 }
 
 TEST_F(ServiceWorkerVersionTest, SetDevToolsAttached) {
diff --git a/content/browser/session_history_browsertest.cc b/content/browser/session_history_browsertest.cc
index 2d81581..263d66d 100644
--- a/content/browser/session_history_browsertest.cc
+++ b/content/browser/session_history_browsertest.cc
@@ -28,7 +28,7 @@
 scoped_ptr<net::test_server::HttpResponse> HandleEchoTitleRequest(
     const std::string& echotitle_path,
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(request.relative_url, echotitle_path, true))
+  if (!base::StartsWithASCII(request.relative_url, echotitle_path, true))
     return scoped_ptr<net::test_server::HttpResponse>();
 
   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
diff --git a/content/browser/shared_worker/OWNERS b/content/browser/shared_worker/OWNERS
index 61fc3fd..63d62763 100644
--- a/content/browser/shared_worker/OWNERS
+++ b/content/browser/shared_worker/OWNERS
@@ -1,3 +1,2 @@
 atwilson@chromium.org
-kinuko@chromium.org
 horo@chromium.org
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 5930d83..f17d578b 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -341,12 +341,11 @@
 }
 
 void SiteInstanceImpl::LockToOrigin() {
-  // We currently only restrict this process to a particular site if the
-  // --enable-strict-site-isolation or --site-per-process flags are present.
+  // We currently only restrict this process to a particular site if --site-per-
+  // process flag is present.
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kEnableStrictSiteIsolation) ||
-      command_line.HasSwitch(switches::kSitePerProcess)) {
+  if (command_line.HasSwitch(switches::kSitePerProcess)) {
     ChildProcessSecurityPolicyImpl* policy =
         ChildProcessSecurityPolicyImpl::GetInstance();
     policy->LockToOrigin(process_->GetID(), site_);
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index ff32c384..4f90163b 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -567,13 +567,11 @@
 // Test to ensure that pages that require certain privileges are grouped
 // in processes with similar pages.
 TEST_F(SiteInstanceTest, ProcessSharingByType) {
-  // This test shouldn't run with --site-per-process or
-  // --enable-strict-site-isolation modes, since they don't allow render
-  // process reuse, which this test explicitly exercises.
+  // This test shouldn't run with --site-per-process mode, which prohibits
+  // the renderer process reuse this test explicitly exercises.
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kSitePerProcess) ||
-      command_line.HasSwitch(switches::kEnableStrictSiteIsolation))
+  if (command_line.HasSwitch(switches::kSitePerProcess))
     return;
 
   // On Android by default the number of renderer hosts is unlimited and process
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 39effd92..d404f130e 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -63,8 +63,6 @@
   }
 }
 
-}  // anonymous namespace
-
 class RedirectNotificationObserver : public NotificationObserver {
  public:
   // Register to listen for notifications of the given type from either a
@@ -244,6 +242,8 @@
   return false;
 }
 
+}  // namespace
+
 //
 // SitePerProcessBrowserTest
 //
@@ -563,8 +563,10 @@
       DepictFrameTree(root));
 }
 
+// TODO(creis): Fix and enable once initial subframe loads are fixed in Blink.
+// See https://crbug.com/498559.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       NavigateRemoteFrame) {
+                       DISABLED_NavigateRemoteFrame) {
   GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
   NavigateToURL(shell(), main_url);
 
@@ -618,17 +620,11 @@
             child->current_frame_host()->GetSiteInstance());
 }
 
-#if defined(OS_WIN)
-// http://crbug.com/465722
-#define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
-    DISABLED_NavigateRemoteFrameToBlankAndDataURLs
-#else
-#define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
-    NavigateRemoteFrameToBlankAndDataURLs
-#endif
-
+// TODO(creis): Fix and enable once initial subframe loads are fixed in Blink.
+// See https://crbug.com/498559.
+// Also disabled on Windows for https://crbug.com/465722.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       MAYBE_NavigateRemoteFrameToBlankAndDataURLs) {
+                       DISABLED_NavigateRemoteFrameToBlankAndDataURLs) {
   GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
   NavigateToURL(shell(), main_url);
 
@@ -1082,10 +1078,6 @@
 
   StartFrameAtDataURL();
 
-  // These must stay in scope with replace_host.
-  GURL::Replacements replace_host;
-  std::string foo_com("foo.com");
-
   // Load cross-site page into iframe.
   EXPECT_TRUE(NavigateIframeToURL(
       shell()->web_contents(), "test",
diff --git a/content/browser/tracing/background_tracing_manager_impl.cc b/content/browser/tracing/background_tracing_manager_impl.cc
index 7f4f15e..74d63800 100644
--- a/content/browser/tracing/background_tracing_manager_impl.cc
+++ b/content/browser/tracing/background_tracing_manager_impl.cc
@@ -5,6 +5,7 @@
 #include "content/browser/tracing/background_tracing_manager_impl.h"
 
 #include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
 #include "content/public/browser/background_tracing_preemptive_config.h"
 #include "content/public/browser/background_tracing_reactive_config.h"
@@ -20,6 +21,25 @@
 base::LazyInstance<BackgroundTracingManagerImpl>::Leaky g_controller =
     LAZY_INSTANCE_INITIALIZER;
 
+// These values are used for a histogram. Do not reorder.
+enum BackgroundTracingMetrics {
+  SCENARIO_ACTIVATION_REQUESTED = 0,
+  SCENARIO_ACTIVATED_SUCCESSFULLY = 1,
+  RECORDING_ENABLED = 2,
+  PREEMPTIVE_TRIGGERED = 3,
+  REACTIVE_TRIGGERED = 4,
+  FINALIZATION_ALLOWED = 5,
+  FINALIZATION_DISALLOWED = 6,
+  FINALIZATION_STARTED = 7,
+  FINALIZATION_COMPLETE = 8,
+  NUMBER_OF_BACKGROUND_TRACING_METRICS,
+};
+
+void RecordBackgroundTracingMetric(BackgroundTracingMetrics metric) {
+  UMA_HISTOGRAM_ENUMERATION("Tracing.Background.ScenarioState", metric,
+                            NUMBER_OF_BACKGROUND_TRACING_METRICS);
+}
+
 }  // namespace
 
 BackgroundTracingManagerImpl::TraceDataEndpointWrapper::
@@ -136,6 +156,8 @@
     const BackgroundTracingManager::ReceiveCallback& receive_callback,
     DataFiltering data_filtering) {
   CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  RecordBackgroundTracingMetric(SCENARIO_ACTIVATION_REQUESTED);
+
   if (is_tracing_)
     return false;
 
@@ -161,6 +183,7 @@
 
   EnableRecordingIfConfigNeedsIt();
 
+  RecordBackgroundTracingMetric(SCENARIO_ACTIVATED_SUCCESSFULLY);
   return true;
 }
 
@@ -253,8 +276,10 @@
   }
 
   if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
+    RecordBackgroundTracingMetric(PREEMPTIVE_TRIGGERED);
     BeginFinalizing(callback);
   } else {
+    RecordBackgroundTracingMetric(REACTIVE_TRIGGERED);
     if (is_tracing_) {
       tracing_timer_->CancelTimer();
       BeginFinalizing(callback);
@@ -334,12 +359,17 @@
 
   is_tracing_ = TracingController::GetInstance()->EnableRecording(
       trace_config, tracing_enabled_callback_for_testing_);
+  RecordBackgroundTracingMetric(RECORDING_ENABLED);
 }
 
 void BackgroundTracingManagerImpl::OnFinalizeStarted(
     scoped_refptr<base::RefCountedString> file_contents) {
   CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
+  RecordBackgroundTracingMetric(FINALIZATION_STARTED);
+  UMA_HISTOGRAM_MEMORY_KB("Tracing.Background.FinalizingTraceSizeInKB",
+                          file_contents->size() / 1024);
+
   if (!receive_callback_.is_null())
     receive_callback_.Run(
         file_contents,
@@ -365,6 +395,7 @@
 
   // Now that a trace has completed, we may need to enable recording again.
   EnableRecordingIfConfigNeedsIt();
+  RecordBackgroundTracingMetric(FINALIZATION_COMPLETE);
 }
 
 void BackgroundTracingManagerImpl::BeginFinalizing(
@@ -381,6 +412,9 @@
   if (is_allowed_finalization) {
     trace_data_sink = content::TracingController::CreateCompressedStringSink(
         data_endpoint_wrapper_);
+    RecordBackgroundTracingMetric(FINALIZATION_ALLOWED);
+  } else {
+    RecordBackgroundTracingMetric(FINALIZATION_DISALLOWED);
   }
 
   content::TracingController::GetInstance()->DisableRecording(trace_data_sink);
diff --git a/content/browser/tracing/file_tracing_provider_impl.cc b/content/browser/tracing/file_tracing_provider_impl.cc
index 21fcf07b..5406231b 100644
--- a/content/browser/tracing/file_tracing_provider_impl.cc
+++ b/content/browser/tracing/file_tracing_provider_impl.cc
@@ -32,24 +32,12 @@
 
 void FileTracingProviderImpl::FileTracingEventBegin(
     const char* name, void* id, const base::FilePath& path, int64 size) {
-  if (size) {
-    TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(kFileTracingEventCategoryGroup, name, id,
-        "path", path.AsUTF8Unsafe(), "size", size);
-  } else {
-    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(kFileTracingEventCategoryGroup, name, id,
-        "path", path.AsUTF8Unsafe());
-  }
+  TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(kFileTracingEventCategoryGroup, name, id,
+      "path", path.AsUTF8Unsafe(), "size", size);
 }
 
-void FileTracingProviderImpl::FileTracingEventEnd(
-    const char* name, void* id, const base::FilePath& path, int64 size) {
-  if (size) {
-    TRACE_EVENT_NESTABLE_ASYNC_END2(kFileTracingEventCategoryGroup, name, id,
-        "path", path.AsUTF8Unsafe(), "size", size);
-  } else {
-    TRACE_EVENT_NESTABLE_ASYNC_END1(kFileTracingEventCategoryGroup, name, id,
-        "path", path.AsUTF8Unsafe());
-  }
+void FileTracingProviderImpl::FileTracingEventEnd(const char* name, void* id) {
+  TRACE_EVENT_NESTABLE_ASYNC_END0(kFileTracingEventCategoryGroup, name, id);
 }
 
 }  // namespace content
diff --git a/content/browser/tracing/file_tracing_provider_impl.h b/content/browser/tracing/file_tracing_provider_impl.h
index e9daf958..ac67558 100644
--- a/content/browser/tracing/file_tracing_provider_impl.h
+++ b/content/browser/tracing/file_tracing_provider_impl.h
@@ -23,8 +23,7 @@
   void FileTracingDisable(void* id) override;
   void FileTracingEventBegin(const char* name, void* id,
                              const base::FilePath& path, int64 size) override;
-  void FileTracingEventEnd(const char* name, void* id,
-                           const base::FilePath& path, int64 size) override;
+  void FileTracingEventEnd(const char* name, void* id) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FileTracingProviderImpl);
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index 28642a4..e29425f5 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -432,6 +432,10 @@
   return true;
 }
 
+bool TracingControllerImpl::IsRecording() const {
+  return is_recording_;
+}
+
 void TracingControllerImpl::AddTraceMessageFilter(
     TraceMessageFilter* trace_message_filter) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h
index e1201902..fa31c7a 100644
--- a/content/browser/tracing/tracing_controller_impl.h
+++ b/content/browser/tracing/tracing_controller_impl.h
@@ -50,6 +50,7 @@
                      const std::string& event_name,
                      const WatchEventCallback& callback) override;
   bool CancelWatchEvent() override;
+  bool IsRecording() const override;
 
   void RegisterTracingUI(TracingUI* tracing_ui);
   void UnregisterTracingUI(TracingUI* tracing_ui);
diff --git a/content/browser/tracing/tracing_ui.cc b/content/browser/tracing/tracing_ui.cc
index c8a417e..8328330f 100644
--- a/content/browser/tracing/tracing_ui.cc
+++ b/content/browser/tracing/tracing_ui.cc
@@ -204,7 +204,7 @@
   }
 
   const char* beginRecordingPath = "json/begin_recording?";
-  if (StartsWithASCII(path, beginRecordingPath, true)) {
+  if (base::StartsWithASCII(path, beginRecordingPath, true)) {
     std::string data = path.substr(strlen(beginRecordingPath));
     return BeginRecording(data, callback);
   }
@@ -248,7 +248,7 @@
 
 bool OnTracingRequest(const std::string& path,
                       const WebUIDataSource::GotDataCallback& callback) {
-  if (StartsWithASCII(path, "json/", true)) {
+  if (base::StartsWithASCII(path, "json/", true)) {
     if (!OnBeginJSONRequest(path, callback)) {
       std::string error("##ERROR##");
       callback.Run(base::RefCountedString::TakeString(&error));
diff --git a/content/browser/web_contents/aura/overscroll_window_delegate.cc b/content/browser/web_contents/aura/overscroll_window_delegate.cc
index d8ce8b6..76aa5836 100644
--- a/content/browser/web_contents/aura/overscroll_window_delegate.cc
+++ b/content/browser/web_contents/aura/overscroll_window_delegate.cc
@@ -10,6 +10,7 @@
 #include "content/browser/renderer_host/overscroll_controller_delegate.h"
 #include "content/public/browser/overscroll_configuration.h"
 #include "ui/aura/window.h"
+#include "ui/events/event.h"
 #include "ui/gfx/image/image_png_rep.h"
 
 namespace content {
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 2ff1f95..a18923a 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -8,7 +8,9 @@
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/command_line.h"
+#include "base/containers/hash_tables.h"
 #include "base/json/json_writer.h"
+#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "content/browser/accessibility/browser_accessibility_android.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
@@ -42,6 +44,11 @@
 
 namespace {
 
+// Track all WebContentsAndroid objects here so that we don't deserialize a
+// destroyed WebContents object.
+base::LazyInstance<base::hash_set<WebContentsAndroid*> >::Leaky
+    g_allocated_web_contents_androids = LAZY_INSTANCE_INITIALIZER;
+
 void JavaScriptResultCallback(const ScopedJavaGlobalRef<jobject>& callback,
                               const base::Value* result) {
   JNIEnv* env = base::android::AttachCurrentThread();
@@ -152,6 +159,25 @@
 }
 
 // static
+jobject FromNativePtr(JNIEnv* env,
+                      jclass clazz,
+                      jlong web_contents_ptr) {
+  WebContentsAndroid* web_contents_android =
+      reinterpret_cast<WebContentsAndroid*>(web_contents_ptr);
+
+  if (!web_contents_android)
+    return 0;
+
+  // Check to make sure this object hasn't been destroyed.
+  if (g_allocated_web_contents_androids.Get().find(web_contents_android) ==
+      g_allocated_web_contents_androids.Get().end()) {
+    return 0;
+  }
+
+  return web_contents_android->GetJavaObject().Release();
+}
+
+// static
 bool WebContentsAndroid::Register(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
@@ -160,6 +186,7 @@
     : web_contents_(web_contents),
       navigation_controller_(&(web_contents->GetController())),
       weak_factory_(this) {
+  g_allocated_web_contents_androids.Get().insert(this);
   JNIEnv* env = AttachCurrentThread();
   obj_.Reset(env,
              Java_WebContentsImpl_create(
@@ -175,6 +202,9 @@
 }
 
 WebContentsAndroid::~WebContentsAndroid() {
+  DCHECK(g_allocated_web_contents_androids.Get().find(this) !=
+      g_allocated_web_contents_androids.Get().end());
+  g_allocated_web_contents_androids.Get().erase(this);
   Java_WebContentsImpl_clearNativePtr(AttachCurrentThread(), obj_.obj());
 }
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 378177e4..9647bc7 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -92,6 +92,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/page_zoom.h"
 #include "content/public/common/result_codes.h"
+#include "content/public/common/security_style.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
 #include "content/public/common/web_preferences.h"
@@ -207,15 +208,20 @@
 }  // namespace
 
 WebContents* WebContents::Create(const WebContents::CreateParams& params) {
-  return WebContentsImpl::CreateWithOpener(
-      params, static_cast<WebContentsImpl*>(params.opener));
+  FrameTreeNode* opener_node = nullptr;
+  if (params.opener_render_frame_id != MSG_ROUTING_NONE) {
+    RenderFrameHostImpl* opener_rfh = RenderFrameHostImpl::FromID(
+        params.opener_render_process_id, params.opener_render_frame_id);
+    if (opener_rfh)
+      opener_node = opener_rfh->frame_tree_node();
+  }
+  return WebContentsImpl::CreateWithOpener(params, opener_node);
 }
 
 WebContents* WebContents::CreateWithSessionStorage(
     const WebContents::CreateParams& params,
     const SessionStorageNamespaceMap& session_storage_namespace_map) {
-  WebContentsImpl* new_contents = new WebContentsImpl(
-      params.browser_context, NULL);
+  WebContentsImpl* new_contents = new WebContentsImpl(params.browser_context);
 
   for (SessionStorageNamespaceMap::const_iterator it =
            session_storage_namespace_map.begin();
@@ -291,13 +297,11 @@
 
 // WebContentsImpl -------------------------------------------------------------
 
-WebContentsImpl::WebContentsImpl(BrowserContext* browser_context,
-                                 WebContentsImpl* opener)
+WebContentsImpl::WebContentsImpl(BrowserContext* browser_context)
     : delegate_(NULL),
       controller_(this, browser_context),
       render_view_host_delegate_view_(NULL),
-      opener_(opener),
-      created_with_opener_(!!opener),
+      created_with_opener_(false),
 #if defined(OS_WIN)
       accessible_parent_(NULL),
 #endif
@@ -426,11 +430,17 @@
 
 WebContentsImpl* WebContentsImpl::CreateWithOpener(
     const WebContents::CreateParams& params,
-    WebContentsImpl* opener) {
+    FrameTreeNode* opener) {
   TRACE_EVENT0("browser", "WebContentsImpl::CreateWithOpener");
-  WebContentsImpl* new_contents = new WebContentsImpl(
-      params.browser_context, params.opener_suppressed ? NULL : opener);
+  WebContentsImpl* new_contents = new WebContentsImpl(params.browser_context);
 
+  if (!params.opener_suppressed && opener) {
+    new_contents->GetFrameTree()->root()->SetOpener(opener);
+    new_contents->created_with_opener_ = true;
+  }
+
+  // This may be true even when opener is null, such as when opening blocked
+  // popups.
   if (params.created_with_opener)
     new_contents->created_with_opener_ = true;
 
@@ -1173,11 +1183,12 @@
 
 WebContents* WebContentsImpl::Clone() {
   // We use our current SiteInstance since the cloned entry will use it anyway.
-  // We pass our own opener so that the cloned page can access it if it was
+  // We pass our own opener so that the cloned page can access it if it was set
   // before.
   CreateParams create_params(GetBrowserContext(), GetSiteInstance());
   create_params.initial_size = GetContainerBounds().size();
-  WebContentsImpl* tc = CreateWithOpener(create_params, opener_);
+  WebContentsImpl* tc =
+      CreateWithOpener(create_params, frame_tree_.root()->opener());
   tc->GetController().CopyStateFrom(controller_);
   FOR_EACH_OBSERVER(WebContentsObserver,
                     observers_,
@@ -1258,10 +1269,6 @@
   gfx::Size initial_size = params.initial_size;
   view_->CreateView(initial_size, params.context);
 
-  // Listen for whether our opener gets destroyed.
-  if (opener_)
-    AddDestructionObserver(opener_);
-
 #if defined(ENABLE_PLUGINS)
   plugin_content_origin_whitelist_.reset(
       new PluginContentOriginWhitelist(this));
@@ -1308,11 +1315,6 @@
 void WebContentsImpl::OnWebContentsDestroyed(WebContentsImpl* web_contents) {
   RemoveDestructionObserver(web_contents);
 
-  // Clear the opener if it has been closed.
-  if (web_contents == opener_) {
-    opener_ = NULL;
-    return;
-  }
   // Clear a pending contents that has been closed before being shown.
   for (PendingContents::iterator iter = pending_contents_.begin();
        iter != pending_contents_.end();
@@ -1614,7 +1616,8 @@
   create_params.routing_id = route_id;
   create_params.main_frame_routing_id = main_frame_route_id;
   create_params.main_frame_name = base::UTF16ToUTF8(params.frame_name);
-  create_params.opener = this;
+  create_params.opener_render_process_id = GetRenderProcessHost()->GetID();
+  create_params.opener_render_frame_id = params.opener_render_frame_id;
   create_params.opener_suppressed = params.opener_suppressed;
   if (params.disposition == NEW_BACKGROUND_TAB)
     create_params.initially_hidden = true;
@@ -2484,11 +2487,12 @@
 }
 
 bool WebContentsImpl::HasOpener() const {
-  return opener_ != NULL;
+  return GetOpener() != NULL;
 }
 
-WebContents* WebContentsImpl::GetOpener() const {
-  return static_cast<WebContents*>(opener_);
+WebContentsImpl* WebContentsImpl::GetOpener() const {
+  FrameTreeNode* opener_ftn = frame_tree_.root()->opener();
+  return opener_ftn ? FromFrameTreeNode(opener_ftn) : nullptr;
 }
 
 void WebContentsImpl::DidChooseColorInColorChooser(SkColor color) {
@@ -3221,8 +3225,13 @@
 }
 
 void WebContentsImpl::DidChangeVisibleSSLState() {
-  if (delegate_)
+  if (delegate_) {
     delegate_->VisibleSSLStateChanged(this);
+
+    content::SecurityStyle security_style = delegate_->GetSecurityStyle(this);
+    FOR_EACH_OBSERVER(WebContentsObserver, observers_,
+                      SecurityStyleChanged(security_style));
+  }
 }
 
 void WebContentsImpl::NotifyBeforeFormRepostWarningShow() {
@@ -3594,6 +3603,13 @@
   if (GetRenderManager()->pending_web_ui())
     GetRenderManager()->pending_web_ui()->RenderViewCreated(render_view_host);
 
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableBrowserSideNavigation) &&
+      GetRenderManager()->speculative_web_ui()) {
+    GetRenderManager()->speculative_web_ui()->RenderViewCreated(
+        render_view_host);
+  }
+
   NavigationEntry* entry = controller_.GetPendingEntry();
   if (entry && entry->IsViewSourceMode()) {
     // Put the renderer in view source mode.
@@ -3842,22 +3858,6 @@
                     FrameNameChanged(render_frame_host, name));
 }
 
-void WebContentsImpl::DidDisownOpener(RenderFrameHost* render_frame_host) {
-  // No action is necessary if the opener has already been cleared.
-  if (!opener_)
-    return;
-
-  // Clear our opener so that future cross-process navigations don't have an
-  // opener assigned.
-  RemoveDestructionObserver(opener_);
-  opener_ = NULL;
-
-  // Notify all swapped out RenderViewHosts for this tab.  This is important
-  // in case we go back to them, or if another window in those processes tries
-  // to access window.opener.
-  GetRenderManager()->DidDisownOpener(render_frame_host);
-}
-
 void WebContentsImpl::DocumentOnLoadCompleted(
     RenderFrameHost* render_frame_host) {
   FOR_EACH_OBSERVER(WebContentsObserver, observers_,
@@ -4134,11 +4134,12 @@
 
 int WebContentsImpl::CreateOpenerRenderViewsForRenderManager(
     SiteInstance* instance) {
-  if (!opener_)
+  WebContentsImpl* opener = GetOpener();
+  if (!opener)
     return MSG_ROUTING_NONE;
 
   // Recursively create RenderViews for anything else in the opener chain.
-  return opener_->CreateOpenerRenderViews(instance);
+  return opener->CreateOpenerRenderViews(instance);
 }
 
 int WebContentsImpl::CreateOpenerRenderViews(SiteInstance* instance) {
@@ -4146,8 +4147,9 @@
 
   // If this tab has an opener, ensure it has a RenderView in the given
   // SiteInstance as well.
-  if (opener_)
-    opener_route_id = opener_->CreateOpenerRenderViews(instance);
+  WebContentsImpl* opener = GetOpener();
+  if (opener)
+    opener_route_id = opener->CreateOpenerRenderViews(instance);
 
   // If any of the renderers (current, pending, or swapped out) for this
   // WebContents has the same SiteInstance, use it.
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index bffa888..005b591 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -105,16 +105,12 @@
 
   static WebContentsImpl* CreateWithOpener(
       const WebContents::CreateParams& params,
-      WebContentsImpl* opener);
+      FrameTreeNode* opener);
 
   static std::vector<WebContentsImpl*> GetAllWebContents();
 
   static WebContentsImpl* FromFrameTreeNode(FrameTreeNode* frame_tree_node);
 
-  // Returns the opener WebContentsImpl, if any. This can be set to null if the
-  // opener is closed or the page clears its window.opener.
-  WebContentsImpl* opener() const { return opener_; }
-
   // Creates a swapped out RenderView. This is used by the browser plugin to
   // create a swapped out RenderView in the embedder render process for the
   // guest, to expose the guest's window object to the embedder.
@@ -345,7 +341,7 @@
   gfx::Size GetPreferredSize() const override;
   bool GotResponseToLockMouseRequest(bool allowed) override;
   bool HasOpener() const override;
-  WebContents* GetOpener() const override;
+  WebContentsImpl* GetOpener() const override;
   void DidChooseColorInColorChooser(SkColor color) override;
   void DidEndColorChooser() override;
   int DownloadImage(const GURL& url,
@@ -400,7 +396,6 @@
   void DidAccessInitialDocument() override;
   void DidChangeName(RenderFrameHost* render_frame_host,
                      const std::string& name) override;
-  void DidDisownOpener(RenderFrameHost* render_frame_host) override;
   void DocumentOnLoadCompleted(RenderFrameHost* render_frame_host) override;
   void UpdateTitle(RenderFrameHost* render_frame_host,
                    int32 page_id,
@@ -731,8 +726,7 @@
   class DestructionObserver;
 
   // See WebContents::Create for a description of these parameters.
-  WebContentsImpl(BrowserContext* browser_context,
-                  WebContentsImpl* opener);
+  WebContentsImpl(BrowserContext* browser_context);
 
   // Add and remove observers for page navigation notifications. The order in
   // which notifications are sent to observers is undefined. Clients must be
@@ -740,7 +734,7 @@
   void AddObserver(WebContentsObserver* observer);
   void RemoveObserver(WebContentsObserver* observer);
 
-  // Clears this tab's opener if it has been closed.
+  // Clears a pending contents that has been closed before being shown.
   void OnWebContentsDestroyed(WebContentsImpl* web_contents);
 
   // Creates and adds to the map a destruction observer watching |web_contents|.
@@ -1018,10 +1012,6 @@
   // the observer list then.
   base::ObserverList<WebContentsObserver> observers_;
 
-  // The tab that opened this tab, if any.  Will be set to null if the opener
-  // is closed.
-  WebContentsImpl* opener_;
-
   // True if this tab was opened by another tab. This is not unset if the opener
   // is closed.
   bool created_with_opener_;
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h
index f184fb2..9e517cf 100644
--- a/content/browser/web_contents/web_contents_view_aura.h
+++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "content/browser/renderer_host/overscroll_controller_delegate.h"
@@ -160,6 +161,8 @@
   // Update the web contents visiblity.
   void UpdateWebContentsVisibility(bool visible);
 
+  FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, EnableDisableOverscroll);
+
   scoped_ptr<aura::Window> window_;
 
   scoped_ptr<WindowObserver> window_observer_;
diff --git a/content/browser/web_contents/web_contents_view_aura_unittest.cc b/content/browser/web_contents/web_contents_view_aura_unittest.cc
new file mode 100644
index 0000000..504ac2b
--- /dev/null
+++ b/content/browser/web_contents/web_contents_view_aura_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/web_contents/web_contents_view_aura.h"
+
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class WebContentsViewAuraTest : public RenderViewHostTestHarness {
+ public:
+  WebContentsViewAuraTest() {}
+  ~WebContentsViewAuraTest() override {}
+
+  WebContentsViewAura* view() {
+    WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents());
+    return static_cast<WebContentsViewAura*>(contents->GetView());
+  }
+};
+
+TEST_F(WebContentsViewAuraTest, EnableDisableOverscroll) {
+  WebContentsViewAura* wcva = view();
+  wcva->SetOverscrollControllerEnabled(false);
+  EXPECT_FALSE(wcva->navigation_overlay_);
+  wcva->SetOverscrollControllerEnabled(true);
+  EXPECT_TRUE(wcva->navigation_overlay_);
+}
+
+}  // namespace content
diff --git a/content/browser/webui/shared_resources_data_source.cc b/content/browser/webui/shared_resources_data_source.cc
index e990648..56c341a0 100644
--- a/content/browser/webui/shared_resources_data_source.cc
+++ b/content/browser/webui/shared_resources_data_source.cc
@@ -48,7 +48,7 @@
     const int resource_id = kWebuiResources[i].value;
     AddResource(resource_name, resource_id, result);
     for (const char* (&alias)[2]: kPathAliases) {
-      if (StartsWithASCII(resource_name, alias[0], true)) {
+      if (base::StartsWithASCII(resource_name, alias[0], true)) {
         AddResource(alias[1] + resource_name.substr(strlen(alias[0])),
                     resource_id, result);
       }
diff --git a/content/browser/webui/web_ui_mojo_browsertest.cc b/content/browser/webui/web_ui_mojo_browsertest.cc
index 2b2f50af..f41c6e2c 100644
--- a/content/browser/webui/web_ui_mojo_browsertest.cc
+++ b/content/browser/webui/web_ui_mojo_browsertest.cc
@@ -21,6 +21,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/service_registry.h"
 #include "content/public/common/url_utils.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
@@ -140,7 +141,7 @@
                                                const GURL& url) const override {
     if (url.query() == "ping")
       return new PingTestWebUIController(web_ui, run_loop_);
-    return NULL;
+    return new TestWebUIController(web_ui, run_loop_);
   }
   WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
                              const GURL& url) const override {
@@ -179,20 +180,25 @@
   DISALLOW_COPY_AND_ASSIGN(WebUIMojoTest);
 };
 
-// Loads a webui page that contains mojo bindings and verifies a message makes
-// it from the browser to the page and back.
-IN_PROC_BROWSER_TEST_F(WebUIMojoTest, EndToEndPing) {
+bool IsGeneratedResourceAvailable(const std::string& resource_path) {
   // Currently there is no way to have a generated file included in the isolate
   // files. If the bindings file doesn't exist assume we're on such a bot and
   // pass.
   // TODO(sky): remove this conditional when isolates support copying from gen.
   const base::FilePath test_file_path(
-      mojo::test::GetFilePathForJSResource(
-          "content/test/data/web_ui_test_mojo_bindings.mojom"));
-  if (!base::PathExists(test_file_path)) {
-    LOG(WARNING) << " mojom binding file doesn't exist, assuming on isolate";
+      mojo::test::GetFilePathForJSResource(resource_path));
+  if (base::PathExists(test_file_path))
+    return true;
+  LOG(WARNING) << " mojom binding file doesn't exist, assuming on isolate";
+  return false;
+}
+
+// Loads a webui page that contains mojo bindings and verifies a message makes
+// it from the browser to the page and back.
+IN_PROC_BROWSER_TEST_F(WebUIMojoTest, EndToEndPing) {
+  if (!IsGeneratedResourceAvailable(
+          "content/test/data/web_ui_test_mojo_bindings.mojom"))
     return;
-  }
 
   got_message = false;
   ASSERT_TRUE(test_server()->Start());
@@ -218,5 +224,22 @@
             other_shell->web_contents()->GetRenderProcessHost());
 }
 
+// Loads a webui page that connects to a test Mojo application via the browser's
+// Mojo shell interface.
+IN_PROC_BROWSER_TEST_F(WebUIMojoTest, ConnectToApplication) {
+  if (!IsGeneratedResourceAvailable(
+          "content/public/test/test_mojo_service.mojom"))
+    return;
+
+  ASSERT_TRUE(test_server()->Start());
+  NavigateToURL(shell(),
+                test_server()->GetURL("files/web_ui_mojo_shell_test.html"));
+
+  DOMMessageQueue message_queue;
+  std::string message;
+  ASSERT_TRUE(message_queue.WaitForMessage(&message));
+  EXPECT_EQ("true", message);
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/child/appcache/web_application_cache_host_impl.cc b/content/child/appcache/web_application_cache_host_impl.cc
index bf110b1..c7328b3 100644
--- a/content/child/appcache/web_application_cache_host_impl.cc
+++ b/content/child/appcache/web_application_cache_host_impl.cc
@@ -167,7 +167,7 @@
 
   std::string method = request.httpMethod().utf8();
   is_get_method_ = (method == kHttpGETMethod);
-  DCHECK(method == StringToUpperASCII(method));
+  DCHECK(method == base::StringToUpperASCII(method));
 
   const WebApplicationCacheHostImpl* spawning_host_impl =
       static_cast<const WebApplicationCacheHostImpl*>(spawning_host);
diff --git a/content/child/assert_matching_enums.cc b/content/child/assert_matching_enums.cc
index 0fc87bf..c211ee15 100644
--- a/content/child/assert_matching_enums.cc
+++ b/content/child/assert_matching_enums.cc
@@ -11,7 +11,7 @@
 #include "media/base/mime_util.h"
 #include "third_party/WebKit/public/platform/WebCompositorAnimation.h"
 #include "third_party/WebKit/public/platform/WebMimeRegistry.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 
 namespace content {
 
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index 5c01528..78939bb0 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -531,8 +531,7 @@
   // through non-network schemes that don't go over the network.
   if (!gurl.has_port())
     return true;
-  return net::IsPortAllowedForScheme(gurl.EffectiveIntPort(), gurl.scheme(),
-                                     net::PORT_OVERRIDES_ALLOWED);
+  return net::IsPortAllowedForScheme(gurl.EffectiveIntPort(), gurl.scheme());
 }
 
 blink::WebThread* BlinkPlatformImpl::createThread(const char* name) {
@@ -1027,8 +1026,8 @@
     return WebData();
 
   // Check the name prefix to see if it's an audio resource.
-  if (StartsWithASCII(name, "IRC_Composite", true) ||
-      StartsWithASCII(name, "Composite", true))
+  if (base::StartsWithASCII(name, "IRC_Composite", true) ||
+      base::StartsWithASCII(name, "Composite", true))
     return loadAudioSpatializationResource(name);
 
   // TODO(flackr): We should use a better than linear search here, a trie would
diff --git a/content/child/bluetooth/bluetooth_dispatcher.cc b/content/child/bluetooth/bluetooth_dispatcher.cc
index 40e5bef0..7435825 100644
--- a/content/child/bluetooth/bluetooth_dispatcher.cc
+++ b/content/child/bluetooth/bluetooth_dispatcher.cc
@@ -12,12 +12,14 @@
 #include "content/common/bluetooth/bluetooth_messages.h"
 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h"
 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h"
+#include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTCharacteristic.h"
 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h"
 #include "third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTService.h"
 
 using blink::WebBluetoothConnectGATTCallbacks;
 using blink::WebBluetoothDevice;
 using blink::WebBluetoothError;
+using blink::WebBluetoothGATTCharacteristic;
 using blink::WebBluetoothGATTRemoteServer;
 using blink::WebBluetoothGATTService;
 using blink::WebBluetoothRequestDeviceCallbacks;
@@ -39,6 +41,21 @@
   scoped_ptr<blink::WebBluetoothGetPrimaryServiceCallbacks> callbacks;
 };
 
+struct BluetoothCharacteristicRequest {
+  BluetoothCharacteristicRequest(
+      blink::WebString service_instance_id,
+      blink::WebString characteristic_uuid,
+      blink::WebBluetoothGetCharacteristicCallbacks* callbacks)
+      : service_instance_id(service_instance_id),
+        characteristic_uuid(characteristic_uuid),
+        callbacks(callbacks) {}
+  ~BluetoothCharacteristicRequest() {}
+
+  blink::WebString service_instance_id;
+  blink::WebString characteristic_uuid;
+  scoped_ptr<blink::WebBluetoothGetCharacteristicCallbacks> callbacks;
+};
+
 namespace content {
 
 namespace {
@@ -123,6 +140,10 @@
                       OnGetPrimaryServiceSuccess);
   IPC_MESSAGE_HANDLER(BluetoothMsg_GetPrimaryServiceError,
                       OnGetPrimaryServiceError);
+  IPC_MESSAGE_HANDLER(BluetoothMsg_GetCharacteristicSuccess,
+                      OnGetCharacteristicSuccess);
+  IPC_MESSAGE_HANDLER(BluetoothMsg_GetCharacteristicError,
+                      OnGetCharacteristicError);
   IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   DCHECK(handled) << "Unhandled message:" << msg.type();
@@ -154,6 +175,18 @@
                                               service_uuid.utf8()));
 }
 
+void BluetoothDispatcher::getCharacteristic(
+    const blink::WebString& service_instance_id,
+    const blink::WebString& characteristic_uuid,
+    blink::WebBluetoothGetCharacteristicCallbacks* callbacks) {
+  int request_id =
+      pending_characteristic_requests_.Add(new BluetoothCharacteristicRequest(
+          service_instance_id, characteristic_uuid, callbacks));
+  Send(new BluetoothHostMsg_GetCharacteristic(CurrentWorkerId(), request_id,
+                                              service_instance_id.utf8(),
+                                              characteristic_uuid.utf8()));
+}
+
 void BluetoothDispatcher::OnWorkerRunLoopStopped() {
   delete this;
 }
@@ -248,4 +281,40 @@
   pending_primary_service_requests_.Remove(request_id);
 }
 
+void BluetoothDispatcher::OnGetCharacteristicSuccess(
+    int thread_id,
+    int request_id,
+    const std::string& characteristic_instance_id) {
+  DCHECK(pending_characteristic_requests_.Lookup(request_id)) << request_id;
+
+  BluetoothCharacteristicRequest* request =
+      pending_characteristic_requests_.Lookup(request_id);
+  request->callbacks->onSuccess(new WebBluetoothGATTCharacteristic(
+      WebString::fromUTF8(characteristic_instance_id),
+      request->service_instance_id, request->characteristic_uuid));
+
+  pending_characteristic_requests_.Remove(request_id);
+}
+
+void BluetoothDispatcher::OnGetCharacteristicError(int thread_id,
+                                                   int request_id,
+                                                   BluetoothError error_type) {
+  DCHECK(pending_characteristic_requests_.Lookup(request_id)) << request_id;
+
+  // Since we couldn't find the characteristic return null. See Step 3 of
+  // getCharacteristic algorithm:
+  // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothgattservice-getcharacteristic
+  if (error_type == BluetoothError::NOT_FOUND) {
+    pending_characteristic_requests_.Lookup(request_id)
+        ->callbacks->onSuccess(nullptr);
+  } else {
+    pending_characteristic_requests_.Lookup(request_id)
+        ->callbacks->onError(new WebBluetoothError(
+            // TODO(ortuno): Return more descriptive error messages.
+            // http://crbug.com/490419
+            WebBluetoothErrorFromBluetoothError(error_type), ""));
+  }
+  pending_characteristic_requests_.Remove(request_id);
+}
+
 }  // namespace content
diff --git a/content/child/bluetooth/bluetooth_dispatcher.h b/content/child/bluetooth/bluetooth_dispatcher.h
index 94a20af..1e1e9e4 100644
--- a/content/child/bluetooth/bluetooth_dispatcher.h
+++ b/content/child/bluetooth/bluetooth_dispatcher.h
@@ -21,6 +21,7 @@
 class Message;
 }
 
+struct BluetoothCharacteristicRequest;
 struct BluetoothPrimaryServiceRequest;
 
 namespace content {
@@ -57,6 +58,11 @@
       const blink::WebString& service_uuid,
       blink::WebBluetoothGetPrimaryServiceCallbacks* callbacks);
 
+  void getCharacteristic(
+      const blink::WebString& service_instance_id,
+      const blink::WebString& characteristic_uuid,
+      blink::WebBluetoothGetCharacteristicCallbacks* callbacks);
+
   // WorkerTaskRunner::Observer implementation.
   void OnWorkerRunLoopStopped() override;
 
@@ -82,6 +88,13 @@
   void OnGetPrimaryServiceError(int thread_id,
                                 int request_id,
                                 BluetoothError error_type);
+  void OnGetCharacteristicSuccess(
+      int thread_id,
+      int request_id,
+      const std::string& characteristic_instance_id);
+  void OnGetCharacteristicError(int thread_id,
+                                int request_id,
+                                BluetoothError error_type);
 
   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
 
@@ -97,6 +110,9 @@
   // Owns request objects.
   IDMap<BluetoothPrimaryServiceRequest, IDMapOwnPointer>
       pending_primary_service_requests_;
+  // Tracks requests to get a characteristic from a service.
+  IDMap<BluetoothCharacteristicRequest, IDMapOwnPointer>
+      pending_characteristic_requests_;
 
   DISALLOW_COPY_AND_ASSIGN(BluetoothDispatcher);
 };
diff --git a/content/child/bluetooth/web_bluetooth_impl.cc b/content/child/bluetooth/web_bluetooth_impl.cc
index 4264efd..02de7552 100644
--- a/content/child/bluetooth/web_bluetooth_impl.cc
+++ b/content/child/bluetooth/web_bluetooth_impl.cc
@@ -34,6 +34,14 @@
                                      callbacks);
 }
 
+void WebBluetoothImpl::getCharacteristic(
+    const blink::WebString& service_instance_id,
+    const blink::WebString& characteristic_uuid,
+    blink::WebBluetoothGetCharacteristicCallbacks* callbacks) {
+  GetDispatcher()->getCharacteristic(service_instance_id, characteristic_uuid,
+                                     callbacks);
+}
+
 BluetoothDispatcher* WebBluetoothImpl::GetDispatcher() {
   return BluetoothDispatcher::GetOrCreateThreadSpecificInstance(
       thread_safe_sender_.get());
diff --git a/content/child/bluetooth/web_bluetooth_impl.h b/content/child/bluetooth/web_bluetooth_impl.h
index 3687f47..89628d2 100644
--- a/content/child/bluetooth/web_bluetooth_impl.h
+++ b/content/child/bluetooth/web_bluetooth_impl.h
@@ -28,14 +28,16 @@
   // blink::WebBluetooth interface:
   void requestDevice(
       blink::WebBluetoothRequestDeviceCallbacks* callbacks) override;
-
   void connectGATT(const blink::WebString& device_instance_id,
       blink::WebBluetoothConnectGATTCallbacks* callbacks) override;
-
   void getPrimaryService(
       const blink::WebString& device_instance_id,
       const blink::WebString& service_uuid,
       blink::WebBluetoothGetPrimaryServiceCallbacks* callbacks) override;
+  void getCharacteristic(
+      const blink::WebString& service_instance_id,
+      const blink::WebString& characteristic_uuid,
+      blink::WebBluetoothGetCharacteristicCallbacks* callbacks) override;
 
  private:
   BluetoothDispatcher* GetDispatcher();
diff --git a/content/child/child_gpu_memory_buffer_manager.cc b/content/child/child_gpu_memory_buffer_manager.cc
index 0e1c312ad..5513e59 100644
--- a/content/child/child_gpu_memory_buffer_manager.cc
+++ b/content/child/child_gpu_memory_buffer_manager.cc
@@ -44,17 +44,15 @@
   IPC::Message* message = new ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer(
       size.width(), size.height(), format, usage, &handle);
   bool success = sender_->Send(message);
-  if (!success)
-    return scoped_ptr<gfx::GpuMemoryBuffer>();
+  if (!success || handle.is_null())
+    return nullptr;
 
   scoped_ptr<GpuMemoryBufferImpl> buffer(GpuMemoryBufferImpl::CreateFromHandle(
-      handle,
-      size,
-      format,
+      handle, size, format, usage,
       base::Bind(&DeletedGpuMemoryBuffer, sender_, handle.id)));
   if (!buffer) {
     sender_->Send(new ChildProcessHostMsg_DeletedGpuMemoryBuffer(handle.id, 0));
-    return scoped_ptr<gfx::GpuMemoryBuffer>();
+    return nullptr;
   }
 
   return buffer.Pass();
diff --git a/content/child/child_thread_impl_browsertest.cc b/content/child/child_thread_impl_browsertest.cc
index 4a37196..d35cc4a4 100644
--- a/content/child/child_thread_impl_browsertest.cc
+++ b/content/child/child_thread_impl_browsertest.cc
@@ -8,7 +8,9 @@
 #include "base/memory/scoped_vector.h"
 #include "base/time/time.h"
 #include "content/child/child_discardable_shared_memory_manager.h"
+#include "content/child/child_gpu_memory_buffer_manager.h"
 #include "content/child/child_thread_impl.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
 #include "content/common/host_discardable_shared_memory_manager.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/content_browser_test.h"
@@ -17,11 +19,13 @@
 #include "url/gurl.h"
 
 namespace content {
+namespace {
 
 class ChildThreadImplBrowserTest : public ContentBrowserTest {
  public:
   ChildThreadImplBrowserTest()
-      : child_discardable_shared_memory_manager_(nullptr) {}
+      : child_gpu_memory_buffer_manager_(nullptr),
+        child_discardable_shared_memory_manager_(nullptr) {}
 
   // Overridden from BrowserTestBase:
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -33,6 +37,10 @@
         base::Bind(&ChildThreadImplBrowserTest::SetUpOnChildThread, this));
   }
 
+  ChildGpuMemoryBufferManager* child_gpu_memory_buffer_manager() {
+    return child_gpu_memory_buffer_manager_;
+  }
+
   ChildDiscardableSharedMemoryManager*
   child_discardable_shared_memory_manager() {
     return child_discardable_shared_memory_manager_;
@@ -40,10 +48,13 @@
 
  private:
   void SetUpOnChildThread() {
+    child_gpu_memory_buffer_manager_ =
+        ChildThreadImpl::current()->gpu_memory_buffer_manager();
     child_discardable_shared_memory_manager_ =
         ChildThreadImpl::current()->discardable_shared_memory_manager();
   }
 
+  ChildGpuMemoryBufferManager* child_gpu_memory_buffer_manager_;
   ChildDiscardableSharedMemoryManager* child_discardable_shared_memory_manager_;
 };
 
@@ -113,4 +124,86 @@
   EXPECT_LT(base::TimeTicks::Now(), end);
 }
 
-}  // content
+enum NativeBufferFlag { kDisableNativeBuffers, kEnableNativeBuffers };
+
+class ChildThreadImplGpuMemoryBufferBrowserTest
+    : public ChildThreadImplBrowserTest,
+      public testing::WithParamInterface<
+          ::testing::tuple<NativeBufferFlag, gfx::GpuMemoryBuffer::Format>> {
+ public:
+  // Overridden from BrowserTestBase:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ChildThreadImplBrowserTest::SetUpCommandLine(command_line);
+    NativeBufferFlag native_buffer_flag = ::testing::get<0>(GetParam());
+    switch (native_buffer_flag) {
+      case kEnableNativeBuffers:
+        command_line->AppendSwitch(switches::kEnableNativeGpuMemoryBuffers);
+        break;
+      case kDisableNativeBuffers:
+        break;
+    }
+  }
+};
+
+IN_PROC_BROWSER_TEST_P(ChildThreadImplGpuMemoryBufferBrowserTest,
+                       DISABLED_Map) {
+  gfx::GpuMemoryBuffer::Format format = ::testing::get<1>(GetParam());
+  gfx::Size buffer_size(4, 4);
+
+  scoped_ptr<gfx::GpuMemoryBuffer> buffer =
+      child_gpu_memory_buffer_manager()->AllocateGpuMemoryBuffer(
+          buffer_size, format, gfx::GpuMemoryBuffer::MAP);
+  ASSERT_TRUE(buffer);
+  EXPECT_EQ(format, buffer->GetFormat());
+
+  size_t num_planes =
+      GpuMemoryBufferImpl::NumberOfPlanesForGpuMemoryBufferFormat(format);
+
+  // Map buffer planes.
+  scoped_ptr<void* []> planes(new void* [num_planes]);
+  bool rv = buffer->Map(planes.get());
+  ASSERT_TRUE(rv);
+  EXPECT_TRUE(buffer->IsMapped());
+
+  // Get strides.
+  scoped_ptr<int[]> strides(new int[num_planes]);
+  buffer->GetStride(strides.get());
+
+  // Write to buffer and check result.
+  for (size_t plane = 0; plane < num_planes; ++plane) {
+    size_t row_size_in_bytes = 0;
+    EXPECT_TRUE(GpuMemoryBufferImpl::RowSizeInBytes(buffer_size.width(), format,
+                                                    plane, &row_size_in_bytes));
+
+    scoped_ptr<char[]> data(new char[row_size_in_bytes]);
+    memset(data.get(), 0x2a + plane, row_size_in_bytes);
+    size_t height = buffer_size.height() /
+                    GpuMemoryBufferImpl::SubsamplingFactor(format, plane);
+    for (size_t y = 0; y < height; ++y) {
+      // Copy |data| to row |y| of |plane| and verify result.
+      memcpy(static_cast<char*>(planes[plane]) + y * strides[plane], data.get(),
+             row_size_in_bytes);
+      EXPECT_EQ(memcmp(static_cast<char*>(planes[plane]) + y * strides[plane],
+                       data.get(), row_size_in_bytes),
+                0);
+    }
+  }
+
+  buffer->Unmap();
+  EXPECT_FALSE(buffer->IsMapped());
+}
+
+INSTANTIATE_TEST_CASE_P(
+    ChildThreadImplGpuMemoryBufferBrowserTests,
+    ChildThreadImplGpuMemoryBufferBrowserTest,
+    ::testing::Combine(::testing::Values(kDisableNativeBuffers,
+                                         kEnableNativeBuffers),
+                       // These formats are guaranteed to work on all platforms.
+                       ::testing::Values(gfx::GpuMemoryBuffer::R_8,
+                                         gfx::GpuMemoryBuffer::RGBA_4444,
+                                         gfx::GpuMemoryBuffer::RGBA_8888,
+                                         gfx::GpuMemoryBuffer::BGRA_8888,
+                                         gfx::GpuMemoryBuffer::YUV_420)));
+
+}  // namespace
+}  // namespace content
diff --git a/content/child/fileapi/OWNERS b/content/child/fileapi/OWNERS
index 334a61e..4d4319a 100644
--- a/content/child/fileapi/OWNERS
+++ b/content/child/fileapi/OWNERS
@@ -1,4 +1,3 @@
-kinuko@chromium.org
 michaeln@chromium.org
 jianli@chromium.org
 tzik@chromium.org
diff --git a/content/child/ftp_directory_listing_response_delegate.cc b/content/child/ftp_directory_listing_response_delegate.cc
index 82fa648..ee6507c7 100644
--- a/content/child/ftp_directory_listing_response_delegate.cc
+++ b/content/child/ftp_directory_listing_response_delegate.cc
@@ -94,7 +94,8 @@
 
     // Skip the current and parent directory entries in the listing. Our header
     // always includes them.
-    if (EqualsASCII(entry.name, ".") || EqualsASCII(entry.name, ".."))
+    if (base::EqualsASCII(entry.name, ".") ||
+        base::EqualsASCII(entry.name, ".."))
       continue;
 
     bool is_directory = (entry.type == FtpDirectoryListingEntry::DIRECTORY);
diff --git a/content/child/multipart_response_delegate.cc b/content/child/multipart_response_delegate.cc
index 21d2d51..2904d86 100644
--- a/content/child/multipart_response_delegate.cc
+++ b/content/child/multipart_response_delegate.cc
@@ -5,9 +5,11 @@
 #include "content/child/multipart_response_delegate.h"
 
 #include "base/logging.h"
+#include "base/memory/ref_counted.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "net/base/net_util.h"
+#include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
 #include "third_party/WebKit/public/platform/WebString.h"
@@ -43,7 +45,7 @@
   virtual void visitHeader(const WebString& name, const WebString& value) {
     const std::string& name_utf8 = name.utf8();
     for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) {
-      if (LowerCaseEqualsASCII(name_utf8, kReplaceHeaders[i]))
+      if (base::LowerCaseEqualsASCII(name_utf8, kReplaceHeaders[i]))
         return;
     }
     response_->setHTTPHeaderField(name, value);
@@ -69,7 +71,7 @@
       stop_sending_(false),
       has_sent_first_response_(false) {
   // Some servers report a boundary prefixed with "--".  See bug 5786.
-  if (StartsWithASCII(boundary, "--", true)) {
+  if (base::StartsWithASCII(boundary, "--", true)) {
     boundary_.assign(boundary);
   } else {
     boundary_.append(boundary);
@@ -209,59 +211,47 @@
 }
 
 bool MultipartResponseDelegate::ParseHeaders() {
-  int line_feed_increment = 1;
+  int headers_end_pos = net::HttpUtil::LocateEndOfAdditionalHeaders(
+      data_.c_str(), data_.size(), 0);
 
-  // Grab the headers being liberal about line endings.
-  size_t line_start_pos = 0;
-  size_t line_end_pos = data_.find('\n');
-  while (line_end_pos != std::string::npos) {
-    // Handle CRLF
-    if (line_end_pos > line_start_pos && data_[line_end_pos - 1] == '\r') {
-      line_feed_increment = 2;
-      --line_end_pos;
-    } else {
-      line_feed_increment = 1;
-    }
-    if (line_start_pos == line_end_pos) {
-      // A blank line, end of headers
-      line_end_pos += line_feed_increment;
-      break;
-    }
-    // Find the next header line.
-    line_start_pos = line_end_pos + line_feed_increment;
-    line_end_pos = data_.find('\n', line_start_pos);
-  }
-  // Truncated in the middle of a header, stop parsing.
-  if (line_end_pos == std::string::npos)
+  if (headers_end_pos < 0)
     return false;
 
-  // Eat headers
-  std::string headers("\n");
-  headers.append(data_, 0, line_end_pos);
-  data_ = data_.substr(line_end_pos);
+  // Eat headers and prepend a status line as is required by
+  // HttpResponseHeaders.
+  std::string headers("HTTP/1.1 200 OK\r\n");
+  headers.append(data_, 0, headers_end_pos);
+  data_ = data_.substr(headers_end_pos);
+
+  scoped_refptr<net::HttpResponseHeaders> response_headers =
+      new net::HttpResponseHeaders(
+          net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
 
   // Create a WebURLResponse based on the original set of headers + the
-  // replacement headers.  We only replace the same few headers that gecko
-  // does.  See netwerk/streamconv/converters/nsMultiMixedConv.cpp.
-  std::string content_type = net::GetSpecificHeader(headers, "content-type");
-  std::string mime_type;
-  std::string charset;
-  bool has_charset = false;
-  net::HttpUtil::ParseContentType(content_type, &mime_type, &charset,
-                                  &has_charset, NULL);
+  // replacement headers. We only replace the same few headers that gecko
+  // does. See netwerk/streamconv/converters/nsMultiMixedConv.cpp.
   WebURLResponse response(original_response_.url());
+
+  std::string mime_type;
+  response_headers->GetMimeType(&mime_type);
   response.setMIMEType(WebString::fromUTF8(mime_type));
+
+  std::string charset;
+  response_headers->GetCharset(&charset);
   response.setTextEncodingName(WebString::fromUTF8(charset));
 
+  // Copy the response headers from the original response.
   HeaderCopier copier(&response);
   original_response_.visitHTTPHeaderFields(&copier);
 
+  // Replace original headers with multipart headers listed in kReplaceHeaders.
   for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) {
     std::string name(kReplaceHeaders[i]);
-    std::string value = net::GetSpecificHeader(headers, name);
-    if (!value.empty()) {
-      response.setHTTPHeaderField(WebString::fromUTF8(name),
-                                  WebString::fromUTF8(value));
+    std::string value;
+    void* iterator = nullptr;
+    while (response_headers->EnumerateHeader(&iterator, name, &value)) {
+      response.addHTTPHeaderField(WebString::fromLatin1(name),
+                                  WebString::fromLatin1(value));
     }
   }
   // To avoid recording every multipart load as a separate visit in
diff --git a/content/child/npapi/plugin_host.cc b/content/child/npapi/plugin_host.cc
index cdda9e4..e201ffb 100644
--- a/content/child/npapi/plugin_host.cc
+++ b/content/child/npapi/plugin_host.cc
@@ -464,7 +464,7 @@
     std::string file_path_ascii(buf);
     base::FilePath file_path;
     static const char kFileUrlPrefix[] = "file:";
-    if (StartsWithASCII(file_path_ascii, kFileUrlPrefix, false)) {
+    if (base::StartsWithASCII(file_path_ascii, kFileUrlPrefix, false)) {
       GURL file_url(file_path_ascii);
       DCHECK(file_url.SchemeIsFile());
       net::FileURLToFilePath(file_url, &file_path);
diff --git a/content/child/npapi/plugin_url_fetcher.cc b/content/child/npapi/plugin_url_fetcher.cc
index c8a93ca3..e56c63a 100644
--- a/content/child/npapi/plugin_url_fetcher.cc
+++ b/content/child/npapi/plugin_url_fetcher.cc
@@ -131,7 +131,7 @@
       if (!request_info.headers.empty())
         request_info.headers += "\r\n";
       request_info.headers += names[i] + ": " + values[i];
-      if (LowerCaseEqualsASCII(names[i], "content-type"))
+      if (base::LowerCaseEqualsASCII(names[i], "content-type"))
         content_type_found = true;
     }
 
diff --git a/content/child/npapi/webplugin_delegate_impl.cc b/content/child/npapi/webplugin_delegate_impl.cc
index 9d76054..18149c3 100644
--- a/content/child/npapi/webplugin_delegate_impl.cc
+++ b/content/child/npapi/webplugin_delegate_impl.cc
@@ -70,7 +70,7 @@
   scoped_ptr<char*[]> argv(new char*[arg_names.size()]);
   for (size_t i = 0; i < arg_names.size(); ++i) {
     if (quirks_ & PLUGIN_QUIRK_NO_WINDOWLESS &&
-        LowerCaseEqualsASCII(arg_names[i], "windowlessvideo")) {
+        base::LowerCaseEqualsASCII(arg_names[i], "windowlessvideo")) {
       continue;
     }
     argn[argc] = const_cast<char*>(arg_names[i].c_str());
diff --git a/content/child/service_worker/OWNERS b/content/child/service_worker/OWNERS
index c84704d..61321a28 100644
--- a/content/child/service_worker/OWNERS
+++ b/content/child/service_worker/OWNERS
@@ -2,6 +2,3 @@
 falken@chromium.org
 horo@chromium.org
 nhiroki@chromium.org
-
-# may not be available
-kinuko@chromium.org
diff --git a/content/child/service_worker/PRESUBMIT.py b/content/child/service_worker/PRESUBMIT.py
new file mode 100644
index 0000000..928d9fe0
--- /dev/null
+++ b/content/child/service_worker/PRESUBMIT.py
@@ -0,0 +1,14 @@
+# 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.
+
+"""Presubmit script for service_worker.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+  results = []
+  results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
+  return results
diff --git a/content/child/service_worker/service_worker_dispatcher.cc b/content/child/service_worker/service_worker_dispatcher.cc
index e68f644..d1c72a7 100644
--- a/content/child/service_worker/service_worker_dispatcher.cc
+++ b/content/child/service_worker/service_worker_dispatcher.cc
@@ -69,6 +69,8 @@
                         OnUnregistered)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistration,
                         OnDidGetRegistration)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistrations,
+                        OnDidGetRegistrations)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetRegistrationForReady,
                         OnDidGetRegistrationForReady)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerRegistrationError,
@@ -77,6 +79,8 @@
                         OnUnregistrationError)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerGetRegistrationError,
                         OnGetRegistrationError)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerGetRegistrationsError,
+                        OnGetRegistrationsError)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ServiceWorkerStateChanged,
                         OnServiceWorkerStateChanged)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SetVersionAttributes,
@@ -180,6 +184,19 @@
       CurrentWorkerId(), request_id, provider_id, document_url));
 }
 
+void ServiceWorkerDispatcher::GetRegistrations(
+    int provider_id,
+    WebServiceWorkerGetRegistrationsCallbacks* callbacks) {
+  DCHECK(callbacks);
+
+  int request_id = pending_get_registrations_callbacks_.Add(callbacks);
+  TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
+                           "ServiceWorkerDispatcher::GetRegistrations",
+                           request_id);
+  thread_safe_sender_->Send(new ServiceWorkerHostMsg_GetRegistrations(
+      CurrentWorkerId(), request_id, provider_id));
+}
+
 void ServiceWorkerDispatcher::GetRegistrationForReady(
     int provider_id,
     WebServiceWorkerGetRegistrationForReadyCallbacks* callbacks) {
@@ -417,6 +434,42 @@
   pending_get_registration_callbacks_.Remove(request_id);
 }
 
+void ServiceWorkerDispatcher::OnDidGetRegistrations(
+    int thread_id,
+    int request_id,
+    const std::vector<ServiceWorkerRegistrationObjectInfo>& infos,
+    const std::vector<ServiceWorkerVersionAttributes>& attrs) {
+  TRACE_EVENT_ASYNC_STEP_INTO0(
+      "ServiceWorker",
+      "ServiceWorkerDispatcher::GetRegistrations",
+      request_id,
+      "OnDidGetRegistrations");
+  TRACE_EVENT_ASYNC_END0("ServiceWorker",
+                         "ServiceWorkerDispatcher::GetRegistrations",
+                         request_id);
+
+  WebServiceWorkerGetRegistrationsCallbacks* callbacks =
+      pending_get_registrations_callbacks_.Lookup(request_id);
+  DCHECK(callbacks);
+  if (!callbacks)
+    return;
+
+  typedef blink::WebVector<blink::WebServiceWorkerRegistration*>
+      WebServiceWorkerRegistrationArray;
+  scoped_ptr<WebServiceWorkerRegistrationArray>
+      registrations(new WebServiceWorkerRegistrationArray(infos.size()));
+  for (size_t i = 0; i < infos.size(); ++i) {
+    if (infos[i].handle_id != kInvalidServiceWorkerHandleId) {
+      ServiceWorkerRegistrationObjectInfo info(infos[i]);
+      ServiceWorkerVersionAttributes attr(attrs[i]);
+      (*registrations)[i] = FindOrCreateRegistration(info, attr);
+    }
+  }
+
+  callbacks->onSuccess(registrations.release());
+  pending_get_registrations_callbacks_.Remove(request_id);
+}
+
 void ServiceWorkerDispatcher::OnDidGetRegistrationForReady(
     int thread_id,
     int request_id,
@@ -517,6 +570,31 @@
   pending_get_registration_callbacks_.Remove(request_id);
 }
 
+void ServiceWorkerDispatcher::OnGetRegistrationsError(
+    int thread_id,
+    int request_id,
+    WebServiceWorkerError::ErrorType error_type,
+    const base::string16& message) {
+  TRACE_EVENT_ASYNC_STEP_INTO0(
+      "ServiceWorker",
+      "ServiceWorkerDispatcher::GetRegistrations",
+      request_id,
+      "OnGetRegistrationsError");
+  TRACE_EVENT_ASYNC_END0("ServiceWorker",
+                         "ServiceWorkerDispatcher::GetRegistrations",
+                         request_id);
+  WebServiceWorkerGetRegistrationsCallbacks* callbacks =
+      pending_get_registrations_callbacks_.Lookup(request_id);
+  DCHECK(callbacks);
+  if (!callbacks)
+    return;
+
+  scoped_ptr<WebServiceWorkerError> error(
+      new WebServiceWorkerError(error_type, message));
+  callbacks->onError(error.release());
+  pending_get_registrations_callbacks_.Remove(request_id);
+}
+
 void ServiceWorkerDispatcher::OnServiceWorkerStateChanged(
     int thread_id,
     int handle_id,
diff --git a/content/child/service_worker/service_worker_dispatcher.h b/content/child/service_worker/service_worker_dispatcher.h
index 28b9f4f9..01b88cc 100644
--- a/content/child/service_worker/service_worker_dispatcher.h
+++ b/content/child/service_worker/service_worker_dispatcher.h
@@ -52,6 +52,9 @@
   typedef
       blink::WebServiceWorkerProvider::WebServiceWorkerGetRegistrationCallbacks
       WebServiceWorkerGetRegistrationCallbacks;
+  typedef
+      blink::WebServiceWorkerProvider::WebServiceWorkerGetRegistrationsCallbacks
+      WebServiceWorkerGetRegistrationsCallbacks;
   typedef blink::WebServiceWorkerProvider::
       WebServiceWorkerGetRegistrationForReadyCallbacks
           WebServiceWorkerGetRegistrationForReadyCallbacks;
@@ -78,6 +81,10 @@
       int provider_id,
       const GURL& document_url,
       WebServiceWorkerRegistrationCallbacks* callbacks);
+  // Corresponds to navigator.serviceWorker.getRegistrations()
+  void GetRegistrations(
+      int provider_id,
+      WebServiceWorkerGetRegistrationsCallbacks* callbacks);
 
   void GetRegistrationForReady(
       int provider_id,
@@ -137,6 +144,8 @@
       IDMapOwnPointer> UnregistrationCallbackMap;
   typedef IDMap<WebServiceWorkerGetRegistrationCallbacks,
       IDMapOwnPointer> GetRegistrationCallbackMap;
+  typedef IDMap<WebServiceWorkerGetRegistrationsCallbacks,
+      IDMapOwnPointer> GetRegistrationsCallbackMap;
   typedef IDMap<WebServiceWorkerGetRegistrationForReadyCallbacks,
       IDMapOwnPointer> GetRegistrationForReadyCallbackMap;
 
@@ -177,6 +186,11 @@
                             int request_id,
                             const ServiceWorkerRegistrationObjectInfo& info,
                             const ServiceWorkerVersionAttributes& attrs);
+  void OnDidGetRegistrations(
+      int thread_id,
+      int request_id,
+      const std::vector<ServiceWorkerRegistrationObjectInfo>& infos,
+      const std::vector<ServiceWorkerVersionAttributes>& attrs);
   void OnDidGetRegistrationForReady(
       int thread_id,
       int request_id,
@@ -195,6 +209,11 @@
       int request_id,
       blink::WebServiceWorkerError::ErrorType error_type,
       const base::string16& message);
+  void OnGetRegistrationsError(
+      int thread_id,
+      int request_id,
+      blink::WebServiceWorkerError::ErrorType error_type,
+      const base::string16& message);
   void OnServiceWorkerStateChanged(int thread_id,
                                    int handle_id,
                                    blink::WebServiceWorkerState state);
@@ -239,6 +258,7 @@
   RegistrationCallbackMap pending_registration_callbacks_;
   UnregistrationCallbackMap pending_unregistration_callbacks_;
   GetRegistrationCallbackMap pending_get_registration_callbacks_;
+  GetRegistrationsCallbackMap pending_get_registrations_callbacks_;
   GetRegistrationForReadyCallbackMap get_for_ready_callbacks_;
 
   ProviderClientMap provider_clients_;
diff --git a/content/child/service_worker/web_service_worker_provider_impl.cc b/content/child/service_worker/web_service_worker_provider_impl.cc
index 9618566..73637962 100644
--- a/content/child/service_worker/web_service_worker_provider_impl.cc
+++ b/content/child/service_worker/web_service_worker_provider_impl.cc
@@ -71,6 +71,12 @@
       context_->provider_id(), document_url, callbacks);
 }
 
+void WebServiceWorkerProviderImpl::getRegistrations(
+    WebServiceWorkerGetRegistrationsCallbacks* callbacks) {
+  GetDispatcher()->GetRegistrations(
+      context_->provider_id(), callbacks);
+}
+
 void WebServiceWorkerProviderImpl::getRegistrationForReady(
     WebServiceWorkerGetRegistrationForReadyCallbacks* callbacks) {
   GetDispatcher()->GetRegistrationForReady(context_->provider_id(), callbacks);
diff --git a/content/child/service_worker/web_service_worker_provider_impl.h b/content/child/service_worker/web_service_worker_provider_impl.h
index 37e99b1a..4d95139 100644
--- a/content/child/service_worker/web_service_worker_provider_impl.h
+++ b/content/child/service_worker/web_service_worker_provider_impl.h
@@ -41,6 +41,7 @@
 
   virtual void getRegistration(const blink::WebURL& document_url,
                                WebServiceWorkerGetRegistrationCallbacks*);
+  virtual void getRegistrations(WebServiceWorkerGetRegistrationsCallbacks*);
   virtual void getRegistrationForReady(
       WebServiceWorkerGetRegistrationForReadyCallbacks*);
 
diff --git a/content/child/simple_webmimeregistry_impl.cc b/content/child/simple_webmimeregistry_impl.cc
index d3276e4..68d8755 100644
--- a/content/child/simple_webmimeregistry_impl.cc
+++ b/content/child/simple_webmimeregistry_impl.cc
@@ -42,7 +42,7 @@
     const WebString& mime_type) {
     std::string ascii_mime_type = ToASCIIOrEmpty(mime_type);
     return (mime_util::IsSupportedImageMimeType(ascii_mime_type) ||
-            (StartsWithASCII(ascii_mime_type, "image/", true) &&
+            (base::StartsWithASCII(ascii_mime_type, "image/", true) &&
              mime_util::IsSupportedNonImageMimeType(ascii_mime_type)))
                ? WebMimeRegistry::IsSupported
                : WebMimeRegistry::IsNotSupported;
diff --git a/content/child/site_isolation_policy.cc b/content/child/site_isolation_policy.cc
index 2320e0e3..5210423 100644
--- a/content/child/site_isolation_policy.cc
+++ b/content/child/site_isolation_policy.cc
@@ -40,8 +40,8 @@
 bool IsRenderableStatusCode(int status_code) {
   // Chrome only uses the content of a response with one of these status codes
   // for CSS/JavaScript. For images, Chrome just ignores status code.
-  const int renderable_status_code[] = {200, 201, 202, 203, 206, 300,
-                                        301, 302, 303, 305, 306, 307};
+  const int renderable_status_code[] = {
+      200, 201, 202, 203, 206, 300, 301, 302, 303, 305, 306, 307};
   for (size_t i = 0; i < arraysize(renderable_status_code); ++i) {
     if (renderable_status_code[i] == status_code)
       return true;
@@ -52,7 +52,6 @@
 bool MatchesSignature(StringPiece data,
                       const StringPiece signatures[],
                       size_t arr_size) {
-
   size_t offset = data.find_first_not_of(" \t\r\n");
   // There is no not-whitespace character in this document.
   if (offset == base::StringPiece::npos)
@@ -67,8 +66,9 @@
     if (length < signature_length)
       continue;
 
-    if (LowerCaseEqualsASCII(
-            data.begin(), data.begin() + signature_length, signature.data()))
+    if (base::LowerCaseEqualsASCII(data.begin(),
+                                   data.begin() + signature_length,
+                                   signature.data()))
       return true;
   }
   return false;
@@ -82,21 +82,18 @@
 }
 
 void IncrementHistogramEnum(const std::string& name,
-                          uint32 sample,
-                          uint32 boundary_value) {
+                            uint32 sample,
+                            uint32 boundary_value) {
   // The default value of min, max, bucket_count are copied from histogram.h.
   base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
-      name,
-      1,
-      boundary_value,
-      boundary_value + 1,
+      name, 1, boundary_value, boundary_value + 1,
       base::HistogramBase::kUmaTargetedHistogramFlag);
   histogram_pointer->Add(sample);
 }
 
 void HistogramCountBlockedResponse(
     const std::string& bucket_prefix,
-    linked_ptr<SiteIsolationResponseMetaData>& resp_data,
+    const linked_ptr<SiteIsolationResponseMetaData>& resp_data,
     bool nosniff_block) {
   std::string block_label(nosniff_block ? ".NoSniffBlocked" : ".Blocked");
   IncrementHistogramCount(bucket_prefix + block_label);
@@ -116,8 +113,7 @@
   if (renderable_status_code) {
     IncrementHistogramEnum(
         bucket_prefix + block_label + ".RenderableStatusCode",
-        resp_data->resource_type,
-        RESOURCE_TYPE_LAST_TYPE);
+        resp_data->resource_type, RESOURCE_TYPE_LAST_TYPE);
   } else {
     IncrementHistogramCount(bucket_prefix + block_label +
                             ".NonRenderableStatusCode");
@@ -133,7 +129,8 @@
 
 }  // namespace
 
-SiteIsolationResponseMetaData::SiteIsolationResponseMetaData() {}
+SiteIsolationResponseMetaData::SiteIsolationResponseMetaData() {
+}
 
 void SiteIsolationPolicy::SetPolicyEnabled(bool enabled) {
   g_policy_enabled = enabled;
@@ -182,8 +179,8 @@
   std::string access_control_origin;
 
   // We can use a case-insensitive header name for EnumerateHeader().
-  info.headers->EnumerateHeader(
-      NULL, "access-control-allow-origin", &access_control_origin);
+  info.headers->EnumerateHeader(NULL, "access-control-allow-origin",
+                                &access_control_origin);
   if (IsValidCorsHeaderSet(frame_origin, response_url, access_control_origin))
     return linked_ptr<SiteIsolationResponseMetaData>();
 
@@ -198,13 +195,13 @@
   resp_data->resource_type = resource_type;
   resp_data->canonical_mime_type = canonical_mime_type;
   resp_data->http_status_code = info.headers->response_code();
-  resp_data->no_sniff = LowerCaseEqualsASCII(no_sniff, "nosniff");
+  resp_data->no_sniff = base::LowerCaseEqualsASCII(no_sniff, "nosniff");
 
   return resp_data;
 }
 
 bool SiteIsolationPolicy::ShouldBlockResponse(
-    linked_ptr<SiteIsolationResponseMetaData>& resp_data,
+    const linked_ptr<SiteIsolationResponseMetaData>& resp_data,
     const char* raw_data,
     int raw_length,
     std::string* alternative_data) {
@@ -222,8 +219,7 @@
   // Record the number of cross-site document responses with a specific mime
   // type (text/html, text/xml, etc).
   UMA_HISTOGRAM_ENUMERATION(
-      "SiteIsolation.XSD.MimeType",
-      resp_data->canonical_mime_type,
+      "SiteIsolation.XSD.MimeType", resp_data->canonical_mime_type,
       SiteIsolationResponseMetaData::MaxCanonicalMimeType);
 
   // Store the result of cross-site document blocking analysis.
@@ -234,20 +230,18 @@
   // type claims it to be. For example, we apply a HTML sniffer for a document
   // tagged with text/html here. Whenever this check becomes true, we'll block
   // the response.
-  if (resp_data->canonical_mime_type !=
-          SiteIsolationResponseMetaData::Plain) {
+  if (resp_data->canonical_mime_type != SiteIsolationResponseMetaData::Plain) {
     std::string bucket_prefix;
     bool sniffed_as_target_document = false;
-    if (resp_data->canonical_mime_type ==
-            SiteIsolationResponseMetaData::HTML) {
+    if (resp_data->canonical_mime_type == SiteIsolationResponseMetaData::HTML) {
       bucket_prefix = "SiteIsolation.XSD.HTML";
       sniffed_as_target_document = SniffForHTML(data);
     } else if (resp_data->canonical_mime_type ==
-                   SiteIsolationResponseMetaData::XML) {
+               SiteIsolationResponseMetaData::XML) {
       bucket_prefix = "SiteIsolation.XSD.XML";
       sniffed_as_target_document = SniffForXML(data);
     } else if (resp_data->canonical_mime_type ==
-                   SiteIsolationResponseMetaData::JSON) {
+               SiteIsolationResponseMetaData::JSON) {
       bucket_prefix = "SiteIsolation.XSD.JSON";
       sniffed_as_target_document = SniffForJSON(data);
     } else {
@@ -306,27 +300,27 @@
 
 SiteIsolationResponseMetaData::CanonicalMimeType
 SiteIsolationPolicy::GetCanonicalMimeType(const std::string& mime_type) {
-  if (LowerCaseEqualsASCII(mime_type, kTextHtml)) {
+  if (base::LowerCaseEqualsASCII(mime_type, kTextHtml)) {
     return SiteIsolationResponseMetaData::HTML;
   }
 
-  if (LowerCaseEqualsASCII(mime_type, kTextPlain)) {
+  if (base::LowerCaseEqualsASCII(mime_type, kTextPlain)) {
     return SiteIsolationResponseMetaData::Plain;
   }
 
-  if (LowerCaseEqualsASCII(mime_type, kAppJson) ||
-      LowerCaseEqualsASCII(mime_type, kTextJson) ||
-      LowerCaseEqualsASCII(mime_type, kTextXjson)) {
+  if (base::LowerCaseEqualsASCII(mime_type, kAppJson) ||
+      base::LowerCaseEqualsASCII(mime_type, kTextJson) ||
+      base::LowerCaseEqualsASCII(mime_type, kTextXjson)) {
     return SiteIsolationResponseMetaData::JSON;
   }
 
-  if (LowerCaseEqualsASCII(mime_type, kTextXml) ||
-      LowerCaseEqualsASCII(mime_type, xAppRssXml) ||
-      LowerCaseEqualsASCII(mime_type, kAppXml)) {
+  if (base::LowerCaseEqualsASCII(mime_type, kTextXml) ||
+      base::LowerCaseEqualsASCII(mime_type, xAppRssXml) ||
+      base::LowerCaseEqualsASCII(mime_type, kAppXml)) {
     return SiteIsolationResponseMetaData::XML;
   }
 
- return SiteIsolationResponseMetaData::Others;
+  return SiteIsolationResponseMetaData::Others;
 }
 
 bool SiteIsolationPolicy::IsBlockableScheme(const GURL& url) {
@@ -338,7 +332,6 @@
 
 bool SiteIsolationPolicy::IsSameSite(const GURL& frame_origin,
                                      const GURL& response_url) {
-
   if (!frame_origin.is_valid() || !response_url.is_valid())
     return false;
 
@@ -348,8 +341,7 @@
   // SameDomainOrHost() extracts the effective domains (public suffix plus one)
   // from the two URLs and compare them.
   return net::registry_controlled_domains::SameDomainOrHost(
-      frame_origin,
-      response_url,
+      frame_origin, response_url,
       net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
 }
 
@@ -399,32 +391,31 @@
   // process, we should do single-thread checking here for the static
   // initializer.
   static const StringPiece kHtmlSignatures[] = {
-    StringPiece("<!DOCTYPE html"),  // HTML5 spec
-    StringPiece("<script"),  // HTML5 spec, Mozilla
-    StringPiece("<html"),    // HTML5 spec, Mozilla
-    StringPiece("<head"),    // HTML5 spec, Mozilla
-    StringPiece("<iframe"),  // Mozilla
-    StringPiece("<h1"),      // Mozilla
-    StringPiece("<div"),     // Mozilla
-    StringPiece("<font"),    // Mozilla
-    StringPiece("<table"),   // Mozilla
-    StringPiece("<a"),       // Mozilla
-    StringPiece("<style"),   // Mozilla
-    StringPiece("<title"),   // Mozilla
-    StringPiece("<b"),       // Mozilla
-    StringPiece("<body"),    // Mozilla
-    StringPiece("<br"),      // Mozilla
-    StringPiece("<p"),       // Mozilla
-    StringPiece("<?xml")     // Mozilla
+      StringPiece("<!DOCTYPE html"),  // HTML5 spec
+      StringPiece("<script"),         // HTML5 spec, Mozilla
+      StringPiece("<html"),           // HTML5 spec, Mozilla
+      StringPiece("<head"),           // HTML5 spec, Mozilla
+      StringPiece("<iframe"),         // Mozilla
+      StringPiece("<h1"),             // Mozilla
+      StringPiece("<div"),            // Mozilla
+      StringPiece("<font"),           // Mozilla
+      StringPiece("<table"),          // Mozilla
+      StringPiece("<a"),              // Mozilla
+      StringPiece("<style"),          // Mozilla
+      StringPiece("<title"),          // Mozilla
+      StringPiece("<b"),              // Mozilla
+      StringPiece("<body"),           // Mozilla
+      StringPiece("<br"),             // Mozilla
+      StringPiece("<p"),              // Mozilla
+      StringPiece("<?xml")            // Mozilla
   };
 
   while (data.length() > 0) {
-    if (MatchesSignature(
-          data, kHtmlSignatures, arraysize(kHtmlSignatures)))
+    if (MatchesSignature(data, kHtmlSignatures, arraysize(kHtmlSignatures)))
       return true;
 
     // If we cannot find "<!--", we fail sniffing this as HTML.
-    static const StringPiece kCommentBegins[] = { StringPiece("<!--") };
+    static const StringPiece kCommentBegins[] = {StringPiece("<!--")};
     if (!MatchesSignature(data, kCommentBegins, arraysize(kCommentBegins)))
       break;
 
@@ -450,7 +441,7 @@
   // TODO(dsjang): Once SiteIsolationPolicy is moved into the browser
   // process, we should do single-thread checking here for the static
   // initializer.
-  static const StringPiece kXmlSignatures[] = { StringPiece("<?xml") };
+  static const StringPiece kXmlSignatures[] = {StringPiece("<?xml")};
   return MatchesSignature(data, kXmlSignatures, arraysize(kXmlSignatures));
 }
 
diff --git a/content/child/site_isolation_policy.h b/content/child/site_isolation_policy.h
index f084288..8a902d7 100644
--- a/content/child/site_isolation_policy.h
+++ b/content/child/site_isolation_policy.h
@@ -94,10 +94,12 @@
   // |alternative_data|. This records various kinds of UMA data stats. This
   // function is called only if the length of received data is non-zero.
   static bool ShouldBlockResponse(
-      linked_ptr<SiteIsolationResponseMetaData>& resp_data, const char* payload,
-      int length, std::string* alternative_data);
+      const linked_ptr<SiteIsolationResponseMetaData>& resp_data,
+      const char* payload,
+      int length,
+      std::string* alternative_data);
 
-private:
+ private:
   FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, IsBlockableScheme);
   FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, IsSameSite);
   FRIEND_TEST_ALL_PREFIXES(SiteIsolationPolicyTest, IsValidCorsHeaderSet);
diff --git a/content/child/web_database_observer_impl.cc b/content/child/web_database_observer_impl.cc
index 3a88133a..98b1cd7 100644
--- a/content/child/web_database_observer_impl.cc
+++ b/content/child/web_database_observer_impl.cc
@@ -19,6 +19,7 @@
 
 const int kResultHistogramSize = 50;
 const int kCallsiteHistogramSize = 10;
+const int kWebSQLSuccess = -1;
 
 int DetermineHistogramResult(int websql_error, int sqlite_error) {
   // If we have a sqlite error, log it after trimming the extended bits.
@@ -28,7 +29,7 @@
 
   // Otherwise, websql_error may be an SQLExceptionCode, SQLErrorCode
   // or a DOMExceptionCode, or -1 for success.
-  if (websql_error == -1)
+  if (websql_error == kWebSQLSuccess)
     return 0;  // no error
 
   // SQLExceptionCode starts at 1000
@@ -97,6 +98,24 @@
   HandleSqliteError(origin_identifier, database_name, sqlite_error);
 }
 
+void WebDatabaseObserverImpl::reportOpenDatabaseResult(
+    const WebString& origin_identifier,
+    const WebString& database_name,
+    int callsite,
+    int websql_error,
+    int sqlite_error,
+    double call_time) {
+  reportOpenDatabaseResult(origin_identifier, database_name, callsite,
+                           websql_error, sqlite_error);
+  if (websql_error == kWebSQLSuccess && sqlite_error == SQLITE_OK) {
+    UMA_HISTOGRAM_TIMES("websql.Async.OpenTime.Success",
+                        base::TimeDelta::FromSecondsD(call_time));
+  } else {
+    UMA_HISTOGRAM_TIMES("websql.Async.OpenTime.Error",
+                        base::TimeDelta::FromSecondsD(call_time));
+  }
+}
+
 void WebDatabaseObserverImpl::reportChangeVersionResult(
     const WebString& origin_identifier,
     const WebString& database_name,
diff --git a/content/child/web_database_observer_impl.h b/content/child/web_database_observer_impl.h
index 0976109..c8e1f28 100644
--- a/content/child/web_database_observer_impl.h
+++ b/content/child/web_database_observer_impl.h
@@ -32,6 +32,13 @@
       const blink::WebString& origin_identifier,
       const blink::WebString& database_name,
       int callsite, int websql_error, int sqlite_error);
+  virtual void reportOpenDatabaseResult(
+      const blink::WebString& origin_identifier,
+      const blink::WebString& database_name,
+      int callsite,
+      int websql_error,
+      int sqlite_error,
+      double call_time);
   virtual void reportChangeVersionResult(
       const blink::WebString& origin_identifier,
       const blink::WebString& database_name,
diff --git a/content/child/web_memory_allocator_dump_impl.cc b/content/child/web_memory_allocator_dump_impl.cc
index 639352129..81e66ea 100644
--- a/content/child/web_memory_allocator_dump_impl.cc
+++ b/content/child/web_memory_allocator_dump_impl.cc
@@ -16,21 +16,21 @@
 WebMemoryAllocatorDumpImpl::~WebMemoryAllocatorDumpImpl() {
 }
 
-void WebMemoryAllocatorDumpImpl::AddScalar(const blink::WebString& name,
+void WebMemoryAllocatorDumpImpl::AddScalar(const char* name,
                                            const char* units,
                                            uint64 value) {
-  memory_allocator_dump_->AddScalar(name.utf8(), units, value);
+  memory_allocator_dump_->AddScalar(name, units, value);
 }
 
-void WebMemoryAllocatorDumpImpl::AddScalarF(const blink::WebString& name,
+void WebMemoryAllocatorDumpImpl::AddScalarF(const char* name,
                                             const char* units,
                                             double value) {
-  memory_allocator_dump_->AddScalarF(name.utf8(), units, value);
+  memory_allocator_dump_->AddScalarF(name, units, value);
 }
 
-void WebMemoryAllocatorDumpImpl::AddString(const blink::WebString& name,
+void WebMemoryAllocatorDumpImpl::AddString(const char* name,
                                            const char* units,
                                            const blink::WebString& value) {
-  memory_allocator_dump_->AddString(name.utf8(), units, value.utf8());
+  memory_allocator_dump_->AddString(name, units, value.utf8());
 }
 }  // namespace content
diff --git a/content/child/web_memory_allocator_dump_impl.h b/content/child/web_memory_allocator_dump_impl.h
index fda18ab..23b7155 100644
--- a/content/child/web_memory_allocator_dump_impl.h
+++ b/content/child/web_memory_allocator_dump_impl.h
@@ -26,13 +26,13 @@
   virtual ~WebMemoryAllocatorDumpImpl();
 
   // blink::WebMemoryAllocatorDump implementation.
-  virtual void AddScalar(const blink::WebString& name,
+  virtual void AddScalar(const char* name,
                          const char* units,
                          uint64 value);
-  virtual void AddScalarF(const blink::WebString& name,
+  virtual void AddScalarF(const char* name,
                           const char* units,
                           double value);
-  virtual void AddString(const blink::WebString& name,
+  virtual void AddString(const char* name,
                          const char* units,
                          const blink::WebString& value);
 
diff --git a/content/child/web_process_memory_dump_impl_unittest.cc b/content/child/web_process_memory_dump_impl_unittest.cc
index d7a6c4d7..40d6aed 100644
--- a/content/child/web_process_memory_dump_impl_unittest.cc
+++ b/content/child/web_process_memory_dump_impl_unittest.cc
@@ -49,19 +49,23 @@
   ASSERT_EQ(wmad, wpmd2->getMemoryAllocatorDump("2/new"));
 
   // Check that the attributes are propagated correctly.
-  const char* attr_type = nullptr;
-  const char* attr_units = nullptr;
-  const base::Value* attr_value = nullptr;
-  bool has_attr = mad->Get("attr_name", &attr_type, &attr_units, &attr_value);
-  ASSERT_TRUE(has_attr);
-  ASSERT_STREQ(base::trace_event::MemoryAllocatorDump::kTypeScalar, attr_type);
-  ASSERT_STREQ("bytes", attr_units);
-  ASSERT_NE(static_cast<base::Value*>(nullptr), attr_value);
-  has_attr = mad->Get("attr_name_2", &attr_type, &attr_units, &attr_value);
-  ASSERT_TRUE(has_attr);
-  ASSERT_STREQ(base::trace_event::MemoryAllocatorDump::kTypeScalar, attr_type);
-  ASSERT_STREQ("rate", attr_units);
-  ASSERT_NE(static_cast<base::Value*>(nullptr), attr_value);
+  auto raw_attrs = mad->attributes_for_testing()->ToBaseValue();
+  base::DictionaryValue* attrs = nullptr;
+  ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs));
+  base::DictionaryValue* attr = nullptr;
+  ASSERT_TRUE(attrs->GetDictionary("attr_name", &attr));
+  std::string attr_value;
+  ASSERT_TRUE(attr->GetString("type", &attr_value));
+  ASSERT_EQ(base::trace_event::MemoryAllocatorDump::kTypeScalar, attr_value);
+  ASSERT_TRUE(attr->GetString("units", &attr_value));
+  ASSERT_EQ("bytes", attr_value);
+
+  ASSERT_TRUE(attrs->GetDictionary("attr_name_2", &attr));
+  ASSERT_TRUE(attr->GetString("type", &attr_value));
+  ASSERT_EQ(base::trace_event::MemoryAllocatorDump::kTypeScalar, attr_value);
+  ASSERT_TRUE(attr->GetString("units", &attr_value));
+  ASSERT_EQ("rate", attr_value);
+  ASSERT_TRUE(attr->HasKey("value"));
 
   // Check that AsValueInto() doesn't cause a crash.
   wpmd2->process_memory_dump()->AsValueInto(traced_value.get());
diff --git a/content/child/web_url_request_util.cc b/content/child/web_url_request_util.cc
index 6737307c..438ccf7 100644
--- a/content/child/web_url_request_util.cc
+++ b/content/child/web_url_request_util.cc
@@ -37,10 +37,10 @@
 
     // Skip over referrer headers found in the header map because we already
     // pulled it out as a separate parameter.
-    if (LowerCaseEqualsASCII(name_latin1, "referer"))
+    if (base::LowerCaseEqualsASCII(name_latin1, "referer"))
       return;
 
-    if (LowerCaseEqualsASCII(name_latin1, "accept"))
+    if (base::LowerCaseEqualsASCII(name_latin1, "accept"))
       has_accept_header_ = true;
 
     if (!buffer_.empty())
diff --git a/content/common/DEPS b/content/common/DEPS
index ad07e4f..1c72772 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -21,12 +21,12 @@
   "+third_party/WebKit/public/platform/WebGraphicsContext3D.h",
   "+third_party/WebKit/public/platform/WebHistoryScrollRestorationType.h",
   "+third_party/WebKit/public/platform/WebHTTPBody.h",
-  "+third_party/WebKit/public/platform/WebLockOrientationError.h",
+  "+third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationError.h",
   "+third_party/WebKit/public/platform/WebPageVisibilityState.h",
   "+third_party/WebKit/public/platform/WebReferrerPolicy.h",
   "+third_party/WebKit/public/platform/WebScreenInfo.h",
-  "+third_party/WebKit/public/platform/WebScreenOrientationLockType.h",
-  "+third_party/WebKit/public/platform/WebScreenOrientationType.h",
+  "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
+  "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h",
   "+third_party/WebKit/public/platform/WebServiceWorkerCacheError.h",
   "+third_party/WebKit/public/platform/WebServiceWorkerClientType.h",
   "+third_party/WebKit/public/platform/WebServiceWorkerError.h",
diff --git a/content/common/accessibility_messages.h b/content/common/accessibility_messages.h
index 91a2b4f9..1acd335 100644
--- a/content/common/accessibility_messages.h
+++ b/content/common/accessibility_messages.h
@@ -30,35 +30,6 @@
 
 #define IPC_MESSAGE_START AccessibilityMsgStart
 
-IPC_ENUM_TRAITS_MAX_VALUE(ui::AXEvent, ui::AX_EVENT_LAST)
-IPC_ENUM_TRAITS_MAX_VALUE(ui::AXRole, ui::AX_ROLE_LAST)
-
-IPC_ENUM_TRAITS_MAX_VALUE(ui::AXBoolAttribute, ui::AX_BOOL_ATTRIBUTE_LAST)
-IPC_ENUM_TRAITS_MAX_VALUE(ui::AXFloatAttribute, ui::AX_FLOAT_ATTRIBUTE_LAST)
-IPC_ENUM_TRAITS_MAX_VALUE(ui::AXIntAttribute, ui::AX_INT_ATTRIBUTE_LAST)
-IPC_ENUM_TRAITS_MAX_VALUE(ui::AXIntListAttribute,
-                          ui::AX_INT_LIST_ATTRIBUTE_LAST)
-IPC_ENUM_TRAITS_MAX_VALUE(ui::AXStringAttribute, ui::AX_STRING_ATTRIBUTE_LAST)
-
-IPC_STRUCT_TRAITS_BEGIN(ui::AXNodeData)
-  IPC_STRUCT_TRAITS_MEMBER(id)
-  IPC_STRUCT_TRAITS_MEMBER(role)
-  IPC_STRUCT_TRAITS_MEMBER(state)
-  IPC_STRUCT_TRAITS_MEMBER(location)
-  IPC_STRUCT_TRAITS_MEMBER(string_attributes)
-  IPC_STRUCT_TRAITS_MEMBER(int_attributes)
-  IPC_STRUCT_TRAITS_MEMBER(float_attributes)
-  IPC_STRUCT_TRAITS_MEMBER(bool_attributes)
-  IPC_STRUCT_TRAITS_MEMBER(intlist_attributes)
-  IPC_STRUCT_TRAITS_MEMBER(html_attributes)
-  IPC_STRUCT_TRAITS_MEMBER(child_ids)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(ui::AXTreeUpdate)
-  IPC_STRUCT_TRAITS_MEMBER(node_id_to_clear)
-  IPC_STRUCT_TRAITS_MEMBER(nodes)
-IPC_STRUCT_TRAITS_END()
-
 IPC_STRUCT_BEGIN(AccessibilityHostMsg_EventParams)
   // The tree update.
   IPC_STRUCT_MEMBER(ui::AXTreeUpdate, update)
diff --git a/content/common/android/address_parser.cc b/content/common/android/address_parser.cc
index 41bdeb7..2b0478a 100644
--- a/content/common/android/address_parser.cc
+++ b/content/common/android/address_parser.cc
@@ -171,10 +171,12 @@
           if (current_word_length == 2 && words.size() > 2) {
             const Word& previous_word = words[state_first_word - 1];
             if (previous_word.end - previous_word.begin == 2 &&
-                LowerCaseEqualsASCII(previous_word.begin, previous_word.end,
-                                     "et") &&
-                LowerCaseEqualsASCII(current_word.begin, current_word.end,
-                                     "al"))
+                base::LowerCaseEqualsASCII(previous_word.begin,
+                                           previous_word.end,
+                                           "et") &&
+                base::LowerCaseEqualsASCII(current_word.begin,
+                                           current_word.end,
+                                           "al"))
               break;
           }
 
diff --git a/content/common/android/address_parser_internal.cc b/content/common/android/address_parser_internal.cc
index 127fb3c..12ac3cc 100644
--- a/content/common/android/address_parser_internal.cc
+++ b/content/common/android/address_parser_internal.cc
@@ -157,7 +157,7 @@
     if (IsAsciiAlpha(*it_)) {
       // Handle special case 'one'.
       if (result_chars_ == 0) {
-        if (it_ + 3 <= end_ && LowerCaseEqualsASCII(it_, it_ + 3, "one"))
+        if (it_ + 3 <= end_ && base::LowerCaseEqualsASCII(it_, it_ + 3, "one"))
           AcceptChars(3);
         else
           RestartOnNextDelimiter();
diff --git a/content/common/appcache_interfaces.cc b/content/common/appcache_interfaces.cc
index 7f3f547..c2c6192 100644
--- a/content/common/appcache_interfaces.cc
+++ b/content/common/appcache_interfaces.cc
@@ -107,7 +107,7 @@
       ReplaceSubstringsAfterOffset(&pattern, 0, "?", "\\?");
     return MatchPattern(url.spec(), pattern);
   }
-  return StartsWithASCII(url.spec(), namespace_url.spec(), true);
+  return base::StartsWithASCII(url.spec(), namespace_url.spec(), true);
 }
 
 bool IsSchemeSupportedForAppCache(const GURL& url) {
diff --git a/content/common/bluetooth/bluetooth_messages.h b/content/common/bluetooth/bluetooth_messages.h
index 1c9f1d8..935c8b912 100644
--- a/content/common/bluetooth/bluetooth_messages.h
+++ b/content/common/bluetooth/bluetooth_messages.h
@@ -141,6 +141,18 @@
                      int /* request_id */,
                      content::BluetoothError /* result */)
 
+// Informs the renderer that characteristic request |request_id| succeeded.
+IPC_MESSAGE_CONTROL3(BluetoothMsg_GetCharacteristicSuccess,
+                     int /* thread_id */,
+                     int /* request_id */,
+                     std::string /* characteristic_instance_id */)
+
+// Informs the renderer that the characteristic request |request_id| failed.
+IPC_MESSAGE_CONTROL3(BluetoothMsg_GetCharacteristicError,
+                     int /* thread_id */,
+                     int /* request_id */,
+                     content::BluetoothError /* result */)
+
 // Messages sent from the renderer to the browser.
 
 // Requests a bluetooth device from the browser.
@@ -166,3 +178,10 @@
                      int /* request_id */,
                      std::string /* device_instance_id */,
                      std::string /* service_uuid */)
+
+// Gets a GATT Characteristic within a GATT Service.
+IPC_MESSAGE_CONTROL4(BluetoothHostMsg_GetCharacteristic,
+                     int /* thread_id */,
+                     int /* request_id */,
+                     std::string /* service_instance_id */,
+                     std::string /* characteristic_uuid */)
diff --git a/content/common/cc_messages.cc b/content/common/cc_messages.cc
index e3988de..cc8dd5f 100644
--- a/content/common/cc_messages.cc
+++ b/content/common/cc_messages.cc
@@ -402,7 +402,7 @@
 bool ParamTraits<cc::RenderPass>::Read(const Message* m,
                                        base::PickleIterator* iter,
                                        param_type* p) {
-  cc::RenderPassId id(-1, -1);
+  cc::RenderPassId id;
   gfx::Rect output_rect;
   gfx::Rect damage_rect;
   gfx::Transform transform_to_root_target;
@@ -854,4 +854,76 @@
   l->append("])");
 }
 
+void ParamTraits<cc::StreamVideoDrawQuad::OverlayResources>::Write(
+    Message* m,
+    const param_type& p) {
+  for (size_t i = 0; i < cc::DrawQuad::Resources::kMaxResourceIdCount; ++i) {
+    WriteParam(m, p.size_in_pixels[i]);
+    WriteParam(m, p.allow_overlay[i]);
+  }
+}
+
+bool ParamTraits<cc::StreamVideoDrawQuad::OverlayResources>::Read(
+    const Message* m,
+    base::PickleIterator* iter,
+    param_type* p) {
+  for (size_t i = 0; i < cc::DrawQuad::Resources::kMaxResourceIdCount; ++i) {
+    if (!ReadParam(m, iter, &p->size_in_pixels[i]))
+      return false;
+    if (!ReadParam(m, iter, &p->allow_overlay[i]))
+      return false;
+  }
+  return true;
+}
+
+void ParamTraits<cc::StreamVideoDrawQuad::OverlayResources>::Log(
+    const param_type& p,
+    std::string* l) {
+  l->append("StreamVideoDrawQuad::OverlayResources([");
+  for (size_t i = 0; i < cc::DrawQuad::Resources::kMaxResourceIdCount; ++i) {
+    LogParam(p.size_in_pixels[i], l);
+    l->append(", ");
+    LogParam(p.allow_overlay[i], l);
+    if (i < (cc::DrawQuad::Resources::kMaxResourceIdCount - 1))
+      l->append(", ");
+  }
+  l->append("])");
+}
+
+void ParamTraits<cc::TextureDrawQuad::OverlayResources>::Write(
+    Message* m,
+    const param_type& p) {
+  for (size_t i = 0; i < cc::DrawQuad::Resources::kMaxResourceIdCount; ++i) {
+    WriteParam(m, p.size_in_pixels[i]);
+    WriteParam(m, p.allow_overlay[i]);
+  }
+}
+
+bool ParamTraits<cc::TextureDrawQuad::OverlayResources>::Read(
+    const Message* m,
+    base::PickleIterator* iter,
+    param_type* p) {
+  for (size_t i = 0; i < cc::DrawQuad::Resources::kMaxResourceIdCount; ++i) {
+    if (!ReadParam(m, iter, &p->size_in_pixels[i]))
+      return false;
+    if (!ReadParam(m, iter, &p->allow_overlay[i]))
+      return false;
+  }
+  return true;
+}
+
+void ParamTraits<cc::TextureDrawQuad::OverlayResources>::Log(
+    const param_type& p,
+    std::string* l) {
+  l->append("TextureDrawQuad::OverlayResources([");
+  for (size_t i = 0; i < cc::DrawQuad::Resources::kMaxResourceIdCount; ++i) {
+    LogParam(p.size_in_pixels[i], l);
+    l->append(", ");
+    LogParam(p.allow_overlay[i], l);
+    if (i < (cc::DrawQuad::Resources::kMaxResourceIdCount - 1))
+      l->append(", ");
+  }
+  l->append("])");
+}
+
 }  // namespace IPC
diff --git a/content/common/cc_messages.h b/content/common/cc_messages.h
index 7560f80..8dfa794 100644
--- a/content/common/cc_messages.h
+++ b/content/common/cc_messages.h
@@ -126,6 +126,22 @@
   static void Log(const param_type& p, std::string* l);
 };
 
+template <>
+struct CONTENT_EXPORT ParamTraits<cc::StreamVideoDrawQuad::OverlayResources> {
+  typedef cc::StreamVideoDrawQuad::OverlayResources param_type;
+  static void Write(Message* m, const param_type& p);
+  static bool Read(const Message* m, base::PickleIterator* iter, param_type* p);
+  static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct CONTENT_EXPORT ParamTraits<cc::TextureDrawQuad::OverlayResources> {
+  typedef cc::TextureDrawQuad::OverlayResources param_type;
+  static void Write(Message* m, const param_type& p);
+  static bool Read(const Message* m, base::PickleIterator* iter, param_type* p);
+  static void Log(const param_type& p, std::string* l);
+};
+
 }  // namespace IPC
 
 #endif  // CONTENT_COMMON_CC_MESSAGES_H_
@@ -206,6 +222,7 @@
 
 IPC_STRUCT_TRAITS_BEGIN(cc::StreamVideoDrawQuad)
   IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
+  IPC_STRUCT_TRAITS_MEMBER(overlay_resources)
   IPC_STRUCT_TRAITS_MEMBER(matrix)
 IPC_STRUCT_TRAITS_END()
 
@@ -216,6 +233,7 @@
 
 IPC_STRUCT_TRAITS_BEGIN(cc::TextureDrawQuad)
   IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
+  IPC_STRUCT_TRAITS_MEMBER(overlay_resources)
   IPC_STRUCT_TRAITS_MEMBER(premultiplied_alpha)
   IPC_STRUCT_TRAITS_MEMBER(uv_top_left)
   IPC_STRUCT_TRAITS_MEMBER(uv_bottom_right)
diff --git a/content/common/cc_messages_unittest.cc b/content/common/cc_messages_unittest.cc
index 8ba443d..88daaa7 100644
--- a/content/common/cc_messages_unittest.cc
+++ b/content/common/cc_messages_unittest.cc
@@ -169,6 +169,8 @@
 
   void Compare(const StreamVideoDrawQuad* a, const StreamVideoDrawQuad* b) {
     EXPECT_EQ(a->resource_id(), b->resource_id());
+    EXPECT_EQ(a->resource_size_in_pixels(), b->resource_size_in_pixels());
+    EXPECT_EQ(a->allow_overlay(), b->allow_overlay());
     EXPECT_EQ(a->matrix, b->matrix);
   }
 
@@ -178,6 +180,8 @@
 
   void Compare(const TextureDrawQuad* a, const TextureDrawQuad* b) {
     EXPECT_EQ(a->resource_id(), b->resource_id());
+    EXPECT_EQ(a->resource_size_in_pixels(), b->resource_size_in_pixels());
+    EXPECT_EQ(a->allow_overlay(), b->allow_overlay());
     EXPECT_EQ(a->premultiplied_alpha, b->premultiplied_alpha);
     EXPECT_EQ(a->uv_top_left, b->uv_top_left);
     EXPECT_EQ(a->uv_bottom_right, b->uv_bottom_right);
@@ -263,6 +267,7 @@
   bool arbitrary_bool2 = false;
   bool arbitrary_bool3 = true;
   bool arbitrary_bool4 = true;
+  bool arbitrary_bool5 = false;
   int arbitrary_context_id1 = 12;
   int arbitrary_context_id2 = 57;
   int arbitrary_context_id3 = -503;
@@ -397,10 +402,10 @@
 
   StreamVideoDrawQuad* streamvideo_in =
       pass_in->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
-  streamvideo_in->SetAll(shared_state3_in, arbitrary_rect2,
-                         arbitrary_rect2_inside_rect2,
-                         arbitrary_rect1_inside_rect2, arbitrary_bool1,
-                         arbitrary_resourceid2, arbitrary_matrix1);
+  streamvideo_in->SetAll(
+      shared_state3_in, arbitrary_rect2, arbitrary_rect2_inside_rect2,
+      arbitrary_rect1_inside_rect2, arbitrary_bool1, arbitrary_resourceid2,
+      arbitrary_size1, arbitrary_bool2, arbitrary_matrix1);
   pass_cmp->CopyFromAndAppendDrawQuad(streamvideo_in,
                                       streamvideo_in->shared_quad_state);
 
@@ -418,19 +423,12 @@
 
   TextureDrawQuad* texture_in =
       pass_in->CreateAndAppendDrawQuad<TextureDrawQuad>();
-  texture_in->SetAll(shared_state3_in,
-                     arbitrary_rect2,
-                     arbitrary_rect2_inside_rect2,
-                     arbitrary_rect1_inside_rect2,
-                     arbitrary_bool1,
-                     arbitrary_resourceid1,
-                     arbitrary_bool2,
-                     arbitrary_pointf1,
-                     arbitrary_pointf2,
-                     arbitrary_color,
-                     arbitrary_float_array,
-                     arbitrary_bool3,
-                     arbitrary_bool4);
+  texture_in->SetAll(shared_state3_in, arbitrary_rect2,
+                     arbitrary_rect2_inside_rect2, arbitrary_rect1_inside_rect2,
+                     arbitrary_bool1, arbitrary_resourceid1, arbitrary_size1,
+                     arbitrary_bool2, arbitrary_bool3, arbitrary_pointf1,
+                     arbitrary_pointf2, arbitrary_color, arbitrary_float_array,
+                     arbitrary_bool4, arbitrary_bool5);
   pass_cmp->CopyFromAndAppendDrawQuad(texture_in,
                                       texture_in->shared_quad_state);
 
diff --git a/content/common/fileapi/OWNERS b/content/common/fileapi/OWNERS
index 334a61e..4d4319a 100644
--- a/content/common/fileapi/OWNERS
+++ b/content/common/fileapi/OWNERS
@@ -1,4 +1,3 @@
-kinuko@chromium.org
 michaeln@chromium.org
 jianli@chromium.org
 tzik@chromium.org
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.cc b/content/common/gpu/client/command_buffer_proxy_impl.cc
index 36e6459..60cc94af 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.cc
+++ b/content/common/gpu/client/command_buffer_proxy_impl.cc
@@ -71,7 +71,17 @@
   scoped_ptr<base::AutoLock> lock;
   if (lock_)
     lock.reset(new base::AutoLock(*lock_));
-  OnDestroyed(gpu::error::kGpuChannelLost, gpu::error::kLostContext);
+
+  gpu::error::ContextLostReason context_lost_reason =
+      gpu::error::kGpuChannelLost;
+  if (shared_state_shm_ && shared_state_shm_->memory()) {
+    TryUpdateState();
+    // The GPU process might have intentionally been crashed
+    // (exit_on_context_lost), so try to find out the original reason.
+    if (last_state_.error == gpu::error::kLostContext)
+      context_lost_reason = last_state_.context_lost_reason;
+  }
+  OnDestroyed(context_lost_reason, gpu::error::kLostContext);
 }
 
 void CommandBufferProxyImpl::OnDestroyed(gpu::error::ContextLostReason reason,
@@ -446,6 +456,10 @@
   lock_ = lock;
 }
 
+bool CommandBufferProxyImpl::IsGpuChannelLost() {
+  return !channel_ || channel_->IsLost();
+}
+
 uint32 CommandBufferProxyImpl::InsertSyncPoint() {
   CheckLock();
   if (last_state_.error != gpu::error::kNoError)
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.h b/content/common/gpu/client/command_buffer_proxy_impl.h
index cf73174c..f418a5b 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.h
+++ b/content/common/gpu/client/command_buffer_proxy_impl.h
@@ -118,6 +118,7 @@
   void SetSurfaceVisible(bool visible) override;
   uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock* lock) override;
+  bool IsGpuChannelLost() override;
 
   int GetRouteID() const;
   bool ProduceFrontBuffer(const gpu::Mailbox& mailbox);
diff --git a/content/common/gpu/client/context_provider_command_buffer.cc b/content/common/gpu/client/context_provider_command_buffer.cc
index 58e34b64..cb827258 100644
--- a/content/common/gpu/client/context_provider_command_buffer.cc
+++ b/content/common/gpu/client/context_provider_command_buffer.cc
@@ -137,7 +137,8 @@
   gr_context_.reset(new GrContextForWebGraphicsContext3D(context3d_.get()));
 
   // If GlContext is already lost, also abandon the new GrContext.
-  if (gr_context_->get() && IsContextLost())
+  if (gr_context_->get() &&
+      ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR)
     gr_context_->get()->abandonContext();
 
   return gr_context_->get();
@@ -168,18 +169,11 @@
   return capabilities_;
 }
 
-bool ContextProviderCommandBuffer::IsContextLost() {
-  DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
-  DCHECK(context_thread_checker_.CalledOnValidThread());
-
-  return context3d_->isContextLost();
-}
-
 void ContextProviderCommandBuffer::VerifyContexts() {
   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
   DCHECK(context_thread_checker_.CalledOnValidThread());
 
-  if (context3d_->isContextLost())
+  if (ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR)
     OnLostContext();
 }
 
diff --git a/content/common/gpu/client/context_provider_command_buffer.h b/content/common/gpu/client/context_provider_command_buffer.h
index 78c1b29b..1e0d23f8 100644
--- a/content/common/gpu/client/context_provider_command_buffer.h
+++ b/content/common/gpu/client/context_provider_command_buffer.h
@@ -43,7 +43,6 @@
   void SetupLock() override;
   base::Lock* GetLock() override;
   Capabilities ContextCapabilities() override;
-  bool IsContextLost() override;
   void VerifyContexts() override;
   void DeleteCachedResources() override;
   bool DestroyedOnMainThread() override;
diff --git a/content/common/gpu/client/gl_helper_scaling.cc b/content/common/gpu/client/gl_helper_scaling.cc
index b248d9d..7b7338d 100644
--- a/content/common/gpu/client/gl_helper_scaling.cc
+++ b/content/common/gpu/client/gl_helper_scaling.cc
@@ -870,15 +870,8 @@
   // The only reason fetching these attribute locations should fail is
   // if the context was spontaneously lost (i.e., because the GPU
   // process crashed, perhaps deliberately for testing).
-  // Unfortunately, the only way to reliably detect context loss from
-  // GLES2Interface would be to repeatedly call GetError(), and this
-  // seems fragile. Most of the APIs in GLHelper should be updated to
-  // be able to return an error. Fortunately, many users of this code
-  // check for context loss at a higher level.
-  if (!Initialized()) {
-    LOG(ERROR) << "ShaderProgram::Setup: initialization failed (context lost?)";
-  }
-  return;
+  DCHECK_IMPLIES(!Initialized(),
+                 gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR);
 }
 
 void ShaderProgram::UseProgram(const gfx::Size& src_size,
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.cc b/content/common/gpu/client/gpu_memory_buffer_impl.cc
index 2dceda2..8976742 100644
--- a/content/common/gpu/client/gpu_memory_buffer_impl.cc
+++ b/content/common/gpu/client/gpu_memory_buffer_impl.cc
@@ -45,6 +45,7 @@
     const gfx::GpuMemoryBufferHandle& handle,
     const gfx::Size& size,
     Format format,
+    Usage usage,
     const DestructionCallback& callback) {
   switch (handle.type) {
     case gfx::SHARED_MEMORY_BUFFER:
@@ -63,11 +64,11 @@
 #if defined(USE_OZONE)
     case gfx::OZONE_NATIVE_BUFFER:
       return GpuMemoryBufferImplOzoneNativeBuffer::CreateFromHandle(
-          handle, size, format, callback);
+          handle, size, format, usage, callback);
 #endif
     default:
       NOTREACHED();
-      return scoped_ptr<GpuMemoryBufferImpl>();
+      return nullptr;
   }
 }
 
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.h b/content/common/gpu/client/gpu_memory_buffer_impl.h
index 1a7e043d..8fdfbd0 100644
--- a/content/common/gpu/client/gpu_memory_buffer_impl.h
+++ b/content/common/gpu/client/gpu_memory_buffer_impl.h
@@ -28,6 +28,7 @@
       const gfx::GpuMemoryBufferHandle& handle,
       const gfx::Size& size,
       Format format,
+      Usage usage,
       const DestructionCallback& callback);
 
   // Type-checking upcast routine. Returns an NULL on failure.
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc b/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc
index 8b3e342..9a427a919 100644
--- a/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc
+++ b/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.cc
@@ -25,6 +25,7 @@
     const gfx::GpuMemoryBufferHandle& handle,
     const gfx::Size& size,
     Format format,
+    Usage usage,
     const DestructionCallback& callback) {
   return make_scoped_ptr<GpuMemoryBufferImpl>(
       new GpuMemoryBufferImplOzoneNativeBuffer(
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h b/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h
index 040eab9..882e1e0 100644
--- a/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h
+++ b/content/common/gpu/client/gpu_memory_buffer_impl_ozone_native_buffer.h
@@ -16,6 +16,7 @@
       const gfx::GpuMemoryBufferHandle& handle,
       const gfx::Size& size,
       Format format,
+      Usage usage,
       const DestructionCallback& callback);
 
   // Overridden from gfx::GpuMemoryBuffer:
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc b/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc
index a0ac335..91be10a 100644
--- a/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc
+++ b/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc
@@ -57,15 +57,11 @@
   for (auto configuration : supported_configurations_) {
     scoped_ptr<GpuMemoryBufferImpl> buffer(
         GpuMemoryBufferImpl::CreateFromHandle(
-            CreateGpuMemoryBuffer(kBufferId,
-                                  buffer_size,
-                                  configuration.format,
+            CreateGpuMemoryBuffer(kBufferId, buffer_size, configuration.format,
                                   configuration.usage),
-            buffer_size,
-            configuration.format,
+            buffer_size, configuration.format, configuration.usage,
             base::Bind(&GpuMemoryBufferImplTest::DestroyGpuMemoryBuffer,
-                       base::Unretained(this),
-                       kBufferId)));
+                       base::Unretained(this), kBufferId)));
     EXPECT_EQ(1, buffer_count_);
     ASSERT_TRUE(buffer);
     EXPECT_EQ(buffer->GetFormat(), configuration.format);
@@ -90,7 +86,7 @@
         GpuMemoryBufferImpl::CreateFromHandle(
             CreateGpuMemoryBuffer(kBufferId, buffer_size, configuration.format,
                                   configuration.usage),
-            buffer_size, configuration.format,
+            buffer_size, configuration.format, configuration.usage,
             base::Bind(&GpuMemoryBufferImplTest::DestroyGpuMemoryBuffer,
                        base::Unretained(this), kBufferId)));
     ASSERT_TRUE(buffer);
@@ -153,7 +149,7 @@
         GpuMemoryBufferImpl::CreateFromHandle(
             CreateGpuMemoryBuffer(kBufferId, buffer_size, configuration.format,
                                   configuration.usage),
-            buffer_size, configuration.format,
+            buffer_size, configuration.format, configuration.usage,
             base::Bind(&GpuMemoryBufferImplTest::DestroyGpuMemoryBuffer,
                        base::Unretained(this), kBufferId)));
     ASSERT_TRUE(buffer);
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
index b06b06ec..0c77e5bf 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
@@ -145,9 +145,6 @@
     return false;
   }
 
-  if (gl_ && attributes_.webGL)
-    gl_->EnableFeatureCHROMIUM("webgl_enable_glsl_webgl_validation");
-
   command_buffer_->SetContextLostCallback(
       base::Bind(&WebGraphicsContext3DCommandBufferImpl::OnContextLost,
                  weak_ptr_factory_.GetWeakPtr()));
@@ -336,21 +333,6 @@
   return real_gl_.get();
 }
 
-bool WebGraphicsContext3DCommandBufferImpl::isContextLost() {
-  return initialize_failed_ ||
-      (command_buffer_ && IsCommandBufferContextLost()) ||
-      context_lost_reason_ != GL_NO_ERROR;
-}
-
-WGC3Denum WebGraphicsContext3DCommandBufferImpl::getGraphicsResetStatusARB() {
-  if (IsCommandBufferContextLost() &&
-      context_lost_reason_ == GL_NO_ERROR) {
-    return GL_UNKNOWN_CONTEXT_RESET_ARB;
-  }
-
-  return context_lost_reason_;
-}
-
 bool WebGraphicsContext3DCommandBufferImpl::IsCommandBufferContextLost() {
   // If the channel shut down unexpectedly, let that supersede the
   // command buffer's state.
@@ -385,33 +367,9 @@
       share_context);
 }
 
-namespace {
-
-WGC3Denum convertReason(gpu::error::ContextLostReason reason) {
-  switch (reason) {
-  case gpu::error::kGuilty:
-    return GL_GUILTY_CONTEXT_RESET_ARB;
-  case gpu::error::kInnocent:
-    return GL_INNOCENT_CONTEXT_RESET_ARB;
-  case gpu::error::kOutOfMemory:
-  case gpu::error::kMakeCurrentFailed:
-  case gpu::error::kUnknown:
-  case gpu::error::kGpuChannelLost:
-    return GL_UNKNOWN_CONTEXT_RESET_ARB;
-  }
-
-  NOTREACHED();
-  return GL_UNKNOWN_CONTEXT_RESET_ARB;
-}
-
-}  // anonymous namespace
-
 void WebGraphicsContext3DCommandBufferImpl::OnContextLost() {
-  context_lost_reason_ =
-      convertReason(command_buffer_->GetLastState().context_lost_reason);
-  if (context_lost_callback_) {
+  if (context_lost_callback_)
     context_lost_callback_->onContextLost();
-  }
 
   share_group_->RemoveAllContexts();
 
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
index 115e167d..0eca015 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
@@ -145,12 +145,6 @@
 
   CONTENT_EXPORT bool InitializeOnCurrentThread();
 
-  //----------------------------------------------------------------------
-  // WebGraphicsContext3D methods
-  virtual bool isContextLost();
-
-  virtual blink::WGC3Denum getGraphicsResetStatusARB();
-
   void SetContextType(CommandBufferContextType type) {
     context_type_ = type;
   }
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index bd57c41..e50de4ca 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -40,6 +40,7 @@
 #include "ui/gl/gl_switches.h"
 
 #if defined(OS_WIN)
+#include "base/win/win_util.h"
 #include "content/public/common/sandbox_init.h"
 #endif
 
@@ -472,14 +473,6 @@
   DCHECK(result);
 
   decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group_.get()));
-
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSingleProcess) &&
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kInProcessGPU)) {
-    decoder_->SetAllowExit(true);
-  }
-
   scheduler_.reset(new gpu::GpuScheduler(command_buffer_.get(),
                                          decoder_.get(),
                                          decoder_.get()));
@@ -1089,6 +1082,21 @@
   DCHECK(command_buffer_);
   gpu::CommandBuffer::State state = command_buffer_->GetLastState();
   bool was_lost = state.error == gpu::error::kLostContext;
+
+  // Work around issues with recovery by allowing a new GPU process to launch.
+  if (was_lost &&
+      context_group_->feature_info()->workarounds().exit_on_context_lost &&
+      !base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSingleProcess) &&
+      !base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kInProcessGPU)) {
+    LOG(ERROR) << "Exiting GPU process because some drivers cannot recover"
+               << " from problems.";
+#if defined(OS_WIN)
+    base::win::SetShouldCrashOnProcessDetach(false);
+#endif
+    exit(0);
+  }
   // Lose all other contexts if the reset was triggered by the robustness
   // extension instead of being synthetic.
   if (was_lost && decoder_ && decoder_->WasContextLostByRobustnessExtension() &&
diff --git a/content/common/gpu/image_transport_surface_fbo_mac.mm b/content/common/gpu/image_transport_surface_fbo_mac.mm
index ec827c2e..e30a42a 100644
--- a/content/common/gpu/image_transport_surface_fbo_mac.mm
+++ b/content/common/gpu/image_transport_surface_fbo_mac.mm
@@ -180,7 +180,11 @@
   DCHECK(backbuffer_suggested_allocation_);
   if (!frontbuffer_suggested_allocation_)
     return true;
-  glFlush();
+
+  {
+    TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::glFlush");
+    glFlush();
+  }
 
   // It is the responsibility of the storage provider to send the swap IPC.
   is_swap_buffers_send_pending_ = true;
diff --git a/content/common/gpu/media/generic_v4l2_device.cc b/content/common/gpu/media/generic_v4l2_device.cc
index 2dde55d..fab5f89 100644
--- a/content/common/gpu/media/generic_v4l2_device.cc
+++ b/content/common/gpu/media/generic_v4l2_device.cc
@@ -36,7 +36,7 @@
 namespace {
 const char kDecoderDevice[] = "/dev/video-dec";
 const char kEncoderDevice[] = "/dev/video-enc";
-const char kImageProcessorDevice[] = "/dev/gsc0";
+const char kImageProcessorDevice[] = "/dev/image-proc0";
 }
 
 GenericV4L2Device::GenericV4L2Device(Type type)
@@ -153,8 +153,9 @@
     return false;
   }
 #if defined(USE_LIBV4L2)
-  if (HANDLE_EINTR(v4l2_fd_open(device_fd_.get(), V4L2_DISABLE_CONVERSION)) !=
-      -1) {
+  if (type_ == kEncoder &&
+      HANDLE_EINTR(v4l2_fd_open(device_fd_.get(), V4L2_DISABLE_CONVERSION)) !=
+          -1) {
     DVLOG(2) << "Using libv4l2 for " << device_path;
     use_libv4l2_ = true;
   }
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
index 2773a408..2d638cb 100644
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
@@ -293,11 +293,14 @@
     return false;
   }
 
-  // TODO(posciak): add back VP8 (crbug.com/490233)
   if (profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX) {
     h264_accelerator_.reset(
         new VaapiH264Accelerator(this, vaapi_wrapper_.get()));
     decoder_.reset(new H264Decoder(h264_accelerator_.get()));
+  } else if (profile >= media::VP8PROFILE_MIN &&
+             profile <= media::VP8PROFILE_MAX) {
+    vp8_accelerator_.reset(new VaapiVP8Accelerator(this, vaapi_wrapper_.get()));
+    decoder_.reset(new VP8Decoder(vp8_accelerator_.get()));
   } else {
     DLOG(ERROR) << "Unsupported profile " << profile;
     return false;
diff --git a/content/common/media/audio_messages.h b/content/common/media/audio_messages.h
index 57dd4a6..bfa51da 100644
--- a/content/common/media/audio_messages.h
+++ b/content/common/media/audio_messages.h
@@ -5,6 +5,8 @@
 // IPC messages for the audio.
 // Multiply-included message file, hence no include guard.
 
+#include <string>
+
 #include "base/basictypes.h"
 #include "base/memory/shared_memory.h"
 #include "base/sync_socket.h"
@@ -14,16 +16,20 @@
 #include "media/audio/audio_input_ipc.h"
 #include "media/audio/audio_output_ipc.h"
 #include "media/audio/audio_parameters.h"
+#include "url/gurl.h"
 
 #undef IPC_MESSAGE_EXPORT
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
 #define IPC_MESSAGE_START AudioMsgStart
 
-IPC_ENUM_TRAITS_MAX_VALUE(media::AudioInputIPCDelegate::State,
-                          media::AudioInputIPCDelegate::kStateLast)
+IPC_ENUM_TRAITS_MAX_VALUE(media::AudioInputIPCDelegateState,
+                          media::AUDIO_INPUT_IPC_DELEGATE_STATE_LAST)
 
-IPC_ENUM_TRAITS_MAX_VALUE(media::AudioOutputIPCDelegate::State,
-                          media::AudioOutputIPCDelegate::kStateLast)
+IPC_ENUM_TRAITS_MAX_VALUE(media::AudioOutputIPCDelegateState,
+                          media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_LAST)
+
+IPC_ENUM_TRAITS_MAX_VALUE(media::SwitchOutputDeviceResult,
+                          media::SWITCH_OUTPUT_DEVICE_RESULT_LAST)
 
 IPC_STRUCT_BEGIN(AudioInputHostMsg_CreateStream_Config)
   IPC_STRUCT_MEMBER(media::AudioParameters, params)
@@ -60,17 +66,24 @@
 // update after the renderer has requested a Create/Start/Close.
 IPC_MESSAGE_CONTROL2(AudioMsg_NotifyStreamStateChanged,
                      int /* stream id */,
-                     media::AudioOutputIPCDelegate::State /* new state */)
+                     media::AudioOutputIPCDelegateState /* new state */)
 
 // Notification message sent from browser to renderer for state update.
 IPC_MESSAGE_CONTROL2(AudioInputMsg_NotifyStreamStateChanged,
                      int /* stream id */,
-                     media::AudioInputIPCDelegate::State /* new state */)
+                     media::AudioInputIPCDelegateState /* new state */)
 
 IPC_MESSAGE_CONTROL2(AudioInputMsg_NotifyStreamVolume,
                      int /* stream id */,
                      double /* volume */)
 
+// Notification message sent from AudioRendererHost to renderer for state
+// update after the renderer has requested a SwitchOutputDevice.
+IPC_MESSAGE_CONTROL3(AudioMsg_NotifyOutputDeviceSwitched,
+                     int /* stream id */,
+                     int /* request id */,
+                     media::SwitchOutputDeviceResult /* result */)
+
 // Messages sent from the renderer to the browser.
 
 // Request that is sent to the browser for creating an audio output stream.
@@ -121,3 +134,11 @@
 IPC_MESSAGE_CONTROL2(AudioInputHostMsg_SetVolume,
                      int /* stream_id */,
                      double /* volume */)
+
+// Switch the output device of the stream specified by stream_id.
+IPC_MESSAGE_CONTROL5(AudioHostMsg_SwitchOutputDevice,
+                     int /* stream_id */,
+                     int /* render_frame_id */,
+                     std::string /* device_id */,
+                     GURL /* security_origin */,
+                     int /* request_id */)
diff --git a/content/common/media/media_player_messages_android.h b/content/common/media/media_player_messages_android.h
index 8cdf703..210d3817 100644
--- a/content/common/media/media_player_messages_android.h
+++ b/content/common/media/media_player_messages_android.h
@@ -206,10 +206,6 @@
                     int /* player_id */,
                     bool /* routes_available */)
 
-// Instructs the video element to enter fullscreen.
-IPC_MESSAGE_ROUTED1(MediaPlayerMsg_RequestFullscreen,
-                    int /*player_id */)
-
 // Messages for controlling the media playback in browser process ----------
 
 // Destroy the media player object.
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc
index b40b457..c067725f 100644
--- a/content/common/page_state_serialization.cc
+++ b/content/common/page_state_serialization.cc
@@ -120,7 +120,7 @@
         index + value_size < index)  // Check for overflow.
       return false;
 
-    if (EqualsASCII(type.string(), "file")) {
+    if (base::EqualsASCII(type.string(), "file")) {
       if (value_size != 2)
         return false;
 
diff --git a/content/common/plugin_list_mac.mm b/content/common/plugin_list_mac.mm
index 8400dce..d32f1713 100644
--- a/content/common/plugin_list_mac.mm
+++ b/content/common/plugin_list_mac.mm
@@ -56,9 +56,9 @@
 
   // Versions of Flip4Mac 2.3 before 2.3.6 often hang the renderer, so don't
   // load them.
-  if (StartsWith(info.name,
-                 base::ASCIIToUTF16("Flip4Mac Windows Media"), false) &&
-      StartsWith(info.version, base::ASCIIToUTF16("2.3"), false)) {
+  if (base::StartsWith(info.name, base::ASCIIToUTF16("Flip4Mac Windows Media"),
+                       false) &&
+      base::StartsWith(info.version, base::ASCIIToUTF16("2.3"), false)) {
     std::vector<base::string16> components;
     base::SplitString(info.version, '.', &components);
     int bugfix_version = 0;
@@ -144,7 +144,8 @@
     // Remove PDF from the list of types handled by QuickTime, since it provides
     // a worse experience than just downloading the PDF.
     if (mime.mime_type == "application/pdf" &&
-        StartsWithASCII(filename.BaseName().value(), "QuickTime", false)) {
+        base::StartsWithASCII(filename.BaseName().value(), "QuickTime",
+                              false)) {
       continue;
     }
 
diff --git a/content/common/presentation/presentation_service.mojom b/content/common/presentation/presentation_service.mojom
index bc06725..d033a48 100644
--- a/content/common/presentation/presentation_service.mojom
+++ b/content/common/presentation/presentation_service.mojom
@@ -29,13 +29,16 @@
 enum PresentationMessageType {
   TEXT,
   ARRAY_BUFFER,
+  BLOB,
 };
 
 struct SessionMessage {
   string presentation_url;
   string presentation_id;
   PresentationMessageType type;
+  // Used when message type is TEXT.
   string? message;
+  // Used when message type is ARRAY_BUFFER or BLOB.
   array<uint8>? data;
 };
 
diff --git a/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.cc b/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.cc
index 338acf9..31339ac1 100644
--- a/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.cc
+++ b/content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.cc
@@ -59,11 +59,11 @@
   // Device file needed by the ARM GPU userspace.
   static const char kMali0Path[] = "/dev/mali0";
 
-  // Video processor used on ARM Exynos platforms.
-  static const char kDevGsc0Path[] = "/dev/gsc0";
+  // Image processor used on ARM platforms.
+  static const char kDevImageProc0Path[] = "/dev/image-proc0";
 
   permissions->push_back(BrokerFilePermission::ReadWrite(kMali0Path));
-  permissions->push_back(BrokerFilePermission::ReadWrite(kDevGsc0Path));
+  permissions->push_back(BrokerFilePermission::ReadWrite(kDevImageProc0Path));
 }
 
 void AddArmGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
diff --git a/content/common/screen_orientation_messages.h b/content/common/screen_orientation_messages.h
index d5c3a60..cb70a7b 100644
--- a/content/common/screen_orientation_messages.h
+++ b/content/common/screen_orientation_messages.h
@@ -7,8 +7,8 @@
 
 #include "content/common/content_export.h"
 #include "ipc/ipc_message_macros.h"
-#include "third_party/WebKit/public/platform/WebLockOrientationError.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationError.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 
 #undef IPC_MESSAGE_EXPORT
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
diff --git a/content/common/service_worker/OWNERS b/content/common/service_worker/OWNERS
index 5f81c89..4926179 100644
--- a/content/common/service_worker/OWNERS
+++ b/content/common/service_worker/OWNERS
@@ -3,9 +3,6 @@
 horo@chromium.org
 nhiroki@chromium.org
 
-# may not be available
-kinuko@chromium.org
-
 # Changes to IPC messages require a security review to avoid introducing
 # new sandbox escapes.
 per-file *_messages*.h=set noparent
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index d18bef7..c2fdbd52 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -131,6 +131,11 @@
                      int /* provider_id */,
                      GURL /* document_url */)
 
+IPC_MESSAGE_CONTROL3(ServiceWorkerHostMsg_GetRegistrations,
+                     int /* thread_id */,
+                     int /* request_id */,
+                     int /* provider_id */)
+
 IPC_MESSAGE_CONTROL3(ServiceWorkerHostMsg_GetRegistrationForReady,
                      int /* thread_id */,
                      int /* request_id */,
@@ -310,6 +315,13 @@
                      content::ServiceWorkerRegistrationObjectInfo,
                      content::ServiceWorkerVersionAttributes)
 
+// Response to ServiceWorkerHostMsg_GetRegistrations.
+IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_DidGetRegistrations,
+                     int /* thread_id */,
+                     int /* request_id */,
+                     std::vector<content::ServiceWorkerRegistrationObjectInfo>,
+                     std::vector<content::ServiceWorkerVersionAttributes>)
+
 // Response to ServiceWorkerHostMsg_GetRegistrationForReady.
 IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_DidGetRegistrationForReady,
                      int /* thread_id */,
@@ -341,6 +353,14 @@
                      blink::WebServiceWorkerError::ErrorType /* code */,
                      base::string16 /* message */)
 
+// Sent when any kind of registration error occurs during a
+// GetRegistrations handler above.
+IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_ServiceWorkerGetRegistrationsError,
+                     int /* thread_id */,
+                     int /* request_id */,
+                     blink::WebServiceWorkerError::ErrorType /* code */,
+                     base::string16 /* message */)
+
 // Informs the child process that the ServiceWorker's state has changed.
 IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_ServiceWorkerStateChanged,
                      int /* thread_id */,
diff --git a/content/common/service_worker/service_worker_status_code.cc b/content/common/service_worker/service_worker_status_code.cc
index 51a58b0..f81aeb7 100644
--- a/content/common/service_worker/service_worker_status_code.cc
+++ b/content/common/service_worker/service_worker_status_code.cc
@@ -45,6 +45,8 @@
       return "ServiceWorker script evaluation failed";
     case SERVICE_WORKER_ERROR_DISK_CACHE:
       return "Disk cache error";
+    case SERVICE_WORKER_ERROR_REDUNDANT:
+      return "Redundant worker";
     case SERVICE_WORKER_ERROR_MAX_VALUE:
       NOTREACHED();
   }
diff --git a/content/common/service_worker/service_worker_status_code.h b/content/common/service_worker/service_worker_status_code.h
index 88c06098..f884aed7 100644
--- a/content/common/service_worker/service_worker_status_code.h
+++ b/content/common/service_worker/service_worker_status_code.h
@@ -66,6 +66,9 @@
   // Generic error to indicate failure to read/write the disk cache.
   SERVICE_WORKER_ERROR_DISK_CACHE,
 
+  // The worker is in REDUNDANT state.
+  SERVICE_WORKER_ERROR_REDUNDANT,
+
   SERVICE_WORKER_ERROR_MAX_VALUE
 };
 
diff --git a/content/common/service_worker/service_worker_types.cc b/content/common/service_worker/service_worker_types.cc
index c6be99d..131c0e60 100644
--- a/content/common/service_worker/service_worker_types.cc
+++ b/content/common/service_worker/service_worker_types.cc
@@ -12,6 +12,8 @@
     "Failed to unregister a ServiceWorkerRegistration: ";
 const char kServiceWorkerGetRegistrationErrorPrefix[] =
     "Failed to get a ServiceWorkerRegistration: ";
+const char kServiceWorkerGetRegistrationsErrorPrefix[] =
+    "Failed to get ServiceWorkerRegistration objects: ";
 const char kFetchScriptError[] =
     "An unknown error occurred when fetching the script.";
 
diff --git a/content/common/service_worker/service_worker_types.h b/content/common/service_worker/service_worker_types.h
index 6e235a77..6aa97d4 100644
--- a/content/common/service_worker/service_worker_types.h
+++ b/content/common/service_worker/service_worker_types.h
@@ -38,6 +38,7 @@
 extern const char kServiceWorkerRegisterErrorPrefix[];
 extern const char kServiceWorkerUnregisterErrorPrefix[];
 extern const char kServiceWorkerGetRegistrationErrorPrefix[];
+extern const char kServiceWorkerGetRegistrationsErrorPrefix[];
 extern const char kFetchScriptError[];
 
 // Constants for invalid identifiers.
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index ee3606c..c7f5b3e1 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -42,7 +42,7 @@
 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
 #include "third_party/WebKit/public/platform/WebFloatRect.h"
 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
 #include "third_party/WebKit/public/web/WebFindOptions.h"
 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 12472fd..18a6b13 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -382,6 +382,8 @@
       'browser/android/in_process/synchronous_compositor_registry.h',
       'browser/android/in_process/synchronous_input_event_filter.cc',
       'browser/android/in_process/synchronous_input_event_filter.h',
+      'browser/android/in_process_surface_texture_manager.cc',
+      'browser/android/in_process_surface_texture_manager.h',
       'browser/android/interstitial_page_delegate_android.cc',
       'browser/android/interstitial_page_delegate_android.h',
       'browser/android/load_url_params.cc',
@@ -581,6 +583,8 @@
       'browser/devtools/protocol/page_handler.h',
       'browser/devtools/protocol/power_handler.cc',
       'browser/devtools/protocol/power_handler.h',
+      'browser/devtools/protocol/security_handler.cc',
+      'browser/devtools/protocol/security_handler.h',
       'browser/devtools/protocol/service_worker_handler.cc',
       'browser/devtools/protocol/service_worker_handler.h',
       'browser/devtools/protocol/system_info_handler.cc',
@@ -701,6 +705,8 @@
       'browser/frame_host/debug_urls.h',
       'browser/frame_host/frame_accessibility.cc',
       'browser/frame_host/frame_accessibility.h',
+      'browser/frame_host/frame_mojo_shell.cc',
+      'browser/frame_host/frame_mojo_shell.h',
       'browser/frame_host/frame_navigation_entry.cc',
       'browser/frame_host/frame_navigation_entry.h',
       'browser/frame_host/frame_tree.cc',
@@ -857,6 +863,8 @@
       'browser/host_zoom_level_context.h',
       'browser/host_zoom_map_impl.cc',
       'browser/host_zoom_map_impl.h',
+      'browser/in_process_io_surface_manager_mac.cc',
+      'browser/in_process_io_surface_manager_mac.h',
       'browser/indexed_db/indexed_db.h',
       'browser/indexed_db/indexed_db_active_blob_registry.cc',
       'browser/indexed_db/indexed_db_active_blob_registry.h',
@@ -1130,8 +1138,6 @@
       'browser/renderer_host/delegated_frame_evictor.h',
       'browser/renderer_host/dip_util.cc',
       'browser/renderer_host/dip_util.h',
-      'browser/renderer_host/display_link_mac.cc',
-      'browser/renderer_host/display_link_mac.h',
       'browser/renderer_host/event_with_latency_info.h',
       'browser/renderer_host/file_utilities_message_filter.cc',
       'browser/renderer_host/file_utilities_message_filter.h',
diff --git a/content/content_browsertests.isolate b/content/content_browsertests.isolate
index 2fcab67..a6f069f 100644
--- a/content/content_browsertests.isolate
+++ b/content/content_browsertests.isolate
@@ -66,7 +66,6 @@
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/content_shell.pak',
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
         ],
       },
@@ -96,7 +95,6 @@
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/Content Shell.app/',
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
           '<(PRODUCT_DIR)/plugins/npapi_test_plugin.plugin/',
           '<(PRODUCT_DIR)/plugins/test_netscape_plugin.plugin/',
           '<(PRODUCT_DIR)/ppapi_tests.plugin/Contents/MacOS/ppapi_tests',
@@ -110,7 +108,6 @@
           '<(PRODUCT_DIR)/Content Shell Helper.app.dSYM/',
           '<(PRODUCT_DIR)/Content Shell.app.dSYM/',
           '<(PRODUCT_DIR)/content_browsertests.dSYM/',
-          '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
           '<(PRODUCT_DIR)/npapi_test_plugin.plugin.dSYM/',
           '<(PRODUCT_DIR)/ppapi_tests.plugin.dSYM/',
           '<(PRODUCT_DIR)/test_netscape_plugin.plugin.dSYM/',
@@ -121,7 +118,6 @@
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/content_shell.pak',
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/osmesa.dll',
           '<(PRODUCT_DIR)/plugins/np_test_netscape_plugin.dll',
           '<(PRODUCT_DIR)/plugins/npapi_test_plugin.dll',
diff --git a/content/content_gl_tests.isolate b/content/content_gl_tests.isolate
index ea9938d..b685ea7 100644
--- a/content/content_gl_tests.isolate
+++ b/content/content_gl_tests.isolate
@@ -24,27 +24,12 @@
         ],
       },
     }],
-    ['OS=="linux"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
-        ],
-      },
-    }],
-    ['OS=="mac"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
-        ],
-      },
-    }],
     ['OS=="win"', {
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/d3dcompiler_47.dll',
           '<(PRODUCT_DIR)/libEGL.dll',
           '<(PRODUCT_DIR)/libGLESv2.dll',
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/osmesa.dll',
         ],
       },
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index a3c6da35..b422e88a 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -375,16 +375,14 @@
       'renderer/screen_orientation/screen_orientation_dispatcher.h',
       'renderer/screen_orientation/screen_orientation_observer.cc',
       'renderer/screen_orientation/screen_orientation_observer.h',
-      'renderer/service_worker/embedded_worker_context_client.cc',
-      'renderer/service_worker/embedded_worker_context_client.h',
-      'renderer/service_worker/embedded_worker_context_message_filter.cc',
-      'renderer/service_worker/embedded_worker_context_message_filter.h',
       'renderer/service_worker/embedded_worker_devtools_agent.cc',
       'renderer/service_worker/embedded_worker_devtools_agent.h',
       'renderer/service_worker/embedded_worker_dispatcher.cc',
       'renderer/service_worker/embedded_worker_dispatcher.h',
-      'renderer/service_worker/service_worker_script_context.cc',
-      'renderer/service_worker/service_worker_script_context.h',
+      'renderer/service_worker/service_worker_context_client.cc',
+      'renderer/service_worker/service_worker_context_client.h',
+      'renderer/service_worker/service_worker_context_message_filter.cc',
+      'renderer/service_worker/service_worker_context_message_filter.h',
       'renderer/service_worker/service_worker_type_util.cc',
       'renderer/service_worker/service_worker_type_util.h',
       'renderer/shared_memory_seqlock_reader.cc',
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index 6893e2d..5e65727 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -226,8 +226,6 @@
         'shell/renderer/layout_test/leak_detector.h',
         'shell/renderer/layout_test/test_media_stream_renderer_factory.cc',
         'shell/renderer/layout_test/test_media_stream_renderer_factory.h',
-        'shell/renderer/layout_test/test_plugin_placeholder.cc',
-        'shell/renderer/layout_test/test_plugin_placeholder.h',
         'shell/renderer/layout_test/test_video_frame_provider.cc',
         'shell/renderer/layout_test/test_video_frame_provider.h',
         'shell/renderer/shell_content_renderer_client.cc',
@@ -769,13 +767,6 @@
           ],
           'copies': [
             {
-              # Copy FFmpeg binaries for audio/video support.
-              'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Libraries',
-              'files': [
-                '<(PRODUCT_DIR)/ffmpegsumo.so',
-              ],
-            },
-            {
               'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Resources',
               'files': [
                 '<(PRODUCT_DIR)/crash_inspector',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 0dfc8ca..b97cff07 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -210,6 +210,7 @@
       'browser/frame_host/navigation_controller_impl_browsertest.cc',
       'browser/frame_host/render_frame_host_impl_browsertest.cc',
       'browser/frame_host/render_frame_host_manager_browsertest.cc',
+      'browser/frame_host/render_widget_host_view_child_frame_browsertest.cc',
       'browser/gpu/gpu_ipc_browsertests.cc',
       'browser/host_zoom_map_impl_browsertest.cc',
       'browser/indexed_db/indexed_db_browsertest.cc',
@@ -229,6 +230,7 @@
       'browser/plugin_browsertest.cc',
       'browser/renderer_host/input/touch_action_browsertest.cc',
       'browser/renderer_host/input/touch_input_browsertest.cc',
+      'browser/renderer_host/render_message_filter_browsertest.cc',
       'browser/renderer_host/render_process_host_browsertest.cc',
       'browser/renderer_host/render_view_host_browsertest.cc',
       'browser/renderer_host/render_widget_host_view_browsertest.cc',
@@ -252,6 +254,7 @@
       'renderer/accessibility/renderer_accessibility_browsertest.cc',
       'renderer/devtools/v8_sampling_profiler_browsertest.cc',
       'renderer/gin_browsertest.cc',
+      'renderer/history_controller_browsertest.cc',
       'renderer/mouse_lock_dispatcher_browsertest.cc',
       'renderer/render_frame_impl_browsertest.cc',
       'renderer/render_thread_impl_browsertest.cc',
@@ -580,6 +583,7 @@
       'browser/web_contents/web_contents_delegate_unittest.cc',
       'browser/web_contents/web_contents_impl_unittest.cc',
       'browser/web_contents/web_contents_user_data_unittest.cc',
+      'browser/web_contents/web_contents_view_aura_unittest.cc',
       'browser/web_contents/web_contents_view_mac_unittest.mm',
       'browser/web_contents/web_drag_dest_mac_unittest.mm',
       'browser/web_contents/web_drag_source_mac_unittest.mm',
@@ -1387,6 +1391,7 @@
             '../third_party/mojo/mojo_edk.gyp:mojo_system_impl',
             '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
             '../third_party/mojo/mojo_public.gyp:mojo_js_bindings',
+            '../third_party/zlib/zlib.gyp:zlib',
             '../ui/accessibility/accessibility.gyp:accessibility',
             '../ui/base/ui_base.gyp:ui_base',
             '../ui/gfx/gfx.gyp:gfx',
diff --git a/content/content_unittests.isolate b/content/content_unittests.isolate
index 07ac6e7..61eca66 100644
--- a/content/content_unittests.isolate
+++ b/content/content_unittests.isolate
@@ -68,7 +68,6 @@
     ['OS=="linux"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
         ],
       },
@@ -76,7 +75,6 @@
     ['OS=="mac"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
           '<(PRODUCT_DIR)/osmesa.so',
         ],
       },
@@ -84,7 +82,6 @@
     ['OS=="win"', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/osmesa.dll',
         ],
       },
@@ -93,7 +90,6 @@
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/content_unittests.dSYM/',
-          '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
           '<(PRODUCT_DIR)/osmesa.so.dSYM/',
         ],
       },
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index c6a59fc..71e493b 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -160,9 +160,22 @@
   bool dead_on_arrival = false;
 
 #if defined(OS_WIN)
+  base::MessageLoop::Type loop_type = base::MessageLoop::TYPE_IO;
   // Use a UI message loop because ANGLE and the desktop GL platform can
   // create child windows to render to.
-  base::MessageLoop main_message_loop(base::MessageLoop::TYPE_UI);
+  // TODO(ananta) : Recent changes to the UI message pump class on Windows
+  // will cause delays in tasks getting processed in the GPU process which
+  // will show up on the bots in webgl conformance tests, perf tests etc.
+  // It will be great if we can work around the issues with desktop GL and
+  // avoid creating a child window in the GPU process which requires a UI
+  // message pump.
+  if ((command_line.HasSwitch(switches::kUseGL) &&
+       command_line.GetSwitchValueASCII(switches::kUseGL) == "desktop") ||
+      (command_line.HasSwitch(switches::kUseANGLE) &&
+       command_line.GetSwitchValueASCII(switches::kUseANGLE) == "gl")) {
+    loop_type = base::MessageLoop::TYPE_UI;
+  }
+  base::MessageLoop main_message_loop(loop_type);
 #elif defined(OS_LINUX) && defined(USE_X11)
   // We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX
   // and https://crbug.com/326995.
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java
index b88614f..873f42d 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewClient.java
@@ -172,7 +172,7 @@
      * @return Whether an externally managed (i.e., not compositor-driven) fling
      *         of this ContentView is active.
      */
-    public boolean isExternalFlingActive() {
+    public boolean isExternalScrollActive() {
         return false;
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index e79a9db4..0ac0bf1e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -1207,9 +1207,8 @@
     }
 
     public boolean isScrollInProgress() {
-        return mTouchScrollInProgress
-                || mPotentiallyActiveFlingCount > 0
-                || getContentViewClient().isExternalFlingActive();
+        return mTouchScrollInProgress || mPotentiallyActiveFlingCount > 0
+                || getContentViewClient().isExternalScrollActive();
     }
 
     @SuppressWarnings("unused")
@@ -1228,10 +1227,6 @@
     @CalledByNative
     private void onFlingStartEventHadNoConsumer(int vx, int vy) {
         mTouchScrollInProgress = false;
-        for (mGestureStateListenersIterator.rewind();
-                    mGestureStateListenersIterator.hasNext();) {
-            mGestureStateListenersIterator.next().onUnhandledFlingStartEvent(vx, vy);
-        }
     }
 
     @SuppressWarnings("unused")
@@ -1315,8 +1310,7 @@
         nativeDoubleTap(mNativeContentViewCore, timeMs, x, y);
     }
 
-    @VisibleForTesting
-    public void flingForTest(long timeMs, int x, int y, int velocityX, int velocityY) {
+    public void fling(long timeMs, int x, int y, int velocityX, int velocityY) {
         if (mNativeContentViewCore == 0) return;
         nativeFlingCancel(mNativeContentViewCore, timeMs);
         nativeScrollBegin(mNativeContentViewCore, timeMs, x, y, velocityX, velocityY);
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index e655e95..3458bec 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -5,9 +5,13 @@
 package org.chromium.content.browser.webcontents;
 
 import android.graphics.Color;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.os.Parcelable;
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.content_public.browser.AccessibilitySnapshotCallback;
 import org.chromium.content_public.browser.AccessibilitySnapshotNode;
 import org.chromium.content_public.browser.JavaScriptCallback;
@@ -16,6 +20,8 @@
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.ui.accessibility.AXTextStyle;
 
+import java.util.UUID;
+
 /**
  * The WebContentsImpl Java wrapper to allow communicating with the native WebContentsImpl
  * object.
@@ -24,6 +30,45 @@
 //TODO(tedchoc): Remove the package restriction once this class moves to a non-public content
 //               package whose visibility will be enforced via DEPS.
 /* package */ class WebContentsImpl implements WebContents {
+    private static final long sParcelableVersionID = 0;
+    // Non-final for testing purposes, so resetting of the UUID can happen.
+    private static UUID sParcelableUUID = UUID.randomUUID();
+
+    /**
+     * Used to reset the internal tracking for whether or not a serialized {@link WebContents}
+     * was created in this process or not.
+     */
+    @VisibleForTesting
+    public static void invalidateSerializedWebContentsForTesting() {
+        sParcelableUUID = UUID.randomUUID();
+    }
+
+    /**
+     * A {@link android.os.Parcelable.Creator} instance that is used to build
+     * {@link WebContentsImpl} objects from a {@link Parcel}.
+     */
+    public static final Parcelable.Creator<WebContents> CREATOR =
+            new Parcelable.Creator<WebContents>() {
+                @Override
+                public WebContents createFromParcel(Parcel source) {
+                    // Read version code and check for mismatch.
+                    long version = source.readLong();
+                    if (version != 0) return null;
+
+                    // Read UUID to check for application restart (in this case pointers are
+                    // invalid).
+                    ParcelUuid parcelUuid = source.readParcelable(null);
+                    if (sParcelableUUID.compareTo(parcelUuid.getUuid()) != 0) return null;
+
+                    // Grab the WebContents object from the native WebContentsAndroid pointer.
+                    return nativeFromNativePtr(source.readLong());
+                }
+
+                @Override
+                public WebContents[] newArray(int size) {
+                    return new WebContents[size];
+                }
+            };
 
     private long mNativeWebContentsAndroid;
     private NavigationController mNavigationController;
@@ -53,6 +98,18 @@
         }
     }
 
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(sParcelableVersionID);
+        dest.writeParcelable(new ParcelUuid(sParcelableUUID), 0);
+        dest.writeLong(mNativeWebContentsAndroid);
+    }
+
     @CalledByNative
     private long getNativePointer() {
         return mNativeWebContentsAndroid;
@@ -64,6 +121,11 @@
     }
 
     @Override
+    public boolean isDestroyed() {
+        return mNativeWebContentsAndroid == 0;
+    }
+
+    @Override
     public NavigationController getNavigationController() {
         return mNavigationController;
     }
@@ -266,6 +328,8 @@
     // This is static to avoid exposing a public destroy method on the native side of this class.
     private static native void nativeDestroyWebContents(long webContentsAndroidPtr);
 
+    private static native WebContents nativeFromNativePtr(long webContentsAndroidPtr);
+
     private native String nativeGetTitle(long nativeWebContentsAndroid);
     private native String nativeGetVisibleURL(long nativeWebContentsAndroid);
     private native boolean nativeIsLoading(long nativeWebContentsAndroid);
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java b/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java
index fe9c9486..efa705b7 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java
@@ -35,11 +35,6 @@
     public void onFlingEndGesture(int scrollOffsetY, int scrollExtentY) {}
 
     /**
-     * Called when a fling event was not handled by the renderer.
-     */
-    public void onUnhandledFlingStartEvent(int vx, int vy) {}
-
-    /**
      * Called to indicate that a scroll update gesture had been consumed by the page.
      * This callback is called whenever any layer is scrolled (like a frame or div). It is
      * not called when a JS touch handler consumes the event (preventDefault), it is not called
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index bf84409..21aee54 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -4,18 +4,46 @@
 
 package org.chromium.content_public.browser;
 
+import android.os.Parcelable;
+
 import org.chromium.base.VisibleForTesting;
 
 /**
  * The WebContents Java wrapper to allow communicating with the native WebContents object.
+ *
+ * Note about serialization and {@link Parcelable}:
+ *   This object is serializable and deserializable as long as it is done in the same process.  That
+ * means it can be passed between Activities inside this process, but not preserved beyond the
+ * process lifetime.  This class will automatically deserialize into {@code null} if a deserialize
+ * attempt happens in another process.
+ *
+ * To properly deserialize a custom Parcelable the right class loader must be used.  See below for
+ * some examples.
+ *
+ * Intent Serialization/Deserialization Example:
+ * intent.putExtra("WEBCONTENTSKEY", webContents);
+ * // ... send to other location ...
+ * intent.setExtrasClassLoader(WebContents.class.getClassLoader());
+ * webContents = intent.getParcelableExtra("WEBCONTENTSKEY");
+ *
+ * Bundle Serialization/Deserialization Example:
+ * bundle.putParcelable("WEBCONTENTSKEY", webContents);
+ * // ... send to other location ...
+ * bundle.setClassLoader(WebContents.class.getClassLoader());
+ * webContents = bundle.get("WEBCONTENTSKEY");
  */
-public interface WebContents {
+public interface WebContents extends Parcelable {
     /**
      * Deletes the Web Contents object.
      */
     void destroy();
 
     /**
+     * @return Whether or not the native object associated with this WebContent is destroyed.
+     */
+    boolean isDestroyed();
+
+    /**
      * @return The navigation controller associated with this WebContents.
      */
     NavigationController getNavigationController();
@@ -54,22 +82,22 @@
     /**
      * To be called when the ContentView is hidden.
      */
-    public void onHide();
+    void onHide();
 
     /**
      * To be called when the ContentView is shown.
      */
-    public void onShow();
+    void onShow();
 
     /**
      * Stops all media players for this WebContents.
      */
-    public void releaseMediaPlayers();
+    void releaseMediaPlayers();
 
     /**
      * Get the Background color from underlying RenderWidgetHost for this WebContent.
      */
-    public int getBackgroundColor();
+    int getBackgroundColor();
 
     /**
      * Shows an interstitial page driven by the passed in delegate.
@@ -78,13 +106,13 @@
      * @param delegate The delegate handling the interstitial.
      */
     @VisibleForTesting
-    public void showInterstitialPage(
+    void showInterstitialPage(
             String url, long interstitialPageDelegateAndroid);
 
     /**
      * @return Whether the page is currently showing an interstitial, such as a bad HTTPS page.
      */
-    public boolean isShowingInterstitialPage();
+    boolean isShowingInterstitialPage();
 
     /**
      * If the view is ready to draw contents to the screen. In hardware mode,
@@ -92,12 +120,12 @@
      * view has been added to the layout. This method will return {@code true}
      * once the texture is actually ready.
      */
-    public boolean isReady();
+    boolean isReady();
 
      /**
      * Inform WebKit that Fullscreen mode has been exited by the user.
      */
-    public void exitFullscreen();
+    void exitFullscreen();
 
     /**
      * Changes whether hiding the top controls is enabled.
@@ -106,31 +134,31 @@
      * @param enableShowing Whether showing the top controls should be enabled or not.
      * @param animate Whether the transition should be animated or not.
      */
-    public void updateTopControlsState(boolean enableHiding, boolean enableShowing,
+    void updateTopControlsState(boolean enableHiding, boolean enableShowing,
             boolean animate);
 
     /**
      * Shows the IME if the focused widget could accept text input.
      */
-    public void showImeIfNeeded();
+    void showImeIfNeeded();
 
     /**
      * Brings the Editable to the visible area while IME is up to make easier for inputing text.
      */
-    public void scrollFocusedEditableNodeIntoView();
+    void scrollFocusedEditableNodeIntoView();
 
     /**
      * Selects the word around the caret, if any.
      * The caller can check if selection actually occurred by listening to OnSelectionChanged.
      */
-    public void selectWordAroundCaret();
+    void selectWordAroundCaret();
 
     /**
      * Get the URL of the current page.
      *
      * @return The URL of the current page.
      */
-    public String getUrl();
+    String getUrl();
 
     /**
      * Gets the last committed URL. It represents the current page that is
@@ -138,19 +166,19 @@
      *
      * @return The last committed URL.
      */
-    public String getLastCommittedUrl();
+    String getLastCommittedUrl();
 
     /**
      * Get the InCognito state of WebContents.
      *
      * @return whether this WebContents is in InCognito mode or not
      */
-    public boolean isIncognito();
+    boolean isIncognito();
 
     /**
      * Resumes the requests for a newly created window.
      */
-    public void resumeLoadingCreatedWebContents();
+    void resumeLoadingCreatedWebContents();
 
     /**
      * Injects the passed Javascript code in the current page and evaluates it.
@@ -162,13 +190,13 @@
      *                 will be made on the main thread.
      *                 If no result is required, pass null.
      */
-    public void evaluateJavaScript(String script, JavaScriptCallback callback);
+    void evaluateJavaScript(String script, JavaScriptCallback callback);
 
     /**
      * Adds a log message to dev tools console. |level| must be a value of
      * org.chromium.content_public.common.ConsoleMessageLevel.
      */
-    public void addMessageToDevToolsConsole(int level, String message);
+    void addMessageToDevToolsConsole(int level, String message);
 
     /**
      * Returns whether the initial empty page has been accessed by a script from another
@@ -176,7 +204,7 @@
      *
      * @return Whether the initial empty page has been accessed by a script.
      */
-    public boolean hasAccessedInitialDocument();
+    boolean hasAccessedInitialDocument();
 
     /**
      * This returns the theme color as set by the theme-color meta tag after getting rid of the
@@ -184,7 +212,7 @@
      * @param The default color to be returned if the cached color is not valid.
      * @return The theme color for the content as set by the theme-color meta tag.
      */
-    public int getThemeColor(int defaultColor);
+    int getThemeColor(int defaultColor);
 
     /**
      * Requests a snapshop of accessibility tree. The result is provided asynchronously
@@ -192,7 +220,7 @@
      * @param callback The callback to be called when the snapshot is ready. The callback
      *                 cannot be null.
      */
-    public void requestAccessibilitySnapshot(AccessibilitySnapshotCallback callback);
+    void requestAccessibilitySnapshot(AccessibilitySnapshotCallback callback);
 
     /**
      * Add an observer to the WebContents
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewReadbackTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewReadbackTest.java
index b3452e47..ea15049 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewReadbackTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewReadbackTest.java
@@ -89,7 +89,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                getContentViewCore().flingForTest(SystemClock.uptimeMillis(), 0, 0, 0, -100);
+                getContentViewCore().fling(SystemClock.uptimeMillis(), 0, 0, 0, -100);
             }
         });
         assertWaitForYScroll(previousYScroll);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
index aee0be1..abf7e4e 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewScrollingTest.java
@@ -122,7 +122,7 @@
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                getContentViewCore().flingForTest(SystemClock.uptimeMillis(), 0, 0, vx, vy);
+                getContentViewCore().fling(SystemClock.uptimeMillis(), 0, 0, vx, vy);
             }
         });
     }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
index 61b9dfe..610ba0b 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
@@ -43,6 +43,7 @@
 
         @Override
         public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
+            ThreadUtils.assertOnUiThread();
             mLastVSyncCpuTimeMillis = SystemClock.uptimeMillis();
             if (mPreviousVSyncTimeMicros == 0) {
                 mPreviousVSyncTimeMicros = vsyncTimeMicros;
@@ -81,6 +82,17 @@
         });
     }
 
+    // Vsync requests should be made on the same thread as that used to create the VSyncMonitor (the
+    // UI thread).
+    private void requestVSyncMonitorUpdate(final VSyncMonitor monitor) {
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                monitor.requestUpdate();
+            }
+        });
+    }
+
     // Check that the vsync period roughly matches the timestamps that the monitor generates.
     @MediumTest
     public void testVSyncPeriod() throws InterruptedException {
@@ -92,7 +104,7 @@
         assertTrue(reportedFramePeriod > 0);
 
         assertFalse(collector.isDone());
-        monitor.requestUpdate();
+        requestVSyncMonitorUpdate(monitor);
         collector.waitTillDone();
         assertTrue(collector.isDone());
 
@@ -122,7 +134,7 @@
         VSyncDataCollector collector = new VSyncDataCollector(1);
         VSyncMonitor monitor = createVSyncMonitor(collector);
 
-        monitor.requestUpdate();
+        requestVSyncMonitorUpdate(monitor);
         collector.waitTillDone();
         assertTrue(collector.isDone());
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java
new file mode 100644
index 0000000..32fcf8a
--- /dev/null
+++ b/content/public/android/javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java
@@ -0,0 +1,260 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser.webcontents;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_shell.Shell;
+import org.chromium.content_shell_apk.ContentShellActivity;
+import org.chromium.content_shell_apk.ContentShellTestBase;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Test various Java WebContents specific features.
+ * TODO(dtrainor): Add more testing for the WebContents methods.
+ */
+public class WebContentsTest extends ContentShellTestBase {
+    private static final String TEST_URL_1 = "about://blank";
+    private static final String WEB_CONTENTS_KEY = "WEBCONTENTSKEY";
+
+    /**
+     * Check that {@link WebContents#isDestroyed()} works as expected.
+     * TODO(dtrainor): Test this using {@link WebContents#destroy()} instead once it is possible to
+     * build a {@link WebContents} directly in the content/ layer.
+     *
+     * @throws InterruptedException
+     * @throws ExecutionException
+     */
+    @SmallTest
+    public void testWebContentsIsDestroyedMethod() throws InterruptedException, ExecutionException {
+        final ContentShellActivity activity = launchContentShellWithUrl(TEST_URL_1);
+        waitForActiveShellToBeDoneLoading();
+        WebContents webContents = activity.getActiveWebContents();
+
+        assertFalse("WebContents incorrectly marked as destroyed", webContents.isDestroyed());
+
+        // Launch a new shell.
+        Shell originalShell = activity.getActiveShell();
+        loadNewShell(TEST_URL_1);
+        assertNotSame("New shell not created", activity.getActiveShell(), originalShell);
+
+        assertTrue("WebContents incorrectly marked as not destroyed", webContents.isDestroyed());
+    }
+
+    /**
+     * Check that it is possible to serialize and deserialize a WebContents object through Parcels.
+     *
+     * @throws InterruptedException
+     */
+    @SmallTest
+    public void testWebContentsSerializeDeserializeInParcel() throws InterruptedException {
+        launchContentShellWithUrl(TEST_URL_1);
+        waitForActiveShellToBeDoneLoading();
+        WebContents webContents = getWebContents();
+
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Serialize the WebContents.
+            parcel.writeParcelable(webContents, 0);
+
+            // Read back the WebContents.
+            parcel.setDataPosition(0);
+            WebContents deserializedWebContents = parcel.readParcelable(
+                    WebContents.class.getClassLoader());
+
+            // Make sure they're equal.
+            assertEquals("Deserialized object does not match",
+                    webContents, deserializedWebContents);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    /**
+     * Check that it is possible to serialize and deserialize a WebContents object through Bundles.
+     * @throws InterruptedException
+     */
+    public void testWebContentsSerializeDeserializeInBundle() throws InterruptedException {
+        launchContentShellWithUrl(TEST_URL_1);
+        waitForActiveShellToBeDoneLoading();
+        WebContents webContents = getWebContents();
+
+        // Use a parcel to force the Bundle to actually serialize and deserialize, otherwise it can
+        // cache the WebContents object.
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Create a bundle and put the WebContents in it.
+            Bundle bundle = new Bundle();
+            bundle.putParcelable(WEB_CONTENTS_KEY, webContents);
+
+            // Serialize the Bundle.
+            parcel.writeBundle(bundle);
+
+            // Read back the Bundle.
+            parcel.setDataPosition(0);
+            Bundle deserializedBundle = parcel.readBundle();
+
+            // Read back the WebContents.
+            deserializedBundle.setClassLoader(WebContents.class.getClassLoader());
+            WebContents deserializedWebContents =
+                    deserializedBundle.getParcelable(WEB_CONTENTS_KEY);
+
+            // Make sure they're equal.
+            assertEquals("Deserialized object does not match",
+                    webContents, deserializedWebContents);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    /**
+     * Check that it is possible to serialize and deserialize a WebContents object through Intents.
+     * @throws InterruptedException
+     */
+    public void testWebContentsSerializeDeserializeInIntent() throws InterruptedException {
+        launchContentShellWithUrl(TEST_URL_1);
+        waitForActiveShellToBeDoneLoading();
+        WebContents webContents = getWebContents();
+
+        // Use a parcel to force the Intent to actually serialize and deserialize, otherwise it can
+        // cache the WebContents object.
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Create an Intent and put the WebContents in it.
+            Intent intent = new Intent();
+            intent.putExtra(WEB_CONTENTS_KEY, webContents);
+
+            // Serialize the Intent
+            parcel.writeParcelable(intent, 0);
+
+            // Read back the Intent.
+            parcel.setDataPosition(0);
+            Intent deserializedIntent = parcel.readParcelable(null);
+
+            // Read back the WebContents.
+            deserializedIntent.setExtrasClassLoader(WebContents.class.getClassLoader());
+            WebContents deserializedWebContents =
+                    (WebContents) deserializedIntent.getParcelableExtra(WEB_CONTENTS_KEY);
+
+            // Make sure they're equal.
+            assertEquals("Deserialized object does not match",
+                    webContents, deserializedWebContents);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    /**
+     * Check that attempting to deserialize a WebContents object from a Parcel from another process
+     * instance fails.
+     * @throws InterruptedException
+     */
+    @SmallTest
+    public void testWebContentsFailDeserializationAcrossProcessBoundary()
+            throws InterruptedException {
+        launchContentShellWithUrl(TEST_URL_1);
+        waitForActiveShellToBeDoneLoading();
+        WebContents webContents = getWebContents();
+
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Serialize the WebContents.
+            parcel.writeParcelable(webContents, 0);
+
+            // Invalidate all serialized WebContents.
+            WebContentsImpl.invalidateSerializedWebContentsForTesting();
+
+            // Try to read back the WebContents.
+            parcel.setDataPosition(0);
+            WebContents deserializedWebContents = parcel.readParcelable(
+                    WebContents.class.getClassLoader());
+
+            // Make sure we weren't able to deserialize the WebContents.
+            assertNull("Unexpectedly deserialized a WebContents", deserializedWebContents);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    /**
+     * Check that serializing a destroyed WebContents always results in a null deserialized
+     * WebContents.
+     * @throws InterruptedException
+     * @throws ExecutionException
+     */
+    @SmallTest
+    public void testSerializingADestroyedWebContentsDoesNotDeserialize()
+            throws InterruptedException, ExecutionException {
+        ContentShellActivity activity = launchContentShellWithUrl(TEST_URL_1);
+        waitForActiveShellToBeDoneLoading();
+        WebContents webContents = activity.getActiveWebContents();
+        loadNewShell(TEST_URL_1);
+
+        assertTrue("WebContents not destroyed", webContents.isDestroyed());
+
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Serialize the WebContents.
+            parcel.writeParcelable(webContents, 0);
+
+            // Try to read back the WebContents.
+            parcel.setDataPosition(0);
+            WebContents deserializedWebContents = parcel.readParcelable(
+                    WebContents.class.getClassLoader());
+
+            // Make sure we weren't able to deserialize the WebContents.
+            assertNull("Unexpectedly deserialized a destroyed WebContents",
+                    deserializedWebContents);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    /**
+     * Check that destroying a WebContents after serializing it always results in a null
+     * deserialized WebContents.
+     * @throws InterruptedException
+     * @throws ExecutionException
+     */
+    @SmallTest
+    public void testDestroyingAWebContentsAfterSerializingDoesNotDeserialize()
+            throws InterruptedException, ExecutionException {
+        ContentShellActivity activity = launchContentShellWithUrl(TEST_URL_1);
+        waitForActiveShellToBeDoneLoading();
+        WebContents webContents = activity.getActiveWebContents();
+
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Serialize the WebContents.
+            parcel.writeParcelable(webContents, 0);
+
+            // Destroy the WebContents.
+            loadNewShell(TEST_URL_1);
+            assertTrue("WebContents not destroyed", webContents.isDestroyed());
+
+            // Try to read back the WebContents.
+            parcel.setDataPosition(0);
+            WebContents deserializedWebContents = parcel.readParcelable(
+                    WebContents.class.getClassLoader());
+
+            // Make sure we weren't able to deserialize the WebContents.
+            assertNull("Unexpectedly deserialized a destroyed WebContents",
+                    deserializedWebContents);
+        } finally {
+            parcel.recycle();
+        }
+    }
+}
\ No newline at end of file
diff --git a/content/public/browser/android/synchronous_compositor_client.h b/content/public/browser/android/synchronous_compositor_client.h
index e42e09aa..c77799c 100644
--- a/content/public/browser/android/synchronous_compositor_client.h
+++ b/content/public/browser/android/synchronous_compositor_client.h
@@ -6,6 +6,8 @@
 #define CONTENT_PUBLIC_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_CLIENT_H_
 
 #include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/time/time.h"
 #include "ui/gfx/geometry/size_f.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 
@@ -33,7 +35,10 @@
                                     float page_scale_factor,
                                     float min_page_scale_factor,
                                     float max_page_scale_factor) = 0;
-  virtual bool IsExternalFlingActive() const = 0;
+  virtual bool IsExternalScrollActive() const = 0;
+
+  typedef base::Callback<void(base::TimeTicks)> AnimationCallback;
+  virtual void SetNeedsAnimateScroll(const AnimationCallback& animation) = 0;
 
   virtual void DidOverscroll(gfx::Vector2dF accumulated_overscroll,
                              gfx::Vector2dF latest_overscroll_delta,
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index dd867845..0e07ec7 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -244,7 +244,8 @@
     bool opener_suppressed,
     ResourceContext* context,
     int render_process_id,
-    int opener_id,
+    int opener_render_view_id,
+    int opener_render_frame_id,
     bool* no_javascript_access) {
   *no_javascript_access = false;
   return true;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 3b050ff..0a97ef2 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -465,7 +465,8 @@
                                bool opener_suppressed,
                                ResourceContext* context,
                                int render_process_id,
-                               int opener_id,
+                               int opener_render_view_id,
+                               int opener_render_frame_id,
                                bool* no_javascript_access);
 
   // Notifies the embedder that the ResourceDispatcherHost has been created.
diff --git a/content/public/browser/mojo_app_connection.h b/content/public/browser/mojo_app_connection.h
index f7c0272..ae92b10 100644
--- a/content/public/browser/mojo_app_connection.h
+++ b/content/public/browser/mojo_app_connection.h
@@ -17,6 +17,11 @@
 
 namespace content {
 
+// A virtual app URL identifying the browser itself. This should be used for
+// a connection's |requestor_url| when connecting from browser code to apps that
+// don't require a more specific request context.
+CONTENT_EXPORT extern const char kBrowserMojoAppUrl[];
+
 // This provides a way for arbitrary browser code to connect to Mojo apps. These
 // objects are not thread-safe but may be constructed and used on any single
 // thread.
@@ -24,9 +29,11 @@
  public:
   virtual ~MojoAppConnection() {}
 
-  // Creates a new connection to the application at |url|. This may be called
-  // from any thread.
-  static scoped_ptr<MojoAppConnection> Create(const GURL& url);
+  // Creates a new connection to the application at |url| using |requestor_url|
+  // to identify the requestor upon connection. This may be called from any
+  // thread.
+  static scoped_ptr<MojoAppConnection> Create(const GURL& url,
+                                              const GURL& requestor_url);
 
   // Connects to a service within the application.
   template <typename Interface>
diff --git a/content/public/browser/presentation_session_message.cc b/content/public/browser/presentation_session_message.cc
index a03a055b..4d7bfd53 100644
--- a/content/public/browser/presentation_session_message.cc
+++ b/content/public/browser/presentation_session_message.cc
@@ -12,6 +12,7 @@
     scoped_ptr<std::string> message)
     : presentation_url(presentation_url),
       presentation_id(presentation_id),
+      type(PresentationMessageType::TEXT),
       message(message.Pass()),
       data(nullptr) {
 }
@@ -19,9 +20,11 @@
 PresentationSessionMessage::PresentationSessionMessage(
     const std::string& presentation_url,
     const std::string& presentation_id,
+    PresentationMessageType type,
     scoped_ptr<std::vector<uint8_t>> data)
     : presentation_url(presentation_url),
       presentation_id(presentation_id),
+      type(type),
       message(nullptr),
       data(data.Pass()) {
 }
@@ -38,12 +41,24 @@
 
 // static
 scoped_ptr<PresentationSessionMessage>
-PresentationSessionMessage::CreateBinaryMessage(
+PresentationSessionMessage::CreateArrayBufferMessage(
     const std::string& presentation_url,
     const std::string& presentation_id,
     scoped_ptr<std::vector<uint8_t>> data) {
   return scoped_ptr<PresentationSessionMessage>(new PresentationSessionMessage(
-      presentation_url, presentation_id, data.Pass()));
+      presentation_url, presentation_id, PresentationMessageType::ARRAY_BUFFER,
+      data.Pass()));
+}
+
+// static
+scoped_ptr<PresentationSessionMessage>
+PresentationSessionMessage::CreateBlobMessage(
+    const std::string& presentation_url,
+    const std::string& presentation_id,
+    scoped_ptr<std::vector<uint8_t>> data) {
+  return scoped_ptr<PresentationSessionMessage>(new PresentationSessionMessage(
+      presentation_url, presentation_id, PresentationMessageType::BLOB,
+      data.Pass()));
 }
 
 bool PresentationSessionMessage::is_binary() const {
diff --git a/content/public/browser/presentation_session_message.h b/content/public/browser/presentation_session_message.h
index 54f65fc..24e6a4c 100644
--- a/content/public/browser/presentation_session_message.h
+++ b/content/public/browser/presentation_session_message.h
@@ -13,6 +13,12 @@
 
 namespace content {
 
+enum CONTENT_EXPORT PresentationMessageType {
+  TEXT,
+  ARRAY_BUFFER,
+  BLOB,
+};
+
 // Represents a presentation session message.
 // If this is a text message, |data| is null; otherwise, |message| is null.
 // Empty messages are allowed.
@@ -26,8 +32,14 @@
       const std::string& presentation_id,
       scoped_ptr<std::string> message);
 
-  // Creates binary message, which takes the ownership of |data|.
-  static scoped_ptr<PresentationSessionMessage> CreateBinaryMessage(
+  // Creates array buffer message, which takes the ownership of |data|.
+  static scoped_ptr<PresentationSessionMessage> CreateArrayBufferMessage(
+      const std::string& presentation_url,
+      const std::string& presentation_id,
+      scoped_ptr<std::vector<uint8_t>> data);
+
+  // Creates blob message, which takes the ownership of |data|.
+  static scoped_ptr<PresentationSessionMessage> CreateBlobMessage(
       const std::string& presentation_url,
       const std::string& presentation_id,
       scoped_ptr<std::vector<uint8_t>> data);
@@ -35,6 +47,7 @@
   bool is_binary() const;
   std::string presentation_url;
   std::string presentation_id;
+  PresentationMessageType type;
   scoped_ptr<std::string> message;
   scoped_ptr<std::vector<uint8_t>> data;
 
@@ -44,6 +57,7 @@
                              scoped_ptr<std::string> message);
   PresentationSessionMessage(const std::string& presentation_url,
                              const std::string& presentation_id,
+                             PresentationMessageType type,
                              scoped_ptr<std::vector<uint8_t>> data);
 };
 
diff --git a/content/public/browser/screen_orientation_delegate.h b/content/public/browser/screen_orientation_delegate.h
index 8dd16db..06822a18 100644
--- a/content/public/browser/screen_orientation_delegate.h
+++ b/content/public/browser/screen_orientation_delegate.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 
 namespace content {
 
diff --git a/content/public/browser/screen_orientation_dispatcher_host.h b/content/public/browser/screen_orientation_dispatcher_host.h
index 0c49b0db4..f91d6bc8 100644
--- a/content/public/browser/screen_orientation_dispatcher_host.h
+++ b/content/public/browser/screen_orientation_dispatcher_host.h
@@ -6,7 +6,7 @@
 #define CONTENT_PUBLIC_BROWSER_SCREEN_ORIENTATION_DISPATCHER_HOST_H_
 
 #include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebLockOrientationError.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationError.h"
 
 namespace content {
 
diff --git a/content/public/browser/screen_orientation_provider.cc b/content/public/browser/screen_orientation_provider.cc
index 849b9465..b575f09 100644
--- a/content/public/browser/screen_orientation_provider.cc
+++ b/content/public/browser/screen_orientation_provider.cc
@@ -9,8 +9,8 @@
 #include "content/public/browser/screen_orientation_delegate.h"
 #include "content/public/browser/screen_orientation_dispatcher_host.h"
 #include "content/public/browser/web_contents.h"
-#include "third_party/WebKit/public/platform/WebLockOrientationError.h"
 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationError.h"
 
 namespace content {
 
diff --git a/content/public/browser/screen_orientation_provider.h b/content/public/browser/screen_orientation_provider.h
index 30fd89c..c3bda14b 100644
--- a/content/public/browser/screen_orientation_provider.h
+++ b/content/public/browser/screen_orientation_provider.h
@@ -9,7 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 
 namespace content {
 
diff --git a/content/public/browser/tracing_controller.h b/content/public/browser/tracing_controller.h
index 9c68fcf3..45c2ce0 100644
--- a/content/public/browser/tracing_controller.h
+++ b/content/public/browser/tracing_controller.h
@@ -199,6 +199,9 @@
   // watch event callback.
   virtual bool CancelWatchEvent() = 0;
 
+  // Check if the tracing system is recording
+  virtual bool IsRecording() const = 0;
+
  protected:
   virtual ~TracingController() {}
 };
diff --git a/content/public/browser/web_contents.cc b/content/public/browser/web_contents.cc
index a0c8a4d..887f242f 100644
--- a/content/public/browser/web_contents.cc
+++ b/content/public/browser/web_contents.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/child_process_host.h"
 
 #include "ipc/ipc_message.h"
 
@@ -11,7 +12,8 @@
 WebContents::CreateParams::CreateParams(BrowserContext* context)
     : browser_context(context),
       site_instance(nullptr),
-      opener(nullptr),
+      opener_render_process_id(content::ChildProcessHost::kInvalidUniqueID),
+      opener_render_frame_id(MSG_ROUTING_NONE),
       opener_suppressed(false),
       created_with_opener(false),
       routing_id(MSG_ROUTING_NONE),
@@ -25,7 +27,8 @@
     BrowserContext* context, SiteInstance* site)
     : browser_context(context),
       site_instance(site),
-      opener(nullptr),
+      opener_render_process_id(content::ChildProcessHost::kInvalidUniqueID),
+      opener_render_frame_id(MSG_ROUTING_NONE),
       opener_suppressed(false),
       created_with_opener(false),
       routing_id(MSG_ROUTING_NONE),
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 768ece2..b2eaf32 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -96,9 +96,11 @@
     // privileged process.
     SiteInstance* site_instance;
 
-    // The opener WebContents is the WebContents that initiated this request,
-    // if any.
-    WebContents* opener;
+    // The process id of the frame initiating the open.
+    int opener_render_process_id;
+
+    // The routing id of the frame initiating the open.
+    int opener_render_frame_id;
 
     // If the opener is suppressed, then the new WebContents doesn't hold a
     // reference to its opener.
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index b1fc250..3f8b87d 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -10,6 +10,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/bindings_policy.h"
+#include "content/public/common/security_style.h"
 #include "content/public/common/url_constants.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -225,4 +226,8 @@
   return false;
 }
 
+SecurityStyle WebContentsDelegate::GetSecurityStyle(WebContents* web_contents) {
+  return content::SECURITY_STYLE_UNKNOWN;
+}
+
 }  // namespace content
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index 66439df..f191672c 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -15,6 +15,7 @@
 #include "content/public/browser/invalidate_type.h"
 #include "content/public/browser/navigation_type.h"
 #include "content/public/common/media_stream_request.h"
+#include "content/public/common/security_style.h"
 #include "content/public/common/window_container_type.h"
 #include "third_party/WebKit/public/platform/WebDisplayMode.h"
 #include "third_party/WebKit/public/web/WebDragOperation.h"
@@ -485,6 +486,10 @@
   // default behavior is suppressed.
   virtual bool SaveFrame(const GURL& url, const Referrer& referrer);
 
+  // Can be overridden by a delegate to return the security style of the given
+  // |web_contents|. Returns SECURITY_STYLE_UNKNOWN if not overriden.
+  virtual SecurityStyle GetSecurityStyle(WebContents* web_contents);
+
  protected:
   virtual ~WebContentsDelegate();
 
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index bacb7cc..fe2dc9d 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -10,6 +10,7 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/common/frame_navigate_params.h"
+#include "content/public/common/security_style.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -176,6 +177,9 @@
       const LoadCommittedDetails& details,
       const FrameNavigateParams& params) {}
 
+  // This method is invoked when the SecurityStyle of the WebContents changes.
+  virtual void SecurityStyleChanged(content::SecurityStyle security_style) {}
+
   // This method is invoked once the window.document object of the main frame
   // was created.
   virtual void DocumentAvailableInMainFrame() {}
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index 9c8e453..060fbb90 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -22,8 +22,11 @@
 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree_update.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/base/window_open_disposition.h"
+#include "ui/gfx/ipc/gfx_param_traits.h"
 
 #undef IPC_MESSAGE_EXPORT
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
@@ -143,6 +146,7 @@
   IPC_STRUCT_TRAITS_MEMBER(webaudio_enabled)
   IPC_STRUCT_TRAITS_MEMBER(experimental_webgl_enabled)
   IPC_STRUCT_TRAITS_MEMBER(pepper_3d_enabled)
+  IPC_STRUCT_TRAITS_MEMBER(invert_viewport_scroll_order)
   IPC_STRUCT_TRAITS_MEMBER(pinch_overlay_scrollbar_thickness)
   IPC_STRUCT_TRAITS_MEMBER(use_solid_color_scrollbars)
   IPC_STRUCT_TRAITS_MEMBER(flash_3d_enabled)
@@ -181,7 +185,6 @@
   IPC_STRUCT_TRAITS_MEMBER(available_hover_types)
   IPC_STRUCT_TRAITS_MEMBER(primary_hover_type)
   IPC_STRUCT_TRAITS_MEMBER(sync_xhr_in_documents_enabled)
-  IPC_STRUCT_TRAITS_MEMBER(deferred_image_decoding_enabled)
   IPC_STRUCT_TRAITS_MEMBER(image_color_profiles_enabled)
   IPC_STRUCT_TRAITS_MEMBER(should_respect_image_orientation)
   IPC_STRUCT_TRAITS_MEMBER(number_of_cpu_cores)
@@ -244,4 +247,33 @@
   IPC_STRUCT_TRAITS_MEMBER(dialog)
 IPC_STRUCT_TRAITS_END()
 
+IPC_ENUM_TRAITS_MAX_VALUE(ui::AXEvent, ui::AX_EVENT_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(ui::AXRole, ui::AX_ROLE_LAST)
+
+IPC_ENUM_TRAITS_MAX_VALUE(ui::AXBoolAttribute, ui::AX_BOOL_ATTRIBUTE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(ui::AXFloatAttribute, ui::AX_FLOAT_ATTRIBUTE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(ui::AXIntAttribute, ui::AX_INT_ATTRIBUTE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(ui::AXIntListAttribute,
+                          ui::AX_INT_LIST_ATTRIBUTE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(ui::AXStringAttribute, ui::AX_STRING_ATTRIBUTE_LAST)
+
+IPC_STRUCT_TRAITS_BEGIN(ui::AXNodeData)
+  IPC_STRUCT_TRAITS_MEMBER(id)
+  IPC_STRUCT_TRAITS_MEMBER(role)
+  IPC_STRUCT_TRAITS_MEMBER(state)
+  IPC_STRUCT_TRAITS_MEMBER(location)
+  IPC_STRUCT_TRAITS_MEMBER(string_attributes)
+  IPC_STRUCT_TRAITS_MEMBER(int_attributes)
+  IPC_STRUCT_TRAITS_MEMBER(float_attributes)
+  IPC_STRUCT_TRAITS_MEMBER(bool_attributes)
+  IPC_STRUCT_TRAITS_MEMBER(intlist_attributes)
+  IPC_STRUCT_TRAITS_MEMBER(html_attributes)
+  IPC_STRUCT_TRAITS_MEMBER(child_ids)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ui::AXTreeUpdate)
+  IPC_STRUCT_TRAITS_MEMBER(node_id_to_clear)
+  IPC_STRUCT_TRAITS_MEMBER(nodes)
+IPC_STRUCT_TRAITS_END()
+
 #endif  // CONTENT_PUBLIC_COMMON_COMMON_PARAM_TRAITS_MACROS_H_
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index f7c94dd..f49c053 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -161,9 +161,6 @@
 // Disable the RenderThread's HistogramCustomizer.
 const char kDisableHistogramCustomizer[]    = "disable-histogram-customizer";
 
-// Paint content on the main thread instead of the compositor thread.
-const char kDisableImplSidePainting[]       = "disable-impl-side-painting";
-
 // Prevent Java from running.
 const char kDisableJava[]                   = "disable-java";
 
@@ -199,7 +196,6 @@
 const char kDisableNotifications[]          = "disable-notifications";
 
 // Disable rasterizer that writes directly to GPU memory.
-// Overrides the kEnableOneCopy flag.
 const char kDisableOneCopy[]                = "disable-one-copy";
 
 // Disable Pepper3D.
@@ -316,9 +312,6 @@
 // PlzNavigate: Use the experimental browser-side navigation path.
 const char kEnableBrowserSideNavigation[]   = "enable-browser-side-navigation";
 
-// Defer image decoding in WebKit until painting.
-const char kEnableDeferredImageDecoding[]   = "enable-deferred-image-decoding";
-
 // Enables Delay Agnostic AEC in WebRTC.
 const char kEnableDelayAgnosticAec[]        = "enable-delay-agnostic-aec";
 
@@ -375,9 +368,6 @@
 // Enables the network information API.
 const char kEnableNetworkInformation[]      = "enable-network-information";
 
-// Enable rasterizer that writes directly to GPU memory.
-const char kEnableOneCopy[]                 = "enable-one-copy";
-
 // Enables use of hardware overlay for fullscreen video playback. Android only.
 const char kEnableOverlayFullscreenVideo[]  = "enable-overlay-fullscreen-video";
 
@@ -437,18 +427,6 @@
 // Enables StatsTable, logging statistics to a global named shared memory table.
 const char kEnableStatsTable[]              = "enable-stats-table";
 
-// Experimentally ensures that each renderer process:
-// 1) Only handles rendering for pages from a single site, apart from iframes.
-// (Note that a page can reference content from multiple origins due to images,
-// JavaScript files, etc.  Cross-site iframes are also loaded in-process.)
-// 2) Only has authority to see or use cookies for the page's top-level origin.
-// (So if a.com iframes b.com, the b.com network request will be sent without
-// cookies.)
-// This is expected to break compatibility with many pages for now.  Unlike the
-// --site-per-process flag, this allows cross-site iframes, but it blocks all
-// cookies on cross-site requests.
-const char kEnableStrictSiteIsolation[]     = "enable-strict-site-isolation";
-
 // Blocks all insecure requests from secure contexts, and prevents the user
 // from overriding that decision.
 const char kEnableStrictMixedContentChecking[] =
@@ -488,10 +466,8 @@
 // only on mobile browsers.
 const char kEnableViewportMeta[]            = "enable-viewport-meta";
 
-// Resizes of the main frame are the caused by changing between landscape
-// and portrait mode (i.e. Android) so the page should be rescaled to fit
-const char kMainFrameResizesAreOrientationChanges[] =
-    "main-frame-resizes-are-orientation-changes";
+// Enables experiment to scroll the inner viewport first in some situations.
+const char kInvertViewportScrollOrder[] = "invert-viewport-scroll-order";
 
 // Enable the Vtune profiler support.
 const char kEnableVtune[]                   = "enable-vtune-support";
@@ -608,6 +584,11 @@
 // Make plugin processes log their sent and received messages to VLOG(1).
 const char kLogPluginMessages[]             = "log-plugin-messages";
 
+// Resizes of the main frame are caused by changing between landscape and
+// portrait mode (i.e. Android) so the page should be rescaled to fit.
+const char kMainFrameResizesAreOrientationChanges[] =
+    "main-frame-resizes-are-orientation-changes";
+
 // Sets the width and height above which a composited layer will get tiled.
 const char kMaxUntiledLayerHeight[]         = "max-untiled-layer-height";
 const char kMaxUntiledLayerWidth[]          = "max-untiled-layer-width";
@@ -749,15 +730,16 @@
 // Runs the renderer and plugins in the same process as the browser
 const char kSingleProcess[]                 = "single-process";
 
-// Experimentally enforces a one-site-per-process security policy.
-// All cross-site navigations force process swaps, and we can restrict a
-// renderer process's access rights based on its site.  For details, see:
-// http://www.chromium.org/developers/design-documents/site-isolation
+// Enforces a one-site-per-process security policy:
+//  * Each renderer process, for its whole lifetime, is dedicated to rendering
+//    pages for just one site.
+//  * Thus, pages from different sites are never in the same process.
+//  * A renderer process's access rights are restricted based on its site.
+//  * All cross-site navigations force process swaps.
+//  * <iframe>s are rendered out-of-process whenever the src= is cross-site.
 //
-// Unlike --enable-strict-site-isolation (which allows cross-site iframes),
-// this flag does not affect which cookies are attached to cross-site requests.
-// Support is being added to render cross-site iframes in a different process
-// than their parent pages.
+// More details here:
+// http://www.chromium.org/developers/design-documents/site-isolation
 const char kSitePerProcess[]                = "site-per-process";
 
 // Skip gpu info collection, blacklist loading, and blacklist auto-update
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index ce8451463..89a5c2ca 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -58,7 +58,6 @@
 CONTENT_EXPORT extern const char kDisableHangMonitor[];
 CONTENT_EXPORT extern const char kDisableHideInactiveStackedTabCloseButtons[];
 extern const char kDisableHistogramCustomizer[];
-CONTENT_EXPORT extern const char kDisableImplSidePainting[];
 CONTENT_EXPORT extern const char kDisableJava[];
 CONTENT_EXPORT extern const char kDisableLCDText[];
 CONTENT_EXPORT extern const char kDisablePrefixedEncryptedMedia[];
@@ -99,7 +98,6 @@
 CONTENT_EXPORT extern const char kEnablePreferCompositingToLCDText[];
 CONTENT_EXPORT extern const char kEnableBlinkFeatures[];
 CONTENT_EXPORT extern const char kEnableBrowserSideNavigation[];
-CONTENT_EXPORT extern const char kEnableDeferredImageDecoding[];
 CONTENT_EXPORT extern const char kEnableDelayAgnosticAec[];
 CONTENT_EXPORT extern const char kEnableDelegatedRenderer[];
 CONTENT_EXPORT extern const char kEnableDisplayList2dCanvas[];
@@ -117,7 +115,6 @@
 CONTENT_EXPORT extern const char kEnableLogging[];
 extern const char kEnableMemoryBenchmarking[];
 CONTENT_EXPORT extern const char kEnableNetworkInformation[];
-CONTENT_EXPORT extern const char kEnableOneCopy[];
 CONTENT_EXPORT extern const char kEnableOverlayFullscreenVideo[];
 CONTENT_EXPORT extern const char kEnablePinch[];
 CONTENT_EXPORT extern const char kEnablePluginPlaceholderTesting[];
@@ -133,7 +130,6 @@
 CONTENT_EXPORT extern const char kEnableStatsTable[];
 CONTENT_EXPORT extern const char kEnableStrictMixedContentChecking[];
 CONTENT_EXPORT extern const char kEnableStrictPowerfulFeatureRestrictions[];
-CONTENT_EXPORT extern const char kEnableStrictSiteIsolation[];
 CONTENT_EXPORT extern const char kEnableServiceWorkerSync[];
 CONTENT_EXPORT extern const char kEnableTcpFastOpen[];
 CONTENT_EXPORT extern const char kEnableThreadedCompositing[];
@@ -142,7 +138,7 @@
 CONTENT_EXPORT extern const char kEnableUserMediaScreenCapturing[];
 CONTENT_EXPORT extern const char kEnableViewport[];
 CONTENT_EXPORT extern const char kEnableViewportMeta[];
-CONTENT_EXPORT extern const char kMainFrameResizesAreOrientationChanges[];
+CONTENT_EXPORT extern const char kInvertViewportScrollOrder[];
 CONTENT_EXPORT extern const char kEnableVtune[];
 CONTENT_EXPORT extern const char kEnableWebGLDraftExtensions[];
 CONTENT_EXPORT extern const char kEnableWebGLImageChromium[];
@@ -175,6 +171,7 @@
 CONTENT_EXPORT extern const char kLoggingLevel[];
 CONTENT_EXPORT extern const char kLogNetLog[];
 extern const char kLogPluginMessages[];
+CONTENT_EXPORT extern const char kMainFrameResizesAreOrientationChanges[];
 extern const char kMaxUntiledLayerHeight[];
 extern const char kMaxUntiledLayerWidth[];
 extern const char kMemoryMetrics[];
diff --git a/content/public/common/manifest.h b/content/public/common/manifest.h
index 33436e7f..43bef5b 100644
--- a/content/public/common/manifest.h
+++ b/content/public/common/manifest.h
@@ -9,7 +9,7 @@
 
 #include "base/strings/nullable_string16.h"
 #include "content/common/content_export.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 #include "ui/gfx/geometry/size.h"
 #include "url/gurl.h"
 
diff --git a/content/public/common/security_style.h b/content/public/common/security_style.h
index 94cd0ed9..a0086d5a 100644
--- a/content/public/common/security_style.h
+++ b/content/public/common/security_style.h
@@ -28,6 +28,11 @@
   // this object in an authenticated manner but were unable to do so.
   SECURITY_STYLE_AUTHENTICATION_BROKEN,
 
+  // SECURITY_STYLE_WARNING means that the object was retrieved in an
+  // authenticated manner, but there were security issues with the retrieval or
+  // the object interacted with less secure objects.
+  SECURITY_STYLE_WARNING,
+
   // SECURITY_STYLE_AUTHENTICATED indicates that we successfully retrieved this
   // object over an authenticated protocol, such as HTTPS.
   SECURITY_STYLE_AUTHENTICATED,
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index 6279aba..480ed69b 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -158,7 +158,6 @@
       available_hover_types(0),
       primary_hover_type(ui::HOVER_TYPE_NONE),
       sync_xhr_in_documents_enabled(true),
-      deferred_image_decoding_enabled(false),
       image_color_profiles_enabled(false),
       should_respect_image_orientation(false),
       number_of_cpu_cores(1),
@@ -184,6 +183,7 @@
       smart_insert_delete_enabled(false),
 #endif
       spatial_navigation_enabled(false),
+      invert_viewport_scroll_order(false),
       pinch_overlay_scrollbar_thickness(0),
       use_solid_color_scrollbars(false),
       navigate_on_drag_drop(true),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h
index 5dfc5d5..444ce51 100644
--- a/content/public/common/web_preferences.h
+++ b/content/public/common/web_preferences.h
@@ -164,7 +164,6 @@
   int available_hover_types;
   ui::HoverType primary_hover_type;
   bool sync_xhr_in_documents_enabled;
-  bool deferred_image_decoding_enabled;
   bool image_color_profiles_enabled;
   bool should_respect_image_orientation;
   int number_of_cpu_cores;
@@ -176,6 +175,7 @@
   bool initialize_at_minimum_page_scale;
   bool smart_insert_delete_enabled;
   bool spatial_navigation_enabled;
+  bool invert_viewport_scroll_order;
   int pinch_overlay_scrollbar_thickness;
   bool use_solid_color_scrollbars;
   bool navigate_on_drag_drop;
diff --git a/content/public/common/window_container_type.cc b/content/public/common/window_container_type.cc
index ec3b12c..57c91d0 100644
--- a/content/public/common/window_container_type.cc
+++ b/content/public/common/window_container_type.cc
@@ -22,11 +22,11 @@
   bool persistent = false;
 
   for (size_t i = 0; i < window_features.additionalFeatures.size(); ++i) {
-    if (LowerCaseEqualsASCII(window_features.additionalFeatures[i],
-                             kBackground))
+    if (base::LowerCaseEqualsASCII(window_features.additionalFeatures[i],
+                                   kBackground))
       background = true;
-    else if (LowerCaseEqualsASCII(window_features.additionalFeatures[i],
-                                  kPersistent))
+    else if (base::LowerCaseEqualsASCII(window_features.additionalFeatures[i],
+                                        kPersistent))
       persistent = true;
   }
 
diff --git a/content/public/renderer/browser_plugin_delegate.h b/content/public/renderer/browser_plugin_delegate.h
index 583c43c..eaec84d 100644
--- a/content/public/renderer/browser_plugin_delegate.h
+++ b/content/public/renderer/browser_plugin_delegate.h
@@ -5,8 +5,6 @@
 #ifndef CONTENT_PUBLIC_RENDERER_BROWSER_PLUGIN_DELEGATE_H_
 #define CONTENT_PUBLIC_RENDERER_BROWSER_PLUGIN_DELEGATE_H_
 
-#include <string>
-
 #include "content/common/content_export.h"
 
 namespace gfx {
@@ -28,8 +26,6 @@
 // behavior of the plugin.
 class CONTENT_EXPORT BrowserPluginDelegate {
  public:
-  virtual ~BrowserPluginDelegate() {}
-
   // Called when the BrowserPlugin's geometry has been computed for the first
   // time.
   virtual void Ready() {}
@@ -47,8 +43,14 @@
   // Called when the plugin resizes.
   virtual void DidResizeElement(const gfx::Size& new_size) {}
 
+  // Called when the plugin is about to be destroyed.
+  virtual void DidDestroyElement() {}
+
   // Return a scriptable object for the plugin.
   virtual v8::Local<v8::Object> V8ScriptableObject(v8::Isolate* isolate);
+
+ protected:
+  virtual ~BrowserPluginDelegate() {}
 };
 
 }  // namespace content
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index 524a6cd..73cff00 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -115,7 +115,7 @@
 }
 #endif
 
-bool ContentRendererClient::ShouldFork(blink::WebFrame* frame,
+bool ContentRendererClient::ShouldFork(blink::WebLocalFrame* frame,
                                        const GURL& url,
                                        const std::string& http_method,
                                        bool is_initial_navigation,
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index 8c7d4fe..2dfb2c5 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -218,7 +218,7 @@
   // If |send_referrer| is set to false (which is the default), no referrer
   // header will be send for the navigation. Otherwise, the referrer header is
   // set according to the frame's referrer policy.
-  virtual bool ShouldFork(blink::WebFrame* frame,
+  virtual bool ShouldFork(blink::WebLocalFrame* frame,
                           const GURL& url,
                           const std::string& http_method,
                           bool is_initial_navigation,
diff --git a/content/public/renderer/plugin_instance_throttler.h b/content/public/renderer/plugin_instance_throttler.h
index 025ccbd..21ac9c2 100644
--- a/content/public/renderer/plugin_instance_throttler.h
+++ b/content/public/renderer/plugin_instance_throttler.h
@@ -52,6 +52,7 @@
     UNTHROTTLE_METHOD_BY_CLICK = 1,
     UNTHROTTLE_METHOD_BY_WHITELIST = 2,
     UNTHROTTLE_METHOD_BY_AUDIO = 3,
+    UNTHROTTLE_METHOD_BY_SIZE_CHANGE = 4,
     UNTHROTTLE_METHOD_NUM_ITEMS
   };
 
@@ -74,6 +75,9 @@
 
   static void RecordUnthrottleMethodMetric(PowerSaverUnthrottleMethod method);
 
+  // Returns true if content is considered "large", and thus essential.
+  static bool IsLargeContent(int width, int height);
+
   virtual ~PluginInstanceThrottler() {}
 
   virtual void AddObserver(Observer* observer) = 0;
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index c722393..821d975 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -231,7 +231,7 @@
     const GURL& server_base_url,
     const net::test_server::HttpRequest& request) {
   std::string prefix("/cross-site/");
-  if (!StartsWithASCII(request.relative_url, prefix, true))
+  if (!base::StartsWithASCII(request.relative_url, prefix, true))
     return scoped_ptr<net::test_server::HttpResponse>();
 
   std::string params = request.relative_url.substr(prefix.length());
diff --git a/content/public/test/layouttest_support.h b/content/public/test/layouttest_support.h
index b3a76b5d..2890139c 100644
--- a/content/public/test/layouttest_support.h
+++ b/content/public/test/layouttest_support.h
@@ -10,7 +10,7 @@
 
 #include "base/callback_forward.h"
 #include "cc/layers/texture_layer.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
 
 class GURL;
 
diff --git a/content/public/test/test_launcher.cc b/content/public/test/test_launcher.cc
index fc65ebd..91fe680 100644
--- a/content/public/test/test_launcher.cc
+++ b/content/public/test/test_launcher.cc
@@ -182,12 +182,12 @@
     const std::string& test_name) {
   all_test_names_.insert(test_case_name + "." + test_name);
 
-  if (StartsWithASCII(test_name, kManualTestPrefix, true) &&
+  if (base::StartsWithASCII(test_name, kManualTestPrefix, true) &&
       !base::CommandLine::ForCurrentProcess()->HasSwitch(kRunManualTestsFlag)) {
     return false;
   }
 
-  if (StartsWithASCII(test_name, kPreTestPrefix, true)) {
+  if (base::StartsWithASCII(test_name, kPreTestPrefix, true)) {
     // We will actually run PRE_ tests, but to ensure they run on the same shard
     // as dependent tests, handle all these details internally.
     return false;
diff --git a/content/public/test/test_mojo_app.cc b/content/public/test/test_mojo_app.cc
index bebb7a7..f4fe6763 100644
--- a/content/public/test/test_mojo_app.cc
+++ b/content/public/test/test_mojo_app.cc
@@ -24,6 +24,7 @@
 
 bool TestMojoApp::ConfigureIncomingConnection(
     mojo::ApplicationConnection* connection) {
+  requestor_url_ = GURL(connection->GetRemoteApplicationURL());
   connection->AddService<TestMojoService>(this);
   return true;
 }
@@ -40,4 +41,8 @@
   app_->Terminate();
 }
 
+void TestMojoApp::GetRequestorURL(const GetRequestorURLCallback& callback) {
+  callback.Run(requestor_url_.spec());
+}
+
 }  // namespace content
diff --git a/content/public/test/test_mojo_app.h b/content/public/test/test_mojo_app.h
index e01e7b50..965c949 100644
--- a/content/public/test/test_mojo_app.h
+++ b/content/public/test/test_mojo_app.h
@@ -10,6 +10,7 @@
 #include "mojo/application/public/cpp/application_delegate.h"
 #include "mojo/application/public/cpp/interface_factory.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
+#include "url/gurl.h"
 
 namespace content {
 
@@ -36,12 +37,16 @@
 
   // TestMojoService:
   void DoSomething(const DoSomethingCallback& callback) override;
+  void GetRequestorURL(const GetRequestorURLCallback& callback) override;
 
   mojo::Binding<TestMojoService> service_binding_;
 
   // Not owned.
   mojo::ApplicationImpl* app_;
 
+  // The URL of the app connecting to us.
+  GURL requestor_url_;
+
   DISALLOW_COPY_AND_ASSIGN(TestMojoApp);
 };
 
diff --git a/content/public/test/test_mojo_service.mojom b/content/public/test/test_mojo_service.mojom
index e417916..cb3728c4 100644
--- a/content/public/test/test_mojo_service.mojom
+++ b/content/public/test/test_mojo_service.mojom
@@ -5,5 +5,9 @@
 module content;
 
 interface TestMojoService {
+  // Doesn't actually do anything, just responds.
   DoSomething() => ();
+
+  // Retrieve the requestor URL as seen by the test app providing this service.
+  GetRequestorURL() => (string url);
 };
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc
index 8ae828e9..5c804bf 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -398,20 +398,8 @@
           line_breaks.push_back(src_line_breaks[i]);
         dst->AddIntListAttribute(ui::AX_ATTR_LINE_BREAKS, line_breaks);
       }
-
-      if (dst->role == ui::AX_ROLE_TEXT_FIELD &&
-          src.textInputType().length()) {
-        dst->AddStringAttribute(ui::AX_ATTR_TEXT_INPUT_TYPE,
-                                UTF16ToUTF8(src.textInputType()));
-      }
     }
 
-    blink::WebAXOptionalBool optionalBool = src.isAriaGrabbed();
-    if (optionalBool == blink::WebAXOptionalBoolFalse)
-      dst->AddBoolAttribute(ui::AX_ATTR_GRABBED, false);
-    else if (optionalBool == blink::WebAXOptionalBoolTrue)
-      dst->AddBoolAttribute(ui::AX_ATTR_GRABBED, true);
-
     // ARIA role.
     if (element.hasAttribute("role")) {
       dst->AddStringAttribute(ui::AX_ATTR_ROLE,
@@ -420,6 +408,8 @@
       std::string role = GetEquivalentAriaRoleString(dst->role);
       if (!role.empty())
         dst->AddStringAttribute(ui::AX_ATTR_ROLE, role);
+      else if (dst->role == ui::AX_ROLE_TIME)
+        dst->AddStringAttribute(ui::AX_ATTR_ROLE, "time");
     }
 
     // Browser plugin (used in a <webview>).
@@ -608,11 +598,6 @@
         ui::AX_ATTR_DESCRIBEDBY_IDS, describedby, dst);
   }
 
-  if (src.ariaDropEffect().length()) {
-    dst->AddStringAttribute(ui::AX_ATTR_DROPEFFECT,
-        UTF16ToUTF8(src.ariaDropEffect()));
-  }
-
   WebVector<WebAXObject> flowTo;
   if (src.ariaFlowTo(flowTo))
     AddIntListAttributeFromWebObjects(ui::AX_ATTR_FLOWTO_IDS, flowTo, dst);
diff --git a/content/renderer/accessibility/renderer_accessibility_browsertest.cc b/content/renderer/accessibility/renderer_accessibility_browsertest.cc
index b1d4c0b0..c5a731ab 100644
--- a/content/renderer/accessibility/renderer_accessibility_browsertest.cc
+++ b/content/renderer/accessibility/renderer_accessibility_browsertest.cc
@@ -51,6 +51,15 @@
     sink_ = &render_thread_->sink();
   }
 
+  void TearDown() override {
+#if defined(LEAK_SANITIZER)
+     // Do this before shutting down V8 in RenderViewTest::TearDown().
+     // http://crbug.com/328552
+     __lsan_do_leak_check();
+#endif
+     RenderViewTest::TearDown();
+  }
+
   void SetMode(AccessibilityMode mode) {
     frame()->OnSetAccessibilityMode(mode);
   }
diff --git a/content/renderer/android/phone_number_detector.cc b/content/renderer/android/phone_number_detector.cc
index 6d0e19c9..6a370a1 100644
--- a/content/renderer/android/phone_number_detector.cc
+++ b/content/renderer/android/phone_number_detector.cc
@@ -36,7 +36,7 @@
 // Region should be empty or an ISO 3166-1 alpha-2 country code.
 PhoneNumberDetector::PhoneNumberDetector(const std::string& region)
     : region_code_(region.empty() ? RegionCode::GetUnknown()
-                                  : StringToUpperASCII(region)) {
+                                  : base::StringToUpperASCII(region)) {
 }
 
 PhoneNumberDetector::~PhoneNumberDetector() {
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index 6d0c17d5..a7baff4 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -61,7 +61,7 @@
 }
 
 BrowserPlugin::BrowserPlugin(RenderFrame* render_frame,
-                             scoped_ptr<BrowserPluginDelegate> delegate)
+                             BrowserPluginDelegate* delegate)
     : attached_(false),
       render_frame_routing_id_(render_frame->GetRoutingID()),
       container_(nullptr),
@@ -73,7 +73,7 @@
       ready_(false),
       browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
       contents_opaque_(true),
-      delegate_(delegate.Pass()),
+      delegate_(delegate),
       weak_ptr_factory_(this) {
   browser_plugin_instance_id_ =
       BrowserPluginManager::Get()->GetNextInstanceID();
@@ -86,6 +86,10 @@
   if (compositing_helper_.get())
     compositing_helper_->OnContainerDestroy();
 
+  if (delegate_)
+    delegate_->DidDestroyElement();
+  delegate_ = nullptr;
+
   BrowserPluginManager::Get()->RemoveBrowserPlugin(browser_plugin_instance_id_);
 }
 
@@ -263,6 +267,16 @@
     container_->invalidate();
 }
 
+void BrowserPlugin::UpdateInternalInstanceId() {
+  // This is a way to notify observers of our attributes that this plugin is
+  // available in render tree.
+  // TODO(lazyboy): This should be done through the delegate instead. Perhaps
+  // by firing an event from there.
+  UpdateDOMAttribute(
+      "internalinstanceid",
+      base::UTF8ToUTF16(base::IntToString(browser_plugin_instance_id_)));
+}
+
 void BrowserPlugin::UpdateGuestFocusState(blink::WebFocusType focus_type) {
   if (!attached())
     return;
@@ -329,16 +343,6 @@
   }
 }
 
-void BrowserPlugin::UpdateInternalInstanceId() {
-  // This is a way to notify observers of our attributes that this plugin is
-  // available in render tree.
-  // TODO(lazyboy): This should be done through the delegate instead. Perhaps
-  // by firing an event from there.
-  UpdateDOMAttribute(
-      "internalinstanceid",
-      base::UTF8ToUTF16(base::IntToString(browser_plugin_instance_id_)));
-}
-
 void BrowserPlugin::destroy() {
   if (container_) {
     // The BrowserPlugin's WebPluginContainer is deleted immediately after this
@@ -379,8 +383,7 @@
 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
   if (guest_crashed_) {
     if (!sad_guest_)  // Lazily initialize bitmap.
-      sad_guest_ = content::GetContentClient()->renderer()->
-          GetSadWebViewBitmap();
+      sad_guest_ = GetContentClient()->renderer()->GetSadWebViewBitmap();
     // content_shell does not have the sad plugin bitmap, so we'll paint black
     // instead to make it clear that something went wrong.
     if (sad_guest_) {
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
index 3793697..1794994 100644
--- a/content/renderer/browser_plugin/browser_plugin.h
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -55,8 +55,6 @@
   // A request to enable hardware compositing.
   void EnableCompositing(bool enable);
 
-  void UpdateInternalInstanceId();
-
   // Provided that a guest instance ID has been allocated, this method attaches
   // this BrowserPlugin instance to that guest.
   void Attach();
@@ -146,13 +144,14 @@
   // uniquely identifies a guest WebContents that's hosted by this
   // BrowserPlugin.
   BrowserPlugin(RenderFrame* render_frame,
-                scoped_ptr<BrowserPluginDelegate> delegate);
+                BrowserPluginDelegate* delegate);
 
   ~BrowserPlugin() override;
 
   gfx::Rect view_rect() const { return view_rect_; }
 
   void ShowSadGraphic();
+  void UpdateInternalInstanceId();
 
   // IPC message handlers.
   // Please keep in alphabetical order.
@@ -201,7 +200,9 @@
 
   std::vector<EditCommand> edit_commands_;
 
-  scoped_ptr<BrowserPluginDelegate> delegate_;
+  // We call lifetime managing methods on |delegate_|, but we do not directly
+  // own this. The delegate destroys itself.
+  BrowserPluginDelegate* delegate_;
 
   // Weak factory used in v8 |MakeWeak| callback, since the v8 callback might
   // get called after BrowserPlugin has been destroyed.
diff --git a/content/renderer/browser_plugin/browser_plugin_manager.cc b/content/renderer/browser_plugin/browser_plugin_manager.cc
index 186d6bf6..695a1ae4 100644
--- a/content/renderer/browser_plugin/browser_plugin_manager.cc
+++ b/content/renderer/browser_plugin/browser_plugin_manager.cc
@@ -68,8 +68,8 @@
 
 BrowserPlugin* BrowserPluginManager::CreateBrowserPlugin(
     RenderFrame* render_frame,
-    scoped_ptr<BrowserPluginDelegate> delegate) {
-  return new BrowserPlugin(render_frame, delegate.Pass());
+    BrowserPluginDelegate* delegate) {
+  return new BrowserPlugin(render_frame, delegate);
 }
 
 void BrowserPluginManager::DidCommitCompositorFrame(
diff --git a/content/renderer/browser_plugin/browser_plugin_manager.h b/content/renderer/browser_plugin/browser_plugin_manager.h
index 34386656..2e9d4df6 100644
--- a/content/renderer/browser_plugin/browser_plugin_manager.h
+++ b/content/renderer/browser_plugin/browser_plugin_manager.h
@@ -34,9 +34,11 @@
   // BrowserPlugin is responsible for associating itself with the
   // BrowserPluginManager via AddBrowserPlugin. When it is destroyed, it is
   // responsible for removing its association via RemoveBrowserPlugin.
-  BrowserPlugin* CreateBrowserPlugin(
-      RenderFrame* render_frame,
-      scoped_ptr<BrowserPluginDelegate> delegate);
+  // The |delegate| is expected to manage its own lifetime.
+  // Generally BrowserPlugin calls DidDestroyElement() on the delegate and
+  // right now the delegate destroys itself once it hears that callback.
+  BrowserPlugin* CreateBrowserPlugin(RenderFrame* render_frame,
+                                     BrowserPluginDelegate* delegate);
 
   void Attach(int browser_plugin_instance_id);
 
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc
index cd99e27..c72df6f 100644
--- a/content/renderer/dom_serializer_browsertest.cc
+++ b/content/renderer/dom_serializer_browsertest.cc
@@ -108,7 +108,7 @@
   charset_info.erase(0, charset_info.length());
   // Check the META charset declaration.
   WebString httpEquiv = meta.getAttribute("http-equiv");
-  if (LowerCaseEqualsASCII(httpEquiv, "content-type")) {
+  if (base::LowerCaseEqualsASCII(httpEquiv, "content-type")) {
     std::string content = meta.getAttribute("content").utf8();
     int pos = content.find("charset", 0);
     if (pos > -1) {
diff --git a/content/renderer/dom_storage/OWNERS b/content/renderer/dom_storage/OWNERS
index 1f62afa..126aa2ed 100644
--- a/content/renderer/dom_storage/OWNERS
+++ b/content/renderer/dom_storage/OWNERS
@@ -1,5 +1,4 @@
 michaeln@chromium.org
-kinuko@chromium.org
 jsbell@chromium.org
 marja@chromium.org
 
diff --git a/content/renderer/drop_data_builder.cc b/content/renderer/drop_data_builder.cc
index 395c2b5..bff73f56 100644
--- a/content/renderer/drop_data_builder.cc
+++ b/content/renderer/drop_data_builder.cc
@@ -26,20 +26,23 @@
     const WebDragData::Item& item = item_list[i];
     switch (item.storageType) {
       case WebDragData::Item::StorageTypeString: {
-        if (EqualsASCII(item.stringType, ui::Clipboard::kMimeTypeText)) {
+        if (base::EqualsASCII(item.stringType, ui::Clipboard::kMimeTypeText)) {
           result.text = base::NullableString16(item.stringData, false);
           break;
         }
-        if (EqualsASCII(item.stringType, ui::Clipboard::kMimeTypeURIList)) {
+        if (base::EqualsASCII(item.stringType,
+                              ui::Clipboard::kMimeTypeURIList)) {
           result.url = GURL(item.stringData);
           result.url_title = item.title;
           break;
         }
-        if (EqualsASCII(item.stringType, ui::Clipboard::kMimeTypeDownloadURL)) {
+        if (base::EqualsASCII(item.stringType,
+                              ui::Clipboard::kMimeTypeDownloadURL)) {
           result.download_metadata = item.stringData;
           break;
         }
-        if (EqualsASCII(item.stringType, ui::Clipboard::kMimeTypeHTML)) {
+        if (base::EqualsASCII(item.stringType,
+                              ui::Clipboard::kMimeTypeHTML)) {
           result.html = base::NullableString16(item.stringData, false);
           result.html_base_url = item.baseURL;
           break;
diff --git a/content/renderer/fetchers/resource_fetcher_impl.cc b/content/renderer/fetchers/resource_fetcher_impl.cc
index e296937..b48ad21 100644
--- a/content/renderer/fetchers/resource_fetcher_impl.cc
+++ b/content/renderer/fetchers/resource_fetcher_impl.cc
@@ -56,7 +56,7 @@
   DCHECK(!request_.isNull());
   DCHECK(!loader_);
 
-  if (LowerCaseEqualsASCII(header, "referer")) {
+  if (base::LowerCaseEqualsASCII(header, "referer")) {
     blink::WebString referrer =
         blink::WebSecurityPolicy::generateReferrerHeader(
             blink::WebReferrerPolicyDefault,
diff --git a/content/renderer/gpu/compositor_dependencies.h b/content/renderer/gpu/compositor_dependencies.h
index 6d95b69..7caab24 100644
--- a/content/renderer/gpu/compositor_dependencies.h
+++ b/content/renderer/gpu/compositor_dependencies.h
@@ -31,7 +31,6 @@
 
 class CompositorDependencies {
  public:
-  virtual bool IsImplSidePaintingEnabled() = 0;
   virtual bool IsGpuRasterizationForced() = 0;
   virtual bool IsGpuRasterizationEnabled() = 0;
   virtual int GetGpuRasterizationMSAASampleCount() = 0;
diff --git a/content/renderer/gpu/compositor_output_surface.cc b/content/renderer/gpu/compositor_output_surface.cc
index 3695a18..c8270a6 100644
--- a/content/renderer/gpu/compositor_output_surface.cc
+++ b/content/renderer/gpu/compositor_output_surface.cc
@@ -60,10 +60,9 @@
   DCHECK(output_surface_filter_.get());
   DCHECK(frame_swap_message_queue_.get());
   DetachFromThread();
+  capabilities_.max_frames_pending = 1;
   message_sender_ = RenderThreadImpl::current()->sync_message_filter();
   DCHECK(message_sender_.get());
-  if (OutputSurface::software_device())
-    capabilities_.max_frames_pending = 1;
 }
 
 CompositorOutputSurface::~CompositorOutputSurface() {
diff --git a/content/renderer/gpu/delegated_compositor_output_surface.cc b/content/renderer/gpu/delegated_compositor_output_surface.cc
index d767ce4..6d02fab 100644
--- a/content/renderer/gpu/delegated_compositor_output_surface.cc
+++ b/content/renderer/gpu/delegated_compositor_output_surface.cc
@@ -21,7 +21,6 @@
                               swap_frame_message_queue,
                               true) {
   capabilities_.delegated_rendering = true;
-  capabilities_.max_frames_pending = 1;
 }
 
 }  // namespace content
diff --git a/content/renderer/gpu/mailbox_output_surface.cc b/content/renderer/gpu/mailbox_output_surface.cc
index dbf7acb..4a598d4 100644
--- a/content/renderer/gpu/mailbox_output_surface.cc
+++ b/content/renderer/gpu/mailbox_output_surface.cc
@@ -41,7 +41,6 @@
       is_backbuffer_discarded_(false),
       format_(format) {
   pending_textures_.push_back(TransferableFrame());
-  capabilities_.max_frames_pending = 1;
   capabilities_.uses_default_gl_framebuffer = false;
 }
 
@@ -199,8 +198,9 @@
   DCHECK(!surface_size_.IsEmpty());
   DCHECK(surface_size_ == current_backing_.size);
   DCHECK(frame->gl_frame_data->size == current_backing_.size);
-  DCHECK(!current_backing_.mailbox.IsZero() ||
-         context_provider_->IsContextLost());
+  DCHECK_IMPLIES(current_backing_.mailbox.IsZero(),
+                 context_provider_->ContextGL()->GetGraphicsResetStatusKHR() !=
+                     GL_NO_ERROR);
 
   frame->gl_frame_data->mailbox = current_backing_.mailbox;
   context_provider_->ContextGL()->Flush();
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 99f2121..0b50b67 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -50,6 +50,7 @@
 #include "ui/native_theme/native_theme_switches.h"
 
 #if defined(OS_ANDROID)
+#include "base/android/build_info.h"
 #include "content/renderer/android/synchronous_compositor_factory.h"
 #include "ui/gfx/android/device_display_info.h"
 #endif
@@ -178,14 +179,6 @@
   return gfx::Size(default_tile_size, default_tile_size);
 }
 
-int GetMaxBytesPerCopyOperation() {
-  const int kMegabyte = 1024 * 1024;
-
-  // 4MiB is the size of 4 512x512 tiles, which has proven to be a good
-  // default batch size for copy operations.
-  return kMegabyte * 4;
-}
-
 // Check cc::TopControlsState, and blink::WebTopControlsState
 // are kept in sync.
 static_assert(int(blink::WebTopControlsBoth) == int(cc::BOTH),
@@ -284,7 +277,7 @@
 
   settings.gpu_rasterization_msaa_sample_count =
       compositor_deps_->GetGpuRasterizationMSAASampleCount();
-  settings.impl_side_painting = compositor_deps_->IsImplSidePaintingEnabled();
+  settings.impl_side_painting = true;
   settings.gpu_rasterization_forced =
       compositor_deps_->IsGpuRasterizationForced();
   settings.gpu_rasterization_enabled =
@@ -362,6 +355,9 @@
         &settings.initial_debug_state.slow_down_raster_scale_factor);
   }
 
+  settings.invert_viewport_scroll_order =
+      cmd->HasSwitch(switches::kInvertViewportScrollOrder);
+
   if (cmd->HasSwitch(cc::switches::kMaxUnusedResourceMemoryUsagePercentage)) {
     int max_unused_resource_memory_percentage;
     if (GetSwitchValueAsInt(
@@ -464,8 +460,6 @@
     settings.use_external_begin_frame_source = false;
   }
 
-  settings.max_bytes_per_copy_operation = GetMaxBytesPerCopyOperation();
-
   scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner =
       compositor_deps_->GetCompositorImplThreadTaskRunner();
   scoped_refptr<base::SingleThreadTaskRunner>
@@ -904,6 +898,8 @@
     return;
   }
 
+  DCHECK_EQ(surface->capabilities().max_frames_pending, 1);
+
   layer_tree_host_->SetOutputSurface(surface.Pass());
 }
 
diff --git a/content/renderer/gpu/render_widget_compositor_unittest.cc b/content/renderer/gpu/render_widget_compositor_unittest.cc
index 35774b7..b8ab096 100644
--- a/content/renderer/gpu/render_widget_compositor_unittest.cc
+++ b/content/renderer/gpu/render_widget_compositor_unittest.cc
@@ -142,11 +142,12 @@
           cc::TestWebGraphicsContext3D::Create();
       // Image support required for synchronous compositing.
       context->set_support_image(true);
-      return cc::FakeOutputSurface::Create3d(context.Pass());
+      // Create delegating surface so that max_pending_frames = 1.
+      return cc::FakeOutputSurface::CreateDelegating3d(context.Pass());
     }
     return use_null_output_surface_
                ? nullptr
-               : make_scoped_ptr(new cc::FailureOutputSurface(false));
+               : make_scoped_ptr(new cc::FailureOutputSurface(true));
   }
 
   // Force a new output surface to be created.
diff --git a/content/renderer/history_controller.cc b/content/renderer/history_controller.cc
index 5f53009..fd566237 100644
--- a/content/renderer/history_controller.cc
+++ b/content/renderer/history_controller.cc
@@ -38,6 +38,7 @@
 #include "content/common/navigation_params.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_view_impl.h"
+#include "third_party/WebKit/public/web/WebFrameLoadType.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 
 using blink::WebFrame;
@@ -89,9 +90,11 @@
       continue;
     render_frame->SetPendingNavigationParams(make_scoped_ptr(
         new NavigationParams(*navigation_params_.get())));
-    frame->loadHistoryItem(item.second,
-                           blink::WebHistorySameDocumentLoad,
-                           cache_policy);
+    WebURLRequest request = frame->toWebLocalFrame()->requestFromHistoryItem(
+        item.second, cache_policy);
+    frame->toWebLocalFrame()->load(
+        request, blink::WebFrameLoadType::BackForward, item.second,
+        blink::WebHistorySameDocumentLoad);
   }
   for (const auto& item : different_document_loads) {
     WebFrame* frame = item.first;
@@ -100,9 +103,11 @@
       continue;
     render_frame->SetPendingNavigationParams(make_scoped_ptr(
         new NavigationParams(*navigation_params_.get())));
-    frame->loadHistoryItem(item.second,
-                           blink::WebHistoryDifferentDocumentLoad,
-                           cache_policy);
+    WebURLRequest request = frame->toWebLocalFrame()->requestFromHistoryItem(
+        item.second, cache_policy);
+    frame->toWebLocalFrame()->load(
+        request, blink::WebFrameLoadType::BackForward, item.second,
+        blink::WebHistoryDifferentDocumentLoad);
   }
 }
 
@@ -179,6 +184,10 @@
       if (current_entry_) {
         if (HistoryEntry::HistoryNode* node =
                 current_entry_->GetHistoryNodeForFrame(frame)) {
+          // Inert commits that reset the page without changing the item (e.g.,
+          // reloads, location.replace) shouldn't keep the old subtree.
+          if (!navigation_within_page)
+            node->RemoveChildren();
           node->set_item(item);
         }
       }
diff --git a/content/renderer/history_controller_browsertest.cc b/content/renderer/history_controller_browsertest.cc
new file mode 100644
index 0000000..002b95a
--- /dev/null
+++ b/content/renderer/history_controller_browsertest.cc
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/test/render_view_test.h"
+#include "content/renderer/history_controller.h"
+#include "content/renderer/render_frame_impl.h"
+#include "content/renderer/render_view_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebHistoryItem.h"
+
+namespace content {
+
+class HistoryControllerTest : public RenderViewTest {
+ public:
+  ~HistoryControllerTest() override {}
+
+  // Create a main frame with a single child frame.
+  void SetUp() override {
+    RenderViewTest::SetUp();
+    LoadHTML("Parent frame <iframe name='frame'></iframe>");
+  }
+
+  void TearDown() override { RenderViewTest::TearDown(); }
+
+  HistoryController* history_controller() {
+    return static_cast<RenderViewImpl*>(view_)->history_controller();
+  }
+};
+
+#if defined(OS_ANDROID)
+// See https://crbug.com/472717
+#define MAYBE_InertCommitRemovesChildren DISABLED_InertCommitRemovesChildren
+#else
+#define MAYBE_InertCommitRemovesChildren InertCommitRemovesChildren
+#endif
+
+TEST_F(HistoryControllerTest, MAYBE_InertCommitRemovesChildren) {
+  HistoryEntry* entry = history_controller()->GetCurrentEntry();
+  ASSERT_TRUE(entry);
+  ASSERT_EQ(1ul, entry->root_history_node()->children().size());
+
+  blink::WebHistoryItem item;
+  item.initialize();
+  RenderFrameImpl* main_frame =
+      static_cast<RenderFrameImpl*>(view_->GetMainRenderFrame());
+
+  // Don't clear children for in-page navigations.
+  history_controller()->UpdateForCommit(main_frame, item,
+                                        blink::WebHistoryInertCommit, true);
+  EXPECT_EQ(1ul, entry->root_history_node()->children().size());
+
+  // Clear children for cross-page navigations.
+  history_controller()->UpdateForCommit(main_frame, item,
+                                        blink::WebHistoryInertCommit, false);
+  EXPECT_EQ(0ul, entry->root_history_node()->children().size());
+}
+
+}  // namespace
diff --git a/content/renderer/input/input_handler_proxy.cc b/content/renderer/input/input_handler_proxy.cc
index a918e9b5..e8e8f37d 100644
--- a/content/renderer/input/input_handler_proxy.cc
+++ b/content/renderer/input/input_handler_proxy.cc
@@ -419,7 +419,9 @@
 
 InputHandlerProxy::EventDisposition InputHandlerProxy::HandleGestureScrollBegin(
     const WebGestureEvent& gesture_event) {
-  DCHECK(!gesture_scroll_on_impl_thread_);
+  if (gesture_scroll_on_impl_thread_)
+    CancelCurrentFling();
+
 #ifndef NDEBUG
   DCHECK(!expect_scroll_update_end_);
   expect_scroll_update_end_ = true;
@@ -531,7 +533,7 @@
           WebPoint(gesture_event.globalX, gesture_event.globalY);
       fling_parameters_.modifiers = gesture_event.modifiers;
       fling_parameters_.sourceDevice = gesture_event.sourceDevice;
-      input_handler_->SetNeedsAnimate();
+      input_handler_->SetNeedsAnimateInput();
       return DID_HANDLE;
     }
     case cc::InputHandler::SCROLL_UNKNOWN:
@@ -753,7 +755,7 @@
         monotonic_time_sec >= fling_parameters_.startTime +
                                   kMaxSecondsFromFlingTimestampToFirstAnimate) {
       fling_parameters_.startTime = monotonic_time_sec;
-      input_handler_->SetNeedsAnimate();
+      input_handler_->SetNeedsAnimateInput();
       return;
     }
   }
@@ -766,7 +768,7 @@
     fling_is_active = false;
 
   if (fling_is_active) {
-    input_handler_->SetNeedsAnimate();
+    input_handler_->SetNeedsAnimateInput();
   } else {
     TRACE_EVENT_INSTANT0("input",
                          "InputHandlerProxy::animate::flingOver",
diff --git a/content/renderer/input/input_handler_proxy_unittest.cc b/content/renderer/input/input_handler_proxy_unittest.cc
index cfa8631..522225e 100644
--- a/content/renderer/input/input_handler_proxy_unittest.cc
+++ b/content/renderer/input/input_handler_proxy_unittest.cc
@@ -82,7 +82,7 @@
                void(float magnify_delta, const gfx::Point& anchor));
   MOCK_METHOD0(PinchGestureEnd, void());
 
-  MOCK_METHOD0(SetNeedsAnimate, void());
+  MOCK_METHOD0(SetNeedsAnimateInput, void());
 
   MOCK_METHOD2(ScrollBegin,
                ScrollStatus(const gfx::Point& viewport_point,
@@ -249,7 +249,7 @@
 
     EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
         .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
-    EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+    EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
 
     gesture_ =
         CreateFling(timestamp, source_device, velocity, position, position, 0);
@@ -551,7 +551,7 @@
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_CALL(mock_input_handler_, ScrollEnd());
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
 
   gesture_.type = WebInputEvent::GestureFlingStart;
   gesture_.data.flingStart.velocityX = 10;
@@ -631,7 +631,7 @@
                          fling_point,
                          fling_global_point,
                          modifiers);
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_CALL(mock_input_handler_, ScrollEnd());
@@ -643,7 +643,7 @@
   // fling start will typically include the last scroll from the gesture that
   // lead to the scroll (either wheel or gesture scroll), so there should be no
   // visible hitch.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .Times(0);
   base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
@@ -652,7 +652,7 @@
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // The second call should start scrolling in the -X direction.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_CALL(mock_input_handler_,
@@ -705,7 +705,7 @@
   // Since we've aborted the fling, the next animation should be a no-op and
   // should not result in another
   // frame being requested.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate()).Times(0);
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(0);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .Times(0);
   time += base::TimeDelta::FromMilliseconds(100);
@@ -736,7 +736,7 @@
                          fling_point,
                          fling_global_point,
                          modifiers);
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_CALL(mock_input_handler_, ScrollEnd());
@@ -746,7 +746,7 @@
 
   // Start the fling animation at time 10. This shouldn't actually scroll, just
   // establish a start time.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .Times(0);
   base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
@@ -755,7 +755,7 @@
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // The second call should start scrolling in the -X direction.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_CALL(mock_input_handler_,
@@ -809,7 +809,7 @@
   // Since we've aborted the fling, the next animation should be a no-op and
   // should not result in another
   // frame being requested.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate()).Times(0);
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(0);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .Times(0);
   time += base::TimeDelta::FromMilliseconds(100);
@@ -837,7 +837,7 @@
                          fling_point,
                          fling_global_point,
                          modifiers);
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_CALL(mock_input_handler_, ScrollEnd());
@@ -847,7 +847,7 @@
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // Start the second fling animation at time 30.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .Times(0);
   time = base::TimeTicks() + base::TimeDelta::FromSeconds(30);
@@ -856,7 +856,7 @@
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // Tick the second fling once normally.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_CALL(mock_input_handler_,
@@ -911,7 +911,7 @@
 
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
 
   gesture_.type = WebInputEvent::GestureFlingStart;
   gesture_.data.flingStart.velocityX = 10;
@@ -1017,7 +1017,7 @@
                          fling_point,
                          fling_global_point,
                          modifiers);
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1028,14 +1028,14 @@
   // fling start will typically include the last scroll from the gesture that
   // lead to the scroll (either wheel or gesture scroll), so there should be no
   // visible hitch.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
   input_handler_->Animate(time);
 
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // The second call should start scrolling in the -X direction.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x, testing::Lt(0))))
@@ -1078,7 +1078,7 @@
                          fling_point,
                          fling_global_point,
                          modifiers);
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1089,7 +1089,7 @@
   // the likelihood of a hitch between the scroll preceding the fling and
   // the first scroll generated by the fling.
   // Scrolling should start in the -X direction.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x, testing::Lt(0))))
@@ -1135,7 +1135,7 @@
   gesture_.globalX = fling_global_point.x;
   gesture_.globalY = fling_global_point.y;
   gesture_.modifiers = modifiers;
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1144,7 +1144,7 @@
   // Event though a time stamp was provided for the fling event, it will be
   // ignored as its too far in the past relative to the first animate call's
   // timestamp.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   base::TimeTicks time =
       base::TimeTicks() + start_time_offset + base::TimeDelta::FromSeconds(1);
   input_handler_->Animate(time);
@@ -1152,7 +1152,7 @@
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // Further animation ticks should update the fling as usual.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x, testing::Lt(0))))
@@ -1197,7 +1197,7 @@
                          fling_point,
                          fling_global_point,
                          modifiers);
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1212,14 +1212,14 @@
   // fling start will typically include the last scroll from the gesture that
   // lead to the scroll (either wheel or gesture scroll), so there should be no
   // visible hitch.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
   input_handler_->Animate(time);
 
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // The second call should start scrolling in the -X direction.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x, testing::Lt(0))))
@@ -1238,6 +1238,59 @@
   EXPECT_TRUE(!input_handler_->gesture_scroll_on_impl_thread_for_testing());
 }
 
+TEST_F(InputHandlerProxyTest,
+       BeginScrollWhenGestureScrollOnImplThreadFlagIsSet) {
+  // We shouldn't send any events to the widget for this gesture.
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+  VERIFY_AND_RESET_MOCKS();
+
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+
+  gesture_.type = WebInputEvent::GestureScrollBegin;
+  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+
+  // After sending a GestureScrollBegin, the member variable
+  // |gesture_scroll_on_impl_thread_| should be true.
+  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
+
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+  VERIFY_AND_RESET_MOCKS();
+
+  // On the fling start, we should schedule an animation but not actually start
+  // scrolling.
+  WebFloatPoint fling_delta = WebFloatPoint(100, 0);
+  WebPoint fling_point = WebPoint(7, 13);
+  WebPoint fling_global_point = WebPoint(17, 23);
+  int modifiers = WebInputEvent::ControlKey | WebInputEvent::AltKey;
+  gesture_ = CreateFling(blink::WebGestureDeviceTouchscreen, fling_delta,
+                         fling_point, fling_global_point, modifiers);
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
+  EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
+      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+
+  // |gesture_scroll_on_impl_thread_| should still be true after
+  // a GestureFlingStart is sent.
+  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
+
+  testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
+
+  // gesture_scroll_on_impl_thread_ is still true when this scroll begins. As a
+  // result, this scroll begin will cancel the previous fling.
+  EXPECT_CALL(mock_input_handler_, ScrollEnd());
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
+
+  gesture_.type = WebInputEvent::GestureScrollBegin;
+  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
+
+  // After sending a GestureScrollBegin, the member variable
+  // |gesture_scroll_on_impl_thread_| should be true.
+  EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
+  VERIFY_AND_RESET_MOCKS();
+}
+
 TEST_F(InputHandlerProxyTest, GestureFlingStopsAtContentEdge) {
   // We shouldn't send any events to the widget for this gesture.
   expected_disposition_ = InputHandlerProxy::DID_HANDLE;
@@ -1252,12 +1305,12 @@
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_CALL(mock_input_handler_, ScrollEnd());
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // The first animate doesn't cause any scrolling.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
   input_handler_->Animate(time);
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -1270,7 +1323,7 @@
                        testing::Property(&gfx::Vector2dF::y, testing::Lt(0))))
       .WillOnce(testing::Return(scroll_result_did_scroll_));
   EXPECT_CALL(mock_input_handler_, ScrollEnd());
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   time += base::TimeDelta::FromMilliseconds(100);
   input_handler_->Animate(time);
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -1301,13 +1354,13 @@
               &DidOverscrollParams::current_fling_velocity,
               testing::Property(&gfx::Vector2dF::y, testing::Lt(0))))));
   EXPECT_CALL(mock_input_handler_, ScrollEnd());
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   time += base::TimeDelta::FromMilliseconds(100);
   input_handler_->Animate(time);
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // The next call to animate will no longer scroll vertically.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_CALL(mock_input_handler_,
@@ -1348,7 +1401,7 @@
                          fling_point,
                          fling_global_point,
                          modifiers);
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1356,7 +1409,7 @@
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
   // With an animation timestamp equivalent to the starting timestamp, the
   // animation will simply be rescheduled.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   input_handler_->Animate(time);
 
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -1364,7 +1417,7 @@
 
   // A small time delta should not stop the fling, even if the client
   // reports no scrolling.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x, testing::Lt(0))))
@@ -1377,7 +1430,7 @@
 
   // A time delta of zero should not stop the fling, and neither should it
   // trigger scrolling on the client.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   input_handler_->Animate(time);
 
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -1421,18 +1474,18 @@
   gesture_.data.flingStart.velocityY = fling_delta.y;
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // The first animate doesn't cause any scrolling.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
   input_handler_->Animate(time);
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // The second animate starts scrolling in the positive X and Y directions.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::y, testing::Lt(0))))
@@ -1460,13 +1513,13 @@
           testing::Field(
               &DidOverscrollParams::current_fling_velocity,
               testing::Property(&gfx::Vector2dF::y, testing::Lt(0))))));
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   time += base::TimeDelta::FromMilliseconds(10);
   input_handler_->Animate(time);
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 
   // The next call to animate will no longer scroll vertically.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::y, testing::Eq(0))))
@@ -1501,7 +1554,7 @@
 
   // The next call to animate will no longer scroll horizontally or vertically,
   // and the fling should be cancelled.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate()).Times(0);
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(0);
   EXPECT_CALL(mock_input_handler_, ScrollBy(testing::_, testing::_)).Times(0);
   time += base::TimeDelta::FromMilliseconds(10);
   input_handler_->Animate(time);
@@ -1589,7 +1642,7 @@
   gesture_.data.flingStart.velocityY = fling_delta.y;
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
   EXPECT_TRUE(input_handler_->gesture_scroll_on_impl_thread_for_testing());
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
@@ -1641,7 +1694,7 @@
                          fling_point,
                          fling_global_point,
                          modifiers);
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, FlingScrollBegin())
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
@@ -1651,7 +1704,7 @@
   // If we get a negative time delta, that is, the Animation tick time happens
   // before the fling's start time then we should *not* try scrolling and
   // instead reset the fling start time.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::_)).Times(0);
@@ -1662,7 +1715,7 @@
 
   // The first call should have reset the start time so subsequent calls should
   // generate scroll events.
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x, testing::Lt(0))))
@@ -1708,7 +1761,7 @@
   time += dt;
   float expected_delta =
       (time - last_animate_time).InSecondsF() * -fling_delta.x;
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x,
@@ -1732,7 +1785,7 @@
   // Animate calls within the deferred cancellation window should continue.
   time += dt;
   expected_delta = (time - last_animate_time).InSecondsF() * -fling_delta.x;
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x,
@@ -1758,7 +1811,7 @@
   time += dt;
   // Note we get *2x* as much delta because 2 flings have combined.
   expected_delta = 2 * (time - last_animate_time).InSecondsF() * -fling_delta.x;
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x,
@@ -1784,7 +1837,7 @@
   time += dt;
   // Note we get *3x* as much delta because 3 flings have combined.
   expected_delta = 3 * (time - last_animate_time).InSecondsF() * -fling_delta.x;
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x,
@@ -1910,7 +1963,7 @@
   // velocity.
   time += dt;
   float expected_delta = dt.InSecondsF() * -orthogonal_fling_delta.y;
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::y,
@@ -1995,7 +2048,7 @@
   // Note that the new fling delta uses the *slow*, unboosted fling velocity.
   time += dt;
   float expected_delta = dt.InSecondsF() * -small_fling_delta.x;
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_,
               ScrollBy(testing::_,
                        testing::Property(&gfx::Vector2dF::x,
@@ -2106,7 +2159,7 @@
   WebFloatPoint fling_delta = WebFloatPoint(100, 100);
   gesture_.data.flingStart.velocityX = fling_delta.x;
   gesture_.data.flingStart.velocityY = fling_delta.y;
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
       .WillOnce(testing::Return(cc::InputHandler::SCROLL_STARTED));
   EXPECT_CALL(mock_input_handler_, ScrollEnd());
@@ -2115,7 +2168,7 @@
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
   testing::Mock::VerifyAndClearExpectations(&mock_client);
 
-  EXPECT_CALL(mock_input_handler_, SetNeedsAnimate());
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput());
   EXPECT_CALL(mock_client, DidAnimateForInput());
   base::TimeTicks time = base::TimeTicks() + base::TimeDelta::FromSeconds(10);
   input_handler_->Animate(time);
diff --git a/content/renderer/manifest/manifest_parser.cc b/content/renderer/manifest/manifest_parser.cc
index 02a5c9c5b..7e2fc77 100644
--- a/content/renderer/manifest/manifest_parser.cc
+++ b/content/renderer/manifest/manifest_parser.cc
@@ -221,13 +221,13 @@
   if (display.is_null())
     return Manifest::DISPLAY_MODE_UNSPECIFIED;
 
-  if (LowerCaseEqualsASCII(display.string(), "fullscreen"))
+  if (base::LowerCaseEqualsASCII(display.string(), "fullscreen"))
     return Manifest::DISPLAY_MODE_FULLSCREEN;
-  else if (LowerCaseEqualsASCII(display.string(), "standalone"))
+  else if (base::LowerCaseEqualsASCII(display.string(), "standalone"))
     return Manifest::DISPLAY_MODE_STANDALONE;
-  else if (LowerCaseEqualsASCII(display.string(), "minimal-ui"))
+  else if (base::LowerCaseEqualsASCII(display.string(), "minimal-ui"))
     return Manifest::DISPLAY_MODE_MINIMAL_UI;
-  else if (LowerCaseEqualsASCII(display.string(), "browser"))
+  else if (base::LowerCaseEqualsASCII(display.string(), "browser"))
     return Manifest::DISPLAY_MODE_BROWSER;
   else {
     errors_.push_back(GetErrorPrefix() + "unknown 'display' value ignored.");
@@ -243,21 +243,25 @@
   if (orientation.is_null())
     return blink::WebScreenOrientationLockDefault;
 
-  if (LowerCaseEqualsASCII(orientation.string(), "any"))
+  if (base::LowerCaseEqualsASCII(orientation.string(), "any"))
     return blink::WebScreenOrientationLockAny;
-  else if (LowerCaseEqualsASCII(orientation.string(), "natural"))
+  else if (base::LowerCaseEqualsASCII(orientation.string(), "natural"))
     return blink::WebScreenOrientationLockNatural;
-  else if (LowerCaseEqualsASCII(orientation.string(), "landscape"))
+  else if (base::LowerCaseEqualsASCII(orientation.string(), "landscape"))
     return blink::WebScreenOrientationLockLandscape;
-  else if (LowerCaseEqualsASCII(orientation.string(), "landscape-primary"))
+  else if (base::LowerCaseEqualsASCII(orientation.string(),
+                                      "landscape-primary"))
     return blink::WebScreenOrientationLockLandscapePrimary;
-  else if (LowerCaseEqualsASCII(orientation.string(), "landscape-secondary"))
+  else if (base::LowerCaseEqualsASCII(orientation.string(),
+                                      "landscape-secondary"))
     return blink::WebScreenOrientationLockLandscapeSecondary;
-  else if (LowerCaseEqualsASCII(orientation.string(), "portrait"))
+  else if (base::LowerCaseEqualsASCII(orientation.string(), "portrait"))
     return blink::WebScreenOrientationLockPortrait;
-  else if (LowerCaseEqualsASCII(orientation.string(), "portrait-primary"))
+  else if (base::LowerCaseEqualsASCII(orientation.string(),
+                                      "portrait-primary"))
     return blink::WebScreenOrientationLockPortraitPrimary;
-  else if (LowerCaseEqualsASCII(orientation.string(), "portrait-secondary"))
+  else if (base::LowerCaseEqualsASCII(orientation.string(),
+                                      "portrait-secondary"))
     return blink::WebScreenOrientationLockPortraitSecondary;
   else {
     errors_.push_back(GetErrorPrefix() +
diff --git a/content/renderer/manifest/manifest_parser_unittest.cc b/content/renderer/manifest/manifest_parser_unittest.cc
index 948d550..39384f8 100644
--- a/content/renderer/manifest/manifest_parser_unittest.cc
+++ b/content/renderer/manifest/manifest_parser_unittest.cc
@@ -127,7 +127,7 @@
   // Smoke test.
   {
     Manifest manifest = ParseManifest("{ \"name\": \"foo\" }");
-    ASSERT_TRUE(EqualsASCII(manifest.name.string(), "foo"));
+    ASSERT_TRUE(base::EqualsASCII(manifest.name.string(), "foo"));
     ASSERT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
   }
@@ -135,7 +135,7 @@
   // Trim whitespaces.
   {
     Manifest manifest = ParseManifest("{ \"name\": \"  foo  \" }");
-    ASSERT_TRUE(EqualsASCII(manifest.name.string(), "foo"));
+    ASSERT_TRUE(base::EqualsASCII(manifest.name.string(), "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
@@ -164,7 +164,7 @@
   // Smoke test.
   {
     Manifest manifest = ParseManifest("{ \"short_name\": \"foo\" }");
-    ASSERT_TRUE(EqualsASCII(manifest.short_name.string(), "foo"));
+    ASSERT_TRUE(base::EqualsASCII(manifest.short_name.string(), "foo"));
     ASSERT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
   }
@@ -172,7 +172,7 @@
   // Trim whitespaces.
   {
     Manifest manifest = ParseManifest("{ \"short_name\": \"  foo  \" }");
-    ASSERT_TRUE(EqualsASCII(manifest.short_name.string(), "foo"));
+    ASSERT_TRUE(base::EqualsASCII(manifest.short_name.string(), "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
@@ -568,7 +568,7 @@
   {
     Manifest manifest =
         ParseManifest("{ \"icons\": [ {\"src\": \"\", \"type\": \"foo\" } ] }");
-    EXPECT_TRUE(EqualsASCII(manifest.icons[0].type.string(), "foo"));
+    EXPECT_TRUE(base::EqualsASCII(manifest.icons[0].type.string(), "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
@@ -576,7 +576,7 @@
   {
     Manifest manifest = ParseManifest("{ \"icons\": [ {\"src\": \"\","
                                       " \"type\": \"  foo  \" } ] }");
-    EXPECT_TRUE(EqualsASCII(manifest.icons[0].type.string(), "foo"));
+    EXPECT_TRUE(base::EqualsASCII(manifest.icons[0].type.string(), "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
@@ -860,8 +860,9 @@
         "{ \"related_applications\": ["
         "{\"platform\": \"play\", \"url\": \"http://www.foo.com\"}]}");
     EXPECT_EQ(manifest.related_applications.size(), 1u);
-    EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].platform.string(),
-                            "play"));
+    EXPECT_TRUE(base::EqualsASCII(
+        manifest.related_applications[0].platform.string(),
+        "play"));
     EXPECT_EQ(manifest.related_applications[0].url.spec(),
               "http://www.foo.com/");
     EXPECT_FALSE(manifest.IsEmpty());
@@ -874,10 +875,11 @@
         "{ \"related_applications\": ["
         "{\"platform\": \"itunes\", \"id\": \"foo\"}]}");
     EXPECT_EQ(manifest.related_applications.size(), 1u);
-    EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].platform.string(),
-                            "itunes"));
-    EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].id.string(),
-                            "foo"));
+    EXPECT_TRUE(base::EqualsASCII(
+        manifest.related_applications[0].platform.string(),
+        "itunes"));
+    EXPECT_TRUE(base::EqualsASCII(manifest.related_applications[0].id.string(),
+                                  "foo"));
     EXPECT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
   }
@@ -889,14 +891,16 @@
         "{\"platform\": \"play\", \"id\": \"foo\"},"
         "{\"platform\": \"itunes\", \"id\": \"bar\"}]}");
     EXPECT_EQ(manifest.related_applications.size(), 2u);
-    EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].platform.string(),
-                            "play"));
-    EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].id.string(),
-                            "foo"));
-    EXPECT_TRUE(EqualsASCII(manifest.related_applications[1].platform.string(),
-                            "itunes"));
-    EXPECT_TRUE(EqualsASCII(manifest.related_applications[1].id.string(),
-                            "bar"));
+    EXPECT_TRUE(base::EqualsASCII(
+        manifest.related_applications[0].platform.string(),
+        "play"));
+    EXPECT_TRUE(base::EqualsASCII(manifest.related_applications[0].id.string(),
+                                  "foo"));
+    EXPECT_TRUE(base::EqualsASCII(
+        manifest.related_applications[1].platform.string(),
+        "itunes"));
+    EXPECT_TRUE(base::EqualsASCII(manifest.related_applications[1].id.string(),
+                                  "bar"));
     EXPECT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(0u, GetErrorCount());
   }
@@ -910,10 +914,11 @@
         "{\"platform\": \"play\", \"id\": \"foo\"},"
         "{}]}");
     EXPECT_EQ(manifest.related_applications.size(), 1u);
-    EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].platform.string(),
-                            "play"));
-    EXPECT_TRUE(EqualsASCII(manifest.related_applications[0].id.string(),
-                            "foo"));
+    EXPECT_TRUE(base::EqualsASCII(
+        manifest.related_applications[0].platform.string(),
+        "play"));
+    EXPECT_TRUE(base::EqualsASCII(manifest.related_applications[0].id.string(),
+                                  "foo"));
     EXPECT_FALSE(manifest.IsEmpty());
     EXPECT_EQ(2u, GetErrorCount());
     EXPECT_EQ("Manifest parsing error: one of 'url' or 'id' is required, "
@@ -978,14 +983,14 @@
   // Smoke test.
   {
     Manifest manifest = ParseManifest("{ \"gcm_sender_id\": \"foo\" }");
-    EXPECT_TRUE(EqualsASCII(manifest.gcm_sender_id.string(), "foo"));
+    EXPECT_TRUE(base::EqualsASCII(manifest.gcm_sender_id.string(), "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
   // Trim whitespaces.
   {
     Manifest manifest = ParseManifest("{ \"gcm_sender_id\": \"  foo  \" }");
-    EXPECT_TRUE(EqualsASCII(manifest.gcm_sender_id.string(), "foo"));
+    EXPECT_TRUE(base::EqualsASCII(manifest.gcm_sender_id.string(), "foo"));
     EXPECT_EQ(0u, GetErrorCount());
   }
 
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc
index 1a5cbe9..5d4aca1 100644
--- a/content/renderer/media/android/media_source_delegate.cc
+++ b/content/renderer/media/android/media_source_delegate.cc
@@ -520,7 +520,7 @@
   DCHECK(!set_decryptor_ready_cb_.is_null());
 
   audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
-      media_task_runner_, set_decryptor_ready_cb_,
+      media_task_runner_, media_log_, set_decryptor_ready_cb_,
       waiting_for_decryption_key_cb_));
   audio_decrypting_demuxer_stream_->Initialize(
       audio_stream_,
@@ -534,7 +534,7 @@
   DCHECK(!set_decryptor_ready_cb_.is_null());
 
   video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
-      media_task_runner_, set_decryptor_ready_cb_,
+      media_task_runner_, media_log_, set_decryptor_ready_cb_,
       waiting_for_decryption_key_cb_));
   video_decrypting_demuxer_stream_->Initialize(
       video_stream_,
diff --git a/content/renderer/media/android/renderer_media_player_manager.cc b/content/renderer/media/android/renderer_media_player_manager.cc
index 9957ced..bb0b966 100644
--- a/content/renderer/media/android/renderer_media_player_manager.cc
+++ b/content/renderer/media/android/renderer_media_player_manager.cc
@@ -6,7 +6,6 @@
 
 #include "content/common/media/media_player_messages_android.h"
 #include "content/public/common/renderer_preferences.h"
-#include "content/renderer/media/android/renderer_media_player_manager.h"
 #include "content/renderer/media/android/webmediaplayer_android.h"
 #include "content/renderer/media/crypto/renderer_cdm_manager.h"
 #include "content/renderer/render_view_impl.h"
@@ -50,8 +49,6 @@
                         OnConnectedToRemoteDevice)
     IPC_MESSAGE_HANDLER(MediaPlayerMsg_DisconnectedFromRemoteDevice,
                         OnDisconnectedFromRemoteDevice)
-    IPC_MESSAGE_HANDLER(MediaPlayerMsg_RequestFullscreen,
-                        OnRequestFullscreen)
     IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidExitFullscreen, OnDidExitFullscreen)
     IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPlay, OnPlayerPlay)
     IPC_MESSAGE_HANDLER(MediaPlayerMsg_DidMediaPlayerPause, OnPlayerPause)
@@ -234,12 +231,6 @@
     player->OnMediaPlayerPause();
 }
 
-void RendererMediaPlayerManager::OnRequestFullscreen(int player_id) {
-  WebMediaPlayerAndroid* player = GetMediaPlayer(player_id);
-  if (player)
-    player->OnRequestFullscreen();
-}
-
 void RendererMediaPlayerManager::OnRemoteRouteAvailabilityChanged(
     int player_id,
     bool routes_available) {
diff --git a/content/renderer/media/android/renderer_media_player_manager.h b/content/renderer/media/android/renderer_media_player_manager.h
index 335c38a..fb97f269 100644
--- a/content/renderer/media/android/renderer_media_player_manager.h
+++ b/content/renderer/media/android/renderer_media_player_manager.h
@@ -141,7 +141,6 @@
   void OnDidEnterFullscreen(int player_id);
   void OnPlayerPlay(int player_id);
   void OnPlayerPause(int player_id);
-  void OnRequestFullscreen(int player_id);
   void OnRemoteRouteAvailabilityChanged(int player_id, bool routes_available);
 
   // Release all video player resources.
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index ccab496..9dfa801 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -981,10 +981,6 @@
   client_->playbackStateChanged();
 }
 
-void WebMediaPlayerAndroid::OnRequestFullscreen() {
-  client_->requestFullscreen();
-}
-
 void WebMediaPlayerAndroid::OnRemoteRouteAvailabilityChanged(
     bool routes_available) {
   client_->remoteRouteAvailabilityChanged(routes_available);
@@ -1205,14 +1201,14 @@
   GLuint texture_mailbox_sync_point = gl->InsertSyncPointCHROMIUM();
 
   scoped_refptr<VideoFrame> new_frame = VideoFrame::WrapNativeTexture(
+      VideoFrame::ARGB,
       gpu::MailboxHolder(texture_mailbox, texture_target,
                          texture_mailbox_sync_point),
       media::BindToCurrentLoop(base::Bind(&OnReleaseTexture,
                                           stream_texture_factory_,
                                           remote_playback_texture_id)),
       canvas_size /* coded_size */, gfx::Rect(canvas_size) /* visible_rect */,
-      canvas_size /* natural_size */, base::TimeDelta() /* timestamp */,
-      false /* allow overlay */, true /* has_alpha */);
+      canvas_size /* natural_size */, base::TimeDelta() /* timestamp */);
   SetCurrentFrameInternal(new_frame);
 }
 
@@ -1243,12 +1239,13 @@
     GLuint texture_mailbox_sync_point = gl->InsertSyncPointCHROMIUM();
 
     scoped_refptr<VideoFrame> new_frame = VideoFrame::WrapNativeTexture(
+        VideoFrame::ARGB,
         gpu::MailboxHolder(texture_mailbox_, texture_target,
                            texture_mailbox_sync_point),
         media::BindToCurrentLoop(base::Bind(
             &OnReleaseTexture, stream_texture_factory_, texture_id_ref)),
         natural_size_, gfx::Rect(natural_size_), natural_size_,
-        base::TimeDelta(), false /* allow_overlay */, true /* has_alpha */);
+        base::TimeDelta());
     SetCurrentFrameInternal(new_frame);
   }
 }
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index 3e67623f8..a643e48 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -212,7 +212,6 @@
   void OnDidExitFullscreen();
   void OnMediaPlayerPlay();
   void OnMediaPlayerPause();
-  void OnRequestFullscreen();
   void OnRemoteRouteAvailabilityChanged(bool routes_available);
 
   // StreamTextureFactoryContextObserver implementation.
diff --git a/content/renderer/media/audio_input_message_filter.cc b/content/renderer/media/audio_input_message_filter.cc
index 286c89e..9c40772 100644
--- a/content/renderer/media/audio_input_message_filter.cc
+++ b/content/renderer/media/audio_input_message_filter.cc
@@ -157,7 +157,7 @@
 }
 
 void AudioInputMessageFilter::OnStreamStateChanged(
-    int stream_id, media::AudioInputIPCDelegate::State state) {
+    int stream_id, media::AudioInputIPCDelegateState state) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
   if (!delegate) {
diff --git a/content/renderer/media/audio_input_message_filter.h b/content/renderer/media/audio_input_message_filter.h
index ad60114..c4fd183 100644
--- a/content/renderer/media/audio_input_message_filter.h
+++ b/content/renderer/media/audio_input_message_filter.h
@@ -75,7 +75,7 @@
   // Received when internal state of browser process' audio input stream has
   // changed.
   void OnStreamStateChanged(int stream_id,
-                            media::AudioInputIPCDelegate::State state);
+                            media::AudioInputIPCDelegateState state);
 
   // A map of stream ids to delegates.
   IDMap<media::AudioInputIPCDelegate> delegates_;
diff --git a/content/renderer/media/audio_message_filter.cc b/content/renderer/media/audio_message_filter.cc
index f2ef3a3d..eb5549b 100644
--- a/content/renderer/media/audio_message_filter.cc
+++ b/content/renderer/media/audio_message_filter.cc
@@ -184,7 +184,7 @@
 }
 
 void AudioMessageFilter::OnStreamStateChanged(
-    int stream_id, media::AudioOutputIPCDelegate::State state) {
+    int stream_id, media::AudioOutputIPCDelegateState state) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   media::AudioOutputIPCDelegate* delegate = delegates_.Lookup(stream_id);
   if (!delegate) {
diff --git a/content/renderer/media/audio_message_filter.h b/content/renderer/media/audio_message_filter.h
index 36ec380..f98b7d69 100644
--- a/content/renderer/media/audio_message_filter.h
+++ b/content/renderer/media/audio_message_filter.h
@@ -74,7 +74,7 @@
   // Received when internal state of browser process' audio output device has
   // changed.
   void OnStreamStateChanged(int stream_id,
-                            media::AudioOutputIPCDelegate::State state);
+                            media::AudioOutputIPCDelegateState state);
 
   // IPC sender for Send(); must only be accesed on |io_task_runner_|.
   IPC::Sender* sender_;
diff --git a/content/renderer/media/audio_message_filter_unittest.cc b/content/renderer/media/audio_message_filter_unittest.cc
index 9122019..267a547a 100644
--- a/content/renderer/media/audio_message_filter_unittest.cc
+++ b/content/renderer/media/audio_message_filter_unittest.cc
@@ -18,7 +18,7 @@
     Reset();
   }
 
-  void OnStateChanged(media::AudioOutputIPCDelegate::State state) override {
+  void OnStateChanged(media::AudioOutputIPCDelegateState state) override {
     state_changed_received_ = true;
     state_ = state;
   }
@@ -35,7 +35,7 @@
 
   void Reset() {
     state_changed_received_ = false;
-    state_ = media::AudioOutputIPCDelegate::kError;
+    state_ = media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR;
 
     created_received_ = false;
     handle_ = base::SharedMemory::NULLHandle();
@@ -46,7 +46,7 @@
   }
 
   bool state_changed_received() { return state_changed_received_; }
-  media::AudioOutputIPCDelegate::State state() { return state_; }
+  media::AudioOutputIPCDelegateState state() { return state_; }
 
   bool created_received() { return created_received_; }
   base::SharedMemoryHandle handle() { return handle_; }
@@ -54,7 +54,7 @@
 
  private:
   bool state_changed_received_;
-  media::AudioOutputIPCDelegate::State state_;
+  media::AudioOutputIPCDelegateState state_;
 
   bool created_received_;
   base::SharedMemoryHandle handle_;
@@ -97,9 +97,9 @@
   EXPECT_FALSE(delegate.state_changed_received());
   filter->OnMessageReceived(
       AudioMsg_NotifyStreamStateChanged(
-          kStreamId, media::AudioOutputIPCDelegate::kPlaying));
+          kStreamId, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING));
   EXPECT_TRUE(delegate.state_changed_received());
-  EXPECT_EQ(media::AudioOutputIPCDelegate::kPlaying, delegate.state());
+  EXPECT_EQ(media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING, delegate.state());
   delegate.Reset();
 
   message_loop.RunUntilIdle();
@@ -134,7 +134,7 @@
   EXPECT_FALSE(delegate2.state_changed_received());
   filter->OnMessageReceived(
       AudioMsg_NotifyStreamStateChanged(
-          kStreamId1, media::AudioOutputIPCDelegate::kPlaying));
+          kStreamId1, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING));
   EXPECT_TRUE(delegate1.state_changed_received());
   EXPECT_FALSE(delegate2.state_changed_received());
   delegate1.Reset();
@@ -143,7 +143,7 @@
   EXPECT_FALSE(delegate2.state_changed_received());
   filter->OnMessageReceived(
       AudioMsg_NotifyStreamStateChanged(
-          kStreamId2, media::AudioOutputIPCDelegate::kPlaying));
+          kStreamId2, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING));
   EXPECT_FALSE(delegate1.state_changed_received());
   EXPECT_TRUE(delegate2.state_changed_received());
   delegate2.Reset();
diff --git a/content/renderer/media/media_stream_audio_processor.cc b/content/renderer/media/media_stream_audio_processor.cc
index 014d2d9..2a3a08e 100644
--- a/content/renderer/media/media_stream_audio_processor.cc
+++ b/content/renderer/media/media_stream_audio_processor.cc
@@ -488,7 +488,7 @@
   // Experimental options provided at creation.
   webrtc::Config config;
   if (goog_experimental_aec)
-    config.Set<webrtc::DelayCorrection>(new webrtc::DelayCorrection(true));
+    config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(true));
   if (goog_experimental_ns)
     config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(true));
   if (IsDelayAgnosticAecEnabled())
diff --git a/content/renderer/media/mock_media_constraint_factory.cc b/content/renderer/media/mock_media_constraint_factory.cc
index 5708d50b..b940317 100644
--- a/content/renderer/media/mock_media_constraint_factory.cc
+++ b/content/renderer/media/mock_media_constraint_factory.cc
@@ -84,7 +84,7 @@
 void MockMediaConstraintFactory::DisableDefaultAudioConstraints() {
   static const char* kDefaultAudioConstraints[] = {
       webrtc::MediaConstraintsInterface::kEchoCancellation,
-      webrtc::MediaConstraintsInterface::kExperimentalEchoCancellation,
+      webrtc::MediaConstraintsInterface::kExtendedFilterEchoCancellation,
       webrtc::MediaConstraintsInterface::kAutoGainControl,
       webrtc::MediaConstraintsInterface::kExperimentalAutoGainControl,
       webrtc::MediaConstraintsInterface::kNoiseSuppression,
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
index e7efe290..7ae9ab6d 100644
--- a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
+++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
@@ -66,7 +66,8 @@
   DCHECK(task_runner_->BelongsToCurrentThread());
   if (!context_provider_.get())
     return NULL;
-  if (context_provider_->IsContextLost()) {
+  if (context_provider_->ContextGL()->GetGraphicsResetStatusKHR() !=
+      GL_NO_ERROR) {
     context_provider_->VerifyContexts();
     context_provider_ = NULL;
     gl_helper_.reset(NULL);
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc
index 2556dc6..16b76eb1 100644
--- a/content/renderer/media/rtc_video_decoder.cc
+++ b/content/renderer/media/rtc_video_decoder.cc
@@ -422,13 +422,18 @@
   // Convert timestamp from 90KHz to ms.
   base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue(
       base::checked_cast<uint64_t>(timestamp) * 1000 / 90);
-  return media::VideoFrame::WrapNativeTexture(
+  scoped_refptr<media::VideoFrame> frame(media::VideoFrame::WrapNativeTexture(
+      media::VideoFrame::ARGB,
       gpu::MailboxHolder(pb.texture_mailbox(), decoder_texture_target_, 0),
       media::BindToCurrentLoop(base::Bind(
           &RTCVideoDecoder::ReleaseMailbox, weak_factory_.GetWeakPtr(),
           factories_, picture.picture_buffer_id(), pb.texture_id())),
-      pb.size(), visible_rect, visible_rect.size(), timestamp_ms,
-      picture.allow_overlay(), true /* has_alpha */);
+      pb.size(), visible_rect, visible_rect.size(), timestamp_ms));
+  if (picture.allow_overlay()) {
+    frame->metadata()->SetBoolean(media::VideoFrameMetadata::ALLOW_OVERLAY,
+                                  true);
+  }
+  return frame;
 }
 
 void RTCVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) {
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc
index e09ccb6..22ec3d1 100644
--- a/content/renderer/media/user_media_client_impl.cc
+++ b/content/renderer/media/user_media_client_impl.cc
@@ -160,7 +160,7 @@
       std::string enable;
       if (options.GetFirstAudioConstraintByName(
               kMediaStreamRenderToAssociatedSink, &enable, NULL) &&
-          LowerCaseEqualsASCII(enable, "true")) {
+          base::LowerCaseEqualsASCII(enable, "true")) {
         enable_automatic_output_device_selection = true;
       }
     }
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index e5791356..23ae799 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -296,11 +296,11 @@
   uint32* const release_sync_point_storage =
       new uint32(0);  // Deleted in DidFinishConsumingFrame().
   scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapNativeTexture(
+      media::VideoFrame::ARGB,
       mailbox_holder,
       base::Bind(&SaveReleaseSyncPoint, release_sync_point_storage),
       packed_frame_size, gfx::Rect(packed_frame_size), packed_frame_size,
-      timestamp - first_frame_timestamp_, false /* allow_overlay */,
-      true /* has_alpha */);
+      timestamp - first_frame_timestamp_);
   frame->AddDestructionObserver(
       base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame,
                  frame->metadata(),
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc
index 7363e606..e96b0bd 100644
--- a/content/renderer/media/webmediaplayer_ms.cc
+++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -429,7 +429,8 @@
   }
 
   if (!video_frame.get() ||
-      video_frame->storage_type() != media::VideoFrame::STORAGE_TEXTURE) {
+      video_frame->storage_type() != media::VideoFrame::STORAGE_TEXTURE ||
+      media::VideoFrame::NumPlanes(video_frame->format()) != 1) {
     return false;
   }
 
@@ -438,7 +439,7 @@
   gpu::gles2::GLES2Interface* gl =
       static_cast<gpu_blink::WebGraphicsContext3DImpl*>(web_graphics_context)
           ->GetGLInterface();
-  media::SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(
+  media::SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
       gl, video_frame.get(), texture, internal_format, type, premultiply_alpha,
       flip_y);
   return true;
diff --git a/content/renderer/media/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc_audio_device_impl.cc
index a0817200..e0e3a489 100644
--- a/content/renderer/media/webrtc_audio_device_impl.cc
+++ b/content/renderer/media/webrtc_audio_device_impl.cc
@@ -67,6 +67,9 @@
   {
     base::AutoLock auto_lock(lock_);
     if (!playing_) {
+      // Force silence to AudioBus after stopping playout in case
+      // there is lingering audio data in AudioBus.
+      audio_bus->Zero();
       return;
     }
     DCHECK(audio_transport_callback_);
diff --git a/content/renderer/npapi/webplugin_impl.cc b/content/renderer/npapi/webplugin_impl.cc
index 127c574..b6e4db1 100644
--- a/content/renderer/npapi/webplugin_impl.cc
+++ b/content/renderer/npapi/webplugin_impl.cc
@@ -208,7 +208,7 @@
   WebString content_encoding =
       response.httpHeaderField(WebString::fromUTF8("Content-Encoding"));
   if (!content_encoding.isNull() &&
-      !EqualsASCII(content_encoding, "identity")) {
+      !base::EqualsASCII(content_encoding, "identity")) {
     // Don't send the compressed content length to the plugin, which only
     // cares about the decoded length.
     response_info->expected_length = 0;
@@ -942,7 +942,7 @@
       // just block cross origin 307 POST redirects.
       if (!client_info->notify_redirects) {
         if (response.httpStatusCode() == 307 &&
-            LowerCaseEqualsASCII(request.httpMethod().utf8(), "post")) {
+            base::LowerCaseEqualsASCII(request.httpMethod().utf8(), "post")) {
           GURL original_request_url(response.url());
           GURL response_url(request.url());
           if (original_request_url.GetOrigin() != response_url.GetOrigin()) {
diff --git a/content/renderer/pepper/pepper_platform_audio_input.cc b/content/renderer/pepper/pepper_platform_audio_input.cc
index f87fa64..d1aaf53 100644
--- a/content/renderer/pepper/pepper_platform_audio_input.cc
+++ b/content/renderer/pepper/pepper_platform_audio_input.cc
@@ -116,7 +116,7 @@
 void PepperPlatformAudioInput::OnVolume(double volume) {}
 
 void PepperPlatformAudioInput::OnStateChanged(
-    media::AudioInputIPCDelegate::State state) {}
+    media::AudioInputIPCDelegateState state) {}
 
 void PepperPlatformAudioInput::OnIPCClosed() { ipc_.reset(); }
 
diff --git a/content/renderer/pepper/pepper_platform_audio_input.h b/content/renderer/pepper/pepper_platform_audio_input.h
index a1ea3cb..3b9f8bb 100644
--- a/content/renderer/pepper/pepper_platform_audio_input.h
+++ b/content/renderer/pepper/pepper_platform_audio_input.h
@@ -63,7 +63,7 @@
                        int length,
                        int total_segments) override;
   void OnVolume(double volume) override;
-  void OnStateChanged(media::AudioInputIPCDelegate::State state) override;
+  void OnStateChanged(media::AudioInputIPCDelegateState state) override;
   void OnIPCClosed() override;
 
  protected:
diff --git a/content/renderer/pepper/pepper_platform_audio_output.cc b/content/renderer/pepper/pepper_platform_audio_output.cc
index 173abcfe..1861b07 100644
--- a/content/renderer/pepper/pepper_platform_audio_output.cc
+++ b/content/renderer/pepper/pepper_platform_audio_output.cc
@@ -70,7 +70,7 @@
 }
 
 void PepperPlatformAudioOutput::OnStateChanged(
-    media::AudioOutputIPCDelegate::State state) {}
+    media::AudioOutputIPCDelegateState state) {}
 
 void PepperPlatformAudioOutput::OnStreamCreated(
     base::SharedMemoryHandle handle,
diff --git a/content/renderer/pepper/pepper_platform_audio_output.h b/content/renderer/pepper/pepper_platform_audio_output.h
index 86bce783..9b144b4 100644
--- a/content/renderer/pepper/pepper_platform_audio_output.h
+++ b/content/renderer/pepper/pepper_platform_audio_output.h
@@ -47,7 +47,7 @@
   void ShutDown();
 
   // media::AudioOutputIPCDelegate implementation.
-  void OnStateChanged(media::AudioOutputIPCDelegate::State state) override;
+  void OnStateChanged(media::AudioOutputIPCDelegateState state) override;
   void OnStreamCreated(base::SharedMemoryHandle handle,
                        base::SyncSocket::Handle socket_handle,
                        int length) override;
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 85449ba..06c7ba9 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -110,6 +110,7 @@
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "third_party/WebKit/public/web/WebPluginScriptForbiddenScope.h"
 #include "third_party/WebKit/public/web/WebPrintParams.h"
 #include "third_party/WebKit/public/web/WebPrintPresetOptions.h"
 #include "third_party/WebKit/public/web/WebPrintScalingOption.h"
@@ -1742,7 +1743,7 @@
   return num_pages;
 }
 
-bool PepperPluginInstanceImpl::PrintPage(int page_number,
+void PepperPluginInstanceImpl::PrintPage(int page_number,
                                          blink::WebCanvas* canvas) {
 #if defined(ENABLE_PRINTING)
   DCHECK(plugin_print_interface_);
@@ -1757,16 +1758,13 @@
   if (save_for_later) {
     ranges_.push_back(page_range);
     canvas_ = skia::SharePtr(canvas);
-    return true;
   } else {
-    return PrintPageHelper(&page_range, 1, canvas);
+    PrintPageHelper(&page_range, 1, canvas);
   }
-#else  // ENABLE_PRINTING
-  return false;
 #endif
 }
 
-bool PepperPluginInstanceImpl::PrintPageHelper(
+void PepperPluginInstanceImpl::PrintPageHelper(
     PP_PrintPageNumberRange_Dev* page_ranges,
     int num_ranges,
     blink::WebCanvas* canvas) {
@@ -1774,21 +1772,17 @@
   scoped_refptr<PepperPluginInstanceImpl> ref(this);
   DCHECK(plugin_print_interface_);
   if (!plugin_print_interface_)
-    return false;
+    return;
   PP_Resource print_output = plugin_print_interface_->PrintPages(
       pp_instance(), page_ranges, num_ranges);
   if (!print_output)
-    return false;
-
-  bool ret = false;
+    return;
 
   if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF)
-    ret = PrintPDFOutput(print_output, canvas);
+    PrintPDFOutput(print_output, canvas);
 
   // Now we need to release the print output resource.
   PluginModule::GetCore()->ReleaseResource(print_output);
-
-  return ret;
 }
 
 void PepperPluginInstanceImpl::PrintEnd() {
@@ -2371,6 +2365,8 @@
                                                PP_Var* exception) {
   if (!container_)
     return PP_MakeUndefined();
+  if (is_deleted_ && blink::WebPluginScriptForbiddenScope::isForbidden())
+    return PP_MakeUndefined();
   RecordFlashJavaScriptUse();
 
   // Executing the script may remove the plugin from the DOM, so we need to keep
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h
index cb0f5ea..bab9c0b 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.h
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.h
@@ -255,7 +255,7 @@
   bool SupportsPrintInterface();
   bool IsPrintScalingDisabled();
   int PrintBegin(const blink::WebPrintParams& print_params);
-  bool PrintPage(int page_number, blink::WebCanvas* canvas);
+  void PrintPage(int page_number, blink::WebCanvas* canvas);
   void PrintEnd();
   bool GetPrintPresetOptionsFromDocument(
       blink::WebPrintPresetOptions* preset_options);
@@ -644,7 +644,7 @@
   void UpdateLayer(bool device_changed);
 
   // Internal helper function for PrintPage().
-  bool PrintPageHelper(PP_PrintPageNumberRange_Dev* page_ranges,
+  void PrintPageHelper(PP_PrintPageNumberRange_Dev* page_ranges,
                        int num_ranges,
                        blink::WebCanvas* canvas);
 
diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc
index baae3f27..914d3950 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.cc
+++ b/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -270,10 +270,16 @@
   return instance_->PrintBegin(print_params);
 }
 
-bool PepperWebPluginImpl::printPage(int page_number, blink::WebCanvas* canvas) {
+void PepperWebPluginImpl::printPage(int page_number, blink::WebCanvas* canvas,
+                                    bool unused) {
   return instance_->PrintPage(page_number, canvas);
 }
 
+bool PepperWebPluginImpl::printPage(int page_number, blink::WebCanvas* canvas) {
+  instance_->PrintPage(page_number, canvas);
+  return true;
+}
+
 void PepperWebPluginImpl::printEnd() { return instance_->PrintEnd(); }
 
 bool PepperWebPluginImpl::getPrintPresetOptionsFromDocument(
diff --git a/content/renderer/pepper/pepper_webplugin_impl.h b/content/renderer/pepper/pepper_webplugin_impl.h
index c975666..6840b5ee 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.h
+++ b/content/renderer/pepper/pepper_webplugin_impl.h
@@ -84,6 +84,8 @@
 
   virtual int printBegin(const blink::WebPrintParams& print_params) override;
   virtual bool printPage(int page_number, blink::WebCanvas* canvas) override;
+  virtual void printPage(int page_number, blink::WebCanvas* canvas,
+                         bool unused);
   virtual void printEnd() override;
 
   virtual bool canRotateView() override;
diff --git a/content/renderer/pepper/pepper_websocket_host.cc b/content/renderer/pepper/pepper_websocket_host.cc
index ad016f3..07740b0 100644
--- a/content/renderer/pepper/pepper_websocket_host.cc
+++ b/content/renderer/pepper/pepper_websocket_host.cc
@@ -213,10 +213,8 @@
     return PP_ERROR_BADARGUMENT;
   if (gurl.has_ref())
     return PP_ERROR_BADARGUMENT;
-  if (!net::IsPortAllowedForScheme(gurl.EffectiveIntPort(), gurl.scheme(),
-                                   net::PORT_OVERRIDES_IGNORED)) {
+  if (!net::IsPortAllowedForScheme(gurl.EffectiveIntPort(), gurl.scheme()))
     return PP_ERROR_BADARGUMENT;
-  }
   WebURL web_url(gurl);
 
   // Validate protocols.
diff --git a/content/renderer/pepper/plugin_instance_throttler_impl.cc b/content/renderer/pepper/plugin_instance_throttler_impl.cc
index a73a2243..7bf11133 100644
--- a/content/renderer/pepper/plugin_instance_throttler_impl.cc
+++ b/content/renderer/pepper/plugin_instance_throttler_impl.cc
@@ -4,6 +4,8 @@
 
 #include "content/renderer/pepper/plugin_instance_throttler_impl.h"
 
+#include <cmath>
+
 #include "base/metrics/histogram.h"
 #include "base/time/time.h"
 #include "content/public/common/content_constants.h"
@@ -21,6 +23,18 @@
 
 namespace {
 
+// Cross-origin plugin content must have a width and height both exceeding
+// these minimums to be considered "large", and thus not peripheral.
+const int kLargeContentMinWidth = 398;
+const int kLargeContentMinHeight = 298;
+
+// Mark some 16:9 aspect ratio plugins as essential (not peripheral). This is to
+// mark as "large" some medium sized video content that meets a minimum area
+// requirement, even if it is below the max width/height above.
+const double kEssentialVideoAspectRatio = 16.0 / 9.0;
+const double kAspectRatioEpsilon = 0.01;
+const int kEssentialVideoMinimumArea = 120000;
+
 // Threshold for 'boring' score to accept a frame as good enough to be a
 // representative keyframe. Units are the ratio of all pixels that are within
 // the most common luma bin. The same threshold is used for history thumbnails.
@@ -49,6 +63,21 @@
       PluginInstanceThrottler::UNTHROTTLE_METHOD_NUM_ITEMS);
 }
 
+// static
+bool PluginInstanceThrottler::IsLargeContent(int width, int height) {
+  if (width >= kLargeContentMinWidth && height >= kLargeContentMinHeight)
+    return true;
+
+  double aspect_ratio = static_cast<double>(width) / height;
+  if (std::abs(aspect_ratio - kEssentialVideoAspectRatio) <
+          kAspectRatioEpsilon &&
+      width * height >= kEssentialVideoMinimumArea) {
+    return true;
+  }
+
+  return false;
+}
+
 PluginInstanceThrottlerImpl::PluginInstanceThrottlerImpl()
     : state_(THROTTLER_STATE_AWAITING_KEYFRAME),
       is_hidden_for_placeholder_(false),
diff --git a/content/renderer/pepper/plugin_power_saver_helper.cc b/content/renderer/pepper/plugin_power_saver_helper.cc
index 7931b41..e21305a2 100644
--- a/content/renderer/pepper/plugin_power_saver_helper.cc
+++ b/content/renderer/pepper/plugin_power_saver_helper.cc
@@ -12,6 +12,7 @@
 #include "content/common/frame_messages.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/renderer/plugin_instance_throttler.h"
 #include "content/public/renderer/render_frame.h"
 #include "ppapi/shared_impl/ppapi_constants.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
@@ -37,11 +38,6 @@
 const char kPeripheralHeuristicHistogram[] =
     "Plugin.PowerSaver.PeripheralHeuristic";
 
-// Maximum dimensions plugin content may have while still being considered
-// peripheral content. These are similar to the numbers used by WebKit.
-const int kPeripheralContentMaxWidth = 398;
-const int kPeripheralContentMaxHeight = 298;
-
 // Plugin content below this size in height and width is considered "tiny".
 // Tiny content is never peripheral, as tiny plugins often serve a critical
 // purpose, and the user often cannot find and click to unthrottle it.
@@ -180,8 +176,7 @@
   }
 
   // Plugin content large in both dimensions are the "main attraction".
-  if (width >= kPeripheralContentMaxWidth &&
-      height >= kPeripheralContentMaxHeight) {
+  if (PluginInstanceThrottler::IsLargeContent(width, height)) {
     RecordDecisionMetric(HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_BIG);
     if (cross_origin_main_content)
       *cross_origin_main_content = true;
diff --git a/content/renderer/pepper/ppb_var_deprecated_impl.cc b/content/renderer/pepper/ppb_var_deprecated_impl.cc
index 4188ee6e..dd2c80b 100644
--- a/content/renderer/pepper/ppb_var_deprecated_impl.cc
+++ b/content/renderer/pepper/ppb_var_deprecated_impl.cc
@@ -20,6 +20,7 @@
 #include "third_party/WebKit/public/web/WebElement.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebPluginContainer.h"
+#include "third_party/WebKit/public/web/WebPluginScriptForbiddenScope.h"
 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
 
 using ppapi::V8ObjectVar;
@@ -56,7 +57,8 @@
     if (exception && exception->type != PP_VARTYPE_UNDEFINED)
       return false;
     if (instance_)
-      return true;
+      return !instance_->is_deleted() ||
+             !blink::WebPluginScriptForbiddenScope::isForbidden();
     if (exception)
       *exception = ppapi::StringVar::StringToPPVar(kInvalidObjectException);
     return false;
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc
index b7bd4ce..ec176bff 100644
--- a/content/renderer/pepper/video_decoder_shim.cc
+++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -788,7 +788,7 @@
   DCHECK(awaiting_decoder_);
 
   scoped_ptr<PendingFrame> pending_frame;
-  if (!frame->IsEndOfStream())
+  if (!frame->metadata()->IsTrue(media::VideoFrameMetadata::END_OF_STREAM))
     pending_frame.reset(new PendingFrame(decode_id_, frame));
   else
     pending_frame.reset(new PendingFrame(decode_id_));
diff --git a/content/renderer/presentation/presentation_dispatcher.cc b/content/renderer/presentation/presentation_dispatcher.cc
index 1205e533f..8100c03b 100644
--- a/content/renderer/presentation/presentation_dispatcher.cc
+++ b/content/renderer/presentation/presentation_dispatcher.cc
@@ -54,6 +54,22 @@
   return url.is_valid() ? url : GURL();
 }
 
+presentation::SessionMessage* GetMojoSessionMessage(
+    const blink::WebString& presentationUrl,
+    const blink::WebString& presentationId,
+    presentation::PresentationMessageType type,
+    const uint8* data,
+    size_t length) {
+  presentation::SessionMessage* session_message =
+      new presentation::SessionMessage();
+  session_message->presentation_url = presentationUrl.utf8();
+  session_message->presentation_id = presentationId.utf8();
+  session_message->type = type;
+  const std::vector<uint8> vector(data, data + length);
+  session_message->data = mojo::Array<uint8>::From(vector);
+  return session_message;
+}
+
 }  // namespace
 
 namespace content {
@@ -165,15 +181,11 @@
     return;
   }
 
-  const std::vector<uint8> vector(data, data + length);
   presentation::SessionMessage* session_message =
-      new presentation::SessionMessage();
-  session_message->presentation_url = presentationUrl.utf8();
-  session_message->presentation_id = presentationId.utf8();
-  session_message->type = presentation::PresentationMessageType::
-                          PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER;
-  session_message->data = mojo::Array<uint8>::From(vector);
-
+      GetMojoSessionMessage(presentationUrl, presentationId,
+                            presentation::PresentationMessageType::
+                                PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER,
+                            data, length);
   message_request_queue_.push(make_linked_ptr(session_message));
   // Start processing request if only one in the queue.
   if (message_request_queue_.size() == 1) {
@@ -183,22 +195,57 @@
   }
 }
 
+void PresentationDispatcher::sendBlobData(
+    const blink::WebString& presentationUrl,
+    const blink::WebString& presentationId,
+    const uint8* data,
+    size_t length) {
+  DCHECK(data);
+  if (length > kMaxPresentationSessionMessageSize) {
+    // TODO(crbug.com/459008): Same as in sendString().
+    LOG(WARNING) << "data size exceeded limit!";
+    return;
+  }
+
+  presentation::SessionMessage* session_message = GetMojoSessionMessage(
+      presentationUrl, presentationId,
+      presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_BLOB,
+      data, length);
+  message_request_queue_.push(make_linked_ptr(session_message));
+  if (message_request_queue_.size() == 1) {
+    const linked_ptr<presentation::SessionMessage>& request =
+        message_request_queue_.front();
+    DoSendMessage(*request);
+  }
+}
+
 void PresentationDispatcher::DoSendMessage(
     const presentation::SessionMessage& session_message) {
   ConnectToPresentationServiceIfNeeded();
-
   presentation::SessionMessagePtr message_request(
       presentation::SessionMessage::New());
   message_request->presentation_url = session_message.presentation_url;
   message_request->presentation_id = session_message.presentation_id;
   message_request->type = session_message.type;
-  if (session_message.type == presentation::PresentationMessageType::
-                              PRESENTATION_MESSAGE_TYPE_TEXT) {
-    message_request->message = session_message.message;
-  } else if (session_message.type == presentation::PresentationMessageType::
-                                      PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER) {
-    message_request->data = mojo::Array<uint8>::From(
-        session_message.data.storage());
+  switch (session_message.type) {
+    case presentation::PresentationMessageType::
+        PRESENTATION_MESSAGE_TYPE_TEXT: {
+      message_request->message = session_message.message;
+      break;
+    }
+    case presentation::PresentationMessageType::
+        PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER:
+    case presentation::PresentationMessageType::
+        PRESENTATION_MESSAGE_TYPE_BLOB: {
+      message_request->data =
+          mojo::Array<uint8>::From(session_message.data.storage());
+      break;
+    }
+    default: {
+      NOTREACHED() << "Invalid presentation message type "
+                   << session_message.type;
+      break;
+    }
   }
 
   presentation_service_->SendSessionMessage(
diff --git a/content/renderer/presentation/presentation_dispatcher.h b/content/renderer/presentation/presentation_dispatcher.h
index 89f6b9f..4642a64 100644
--- a/content/renderer/presentation/presentation_dispatcher.h
+++ b/content/renderer/presentation/presentation_dispatcher.h
@@ -50,6 +50,11 @@
       const blink::WebString& presentationId,
       const uint8* data,
       size_t length);
+  virtual void sendBlobData(
+      const blink::WebString& presentationUrl,
+      const blink::WebString& presentationId,
+      const uint8* data,
+      size_t length);
   virtual void closeSession(
       const blink::WebString& presentationUrl,
       const blink::WebString& presentationId);
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index aba81ee..fe655f5 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1799,11 +1799,10 @@
   DCHECK_EQ(frame_, frame);
 #if defined(ENABLE_PLUGINS)
   if (info.type == WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN) {
-    scoped_ptr<BrowserPluginDelegate> browser_plugin_delegate(
+    return BrowserPluginManager::Get()->CreateBrowserPlugin(
+        this,
         GetContentClient()->renderer()->CreateBrowserPluginDelegate(
             this, params.mimeType.utf8(), GURL(params.url)));
-    return BrowserPluginManager::Get()->CreateBrowserPlugin(
-        this, browser_plugin_delegate.Pass());
   }
 
   bool pepper_plugin_was_registered = false;
@@ -1919,11 +1918,10 @@
   }
 
   if (base::UTF16ToUTF8(params.mimeType) == kBrowserPluginMimeType) {
-    scoped_ptr<BrowserPluginDelegate> browser_plugin_delegate(
+    return BrowserPluginManager::Get()->CreateBrowserPlugin(
+        this,
         GetContentClient()->renderer()->CreateBrowserPluginDelegate(this,
             kBrowserPluginMimeType, GURL(params.url)));
-    return BrowserPluginManager::Get()->CreateBrowserPlugin(
-        this, browser_plugin_delegate.Pass());
   }
 
 #if defined(ENABLE_PLUGINS)
@@ -3249,7 +3247,7 @@
              navigation_state->start_params().extra_headers.begin(),
              navigation_state->start_params().extra_headers.end(), "\n");
          i.GetNext();) {
-      if (LowerCaseEqualsASCII(i.name(), "referer")) {
+      if (base::LowerCaseEqualsASCII(i.name(), "referer")) {
         WebString referrer = WebSecurityPolicy::generateReferrerHeader(
             blink::WebReferrerPolicyDefault,
             request.url(),
@@ -3384,6 +3382,9 @@
       render_view_->GetRoutingID(),
       origin.toString().utf8(),
       target));
+  GetContentClient()->renderer()->RecordRapporURL(
+      "ContentSettings.MixedScript.RanMixedScript",
+      GURL(origin.toString().utf8()));
 }
 
 void RenderFrameImpl::didAbortLoading(blink::WebLocalFrame* frame) {
@@ -3937,7 +3938,7 @@
     }
 
     base::string16 method = request.httpMethod();
-    if (EqualsASCII(method, "POST")) {
+    if (base::EqualsASCII(method, "POST")) {
       params.is_post = true;
       params.post_id = ExtractPostId(entry);
     }
@@ -4161,40 +4162,12 @@
   bool is_content_initiated =
       document_state->navigation_state()->IsContentInitiated();
 
-  // Experimental:
-  // If --enable-strict-site-isolation is enabled, send all top-level
-  // navigations to the browser to let it swap processes when crossing site
-  // boundaries.  This is currently expected to break some script calls and
-  // navigations, such as form submissions.
-  bool force_swap_due_to_flag =
-      command_line.HasSwitch(switches::kEnableStrictSiteIsolation);
-  if (force_swap_due_to_flag &&
-      !info.frame->parent() && (is_content_initiated || info.isRedirect)) {
-    WebString origin_str = info.frame->document().securityOrigin().toString();
-    GURL frame_url(origin_str.utf8().data());
-    // TODO(cevans): revisit whether this site check is still necessary once
-    // crbug.com/101395 is fixed.
-    bool same_domain_or_host =
-        net::registry_controlled_domains::SameDomainOrHost(
-            frame_url,
-            url,
-            net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
-    // Only keep same-site (domain + scheme) and data URLs in the same process.
-    bool is_same_site =
-        (same_domain_or_host && frame_url.scheme() == url.scheme()) ||
-        url.SchemeIs(url::kDataScheme);
-    if (!is_same_site) {
-      OpenURL(info.frame, url, referrer, info.defaultPolicy);
-      return blink::WebNavigationPolicyIgnore;
-    }
-  }
-
   // If the browser is interested, then give it a chance to look at the request.
   if (is_content_initiated) {
     bool is_form_post =
         ((info.navigationType == blink::WebNavigationTypeFormSubmitted) ||
             (info.navigationType == blink::WebNavigationTypeFormResubmitted)) &&
-        EqualsASCII(info.urlRequest.httpMethod(), "POST");
+        base::EqualsASCII(info.urlRequest.httpMethod(), "POST");
     bool browser_handles_request =
         render_view_->renderer_preferences_
             .browser_handles_non_local_top_level_requests
@@ -4409,27 +4382,38 @@
   pending_navigation_params_.reset(
       new NavigationParams(common_params, start_params, request_params));
 
-  // If we are reloading, then Blink will use the history state of the current
-  // page, so we should just ignore any given history state.  Otherwise, if we
-  // have history state, then we need to navigate to it, which corresponds to a
-  // back/forward navigation event.
-  if (is_reload && !browser_side_navigation) {
-    // TODO(clamy): adapt this code for PlzNavigate. In particular the stream
-    // override should be given to the generated request.
-    bool reload_original_url =
-        (common_params.navigation_type ==
-         FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
+  // Create parameters for a standard navigation.
+  blink::WebFrameLoadType load_type = blink::WebFrameLoadType::Standard;
+  bool should_load_request = false;
+  WebHistoryItem item_for_history_navigation;
+  WebURLRequest request = CreateURLRequestForNavigation(
+      common_params, stream_params.Pass(), frame_->isViewSourceModeEnabled());
+
+  // PlzNavigate: Make sure that Blink's loader will not try to use browser side
+  // navigation for this request (since it already went to the browser).
+  if (browser_side_navigation)
+    request.setCheckForBrowserSideNavigation(false);
+
+  // If we are reloading, then use the history state of the current frame.
+  // Otherwise, if we have history state, then we need to navigate to it, which
+  // corresponds to a back/forward navigation event. Update the parameters
+  // depending on the navigation type.
+  if (is_reload) {
     bool ignore_cache = (common_params.navigation_type ==
                          FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE);
+    load_type = ignore_cache ? blink::WebFrameLoadType::ReloadFromOrigin
+                             : blink::WebFrameLoadType::Reload;
 
-    if (reload_original_url)
-      frame_->reloadWithOverrideURL(common_params.url, true);
-    else
-      frame_->reload(ignore_cache);
-  } else if (is_history_navigation && !browser_side_navigation) {
-    // TODO(clamy): adapt this code for PlzNavigate. In particular the stream
-    // override should be given to the generated request.
-
+    if (!browser_side_navigation) {
+      const GURL override_url =
+          (common_params.navigation_type ==
+           FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL)
+              ? common_params.url
+              : GURL();
+      request = frame_->requestForReload(load_type, override_url);
+    }
+    should_load_request = true;
+  } else if (is_history_navigation) {
     // We must know the page ID of the page we are navigating back to.
     DCHECK_NE(request_params.page_id, -1);
     // We must know the nav entry ID of the page we are navigating back to,
@@ -4442,20 +4426,26 @@
       // Ensure we didn't save the swapped out URL in UpdateState, since the
       // browser should never be telling us to navigate to swappedout://.
       CHECK(entry->root().urlString() != WebString::fromUTF8(kSwappedOutURL));
-      scoped_ptr<NavigationParams> navigation_params(
-          new NavigationParams(*pending_navigation_params_.get()));
-      render_view_->history_controller()->GoToEntry(
-          entry.Pass(), navigation_params.Pass(), cache_policy);
+
+      if (!browser_side_navigation) {
+        scoped_ptr<NavigationParams> navigation_params(
+            new NavigationParams(*pending_navigation_params_.get()));
+        render_view_->history_controller()->GoToEntry(
+            entry.Pass(), navigation_params.Pass(), cache_policy);
+      } else {
+        // TODO(clamy): this should be set to the HistoryItem sent by the
+        // browser once the HistoryController has moved to the browser.
+        // TODO(clamy): distinguish between different document and same document
+        // loads.
+        // TODO(clamy): update this for subframes history loads.
+        item_for_history_navigation =
+            entry->GetHistoryNodeForFrame(this)->item();
+        load_type = blink::WebFrameLoadType::BackForward;
+        should_load_request = true;
+      }
     }
-  } else if (!common_params.base_url_for_data_url.is_empty() ||
-             (browser_side_navigation &&
-              common_params.url.SchemeIs(url::kDataScheme))) {
-    LoadDataURL(common_params, frame_);
   } else {
     // Navigate to the given URL.
-    WebURLRequest request = CreateURLRequestForNavigation(
-        common_params, stream_params.Pass(), frame_->isViewSourceModeEnabled());
-
     if (!start_params.extra_headers.empty() && !browser_side_navigation) {
       for (net::HttpUtil::HeadersIterator i(start_params.extra_headers.begin(),
                                             start_params.extra_headers.end(),
@@ -4485,18 +4475,30 @@
     // A session history navigation should have been accompanied by state.
     CHECK_EQ(request_params.page_id, -1);
 
-    // PlzNavigate: Make sure that Blink's loader will not try to use browser
-    // side navigation for this request (since it already went to the browser).
-    if (browser_side_navigation)
-      request.setCheckForBrowserSideNavigation(false);
+    should_load_request = true;
+  }
 
-    // Record this before starting the load. We need a lower bound of this time
-    // to sanitize the navigationStart override set below.
-    base::TimeTicks renderer_navigation_start = base::TimeTicks::Now();
-    frame_->loadRequest(request);
+  if (should_load_request) {
+    // Perform a navigation to a data url if needed.
+    if (!common_params.base_url_for_data_url.is_empty() ||
+        (browser_side_navigation &&
+         common_params.url.SchemeIs(url::kDataScheme))) {
+      LoadDataURL(common_params, frame_);
+    } else {
+      // Record this before starting the load. We need a lower bound of this
+      // time to sanitize the navigationStart override set below.
+      base::TimeTicks renderer_navigation_start = base::TimeTicks::Now();
 
-    UpdateFrameNavigationTiming(frame_, request_params.browser_navigation_start,
-                                renderer_navigation_start);
+      // Load the request.
+      frame_->toWebLocalFrame()->load(request, load_type,
+                                      item_for_history_navigation);
+
+      if (load_type == blink::WebFrameLoadType::Standard) {
+        UpdateFrameNavigationTiming(frame_,
+                                    request_params.browser_navigation_start,
+                                    renderer_navigation_start);
+      }
+    }
   }
 
   // In case LoadRequest failed before didCreateDataSource was called.
@@ -4731,8 +4733,9 @@
     const blink::WebURLRequest& request,
     const blink::WebURLError& error,
     blink::WebLocalFrame* frame) {
-  bool show_repost_interstitial = (error.reason == net::ERR_CACHE_MISS &&
-                                   EqualsASCII(request.httpMethod(), "POST"));
+  bool show_repost_interstitial =
+      (error.reason == net::ERR_CACHE_MISS &&
+       base::EqualsASCII(request.httpMethod(), "POST"));
 
   FrameHostMsg_DidFailProvisionalLoadWithError_Params params;
   params.error_code = error.reason;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 8fe83ef2..ebd6fde 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -109,8 +109,8 @@
 #include "content/renderer/render_view_impl.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
 #include "content/renderer/scheduler/resource_dispatch_throttler.h"
-#include "content/renderer/service_worker/embedded_worker_context_message_filter.h"
 #include "content/renderer/service_worker/embedded_worker_dispatcher.h"
+#include "content/renderer/service_worker/service_worker_context_message_filter.h"
 #include "content/renderer/shared_worker/embedded_shared_worker_stub.h"
 #include "gin/public/debug.h"
 #include "gpu/GLES2/gl2extchromium.h"
@@ -269,8 +269,9 @@
 class CompositorRasterThread : public base::SimpleThread {
  public:
   CompositorRasterThread(cc::TaskGraphRunner* task_graph_runner,
-                         const std::string& name_prefix)
-      : base::SimpleThread(name_prefix),
+                         const std::string& name_prefix,
+                         base::SimpleThread::Options options)
+      : base::SimpleThread(name_prefix, options),
         task_graph_runner_(task_graph_runner) {}
 
   // Overridden from base::SimpleThread:
@@ -565,7 +566,7 @@
 
   AddFilter((new CacheStorageMessageFilter(thread_safe_sender()))->GetFilter());
 
-  AddFilter((new EmbeddedWorkerContextMessageFilter())->GetFilter());
+  AddFilter((new ServiceWorkerContextMessageFilter())->GetFilter());
 
   GetContentClient()->renderer()->RenderThreadStarted();
 
@@ -574,11 +575,6 @@
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
 
-  is_impl_side_painting_enabled_ =
-      !command_line.HasSwitch(switches::kDisableImplSidePainting);
-  cc_blink::WebLayerImpl::SetImplSidePaintingEnabled(
-      is_impl_side_painting_enabled_);
-
   cc::LayerSettings layer_settings;
   if (command_line.HasSwitch(switches::kEnableCompositorAnimationTimelines))
     layer_settings.use_compositor_animation_timelines = true;
@@ -646,10 +642,7 @@
 
   // Note that under Linux, the media library will normally already have
   // been initialized by the Zygote before this instance became a Renderer.
-  base::FilePath media_path;
-  PathService::Get(DIR_MEDIA_LIBS, &media_path);
-  if (!media_path.empty())
-    media::InitializeMediaLibrary(media_path);
+  media::InitializeMediaLibrary();
 
   memory_pressure_listener_.reset(new base::MemoryPressureListener(
       base::Bind(&RenderThreadImpl::OnMemoryPressure, base::Unretained(this))));
@@ -658,39 +651,37 @@
 
   is_gather_pixel_refs_enabled_ = false;
 
-  if (is_impl_side_painting_enabled_) {
-    int num_raster_threads = 0;
-    std::string string_value =
-        command_line.GetSwitchValueASCII(switches::kNumRasterThreads);
-    bool parsed_num_raster_threads =
-        base::StringToInt(string_value, &num_raster_threads);
-    DCHECK(parsed_num_raster_threads) << string_value;
-    DCHECK_GT(num_raster_threads, 0);
+  int num_raster_threads = 0;
+  std::string string_value =
+      command_line.GetSwitchValueASCII(switches::kNumRasterThreads);
+  bool parsed_num_raster_threads =
+      base::StringToInt(string_value, &num_raster_threads);
+  DCHECK(parsed_num_raster_threads) << string_value;
+  DCHECK_GT(num_raster_threads, 0);
 
-    // Note: Currently, gathering of pixel refs when using a single
-    // raster thread doesn't provide any benefit. This might change
-    // in the future but we avoid it for now to reduce the cost of
-    // Picture::Create.
-    is_gather_pixel_refs_enabled_ = num_raster_threads > 1;
+  // Note: Currently, gathering of pixel refs when using a single
+  // raster thread doesn't provide any benefit. This might change
+  // in the future but we avoid it for now to reduce the cost of
+  // Picture::Create.
+  is_gather_pixel_refs_enabled_ = num_raster_threads > 1;
 
-    while (compositor_raster_threads_.size() <
-           static_cast<size_t>(num_raster_threads)) {
-      scoped_ptr<CompositorRasterThread> raster_thread(
-          new CompositorRasterThread(
-              compositor_task_graph_runner_.get(),
-              base::StringPrintf(
-                  "CompositorTileWorker%u",
-                  static_cast<unsigned>(compositor_raster_threads_.size() + 1))
-                  .c_str()));
-      raster_thread->Start();
+  base::SimpleThread::Options thread_options;
 #if defined(OS_ANDROID) || defined(OS_LINUX)
-      if (!command_line.HasSwitch(
-              switches::kUseNormalPriorityForTileTaskWorkerThreads)) {
-        raster_thread->SetThreadPriority(base::ThreadPriority::BACKGROUND);
-      }
+  if (!command_line.HasSwitch(
+          switches::kUseNormalPriorityForTileTaskWorkerThreads)) {
+    thread_options.set_priority(base::ThreadPriority::BACKGROUND);
+  }
 #endif
-      compositor_raster_threads_.push_back(raster_thread.Pass());
-    }
+  while (compositor_raster_threads_.size() <
+         static_cast<size_t>(num_raster_threads)) {
+    scoped_ptr<CompositorRasterThread> raster_thread(new CompositorRasterThread(
+        compositor_task_graph_runner_.get(),
+        base::StringPrintf("CompositorTileWorker%u",
+                           static_cast<unsigned>(
+                               compositor_raster_threads_.size() + 1)).c_str(),
+        thread_options));
+    raster_thread->Start();
+    compositor_raster_threads_.push_back(raster_thread.Pass());
   }
 
   // In single process, browser main loop set up the discardable memory
@@ -1106,10 +1097,6 @@
   EnableBlinkPlatformLogChannels(
       command_line.GetSwitchValueASCII(switches::kBlinkPlatformLogChannels));
 
-  if (!media::IsMediaLibraryInitialized()) {
-    WebRuntimeFeatures::enableWebAudio(false);
-  }
-
   RenderMediaClient::Initialize();
 
   FOR_EACH_OBSERVER(RenderProcessObserver, observers_, WebKitInitialized());
@@ -1124,12 +1111,6 @@
 
   cc_blink::SetSharedBitmapAllocationFunction(AllocateSharedBitmapFunction);
 
-  // Limit use of the scaled image cache to when deferred image decoding is
-  // enabled.
-  if (!command_line.HasSwitch(switches::kEnableDeferredImageDecoding) &&
-      !is_impl_side_painting_enabled_)
-    SkGraphics::SetResourceCacheTotalByteLimit(0u);
-
   SkGraphics::SetResourceCacheSingleAllocationByteLimit(
       kImageCacheSingleAllocationByteLimit);
 
@@ -1207,15 +1188,13 @@
     if (idle_notifications_to_skip_ > 0) {
       --idle_notifications_to_skip_;
     } else {
-      base::allocator::ReleaseFreeMemory();
-      discardable_shared_memory_manager()->ReleaseFreeMemory();
+      ReleaseFreeMemory();
     }
     ScheduleIdleHandler(kLongIdleHandlerDelayMs);
     return;
   }
 
-  base::allocator::ReleaseFreeMemory();
-  discardable_shared_memory_manager()->ReleaseFreeMemory();
+  ReleaseFreeMemory();
 
   // Continue the idle timer if the webkit shared timer is not suspended or
   // something is left to do.
@@ -1397,10 +1376,6 @@
   return service_registry();
 }
 
-bool RenderThreadImpl::IsImplSidePaintingEnabled() {
-  return is_impl_side_painting_enabled_;
-}
-
 bool RenderThreadImpl::IsGpuRasterizationForced() {
   return is_gpu_rasterization_forced_;
 }
@@ -1881,6 +1856,14 @@
   ScheduleIdleHandler(kLongIdleHandlerDelayMs);
 }
 
+void RenderThreadImpl::ReleaseFreeMemory() {
+  base::allocator::ReleaseFreeMemory();
+  discardable_shared_memory_manager()->ReleaseFreeMemory();
+
+  if (blink_platform_impl_)
+    blink::decommitFreeableMemory();
+}
+
 RenderThreadImpl::PendingRenderFrameConnect::PendingRenderFrameConnect(
     int routing_id,
     mojo::InterfaceRequest<mojo::ServiceProvider> services,
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 0c8ee8f..52fc453 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -183,7 +183,6 @@
   ServiceRegistry* GetServiceRegistry() override;
 
   // CompositorDependencies implementation.
-  bool IsImplSidePaintingEnabled() override;
   bool IsGpuRasterizationForced() override;
   bool IsGpuRasterizationEnabled() override;
   int GetGpuRasterizationMSAASampleCount() override;
@@ -469,6 +468,8 @@
   void OnRendererHidden();
   void OnRendererVisible();
 
+  void ReleaseFreeMemory();
+
   scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateOffscreenContext3d();
 
   // These objects live solely on the render thread.
@@ -602,7 +603,6 @@
   bool is_gpu_rasterization_enabled_;
   bool is_gpu_rasterization_forced_;
   int gpu_rasterization_msaa_sample_count_;
-  bool is_impl_side_painting_enabled_;
   bool is_lcd_text_enabled_;
   bool is_distance_field_text_enabled_;
   bool is_zero_copy_enabled_;
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index ca040045..5bc9ca6 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -147,11 +147,11 @@
   ~RenderViewImplTest() override {}
 
   void SetUp() override {
-    RenderViewTest::SetUp();
     // Enable Blink's experimental and test only features so that test code
     // does not have to bother enabling each feature.
     WebRuntimeFeatures::enableExperimentalFeatures(true);
     WebRuntimeFeatures::enableTestOnlyFeatures(true);
+    RenderViewTest::SetUp();
   }
 
   RenderViewImpl* view() {
@@ -519,7 +519,20 @@
   policy_info.defaultPolicy = blink::WebNavigationPolicyCurrentTab;
   blink::WebNavigationPolicy policy = frame()->decidePolicyForNavigation(
           policy_info);
-  EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableBrowserSideNavigation)) {
+    EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
+  } else {
+    // If this is a renderer-initiated navigation that just begun, it should
+    // stop and be sent to the browser.
+    EXPECT_EQ(blink::WebNavigationPolicyIgnore, policy);
+
+    // If this a navigation that is ready to commit, it should be handled
+    // locally.
+    request.setCheckForBrowserSideNavigation(false);
+    policy = frame()->decidePolicyForNavigation(policy_info);
+    EXPECT_EQ(blink::WebNavigationPolicyCurrentTab, policy);
+  }
 
   // Verify that form posts to WebUI URLs will be sent to the browser process.
   blink::WebURLRequest form_request(GURL("chrome://foo"));
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 1c4f8098..4f6735c5 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1041,8 +1041,6 @@
   settings->setMultiTargetTapNotificationEnabled(
       switches::IsLinkDisambiguationPopupEnabled());
 
-  settings->setDeferredImageDecodingEnabled(
-      prefs.deferred_image_decoding_enabled);
   WebRuntimeFeatures::enableImageColorProfiles(
       prefs.image_color_profiles_enabled);
   settings->setShouldRespectImageOrientation(
@@ -2219,8 +2217,8 @@
 
     // Also return true if it has an ARIA role of 'textbox'.
     for (unsigned i = 0; i < element.attributeCount(); ++i) {
-      if (LowerCaseEqualsASCII(element.attributeLocalName(i), "role")) {
-        if (LowerCaseEqualsASCII(element.attributeValue(i), "textbox"))
+      if (base::LowerCaseEqualsASCII(element.attributeLocalName(i), "role")) {
+        if (base::LowerCaseEqualsASCII(element.attributeValue(i), "textbox"))
           return true;
         break;
       }
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 9a206983..c512d41 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -2216,6 +2216,24 @@
 #endif
 }
 
+void RenderWidget::didOverscroll(
+    const blink::WebFloatSize& unusedDelta,
+    const blink::WebFloatSize& accumulatedRootOverScroll,
+    const blink::WebFloatPoint& position,
+    const blink::WebFloatSize& velocity) {
+  DidOverscrollParams params;
+  // TODO(jdduke): Consider bundling the overscroll with the input event ack to
+  // save an IPC.
+  params.accumulated_overscroll = gfx::Vector2dF(
+      accumulatedRootOverScroll.width, accumulatedRootOverScroll.height);
+  params.latest_overscroll_delta =
+      gfx::Vector2dF(unusedDelta.width, unusedDelta.height);
+  params.current_fling_velocity =
+      gfx::Vector2dF(velocity.width, velocity.height);
+  params.causal_event_viewport_point = gfx::PointF(position.x, position.y);
+  Send(new InputHostMsg_DidOverscroll(routing_id_, params));
+}
+
 void RenderWidget::StartCompositor() {
   // For widgets that are never visible, we don't need the compositor to run
   // at all.
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 5b82c40..ef3e9d14 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -190,6 +190,11 @@
   virtual void resetInputMethod();
   virtual void didHandleGestureEvent(const blink::WebGestureEvent& event,
                                      bool event_cancelled);
+  virtual void didOverscroll(
+      const blink::WebFloatSize& unusedDelta,
+      const blink::WebFloatSize& accumulatedRootOverScroll,
+      const blink::WebFloatPoint& position,
+      const blink::WebFloatSize& velocity);
   virtual void showImeIfNeeded();
 
 #if defined(OS_ANDROID)
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index a02f755..86264e1 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -14,8 +14,8 @@
 #include "content/renderer/webpublicsuffixlist_impl.h"
 #include "device/vibration/vibration_manager.mojom.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBFactory.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
 
 namespace cc {
 class ContextProvider;
diff --git a/content/renderer/savable_resources.cc b/content/renderer/savable_resources.cc
index 958003f..929a25b2 100644
--- a/content/renderer/savable_resources.cc
+++ b/content/renderer/savable_resources.cc
@@ -166,7 +166,7 @@
     attribute_name = "cite";
   } else if (element.hasHTMLTagName("link")) {
     // If the link element is not linked to css, ignore it.
-    if (LowerCaseEqualsASCII(element.getAttribute("type"), "text/css")) {
+    if (base::LowerCaseEqualsASCII(element.getAttribute("type"), "text/css")) {
       // TODO(jnd): Add support for extracting links of sub-resources which
       // are inside style-sheet such as @import, url(), etc.
       // See bug: http://b/issue?id=1111667.
@@ -179,7 +179,7 @@
   // If value has content and not start with "javascript:" then return it,
   // otherwise return NULL.
   if (!value.isNull() && !value.isEmpty() &&
-      !StartsWithASCII(value.utf8(), "javascript:", false))
+      !base::StartsWithASCII(value.utf8(), "javascript:", false))
     return value;
 
   return WebString();
diff --git a/content/renderer/screen_orientation/screen_orientation_dispatcher.h b/content/renderer/screen_orientation/screen_orientation_dispatcher.h
index e04c0d3..e195f5fe 100644
--- a/content/renderer/screen_orientation/screen_orientation_dispatcher.h
+++ b/content/renderer/screen_orientation/screen_orientation_dispatcher.h
@@ -9,10 +9,10 @@
 #include "base/id_map.h"
 #include "base/macros.h"
 #include "content/public/renderer/render_frame_observer.h"
-#include "third_party/WebKit/public/platform/WebLockOrientationCallback.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationClient.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationCallback.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationClient.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
 
 namespace content {
 
diff --git a/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc b/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc
index f6086a4..0121f8e 100644
--- a/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc
+++ b/content/renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc
@@ -12,7 +12,7 @@
 #include "content/public/test/test_utils.h"
 #include "ipc/ipc_test_sink.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebLockOrientationCallback.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebLockOrientationCallback.h"
 
 namespace content {
 
diff --git a/content/renderer/service_worker/OWNERS b/content/renderer/service_worker/OWNERS
index c84704d..61321a28 100644
--- a/content/renderer/service_worker/OWNERS
+++ b/content/renderer/service_worker/OWNERS
@@ -2,6 +2,3 @@
 falken@chromium.org
 horo@chromium.org
 nhiroki@chromium.org
-
-# may not be available
-kinuko@chromium.org
diff --git a/content/renderer/service_worker/PRESUBMIT.py b/content/renderer/service_worker/PRESUBMIT.py
new file mode 100644
index 0000000..928d9fe0
--- /dev/null
+++ b/content/renderer/service_worker/PRESUBMIT.py
@@ -0,0 +1,14 @@
+# 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.
+
+"""Presubmit script for service_worker.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def CheckChangeOnUpload(input_api, output_api):
+  results = []
+  results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
+  return results
diff --git a/content/renderer/service_worker/embedded_worker_context_client.cc b/content/renderer/service_worker/embedded_worker_context_client.cc
deleted file mode 100644
index abbb66a..0000000
--- a/content/renderer/service_worker/embedded_worker_context_client.cc
+++ /dev/null
@@ -1,486 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/service_worker/embedded_worker_context_client.h"
-
-#include <map>
-#include <string>
-
-#include "base/lazy_instance.h"
-#include "base/pickle.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/thread_task_runner_handle.h"
-#include "base/threading/thread_local.h"
-#include "base/trace_event/trace_event.h"
-#include "content/child/request_extra_data.h"
-#include "content/child/service_worker/service_worker_dispatcher.h"
-#include "content/child/service_worker/service_worker_network_provider.h"
-#include "content/child/service_worker/service_worker_provider_context.h"
-#include "content/child/service_worker/service_worker_registration_handle_reference.h"
-#include "content/child/service_worker/web_service_worker_impl.h"
-#include "content/child/service_worker/web_service_worker_provider_impl.h"
-#include "content/child/service_worker/web_service_worker_registration_impl.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_task_runner.h"
-#include "content/common/devtools_messages.h"
-#include "content/common/service_worker/embedded_worker_messages.h"
-#include "content/common/service_worker/service_worker_types.h"
-#include "content/public/renderer/document_state.h"
-#include "content/renderer/devtools/devtools_agent.h"
-#include "content/renderer/render_thread_impl.h"
-#include "content/renderer/service_worker/embedded_worker_dispatcher.h"
-#include "content/renderer/service_worker/service_worker_script_context.h"
-#include "content/renderer/service_worker/service_worker_type_util.h"
-#include "ipc/ipc_message_macros.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerResponse.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/web/WebDataSource.h"
-#include "third_party/WebKit/public/web/WebServiceWorkerNetworkProvider.h"
-
-namespace content {
-
-namespace {
-
-// For now client must be a per-thread instance.
-// TODO(kinuko): This needs to be refactored when we start using thread pool
-// or having multiple clients per one thread.
-base::LazyInstance<base::ThreadLocalPointer<EmbeddedWorkerContextClient> >::
-    Leaky g_worker_client_tls = LAZY_INSTANCE_INITIALIZER;
-
-void CallWorkerContextDestroyedOnMainThread(int embedded_worker_id) {
-  if (!RenderThreadImpl::current() ||
-      !RenderThreadImpl::current()->embedded_worker_dispatcher())
-    return;
-  RenderThreadImpl::current()->embedded_worker_dispatcher()->
-      WorkerContextDestroyed(embedded_worker_id);
-}
-
-// We store an instance of this class in the "extra data" of the WebDataSource
-// and attach a ServiceWorkerNetworkProvider to it as base::UserData.
-// (see createServiceWorkerNetworkProvider).
-class DataSourceExtraData
-    : public blink::WebDataSource::ExtraData,
-      public base::SupportsUserData {
- public:
-  DataSourceExtraData() {}
-  virtual ~DataSourceExtraData() {}
-};
-
-// Called on the main thread only and blink owns it.
-class WebServiceWorkerNetworkProviderImpl
-    : public blink::WebServiceWorkerNetworkProvider {
- public:
-  // Blink calls this method for each request starting with the main script,
-  // we tag them with the provider id.
-  virtual void willSendRequest(
-      blink::WebDataSource* data_source,
-      blink::WebURLRequest& request) {
-    ServiceWorkerNetworkProvider* provider =
-        ServiceWorkerNetworkProvider::FromDocumentState(
-            static_cast<DataSourceExtraData*>(data_source->extraData()));
-    scoped_ptr<RequestExtraData> extra_data(new RequestExtraData);
-    extra_data->set_service_worker_provider_id(provider->provider_id());
-    request.setExtraData(extra_data.release());
-  }
-};
-
-}  // namespace
-
-EmbeddedWorkerContextClient*
-EmbeddedWorkerContextClient::ThreadSpecificInstance() {
-  return g_worker_client_tls.Pointer()->Get();
-}
-
-EmbeddedWorkerContextClient::EmbeddedWorkerContextClient(
-    int embedded_worker_id,
-    int64 service_worker_version_id,
-    const GURL& service_worker_scope,
-    const GURL& script_url,
-    int worker_devtools_agent_route_id)
-    : embedded_worker_id_(embedded_worker_id),
-      service_worker_version_id_(service_worker_version_id),
-      service_worker_scope_(service_worker_scope),
-      script_url_(script_url),
-      worker_devtools_agent_route_id_(worker_devtools_agent_route_id),
-      sender_(ChildThreadImpl::current()->thread_safe_sender()),
-      main_thread_task_runner_(RenderThreadImpl::current()->GetTaskRunner()),
-      weak_factory_(this) {
-  TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
-                           "EmbeddedWorkerContextClient::StartingWorkerContext",
-                           this);
-  TRACE_EVENT_ASYNC_STEP_INTO0(
-      "ServiceWorker",
-      "EmbeddedWorkerContextClient::StartingWorkerContext",
-      this,
-      "PrepareWorker");
-}
-
-EmbeddedWorkerContextClient::~EmbeddedWorkerContextClient() {
-}
-
-bool EmbeddedWorkerContextClient::OnMessageReceived(
-    const IPC::Message& msg) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerContextClient, msg)
-    IPC_MESSAGE_HANDLER(EmbeddedWorkerContextMsg_MessageToWorker,
-                        OnMessageToWorker)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void EmbeddedWorkerContextClient::Send(IPC::Message* message) {
-  sender_->Send(message);
-}
-
-blink::WebURL EmbeddedWorkerContextClient::scope() const {
-  return service_worker_scope_;
-}
-
-void EmbeddedWorkerContextClient::didPauseAfterDownload() {
-  Send(new EmbeddedWorkerHostMsg_DidPauseAfterDownload(embedded_worker_id_));
-}
-
-void EmbeddedWorkerContextClient::getClients(
-    const blink::WebServiceWorkerClientQueryOptions& options,
-    blink::WebServiceWorkerClientsCallbacks* callbacks) {
-  DCHECK(script_context_);
-  script_context_->GetClients(options, callbacks);
-}
-
-void EmbeddedWorkerContextClient::openWindow(
-    const blink::WebURL& url,
-    blink::WebServiceWorkerClientCallbacks* callbacks) {
-  DCHECK(script_context_);
-  script_context_->OpenWindow(url, callbacks);
-}
-
-void EmbeddedWorkerContextClient::setCachedMetadata(const blink::WebURL& url,
-                                                    const char* data,
-                                                    size_t size) {
-  DCHECK(script_context_);
-  script_context_->SetCachedMetadata(url, data, size);
-}
-
-void EmbeddedWorkerContextClient::clearCachedMetadata(
-    const blink::WebURL& url) {
-  DCHECK(script_context_);
-  script_context_->ClearCachedMetadata(url);
-}
-
-void EmbeddedWorkerContextClient::workerReadyForInspection() {
-  Send(new EmbeddedWorkerHostMsg_WorkerReadyForInspection(embedded_worker_id_));
-}
-
-void EmbeddedWorkerContextClient::workerContextFailedToStart() {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
-  DCHECK(!script_context_);
-
-  Send(new EmbeddedWorkerHostMsg_WorkerScriptLoadFailed(embedded_worker_id_));
-
-  RenderThreadImpl::current()->embedded_worker_dispatcher()->
-      WorkerContextDestroyed(embedded_worker_id_);
-}
-
-void EmbeddedWorkerContextClient::workerContextStarted(
-    blink::WebServiceWorkerContextProxy* proxy) {
-  DCHECK(!worker_task_runner_.get());
-  DCHECK_NE(0, WorkerTaskRunner::Instance()->CurrentWorkerId());
-  worker_task_runner_ = base::ThreadTaskRunnerHandle::Get();
-  // g_worker_client_tls.Pointer()->Get() could return NULL if this context
-  // gets deleted before workerContextStarted() is called.
-  DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
-  DCHECK(!script_context_);
-  g_worker_client_tls.Pointer()->Set(this);
-  script_context_.reset(new ServiceWorkerScriptContext(this, proxy));
-
-  SetRegistrationInServiceWorkerGlobalScope();
-
-  Send(new EmbeddedWorkerHostMsg_WorkerScriptLoaded(
-      embedded_worker_id_,
-      WorkerTaskRunner::Instance()->CurrentWorkerId(),
-      provider_context_->provider_id()));
-
-  TRACE_EVENT_ASYNC_STEP_INTO0(
-      "ServiceWorker",
-      "EmbeddedWorkerContextClient::StartingWorkerContext",
-      this,
-      "ExecuteScript");
-}
-
-void EmbeddedWorkerContextClient::didEvaluateWorkerScript(bool success) {
-  Send(new EmbeddedWorkerHostMsg_WorkerScriptEvaluated(
-      embedded_worker_id_, success));
-
-  // Schedule a task to send back WorkerStarted asynchronously,
-  // so that at the time we send it we can be sure that the
-  // worker run loop has been started.
-  worker_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&EmbeddedWorkerContextClient::SendWorkerStarted,
-                            weak_factory_.GetWeakPtr()));
-}
-
-void EmbeddedWorkerContextClient::willDestroyWorkerContext() {
-  // At this point OnWorkerRunLoopStopped is already called, so
-  // worker_task_runner_->RunsTasksOnCurrentThread() returns false
-  // (while we're still on the worker thread).
-  script_context_.reset();
-
-  // This also lets the message filter stop dispatching messages to
-  // this client.
-  g_worker_client_tls.Pointer()->Set(NULL);
-}
-
-void EmbeddedWorkerContextClient::workerContextDestroyed() {
-  DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
-
-  // Now we should be able to free the WebEmbeddedWorker container on the
-  // main thread.
-  main_thread_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&CallWorkerContextDestroyedOnMainThread,
-                 embedded_worker_id_));
-}
-
-void EmbeddedWorkerContextClient::reportException(
-    const blink::WebString& error_message,
-    int line_number,
-    int column_number,
-    const blink::WebString& source_url) {
-  Send(new EmbeddedWorkerHostMsg_ReportException(
-      embedded_worker_id_, error_message, line_number,
-      column_number, GURL(source_url)));
-}
-
-void EmbeddedWorkerContextClient::reportConsoleMessage(
-    int source,
-    int level,
-    const blink::WebString& message,
-    int line_number,
-    const blink::WebString& source_url) {
-  EmbeddedWorkerHostMsg_ReportConsoleMessage_Params params;
-  params.source_identifier = source;
-  params.message_level = level;
-  params.message = message;
-  params.line_number = line_number;
-  params.source_url = GURL(source_url);
-
-  Send(new EmbeddedWorkerHostMsg_ReportConsoleMessage(
-      embedded_worker_id_, params));
-}
-
-void EmbeddedWorkerContextClient::sendDevToolsMessage(
-    int call_id,
-    const blink::WebString& message,
-    const blink::WebString& state_cookie) {
-  DevToolsAgent::SendChunkedProtocolMessage(
-      sender_.get(), worker_devtools_agent_route_id_,
-      call_id, message.utf8(), state_cookie.utf8());
-}
-
-void EmbeddedWorkerContextClient::didHandleActivateEvent(
-    int request_id,
-    blink::WebServiceWorkerEventResult result) {
-  DCHECK(script_context_);
-  script_context_->DidHandleActivateEvent(request_id, result);
-}
-
-void EmbeddedWorkerContextClient::didHandleInstallEvent(
-    int request_id,
-    blink::WebServiceWorkerEventResult result) {
-  DCHECK(script_context_);
-  script_context_->DidHandleInstallEvent(request_id, result);
-}
-
-void EmbeddedWorkerContextClient::didHandleFetchEvent(int request_id) {
-  DCHECK(script_context_);
-  script_context_->DidHandleFetchEvent(
-      request_id,
-      SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
-      ServiceWorkerResponse());
-}
-
-void EmbeddedWorkerContextClient::didHandleFetchEvent(
-    int request_id,
-    const blink::WebServiceWorkerResponse& web_response) {
-  DCHECK(script_context_);
-  ServiceWorkerHeaderMap headers;
-  GetServiceWorkerHeaderMapFromWebResponse(web_response, &headers);
-  ServiceWorkerResponse response(web_response.url(),
-                                 web_response.status(),
-                                 web_response.statusText().utf8(),
-                                 web_response.responseType(),
-                                 headers,
-                                 web_response.blobUUID().utf8(),
-                                 web_response.blobSize(),
-                                 web_response.streamURL());
-  script_context_->DidHandleFetchEvent(
-      request_id, SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, response);
-}
-
-void EmbeddedWorkerContextClient::didHandleNotificationClickEvent(
-    int request_id,
-    blink::WebServiceWorkerEventResult result) {
-  DCHECK(script_context_);
-  script_context_->DidHandleNotificationClickEvent(request_id, result);
-}
-
-void EmbeddedWorkerContextClient::didHandlePushEvent(
-    int request_id,
-    blink::WebServiceWorkerEventResult result) {
-  DCHECK(script_context_);
-  script_context_->DidHandlePushEvent(request_id, result);
-}
-
-// TODO(chasej): crbug.com/486890 - Remove when matching blink changes land
-void EmbeddedWorkerContextClient::didHandleSyncEvent(int request_id) {
-  didHandleSyncEvent(request_id, blink::WebServiceWorkerEventResultCompleted);
-}
-
-void EmbeddedWorkerContextClient::didHandleSyncEvent(
-    int request_id,
-    blink::WebServiceWorkerEventResult result) {
-  DCHECK(script_context_);
-  script_context_->DidHandleSyncEvent(request_id, result);
-}
-
-void EmbeddedWorkerContextClient::didHandleCrossOriginConnectEvent(
-    int request_id,
-    bool accept_connection) {
-  DCHECK(script_context_);
-  script_context_->DidHandleCrossOriginConnectEvent(request_id,
-                                                    accept_connection);
-}
-
-blink::WebServiceWorkerNetworkProvider*
-EmbeddedWorkerContextClient::createServiceWorkerNetworkProvider(
-    blink::WebDataSource* data_source) {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
-
-  // Create a content::ServiceWorkerNetworkProvider for this data source so
-  // we can observe its requests.
-  scoped_ptr<ServiceWorkerNetworkProvider> provider(
-      new ServiceWorkerNetworkProvider(
-          MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_CONTROLLER));
-  provider_context_ = provider->context();
-
-  // Tell the network provider about which version to load.
-  provider->SetServiceWorkerVersionId(service_worker_version_id_);
-
-  // The provider is kept around for the lifetime of the DataSource
-  // and ownership is transferred to the DataSource.
-  DataSourceExtraData* extra_data = new DataSourceExtraData();
-  data_source->setExtraData(extra_data);
-  ServiceWorkerNetworkProvider::AttachToDocumentState(
-      extra_data, provider.Pass());
-
-  // Blink is responsible for deleting the returned object.
-  return new WebServiceWorkerNetworkProviderImpl();
-}
-
-blink::WebServiceWorkerProvider*
-EmbeddedWorkerContextClient::createServiceWorkerProvider() {
-  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
-  DCHECK(provider_context_);
-
-  // Blink is responsible for deleting the returned object.
-  return new WebServiceWorkerProviderImpl(
-      thread_safe_sender(), provider_context_.get());
-}
-
-void EmbeddedWorkerContextClient::postMessageToClient(
-    const blink::WebString& uuid,
-    const blink::WebString& message,
-    blink::WebMessagePortChannelArray* channels) {
-  DCHECK(script_context_);
-  script_context_->PostMessageToClient(
-      uuid, message, make_scoped_ptr(channels));
-}
-
-void EmbeddedWorkerContextClient::postMessageToCrossOriginClient(
-    const blink::WebCrossOriginServiceWorkerClient& client,
-    const blink::WebString& message,
-    blink::WebMessagePortChannelArray* channels) {
-  DCHECK(script_context_);
-  script_context_->PostCrossOriginMessageToClient(client, message,
-                                                  make_scoped_ptr(channels));
-}
-
-void EmbeddedWorkerContextClient::focus(
-    const blink::WebString& uuid,
-    blink::WebServiceWorkerClientCallbacks* callback) {
-  DCHECK(script_context_);
-  script_context_->FocusClient(uuid, callback);
-}
-
-void EmbeddedWorkerContextClient::skipWaiting(
-    blink::WebServiceWorkerSkipWaitingCallbacks* callbacks) {
-  DCHECK(script_context_);
-  script_context_->SkipWaiting(callbacks);
-}
-
-void EmbeddedWorkerContextClient::claim(
-    blink::WebServiceWorkerClientsClaimCallbacks* callbacks) {
-  DCHECK(script_context_);
-  script_context_->ClaimClients(callbacks);
-}
-
-void EmbeddedWorkerContextClient::stashMessagePort(
-    blink::WebMessagePortChannel* channel,
-    const blink::WebString& name) {
-  DCHECK(script_context_);
-  script_context_->StashMessagePort(channel, name);
-}
-
-void EmbeddedWorkerContextClient::OnMessageToWorker(
-    int thread_id,
-    int embedded_worker_id,
-    const IPC::Message& message) {
-  if (!script_context_)
-    return;
-  DCHECK_EQ(embedded_worker_id_, embedded_worker_id);
-  script_context_->OnMessageReceived(message);
-}
-
-void EmbeddedWorkerContextClient::SendWorkerStarted() {
-  DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
-  TRACE_EVENT_ASYNC_END0("ServiceWorker",
-                         "EmbeddedWorkerContextClient::StartingWorkerContext",
-                         this);
-  Send(new EmbeddedWorkerHostMsg_WorkerStarted(embedded_worker_id_));
-}
-
-void EmbeddedWorkerContextClient::SetRegistrationInServiceWorkerGlobalScope() {
-  DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
-  DCHECK(provider_context_);
-  DCHECK(script_context_);
-
-  ServiceWorkerRegistrationObjectInfo info;
-  ServiceWorkerVersionAttributes attrs;
-  bool found =
-      provider_context_->GetRegistrationInfoAndVersionAttributes(&info, &attrs);
-  if (!found)
-    return;  // Cannot be associated with a registration in some tests.
-
-  ServiceWorkerDispatcher* dispatcher =
-      ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
-          thread_safe_sender());
-
-  // Register a registration and its version attributes with the dispatcher
-  // living on the worker thread.
-  scoped_ptr<WebServiceWorkerRegistrationImpl> registration(
-      dispatcher->CreateServiceWorkerRegistration(info, false));
-  registration->SetInstalling(
-      dispatcher->GetServiceWorker(attrs.installing, false));
-  registration->SetWaiting(
-      dispatcher->GetServiceWorker(attrs.waiting, false));
-  registration->SetActive(
-      dispatcher->GetServiceWorker(attrs.active, false));
-
-  script_context_->SetRegistrationInServiceWorkerGlobalScope(
-      registration.Pass());
-}
-
-}  // namespace content
diff --git a/content/renderer/service_worker/embedded_worker_context_client.h b/content/renderer/service_worker/embedded_worker_context_client.h
deleted file mode 100644
index 9511ac7..0000000
--- a/content/renderer/service_worker/embedded_worker_context_client.h
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_CONTEXT_CLIENT_H_
-#define CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_CONTEXT_CLIENT_H_
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "content/common/service_worker/service_worker_types.h"
-#include "ipc/ipc_listener.h"
-#include "third_party/WebKit/public/web/WebServiceWorkerContextClient.h"
-#include "url/gurl.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-class TaskRunner;
-}
-
-namespace blink {
-class WebDataSource;
-class WebServiceWorkerProvider;
-}
-
-namespace content {
-
-class ServiceWorkerProviderContext;
-class ServiceWorkerScriptContext;
-class ThreadSafeSender;
-
-// This class provides access to/from an embedded worker's WorkerGlobalScope.
-// Unless otherwise noted, all methods are called on the worker thread.
-//
-// TODO(kinuko): Currently EW/SW separation is made a little hazily.
-// This should implement WebEmbeddedWorkerContextClient
-// or sort of it (which doesn't exist yet) rather than
-// WebServiceWorkerContextClient if we want to separate them more cleanly,
-// or ServiceWorkerScriptContext should be merged into this class
-// if we consider EW == SW script context.
-class EmbeddedWorkerContextClient
-    : public blink::WebServiceWorkerContextClient {
- public:
-  // Returns a thread-specific client instance.  This does NOT create a
-  // new instance.
-  static EmbeddedWorkerContextClient* ThreadSpecificInstance();
-
-  // Called on the main thread.
-  EmbeddedWorkerContextClient(int embedded_worker_id,
-                              int64 service_worker_version_id,
-                              const GURL& service_worker_scope,
-                              const GURL& script_url,
-                              int worker_devtools_agent_route_id);
-
-  virtual ~EmbeddedWorkerContextClient();
-
-  bool OnMessageReceived(const IPC::Message& msg);
-
-  void Send(IPC::Message* message);
-
-  // WebServiceWorkerContextClient overrides, some of them are just dispatched
-  // on to script_context_.
-  virtual blink::WebURL scope() const;
-  virtual void didPauseAfterDownload();
-  virtual void getClients(const blink::WebServiceWorkerClientQueryOptions&,
-                          blink::WebServiceWorkerClientsCallbacks*);
-  virtual void openWindow(const blink::WebURL&,
-                          blink::WebServiceWorkerClientCallbacks*);
-  virtual void setCachedMetadata(const blink::WebURL&,
-                                 const char* data,
-                                 size_t size);
-  virtual void clearCachedMetadata(const blink::WebURL&);
-  virtual void workerReadyForInspection();
-
-  // Called on the main thread.
-  virtual void workerContextFailedToStart();
-
-  virtual void workerContextStarted(blink::WebServiceWorkerContextProxy* proxy);
-  virtual void didEvaluateWorkerScript(bool success);
-  virtual void willDestroyWorkerContext();
-  virtual void workerContextDestroyed();
-  virtual void reportException(const blink::WebString& error_message,
-                               int line_number,
-                               int column_number,
-                               const blink::WebString& source_url);
-  virtual void reportConsoleMessage(int source,
-                                    int level,
-                                    const blink::WebString& message,
-                                    int line_number,
-                                    const blink::WebString& source_url);
-  virtual void sendDevToolsMessage(int call_id,
-                                   const blink::WebString& message,
-                                   const blink::WebString& state);
-  virtual void didHandleActivateEvent(int request_id,
-                                      blink::WebServiceWorkerEventResult);
-  virtual void didHandleInstallEvent(int request_id,
-                                     blink::WebServiceWorkerEventResult result);
-  virtual void didHandleFetchEvent(int request_id);
-  virtual void didHandleFetchEvent(
-      int request_id,
-      const blink::WebServiceWorkerResponse& response);
-  virtual void didHandleNotificationClickEvent(
-      int request_id,
-      blink::WebServiceWorkerEventResult result);
-  virtual void didHandlePushEvent(int request_id,
-                                  blink::WebServiceWorkerEventResult result);
-  // TODO(chasej): crbug.com/486890 - Remove when matching blink changes land
-  virtual void didHandleSyncEvent(int request_id);
-  virtual void didHandleSyncEvent(int request_id,
-                                  blink::WebServiceWorkerEventResult result);
-  virtual void didHandleCrossOriginConnectEvent(int request_id,
-                                                bool accept_connection);
-
-  // Called on the main thread.
-  virtual blink::WebServiceWorkerNetworkProvider*
-      createServiceWorkerNetworkProvider(blink::WebDataSource* data_source);
-  virtual blink::WebServiceWorkerProvider* createServiceWorkerProvider();
-
-  virtual void postMessageToClient(
-      const blink::WebString& uuid,
-      const blink::WebString& message,
-      blink::WebMessagePortChannelArray* channels);
-  virtual void postMessageToCrossOriginClient(
-      const blink::WebCrossOriginServiceWorkerClient& client,
-      const blink::WebString& message,
-      blink::WebMessagePortChannelArray* channels);
-  virtual void focus(const blink::WebString& uuid,
-                     blink::WebServiceWorkerClientCallbacks*);
-  virtual void skipWaiting(
-      blink::WebServiceWorkerSkipWaitingCallbacks* callbacks);
-  virtual void claim(blink::WebServiceWorkerClientsClaimCallbacks* callbacks);
-  virtual void stashMessagePort(blink::WebMessagePortChannel* channel,
-                                const blink::WebString& name);
-
-  // TODO: Implement DevTools related method overrides.
-
-  int embedded_worker_id() const { return embedded_worker_id_; }
-  base::SingleThreadTaskRunner* main_thread_task_runner() const {
-    return main_thread_task_runner_.get();
-  }
-  ThreadSafeSender* thread_safe_sender() { return sender_.get(); }
-
- private:
-  void OnMessageToWorker(int thread_id,
-                         int embedded_worker_id,
-                         const IPC::Message& message);
-  void SendWorkerStarted();
-  void SetRegistrationInServiceWorkerGlobalScope();
-
-  const int embedded_worker_id_;
-  const int64 service_worker_version_id_;
-  const GURL service_worker_scope_;
-  const GURL script_url_;
-  const int worker_devtools_agent_route_id_;
-  scoped_refptr<ThreadSafeSender> sender_;
-  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
-  scoped_refptr<base::TaskRunner> worker_task_runner_;
-
-  scoped_ptr<ServiceWorkerScriptContext> script_context_;
-  scoped_refptr<ServiceWorkerProviderContext> provider_context_;
-
-  base::WeakPtrFactory<EmbeddedWorkerContextClient> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerContextClient);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_CONTEXT_CLIENT_H_
diff --git a/content/renderer/service_worker/embedded_worker_context_message_filter.cc b/content/renderer/service_worker/embedded_worker_context_message_filter.cc
deleted file mode 100644
index 03120e1..0000000
--- a/content/renderer/service_worker/embedded_worker_context_message_filter.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/service_worker/embedded_worker_context_message_filter.h"
-
-#include "content/child/child_thread_impl.h"
-#include "content/renderer/service_worker/embedded_worker_context_client.h"
-#include "ipc/ipc_message_macros.h"
-
-namespace content {
-
-EmbeddedWorkerContextMessageFilter::EmbeddedWorkerContextMessageFilter()
-    : WorkerThreadMessageFilter(
-          ChildThreadImpl::current()->thread_safe_sender()) {
-}
-
-EmbeddedWorkerContextMessageFilter::~EmbeddedWorkerContextMessageFilter() {}
-
-bool EmbeddedWorkerContextMessageFilter::ShouldHandleMessage(
-    const IPC::Message& msg) const {
-  return IPC_MESSAGE_CLASS(msg) == EmbeddedWorkerContextMsgStart;
-}
-
-void EmbeddedWorkerContextMessageFilter::OnFilteredMessageReceived(
-    const IPC::Message& msg) {
-  EmbeddedWorkerContextClient* client =
-      EmbeddedWorkerContextClient::ThreadSpecificInstance();
-  if (!client)
-    LOG(ERROR) << "Stray message is sent to nonexistent worker";
-  else
-    client->OnMessageReceived(msg);
-}
-
-bool EmbeddedWorkerContextMessageFilter::GetWorkerThreadIdForMessage(
-    const IPC::Message& msg,
-    int* ipc_thread_id) {
-  return base::PickleIterator(msg).ReadInt(ipc_thread_id);
-}
-
-}  // namespace content
diff --git a/content/renderer/service_worker/embedded_worker_context_message_filter.h b/content/renderer/service_worker/embedded_worker_context_message_filter.h
deleted file mode 100644
index cefdc58..0000000
--- a/content/renderer/service_worker/embedded_worker_context_message_filter.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_CONTEXT_MESSAGE_FILTER_H_
-#define CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_CONTEXT_MESSAGE_FILTER_H_
-
-#include "content/child/worker_thread_message_filter.h"
-
-namespace content {
-
-class EmbeddedWorkerContextMessageFilter : public WorkerThreadMessageFilter {
- public:
-  EmbeddedWorkerContextMessageFilter();
-
- protected:
-  ~EmbeddedWorkerContextMessageFilter() override;
-
-  // WorkerThreadMessageFilter:
-  bool ShouldHandleMessage(const IPC::Message& msg) const override;
-  void OnFilteredMessageReceived(const IPC::Message& msg) override;
-  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
-                                   int* ipc_thread_id) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerContextMessageFilter);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_CONTEXT_MESSAGE_FILTER_H_
diff --git a/content/renderer/service_worker/embedded_worker_dispatcher.cc b/content/renderer/service_worker/embedded_worker_dispatcher.cc
index f852114a..0a5c3fd8 100644
--- a/content/renderer/service_worker/embedded_worker_dispatcher.cc
+++ b/content/renderer/service_worker/embedded_worker_dispatcher.cc
@@ -15,8 +15,8 @@
 #include "content/common/service_worker/embedded_worker_messages.h"
 #include "content/public/common/content_client.h"
 #include "content/renderer/render_thread_impl.h"
-#include "content/renderer/service_worker/embedded_worker_context_client.h"
 #include "content/renderer/service_worker/embedded_worker_devtools_agent.h"
+#include "content/renderer/service_worker/service_worker_context_client.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
 #include "third_party/WebKit/public/web/WebEmbeddedWorker.h"
@@ -73,7 +73,7 @@
   RenderThread::Get()->EnsureWebKitInitialized();
   scoped_ptr<WorkerWrapper> wrapper(
       new WorkerWrapper(blink::WebEmbeddedWorker::create(
-                            new EmbeddedWorkerContextClient(
+                            new ServiceWorkerContextClient(
                                 params.embedded_worker_id,
                                 params.service_worker_version_id,
                                 params.scope,
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
new file mode 100644
index 0000000..ee0ffde
--- /dev/null
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -0,0 +1,985 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/service_worker/service_worker_context_client.h"
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_local.h"
+#include "base/trace_event/trace_event.h"
+#include "content/child/notifications/notification_data_conversions.h"
+#include "content/child/request_extra_data.h"
+#include "content/child/service_worker/service_worker_dispatcher.h"
+#include "content/child/service_worker/service_worker_network_provider.h"
+#include "content/child/service_worker/service_worker_provider_context.h"
+#include "content/child/service_worker/service_worker_registration_handle_reference.h"
+#include "content/child/service_worker/web_service_worker_impl.h"
+#include "content/child/service_worker/web_service_worker_provider_impl.h"
+#include "content/child/service_worker/web_service_worker_registration_impl.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/child/webmessageportchannel_impl.h"
+#include "content/child/worker_task_runner.h"
+#include "content/common/devtools_messages.h"
+#include "content/common/message_port_messages.h"
+#include "content/common/service_worker/embedded_worker_messages.h"
+#include "content/common/service_worker/service_worker_messages.h"
+#include "content/public/common/referrer.h"
+#include "content/public/renderer/document_state.h"
+#include "content/renderer/devtools/devtools_agent.h"
+#include "content/renderer/render_thread_impl.h"
+#include "content/renderer/service_worker/embedded_worker_dispatcher.h"
+#include "content/renderer/service_worker/service_worker_type_util.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "third_party/WebKit/public/platform/WebCrossOriginServiceWorkerClient.h"
+#include "third_party/WebKit/public/platform/WebMessagePortChannel.h"
+#include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerClientQueryOptions.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerRequest.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerResponse.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationData.h"
+#include "third_party/WebKit/public/web/WebDataSource.h"
+#include "third_party/WebKit/public/web/WebServiceWorkerContextClient.h"
+#include "third_party/WebKit/public/web/WebServiceWorkerContextProxy.h"
+#include "third_party/WebKit/public/web/WebServiceWorkerNetworkProvider.h"
+
+namespace content {
+
+namespace {
+
+// For now client must be a per-thread instance.
+base::LazyInstance<base::ThreadLocalPointer<ServiceWorkerContextClient>>::
+    Leaky g_worker_client_tls = LAZY_INSTANCE_INITIALIZER;
+
+void CallWorkerContextDestroyedOnMainThread(int embedded_worker_id) {
+  if (!RenderThreadImpl::current() ||
+      !RenderThreadImpl::current()->embedded_worker_dispatcher())
+    return;
+  RenderThreadImpl::current()->embedded_worker_dispatcher()->
+      WorkerContextDestroyed(embedded_worker_id);
+}
+
+// We store an instance of this class in the "extra data" of the WebDataSource
+// and attach a ServiceWorkerNetworkProvider to it as base::UserData.
+// (see createServiceWorkerNetworkProvider).
+class DataSourceExtraData
+    : public blink::WebDataSource::ExtraData,
+      public base::SupportsUserData {
+ public:
+  DataSourceExtraData() {}
+  virtual ~DataSourceExtraData() {}
+};
+
+// Called on the main thread only and blink owns it.
+class WebServiceWorkerNetworkProviderImpl
+    : public blink::WebServiceWorkerNetworkProvider {
+ public:
+  // Blink calls this method for each request starting with the main script,
+  // we tag them with the provider id.
+  virtual void willSendRequest(
+      blink::WebDataSource* data_source,
+      blink::WebURLRequest& request) {
+    ServiceWorkerNetworkProvider* provider =
+        ServiceWorkerNetworkProvider::FromDocumentState(
+            static_cast<DataSourceExtraData*>(data_source->extraData()));
+    scoped_ptr<RequestExtraData> extra_data(new RequestExtraData);
+    extra_data->set_service_worker_provider_id(provider->provider_id());
+    request.setExtraData(extra_data.release());
+  }
+};
+
+void SendPostMessageToClientOnMainThread(
+    ThreadSafeSender* sender,
+    int routing_id,
+    const std::string& uuid,
+    const base::string16& message,
+    scoped_ptr<blink::WebMessagePortChannelArray> channels) {
+  sender->Send(new ServiceWorkerHostMsg_PostMessageToClient(
+      routing_id, uuid, message,
+      WebMessagePortChannelImpl::ExtractMessagePortIDs(channels.release())));
+}
+
+void SendCrossOriginMessageToClientOnMainThread(
+    ThreadSafeSender* sender,
+    int message_port_id,
+    const base::string16& message,
+    scoped_ptr<blink::WebMessagePortChannelArray> channels) {
+  sender->Send(new MessagePortHostMsg_PostMessage(
+      message_port_id,
+      MessagePortMessage(message),
+                         WebMessagePortChannelImpl::ExtractMessagePortIDs(
+                             channels.release())));
+}
+
+void StashMessagePortOnMainThread(ThreadSafeSender* sender,
+                                  int routing_id,
+                                  WebMessagePortChannelImpl* channel,
+                                  const base::string16& name) {
+  DCHECK_GE(channel->message_port_id(), 0);
+  channel->set_is_stashed();
+  sender->Send(new ServiceWorkerHostMsg_StashMessagePort(
+      routing_id, channel->message_port_id(), name));
+}
+
+blink::WebURLRequest::FetchRequestMode GetBlinkFetchRequestMode(
+    FetchRequestMode mode) {
+  return static_cast<blink::WebURLRequest::FetchRequestMode>(mode);
+}
+
+blink::WebURLRequest::FetchCredentialsMode GetBlinkFetchCredentialsMode(
+    FetchCredentialsMode credentials_mode) {
+  return static_cast<blink::WebURLRequest::FetchCredentialsMode>(
+      credentials_mode);
+}
+
+blink::WebURLRequest::RequestContext GetBlinkRequestContext(
+    RequestContextType request_context_type) {
+  return static_cast<blink::WebURLRequest::RequestContext>(
+      request_context_type);
+}
+
+blink::WebURLRequest::FrameType GetBlinkFrameType(
+    RequestContextFrameType frame_type) {
+  return static_cast<blink::WebURLRequest::FrameType>(frame_type);
+}
+
+blink::WebServiceWorkerClientInfo
+ToWebServiceWorkerClientInfo(const ServiceWorkerClientInfo& client_info) {
+  DCHECK(client_info.IsValid());
+
+  blink::WebServiceWorkerClientInfo web_client_info;
+
+  web_client_info.uuid = base::UTF8ToUTF16(client_info.client_uuid);
+  web_client_info.pageVisibilityState = client_info.page_visibility_state;
+  web_client_info.isFocused = client_info.is_focused;
+  web_client_info.url = client_info.url;
+  web_client_info.frameType = GetBlinkFrameType(client_info.frame_type);
+  web_client_info.clientType = client_info.client_type;
+
+  return web_client_info;
+}
+
+}  // namespace
+
+// Holding data that needs to be bound to the worker context on the
+// worker thread.
+struct ServiceWorkerContextClient::WorkerContextData {
+  using ClientsCallbacksMap =
+      IDMap<blink::WebServiceWorkerClientsCallbacks, IDMapOwnPointer>;
+  using ClaimClientsCallbacksMap =
+      IDMap<blink::WebServiceWorkerClientsClaimCallbacks, IDMapOwnPointer>;
+  using ClientCallbacksMap =
+      IDMap<blink::WebServiceWorkerClientCallbacks, IDMapOwnPointer>;
+  using SkipWaitingCallbacksMap =
+      IDMap<blink::WebServiceWorkerSkipWaitingCallbacks, IDMapOwnPointer>;
+
+  explicit WorkerContextData(ServiceWorkerContextClient* owner)
+      : weak_factory(owner) {}
+
+  ~WorkerContextData() {
+    DCHECK(thread_checker.CalledOnValidThread());
+  }
+
+  // Pending callbacks for GetClientDocuments().
+  ClientsCallbacksMap clients_callbacks;
+
+  // Pending callbacks for OpenWindow() and FocusClient().
+  ClientCallbacksMap client_callbacks;
+
+  // Pending callbacks for SkipWaiting().
+  SkipWaitingCallbacksMap skip_waiting_callbacks;
+
+  // Pending callbacks for ClaimClients().
+  ClaimClientsCallbacksMap claim_clients_callbacks;
+
+  base::ThreadChecker thread_checker;
+  base::WeakPtrFactory<ServiceWorkerContextClient> weak_factory;
+};
+
+ServiceWorkerContextClient*
+ServiceWorkerContextClient::ThreadSpecificInstance() {
+  return g_worker_client_tls.Pointer()->Get();
+}
+
+ServiceWorkerContextClient::ServiceWorkerContextClient(
+    int embedded_worker_id,
+    int64 service_worker_version_id,
+    const GURL& service_worker_scope,
+    const GURL& script_url,
+    int worker_devtools_agent_route_id)
+    : embedded_worker_id_(embedded_worker_id),
+      service_worker_version_id_(service_worker_version_id),
+      service_worker_scope_(service_worker_scope),
+      script_url_(script_url),
+      worker_devtools_agent_route_id_(worker_devtools_agent_route_id),
+      sender_(ChildThreadImpl::current()->thread_safe_sender()),
+      main_thread_task_runner_(RenderThreadImpl::current()->GetTaskRunner()),
+      proxy_(nullptr) {
+  TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
+                           "ServiceWorkerContextClient::StartingWorkerContext",
+                           this);
+  TRACE_EVENT_ASYNC_STEP_INTO0(
+      "ServiceWorker",
+      "ServiceWorkerContextClient::StartingWorkerContext",
+      this,
+      "PrepareWorker");
+}
+
+ServiceWorkerContextClient::~ServiceWorkerContextClient() {}
+
+void ServiceWorkerContextClient::OnMessageReceived(
+    int thread_id,
+    int embedded_worker_id,
+    const IPC::Message& message) {
+  CHECK_EQ(embedded_worker_id_, embedded_worker_id);
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(ServiceWorkerContextClient, message)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ActivateEvent, OnActivateEvent)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FetchEvent, OnFetchEvent)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent, OnInstallEvent)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SyncEvent, OnSyncEvent)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_NotificationClickEvent,
+                        OnNotificationClickEvent)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_PushEvent, OnPushEvent)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_GeofencingEvent, OnGeofencingEvent)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CrossOriginConnectEvent,
+                        OnCrossOriginConnectEvent)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToWorker, OnPostMessage)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CrossOriginMessageToWorker,
+                        OnCrossOriginMessageToWorker)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SendStashedMessagePorts,
+                        OnSendStashedMessagePorts)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClients, OnDidGetClients)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_OpenWindowResponse,
+                        OnOpenWindowResponse)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_OpenWindowError,
+                        OnOpenWindowError)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FocusClientResponse,
+                        OnFocusClientResponse)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidSkipWaiting, OnDidSkipWaiting)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidClaimClients, OnDidClaimClients)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ClaimClientsError, OnClaimClientsError)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_Ping, OnPing);
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  DCHECK(handled);
+}
+
+blink::WebURL ServiceWorkerContextClient::scope() const {
+  return service_worker_scope_;
+}
+
+void ServiceWorkerContextClient::didPauseAfterDownload() {
+  Send(new EmbeddedWorkerHostMsg_DidPauseAfterDownload(embedded_worker_id_));
+}
+
+void ServiceWorkerContextClient::getClients(
+    const blink::WebServiceWorkerClientQueryOptions& weboptions,
+    blink::WebServiceWorkerClientsCallbacks* callbacks) {
+  DCHECK(callbacks);
+  int request_id = context_->clients_callbacks.Add(callbacks);
+  ServiceWorkerClientQueryOptions options;
+  options.client_type = weboptions.clientType;
+  options.include_uncontrolled = weboptions.includeUncontrolled;
+  Send(new ServiceWorkerHostMsg_GetClients(
+      GetRoutingID(), request_id, options));
+}
+
+void ServiceWorkerContextClient::openWindow(
+    const blink::WebURL& url,
+    blink::WebServiceWorkerClientCallbacks* callbacks) {
+  DCHECK(callbacks);
+  int request_id = context_->client_callbacks.Add(callbacks);
+  Send(new ServiceWorkerHostMsg_OpenWindow(
+      GetRoutingID(), request_id, url));
+}
+
+void ServiceWorkerContextClient::setCachedMetadata(const blink::WebURL& url,
+                                                    const char* data,
+                                                    size_t size) {
+  std::vector<char> copy(data, data + size);
+  Send(new ServiceWorkerHostMsg_SetCachedMetadata(GetRoutingID(), url, copy));
+}
+
+void ServiceWorkerContextClient::clearCachedMetadata(
+    const blink::WebURL& url) {
+  Send(new ServiceWorkerHostMsg_ClearCachedMetadata(GetRoutingID(), url));
+}
+
+void ServiceWorkerContextClient::workerReadyForInspection() {
+  Send(new EmbeddedWorkerHostMsg_WorkerReadyForInspection(embedded_worker_id_));
+}
+
+void ServiceWorkerContextClient::workerContextFailedToStart() {
+  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(!proxy_);
+
+  Send(new EmbeddedWorkerHostMsg_WorkerScriptLoadFailed(embedded_worker_id_));
+
+  RenderThreadImpl::current()->embedded_worker_dispatcher()->
+      WorkerContextDestroyed(embedded_worker_id_);
+}
+
+void ServiceWorkerContextClient::workerContextStarted(
+    blink::WebServiceWorkerContextProxy* proxy) {
+  DCHECK(!worker_task_runner_.get());
+  DCHECK_NE(0, WorkerTaskRunner::Instance()->CurrentWorkerId());
+  worker_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+  // g_worker_client_tls.Pointer()->Get() could return NULL if this context
+  // gets deleted before workerContextStarted() is called.
+  DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
+  DCHECK(!proxy_);
+  g_worker_client_tls.Pointer()->Set(this);
+  proxy_ = proxy;
+
+  // Initialize pending callback maps. This needs to be freed on the
+  // same thread before the worker context goes away in
+  // willDestroyWorkerContext.
+  context_.reset(new WorkerContextData(this));
+
+  SetRegistrationInServiceWorkerGlobalScope();
+
+  Send(new EmbeddedWorkerHostMsg_WorkerScriptLoaded(
+      embedded_worker_id_,
+      WorkerTaskRunner::Instance()->CurrentWorkerId(),
+      provider_context_->provider_id()));
+
+  TRACE_EVENT_ASYNC_STEP_INTO0(
+      "ServiceWorker",
+      "ServiceWorkerContextClient::StartingWorkerContext",
+      this,
+      "ExecuteScript");
+}
+
+void ServiceWorkerContextClient::didEvaluateWorkerScript(bool success) {
+  Send(new EmbeddedWorkerHostMsg_WorkerScriptEvaluated(
+      embedded_worker_id_, success));
+
+  // Schedule a task to send back WorkerStarted asynchronously,
+  // so that at the time we send it we can be sure that the
+  // worker run loop has been started.
+  worker_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&ServiceWorkerContextClient::SendWorkerStarted,
+                            GetWeakPtr()));
+}
+
+void ServiceWorkerContextClient::willDestroyWorkerContext() {
+  // At this point OnWorkerRunLoopStopped is already called, so
+  // worker_task_runner_->RunsTasksOnCurrentThread() returns false
+  // (while we're still on the worker thread).
+  proxy_ = NULL;
+
+  // We have to clear callbacks now, as they need to be freed on the
+  // same thread.
+  context_.reset();
+
+  // This also lets the message filter stop dispatching messages to
+  // this client.
+  g_worker_client_tls.Pointer()->Set(NULL);
+}
+
+void ServiceWorkerContextClient::workerContextDestroyed() {
+  DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
+
+  // Now we should be able to free the WebEmbeddedWorker container on the
+  // main thread.
+  main_thread_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&CallWorkerContextDestroyedOnMainThread,
+                 embedded_worker_id_));
+}
+
+void ServiceWorkerContextClient::reportException(
+    const blink::WebString& error_message,
+    int line_number,
+    int column_number,
+    const blink::WebString& source_url) {
+  Send(new EmbeddedWorkerHostMsg_ReportException(
+      embedded_worker_id_,
+      error_message,
+      line_number,
+      column_number, GURL(source_url)));
+}
+
+void ServiceWorkerContextClient::reportConsoleMessage(
+    int source,
+    int level,
+    const blink::WebString& message,
+    int line_number,
+    const blink::WebString& source_url) {
+  EmbeddedWorkerHostMsg_ReportConsoleMessage_Params params;
+  params.source_identifier = source;
+  params.message_level = level;
+  params.message = message;
+  params.line_number = line_number;
+  params.source_url = GURL(source_url);
+
+  Send(new EmbeddedWorkerHostMsg_ReportConsoleMessage(
+      embedded_worker_id_, params));
+}
+
+void ServiceWorkerContextClient::sendDevToolsMessage(
+    int call_id,
+    const blink::WebString& message,
+    const blink::WebString& state_cookie) {
+  DevToolsAgent::SendChunkedProtocolMessage(
+      sender_.get(), worker_devtools_agent_route_id_,
+      call_id, message.utf8(), state_cookie.utf8());
+}
+
+void ServiceWorkerContextClient::didHandleActivateEvent(
+    int request_id,
+    blink::WebServiceWorkerEventResult result) {
+  UMA_HISTOGRAM_MEDIUM_TIMES(
+      "ServiceWorker.ActivateEvent.Time",
+      base::TimeTicks::Now() - activate_start_timings_[request_id]);
+  activate_start_timings_.erase(request_id);
+
+  Send(new ServiceWorkerHostMsg_ActivateEventFinished(
+      GetRoutingID(), request_id, result));
+}
+
+void ServiceWorkerContextClient::didHandleInstallEvent(
+    int request_id,
+    blink::WebServiceWorkerEventResult result) {
+  UMA_HISTOGRAM_MEDIUM_TIMES(
+      "ServiceWorker.InstallEvent.Time",
+      base::TimeTicks::Now() - install_start_timings_[request_id]);
+  install_start_timings_.erase(request_id);
+
+  Send(new ServiceWorkerHostMsg_InstallEventFinished(
+      GetRoutingID(), request_id, result));
+}
+
+void ServiceWorkerContextClient::didHandleFetchEvent(int request_id) {
+  UMA_HISTOGRAM_TIMES(
+      "ServiceWorker.FetchEventExecutionTime",
+      base::TimeTicks::Now() - fetch_start_timings_[request_id]);
+  fetch_start_timings_.erase(request_id);
+  Send(new ServiceWorkerHostMsg_FetchEventFinished(
+      GetRoutingID(), request_id,
+      SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
+      ServiceWorkerResponse()));
+}
+
+void ServiceWorkerContextClient::didHandleFetchEvent(
+    int request_id,
+    const blink::WebServiceWorkerResponse& web_response) {
+  UMA_HISTOGRAM_MEDIUM_TIMES(
+      "ServiceWorker.FetchEvent.Time",
+      base::TimeTicks::Now() - fetch_start_timings_[request_id]);
+  fetch_start_timings_.erase(request_id);
+
+  ServiceWorkerHeaderMap headers;
+  GetServiceWorkerHeaderMapFromWebResponse(web_response, &headers);
+  ServiceWorkerResponse response(web_response.url(),
+                                 web_response.status(),
+                                 web_response.statusText().utf8(),
+                                 web_response.responseType(),
+                                 headers,
+                                 web_response.blobUUID().utf8(),
+                                 web_response.blobSize(),
+                                 web_response.streamURL());
+  Send(new ServiceWorkerHostMsg_FetchEventFinished(
+      GetRoutingID(), request_id,
+      SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE,
+      response));
+}
+
+void ServiceWorkerContextClient::didHandleNotificationClickEvent(
+    int request_id,
+    blink::WebServiceWorkerEventResult result) {
+  UMA_HISTOGRAM_MEDIUM_TIMES(
+      "ServiceWorker.NotificationClickEvent.Time",
+      base::TimeTicks::Now() - notification_click_start_timings_[request_id]);
+  notification_click_start_timings_.erase(request_id);
+
+  Send(new ServiceWorkerHostMsg_NotificationClickEventFinished(
+      GetRoutingID(), request_id));
+}
+
+void ServiceWorkerContextClient::didHandlePushEvent(
+    int request_id,
+    blink::WebServiceWorkerEventResult result) {
+  if (result == blink::WebServiceWorkerEventResultCompleted) {
+    UMA_HISTOGRAM_MEDIUM_TIMES(
+        "ServiceWorker.PushEvent.Time",
+        base::TimeTicks::Now() - push_start_timings_[request_id]);
+  }
+  push_start_timings_.erase(request_id);
+
+  Send(new ServiceWorkerHostMsg_PushEventFinished(
+      GetRoutingID(), request_id, result));
+}
+
+// TODO(chasej): crbug.com/486890 - Remove when matching blink changes land
+void ServiceWorkerContextClient::didHandleSyncEvent(int request_id) {
+  didHandleSyncEvent(request_id, blink::WebServiceWorkerEventResultCompleted);
+}
+
+void ServiceWorkerContextClient::didHandleSyncEvent(
+    int request_id,
+    blink::WebServiceWorkerEventResult result) {
+  Send(new ServiceWorkerHostMsg_SyncEventFinished(GetRoutingID(), request_id,
+                                                  result));
+}
+
+void ServiceWorkerContextClient::didHandleCrossOriginConnectEvent(
+    int request_id,
+    bool accept_connection) {
+  Send(new ServiceWorkerHostMsg_CrossOriginConnectEventFinished(
+      GetRoutingID(), request_id, accept_connection));
+}
+
+blink::WebServiceWorkerNetworkProvider*
+ServiceWorkerContextClient::createServiceWorkerNetworkProvider(
+    blink::WebDataSource* data_source) {
+  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+
+  // Create a content::ServiceWorkerNetworkProvider for this data source so
+  // we can observe its requests.
+  scoped_ptr<ServiceWorkerNetworkProvider> provider(
+      new ServiceWorkerNetworkProvider(
+          MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_CONTROLLER));
+  provider_context_ = provider->context();
+
+  // Tell the network provider about which version to load.
+  provider->SetServiceWorkerVersionId(service_worker_version_id_);
+
+  // The provider is kept around for the lifetime of the DataSource
+  // and ownership is transferred to the DataSource.
+  DataSourceExtraData* extra_data = new DataSourceExtraData();
+  data_source->setExtraData(extra_data);
+  ServiceWorkerNetworkProvider::AttachToDocumentState(
+      extra_data, provider.Pass());
+
+  // Blink is responsible for deleting the returned object.
+  return new WebServiceWorkerNetworkProviderImpl();
+}
+
+blink::WebServiceWorkerProvider*
+ServiceWorkerContextClient::createServiceWorkerProvider() {
+  DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(provider_context_);
+
+  // Blink is responsible for deleting the returned object.
+  return new WebServiceWorkerProviderImpl(
+      sender_.get(), provider_context_.get());
+}
+
+void ServiceWorkerContextClient::postMessageToClient(
+    const blink::WebString& uuid,
+    const blink::WebString& message,
+    blink::WebMessagePortChannelArray* channels) {
+  // This may send channels for MessagePorts, and all internal book-keeping
+  // messages for MessagePort (e.g. QueueMessages) are sent from main thread
+  // (with thread hopping), so we need to do the same thread hopping here not
+  // to overtake those messages.
+  scoped_ptr<blink::WebMessagePortChannelArray> channel_array(channels);
+  main_thread_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&SendPostMessageToClientOnMainThread,
+                 sender_,
+                 GetRoutingID(),
+                 base::UTF16ToUTF8(uuid),
+                 static_cast<base::string16>(message),
+                 base::Passed(&channel_array)));
+}
+
+void ServiceWorkerContextClient::postMessageToCrossOriginClient(
+    const blink::WebCrossOriginServiceWorkerClient& client,
+    const blink::WebString& message,
+    blink::WebMessagePortChannelArray* channels) {
+  // This may send channels for MessagePorts, and all internal book-keeping
+  // messages for MessagePort (e.g. QueueMessages) are sent from main thread
+  // (with thread hopping), so we need to do the same thread hopping here not
+  // to overtake those messages.
+  scoped_ptr<blink::WebMessagePortChannelArray> channel_array(channels);
+  main_thread_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&SendCrossOriginMessageToClientOnMainThread,
+                 sender_, client.clientID,
+                 static_cast<base::string16>(message),
+                 base::Passed(&channel_array)));
+}
+
+void ServiceWorkerContextClient::focus(
+    const blink::WebString& uuid,
+    blink::WebServiceWorkerClientCallbacks* callback) {
+  DCHECK(callback);
+  int request_id = context_->client_callbacks.Add(callback);
+  Send(new ServiceWorkerHostMsg_FocusClient(GetRoutingID(), request_id,
+                                            base::UTF16ToUTF8(uuid)));
+}
+
+void ServiceWorkerContextClient::skipWaiting(
+    blink::WebServiceWorkerSkipWaitingCallbacks* callbacks) {
+  DCHECK(callbacks);
+  int request_id = context_->skip_waiting_callbacks.Add(callbacks);
+  Send(new ServiceWorkerHostMsg_SkipWaiting(GetRoutingID(), request_id));
+}
+
+void ServiceWorkerContextClient::claim(
+    blink::WebServiceWorkerClientsClaimCallbacks* callbacks) {
+  DCHECK(callbacks);
+  int request_id = context_->claim_clients_callbacks.Add(callbacks);
+  Send(new ServiceWorkerHostMsg_ClaimClients(GetRoutingID(), request_id));
+}
+
+void ServiceWorkerContextClient::stashMessagePort(
+    blink::WebMessagePortChannel* channel,
+    const blink::WebString& name) {
+  // All internal book-keeping messages for MessagePort are sent from main
+  // thread (with thread hopping), so we need to do the same thread hopping here
+  // not to overtake those messages.
+  WebMessagePortChannelImpl* channel_impl =
+      static_cast<WebMessagePortChannelImpl*>(channel);
+  main_thread_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&StashMessagePortOnMainThread,
+                 sender_, GetRoutingID(),
+                 base::Unretained(channel_impl),
+                 static_cast<base::string16>(name)));
+}
+
+void ServiceWorkerContextClient::Send(IPC::Message* message) {
+  sender_->Send(message);
+}
+
+void ServiceWorkerContextClient::SendWorkerStarted() {
+  DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
+  TRACE_EVENT_ASYNC_END0("ServiceWorker",
+                         "ServiceWorkerContextClient::StartingWorkerContext",
+                         this);
+  Send(new EmbeddedWorkerHostMsg_WorkerStarted(embedded_worker_id_));
+}
+
+void ServiceWorkerContextClient::SetRegistrationInServiceWorkerGlobalScope() {
+  DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(provider_context_);
+
+  ServiceWorkerRegistrationObjectInfo info;
+  ServiceWorkerVersionAttributes attrs;
+  bool found =
+      provider_context_->GetRegistrationInfoAndVersionAttributes(&info, &attrs);
+  if (!found)
+    return;  // Cannot be associated with a registration in some tests.
+
+  ServiceWorkerDispatcher* dispatcher =
+      ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(sender_.get());
+
+  // Register a registration and its version attributes with the dispatcher
+  // living on the worker thread.
+  scoped_ptr<WebServiceWorkerRegistrationImpl> registration(
+      dispatcher->CreateServiceWorkerRegistration(info, false));
+  registration->SetInstalling(
+      dispatcher->GetServiceWorker(attrs.installing, false));
+  registration->SetWaiting(
+      dispatcher->GetServiceWorker(attrs.waiting, false));
+  registration->SetActive(
+      dispatcher->GetServiceWorker(attrs.active, false));
+
+  proxy_->setRegistration(registration.release());
+}
+
+void ServiceWorkerContextClient::OnActivateEvent(int request_id) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnActivateEvent");
+  activate_start_timings_[request_id] = base::TimeTicks::Now();
+  proxy_->dispatchActivateEvent(request_id);
+}
+
+void ServiceWorkerContextClient::OnInstallEvent(int request_id) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnInstallEvent");
+  install_start_timings_[request_id] = base::TimeTicks::Now();
+  proxy_->dispatchInstallEvent(request_id);
+}
+
+void ServiceWorkerContextClient::OnFetchEvent(
+    int request_id,
+    const ServiceWorkerFetchRequest& request) {
+  blink::WebServiceWorkerRequest webRequest;
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnFetchEvent");
+  webRequest.setURL(blink::WebURL(request.url));
+  webRequest.setMethod(blink::WebString::fromUTF8(request.method));
+  for (ServiceWorkerHeaderMap::const_iterator it = request.headers.begin();
+       it != request.headers.end();
+       ++it) {
+    webRequest.setHeader(blink::WebString::fromUTF8(it->first),
+                         blink::WebString::fromUTF8(it->second));
+  }
+  if (!request.blob_uuid.empty()) {
+    webRequest.setBlob(blink::WebString::fromUTF8(request.blob_uuid),
+                       request.blob_size);
+  }
+  webRequest.setReferrer(
+      blink::WebString::fromUTF8(request.referrer.url.spec()),
+      request.referrer.policy);
+  webRequest.setMode(GetBlinkFetchRequestMode(request.mode));
+  webRequest.setCredentialsMode(
+      GetBlinkFetchCredentialsMode(request.credentials_mode));
+  webRequest.setRequestContext(
+      GetBlinkRequestContext(request.request_context_type));
+  webRequest.setFrameType(GetBlinkFrameType(request.frame_type));
+  webRequest.setIsReload(request.is_reload);
+  fetch_start_timings_[request_id] = base::TimeTicks::Now();
+  proxy_->dispatchFetchEvent(request_id, webRequest);
+}
+
+void ServiceWorkerContextClient::OnSyncEvent(int request_id) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnSyncEvent");
+  proxy_->dispatchSyncEvent(request_id);
+}
+
+void ServiceWorkerContextClient::OnNotificationClickEvent(
+    int request_id,
+    int64_t persistent_notification_id,
+    const PlatformNotificationData& notification_data) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnNotificationClickEvent");
+  notification_click_start_timings_[request_id] = base::TimeTicks::Now();
+  proxy_->dispatchNotificationClickEvent(
+      request_id,
+      persistent_notification_id,
+      ToWebNotificationData(notification_data));
+}
+
+void ServiceWorkerContextClient::OnPushEvent(int request_id,
+                                             const std::string& data) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnPushEvent");
+  push_start_timings_[request_id] = base::TimeTicks::Now();
+  proxy_->dispatchPushEvent(request_id, blink::WebString::fromUTF8(data));
+}
+
+void ServiceWorkerContextClient::OnGeofencingEvent(
+    int request_id,
+    blink::WebGeofencingEventType event_type,
+    const std::string& region_id,
+    const blink::WebCircularGeofencingRegion& region) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnGeofencingEvent");
+  proxy_->dispatchGeofencingEvent(
+      request_id, event_type, blink::WebString::fromUTF8(region_id), region);
+  Send(new ServiceWorkerHostMsg_GeofencingEventFinished(GetRoutingID(),
+                                                        request_id));
+}
+
+void ServiceWorkerContextClient::OnCrossOriginConnectEvent(
+    int request_id,
+    const NavigatorConnectClient& client) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnCrossOriginConnectEvent");
+  blink::WebCrossOriginServiceWorkerClient web_client;
+  web_client.origin = client.origin;
+  web_client.targetURL = client.target_url;
+  web_client.clientID = client.message_port_id;
+  proxy_->dispatchCrossOriginConnectEvent(request_id, web_client);
+}
+
+void ServiceWorkerContextClient::OnPostMessage(
+    const base::string16& message,
+    const std::vector<TransferredMessagePort>& sent_message_ports,
+    const std::vector<int>& new_routing_ids) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnPostEvent");
+  blink::WebMessagePortChannelArray ports =
+      WebMessagePortChannelImpl::CreatePorts(
+          sent_message_ports, new_routing_ids,
+          main_thread_task_runner_);
+
+  // dispatchMessageEvent is expected to execute onmessage function
+  // synchronously.
+  base::TimeTicks before = base::TimeTicks::Now();
+  proxy_->dispatchMessageEvent(message, ports);
+  UMA_HISTOGRAM_MEDIUM_TIMES(
+      "ServiceWorker.MessageEvent.Time",
+      base::TimeTicks::Now() - before);
+}
+
+void ServiceWorkerContextClient::OnCrossOriginMessageToWorker(
+    const NavigatorConnectClient& client,
+    const base::string16& message,
+    const std::vector<TransferredMessagePort>& sent_message_ports,
+    const std::vector<int>& new_routing_ids) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnCrossOriginMessageToWorker");
+  blink::WebMessagePortChannelArray ports =
+      WebMessagePortChannelImpl::CreatePorts(
+          sent_message_ports, new_routing_ids,
+          main_thread_task_runner_);
+
+  blink::WebCrossOriginServiceWorkerClient web_client;
+  web_client.origin = client.origin;
+  web_client.targetURL = client.target_url;
+  web_client.clientID = client.message_port_id;
+  proxy_->dispatchCrossOriginMessageEvent(web_client, message, ports);
+}
+
+void ServiceWorkerContextClient::OnSendStashedMessagePorts(
+    const std::vector<TransferredMessagePort>& stashed_message_ports,
+    const std::vector<int>& new_routing_ids,
+    const std::vector<base::string16>& port_names) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnSendStashedMessagePorts");
+  blink::WebMessagePortChannelArray ports =
+      WebMessagePortChannelImpl::CreatePorts(
+          stashed_message_ports, new_routing_ids, main_thread_task_runner_);
+  for (blink::WebMessagePortChannel* port : ports)
+    static_cast<WebMessagePortChannelImpl*>(port)->set_is_stashed();
+  proxy_->addStashedMessagePorts(ports, port_names);
+}
+
+void ServiceWorkerContextClient::OnDidGetClients(
+    int request_id, const std::vector<ServiceWorkerClientInfo>& clients) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnDidGetClients");
+  blink::WebServiceWorkerClientsCallbacks* callbacks =
+      context_->clients_callbacks.Lookup(request_id);
+  if (!callbacks) {
+    NOTREACHED() << "Got stray response: " << request_id;
+    return;
+  }
+  scoped_ptr<blink::WebServiceWorkerClientsInfo> info(
+      new blink::WebServiceWorkerClientsInfo);
+  blink::WebVector<blink::WebServiceWorkerClientInfo> convertedClients(
+      clients.size());
+  for (size_t i = 0; i < clients.size(); ++i)
+    convertedClients[i] = ToWebServiceWorkerClientInfo(clients[i]);
+  info->clients.swap(convertedClients);
+  callbacks->onSuccess(info.release());
+  context_->clients_callbacks.Remove(request_id);
+}
+
+void ServiceWorkerContextClient::OnOpenWindowResponse(
+    int request_id,
+    const ServiceWorkerClientInfo& client) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnOpenWindowResponse");
+  blink::WebServiceWorkerClientCallbacks* callbacks =
+      context_->client_callbacks.Lookup(request_id);
+  if (!callbacks) {
+    NOTREACHED() << "Got stray response: " << request_id;
+    return;
+  }
+  scoped_ptr<blink::WebServiceWorkerClientInfo> web_client;
+  if (!client.IsEmpty()) {
+    DCHECK(client.IsValid());
+    web_client.reset(new blink::WebServiceWorkerClientInfo(
+        ToWebServiceWorkerClientInfo(client)));
+  }
+  callbacks->onSuccess(web_client.release());
+  context_->client_callbacks.Remove(request_id);
+}
+
+void ServiceWorkerContextClient::OnOpenWindowError(
+    int request_id,
+    const std::string& message) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnOpenWindowError");
+  blink::WebServiceWorkerClientCallbacks* callbacks =
+      context_->client_callbacks.Lookup(request_id);
+  if (!callbacks) {
+    NOTREACHED() << "Got stray response: " << request_id;
+    return;
+  }
+  scoped_ptr<blink::WebServiceWorkerError> error(
+      new blink::WebServiceWorkerError(
+          blink::WebServiceWorkerError::ErrorTypeUnknown,
+          blink::WebString::fromUTF8(message)));
+  callbacks->onError(error.release());
+  context_->client_callbacks.Remove(request_id);
+}
+
+void ServiceWorkerContextClient::OnFocusClientResponse(
+    int request_id, const ServiceWorkerClientInfo& client) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnFocusClientResponse");
+  blink::WebServiceWorkerClientCallbacks* callback =
+      context_->client_callbacks.Lookup(request_id);
+  if (!callback) {
+    NOTREACHED() << "Got stray response: " << request_id;
+    return;
+  }
+  if (!client.IsEmpty()) {
+    DCHECK(client.IsValid());
+    scoped_ptr<blink::WebServiceWorkerClientInfo> web_client (
+        new blink::WebServiceWorkerClientInfo(
+            ToWebServiceWorkerClientInfo(client)));
+    callback->onSuccess(web_client.release());
+  } else {
+    scoped_ptr<blink::WebServiceWorkerError> error(
+        new blink::WebServiceWorkerError(
+            blink::WebServiceWorkerError::ErrorTypeNotFound,
+            "The WindowClient was not found."));
+    callback->onError(error.release());
+  }
+
+  context_->client_callbacks.Remove(request_id);
+}
+
+void ServiceWorkerContextClient::OnDidSkipWaiting(int request_id) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnDidSkipWaiting");
+  blink::WebServiceWorkerSkipWaitingCallbacks* callbacks =
+      context_->skip_waiting_callbacks.Lookup(request_id);
+  if (!callbacks) {
+    NOTREACHED() << "Got stray response: " << request_id;
+    return;
+  }
+  callbacks->onSuccess();
+  context_->skip_waiting_callbacks.Remove(request_id);
+}
+
+void ServiceWorkerContextClient::OnDidClaimClients(int request_id) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnDidClaimClients");
+  blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
+      context_->claim_clients_callbacks.Lookup(request_id);
+  if (!callbacks) {
+    NOTREACHED() << "Got stray response: " << request_id;
+    return;
+  }
+  callbacks->onSuccess();
+  context_->claim_clients_callbacks.Remove(request_id);
+}
+
+void ServiceWorkerContextClient::OnClaimClientsError(
+    int request_id,
+    blink::WebServiceWorkerError::ErrorType error_type,
+    const base::string16& message) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerContextClient::OnClaimClientsError");
+  blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
+      context_->claim_clients_callbacks.Lookup(request_id);
+  if (!callbacks) {
+    NOTREACHED() << "Got stray response: " << request_id;
+    return;
+  }
+  scoped_ptr<blink::WebServiceWorkerError> error(
+      new blink::WebServiceWorkerError(error_type, message));
+  callbacks->onError(error.release());
+  context_->claim_clients_callbacks.Remove(request_id);
+}
+
+void ServiceWorkerContextClient::OnPing() {
+  Send(new ServiceWorkerHostMsg_Pong(GetRoutingID()));
+}
+
+base::WeakPtr<ServiceWorkerContextClient>
+ServiceWorkerContextClient::GetWeakPtr() {
+  DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(context_);
+  return context_->weak_factory.GetWeakPtr();
+}
+
+}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
new file mode 100644
index 0000000..0b5b5d7
--- /dev/null
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -0,0 +1,237 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_CLIENT_H_
+#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_CLIENT_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/id_map.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "content/child/webmessageportchannel_impl.h"
+#include "content/common/service_worker/service_worker_types.h"
+#include "ipc/ipc_listener.h"
+#include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
+#include "third_party/WebKit/public/platform/WebMessagePortChannel.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
+#include "third_party/WebKit/public/web/WebServiceWorkerContextClient.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+class TaskRunner;
+}
+
+namespace blink {
+struct WebCircularGeofencingRegion;
+struct WebCrossOriginServiceWorkerClient;
+class WebDataSource;
+struct WebServiceWorkerClientQueryOptions;
+class WebServiceWorkerContextProxy;
+class WebServiceWorkerProvider;
+}
+
+namespace IPC {
+class Message;
+}
+
+namespace content {
+
+struct NavigatorConnectClient;
+struct PlatformNotificationData;
+struct ServiceWorkerClientInfo;
+class ServiceWorkerProviderContext;
+class ServiceWorkerContextClient;
+class ThreadSafeSender;
+class WebServiceWorkerRegistrationImpl;
+
+// This class provides access to/from an ServiceWorker's WorkerGlobalScope.
+// Unless otherwise noted, all methods are called on the worker thread.
+class ServiceWorkerContextClient
+    : public blink::WebServiceWorkerContextClient {
+ public:
+  // Returns a thread-specific client instance.  This does NOT create a
+  // new instance.
+  static ServiceWorkerContextClient* ThreadSpecificInstance();
+
+  // Called on the main thread.
+  ServiceWorkerContextClient(int embedded_worker_id,
+                             int64 service_worker_version_id,
+                             const GURL& service_worker_scope,
+                             const GURL& script_url,
+                             int worker_devtools_agent_route_id);
+  ~ServiceWorkerContextClient() override;
+
+  void OnMessageReceived(int thread_id,
+                         int embedded_worker_id,
+                         const IPC::Message& message);
+
+  // WebServiceWorkerContextClient overrides.
+  virtual blink::WebURL scope() const;
+  virtual void didPauseAfterDownload();
+  virtual void getClients(const blink::WebServiceWorkerClientQueryOptions&,
+                          blink::WebServiceWorkerClientsCallbacks*);
+  virtual void openWindow(const blink::WebURL&,
+                          blink::WebServiceWorkerClientCallbacks*);
+  virtual void setCachedMetadata(const blink::WebURL&,
+                                 const char* data,
+                                 size_t size);
+  virtual void clearCachedMetadata(const blink::WebURL&);
+  virtual void workerReadyForInspection();
+
+  // Called on the main thread.
+  virtual void workerContextFailedToStart();
+
+  virtual void workerContextStarted(blink::WebServiceWorkerContextProxy* proxy);
+  virtual void didEvaluateWorkerScript(bool success);
+  virtual void willDestroyWorkerContext();
+  virtual void workerContextDestroyed();
+  virtual void reportException(const blink::WebString& error_message,
+                               int line_number,
+                               int column_number,
+                               const blink::WebString& source_url);
+  virtual void reportConsoleMessage(int source,
+                                    int level,
+                                    const blink::WebString& message,
+                                    int line_number,
+                                    const blink::WebString& source_url);
+  virtual void sendDevToolsMessage(int call_id,
+                                   const blink::WebString& message,
+                                   const blink::WebString& state);
+  virtual void didHandleActivateEvent(int request_id,
+                                      blink::WebServiceWorkerEventResult);
+  virtual void didHandleInstallEvent(int request_id,
+                                     blink::WebServiceWorkerEventResult result);
+  virtual void didHandleFetchEvent(int request_id);
+  virtual void didHandleFetchEvent(
+      int request_id,
+      const blink::WebServiceWorkerResponse& response);
+  virtual void didHandleNotificationClickEvent(
+      int request_id,
+      blink::WebServiceWorkerEventResult result);
+  virtual void didHandlePushEvent(int request_id,
+                                  blink::WebServiceWorkerEventResult result);
+  // TODO(chasej): crbug.com/486890 - Remove when matching blink changes land
+  virtual void didHandleSyncEvent(int request_id);
+  virtual void didHandleSyncEvent(int request_id,
+                                  blink::WebServiceWorkerEventResult result);
+  virtual void didHandleCrossOriginConnectEvent(int request_id,
+                                                bool accept_connection);
+
+  // Called on the main thread.
+  virtual blink::WebServiceWorkerNetworkProvider*
+      createServiceWorkerNetworkProvider(blink::WebDataSource* data_source);
+  virtual blink::WebServiceWorkerProvider* createServiceWorkerProvider();
+
+  virtual void postMessageToClient(
+      const blink::WebString& uuid,
+      const blink::WebString& message,
+      blink::WebMessagePortChannelArray* channels);
+  virtual void postMessageToCrossOriginClient(
+      const blink::WebCrossOriginServiceWorkerClient& client,
+      const blink::WebString& message,
+      blink::WebMessagePortChannelArray* channels);
+  virtual void focus(const blink::WebString& uuid,
+                     blink::WebServiceWorkerClientCallbacks*);
+  virtual void skipWaiting(
+      blink::WebServiceWorkerSkipWaitingCallbacks* callbacks);
+  virtual void claim(blink::WebServiceWorkerClientsClaimCallbacks* callbacks);
+  virtual void stashMessagePort(blink::WebMessagePortChannel* channel,
+                                const blink::WebString& name);
+
+ private:
+  struct WorkerContextData;
+
+  // Get routing_id for sending message to the ServiceWorkerVersion
+  // in the browser process.
+  int GetRoutingID() const { return embedded_worker_id_; }
+
+  void Send(IPC::Message* message);
+  void SendWorkerStarted();
+  void SetRegistrationInServiceWorkerGlobalScope();
+
+  void OnActivateEvent(int request_id);
+  void OnInstallEvent(int request_id);
+  void OnFetchEvent(int request_id, const ServiceWorkerFetchRequest& request);
+  void OnSyncEvent(int request_id);
+  void OnNotificationClickEvent(
+      int request_id,
+      int64_t persistent_notification_id,
+      const PlatformNotificationData& notification_data);
+  void OnPushEvent(int request_id, const std::string& data);
+  void OnGeofencingEvent(int request_id,
+                         blink::WebGeofencingEventType event_type,
+                         const std::string& region_id,
+                         const blink::WebCircularGeofencingRegion& region);
+  void OnCrossOriginConnectEvent(int request_id,
+                                 const NavigatorConnectClient& client);
+  void OnPostMessage(
+      const base::string16& message,
+      const std::vector<TransferredMessagePort>& sent_message_ports,
+      const std::vector<int>& new_routing_ids);
+  void OnCrossOriginMessageToWorker(
+      const NavigatorConnectClient& client,
+      const base::string16& message,
+      const std::vector<TransferredMessagePort>& sent_message_ports,
+      const std::vector<int>& new_routing_ids);
+  void OnSendStashedMessagePorts(
+      const std::vector<TransferredMessagePort>& stashed_message_ports,
+      const std::vector<int>& new_routing_ids,
+      const std::vector<base::string16>& port_names);
+  void OnDidGetClients(
+      int request_id, const std::vector<ServiceWorkerClientInfo>& clients);
+  void OnOpenWindowResponse(int request_id,
+                            const ServiceWorkerClientInfo& client);
+  void OnOpenWindowError(int request_id, const std::string& message);
+  void OnFocusClientResponse(int request_id,
+                             const ServiceWorkerClientInfo& client);
+  void OnDidSkipWaiting(int request_id);
+  void OnDidClaimClients(int request_id);
+  void OnClaimClientsError(int request_id,
+                           blink::WebServiceWorkerError::ErrorType error_type,
+                           const base::string16& message);
+  void OnPing();
+
+  base::WeakPtr<ServiceWorkerContextClient> GetWeakPtr();
+
+  const int embedded_worker_id_;
+  const int64 service_worker_version_id_;
+  const GURL service_worker_scope_;
+  const GURL script_url_;
+  const int worker_devtools_agent_route_id_;
+  scoped_refptr<ThreadSafeSender> sender_;
+  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+  scoped_refptr<base::TaskRunner> worker_task_runner_;
+
+  scoped_refptr<ServiceWorkerProviderContext> provider_context_;
+
+  // Not owned; this object is destroyed when proxy_ becomes invalid.
+  blink::WebServiceWorkerContextProxy* proxy_;
+
+  // Used for incoming messages from the browser for which an outgoing response
+  // back to the browser is expected, the id must be sent back with the
+  // response.
+  int current_request_id_;
+
+  // Initialized on the worker thread in workerContextStarted and
+  // destructed on the worker thread in willDestroyWorkerContext.
+  scoped_ptr<WorkerContextData> context_;
+
+  // Capture timestamps for UMA
+  std::map<int, base::TimeTicks> activate_start_timings_;
+  std::map<int, base::TimeTicks> fetch_start_timings_;
+  std::map<int, base::TimeTicks> install_start_timings_;
+  std::map<int, base::TimeTicks> notification_click_start_timings_;
+  std::map<int, base::TimeTicks> push_start_timings_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextClient);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_CLIENT_H_
diff --git a/content/renderer/service_worker/service_worker_context_message_filter.cc b/content/renderer/service_worker/service_worker_context_message_filter.cc
new file mode 100644
index 0000000..d380dba
--- /dev/null
+++ b/content/renderer/service_worker/service_worker_context_message_filter.cc
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/service_worker/service_worker_context_message_filter.h"
+
+#include "content/child/child_thread_impl.h"
+#include "content/common/service_worker/embedded_worker_messages.h"
+#include "content/renderer/service_worker/service_worker_context_client.h"
+#include "ipc/ipc_message_macros.h"
+
+namespace content {
+
+ServiceWorkerContextMessageFilter::ServiceWorkerContextMessageFilter()
+    : WorkerThreadMessageFilter(
+          ChildThreadImpl::current()->thread_safe_sender()) {
+}
+
+ServiceWorkerContextMessageFilter::~ServiceWorkerContextMessageFilter() {}
+
+bool ServiceWorkerContextMessageFilter::ShouldHandleMessage(
+    const IPC::Message& msg) const {
+  return IPC_MESSAGE_CLASS(msg) == EmbeddedWorkerContextMsgStart;
+}
+
+void ServiceWorkerContextMessageFilter::OnFilteredMessageReceived(
+    const IPC::Message& msg) {
+  ServiceWorkerContextClient* context =
+      ServiceWorkerContextClient::ThreadSpecificInstance();
+  if (!context) {
+    LOG(ERROR) << "Stray message is sent to nonexistent worker";
+    return;
+  }
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(ServiceWorkerContextClient, msg)
+    IPC_MESSAGE_FORWARD(EmbeddedWorkerContextMsg_MessageToWorker,
+                        context,
+                        ServiceWorkerContextClient::OnMessageReceived)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  DCHECK(handled);
+}
+
+bool ServiceWorkerContextMessageFilter::GetWorkerThreadIdForMessage(
+    const IPC::Message& msg,
+    int* ipc_thread_id) {
+  return base::PickleIterator(msg).ReadInt(ipc_thread_id);
+}
+
+}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_context_message_filter.h b/content/renderer/service_worker/service_worker_context_message_filter.h
new file mode 100644
index 0000000..e34f866
--- /dev/null
+++ b/content/renderer/service_worker/service_worker_context_message_filter.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_MESSAGE_FILTER_H_
+#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_MESSAGE_FILTER_H_
+
+#include "content/child/worker_thread_message_filter.h"
+
+namespace content {
+
+class ServiceWorkerContextMessageFilter : public WorkerThreadMessageFilter {
+ public:
+  ServiceWorkerContextMessageFilter();
+
+ protected:
+  ~ServiceWorkerContextMessageFilter() override;
+
+  // WorkerThreadMessageFilter:
+  bool ShouldHandleMessage(const IPC::Message& msg) const override;
+  void OnFilteredMessageReceived(const IPC::Message& msg) override;
+  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                   int* ipc_thread_id) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextMessageFilter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_MESSAGE_FILTER_H_
diff --git a/content/renderer/service_worker/service_worker_script_context.cc b/content/renderer/service_worker/service_worker_script_context.cc
deleted file mode 100644
index d314ce78..0000000
--- a/content/renderer/service_worker/service_worker_script_context.cc
+++ /dev/null
@@ -1,631 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/service_worker/service_worker_script_context.h"
-
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/trace_event/trace_event.h"
-#include "content/child/notifications/notification_data_conversions.h"
-#include "content/child/service_worker/web_service_worker_registration_impl.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/webmessageportchannel_impl.h"
-#include "content/common/message_port_messages.h"
-#include "content/common/service_worker/service_worker_messages.h"
-#include "content/public/common/referrer.h"
-#include "content/renderer/service_worker/embedded_worker_context_client.h"
-#include "ipc/ipc_message.h"
-#include "third_party/WebKit/public/platform/WebCrossOriginServiceWorkerClient.h"
-#include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerClientQueryOptions.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerRequest.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationData.h"
-#include "third_party/WebKit/public/web/WebServiceWorkerContextClient.h"
-#include "third_party/WebKit/public/web/WebServiceWorkerContextProxy.h"
-
-namespace content {
-
-namespace {
-
-void SendPostMessageToClientOnMainThread(
-    ThreadSafeSender* sender,
-    int routing_id,
-    const std::string& uuid,
-    const base::string16& message,
-    scoped_ptr<blink::WebMessagePortChannelArray> channels) {
-  sender->Send(new ServiceWorkerHostMsg_PostMessageToClient(
-      routing_id, uuid, message,
-      WebMessagePortChannelImpl::ExtractMessagePortIDs(channels.release())));
-}
-
-void SendCrossOriginMessageToClientOnMainThread(
-    ThreadSafeSender* sender,
-    int message_port_id,
-    const base::string16& message,
-    scoped_ptr<blink::WebMessagePortChannelArray> channels) {
-  sender->Send(new MessagePortHostMsg_PostMessage(
-      message_port_id,
-      MessagePortMessage(message),
-                         WebMessagePortChannelImpl::ExtractMessagePortIDs(
-                             channels.release())));
-}
-
-void StashMessagePortOnMainThread(ThreadSafeSender* sender,
-                                  int routing_id,
-                                  WebMessagePortChannelImpl* channel,
-                                  const base::string16& name) {
-  DCHECK_GE(channel->message_port_id(), 0);
-  channel->set_is_stashed();
-  sender->Send(new ServiceWorkerHostMsg_StashMessagePort(
-      routing_id, channel->message_port_id(), name));
-}
-
-blink::WebURLRequest::FetchRequestMode GetBlinkFetchRequestMode(
-    FetchRequestMode mode) {
-  return static_cast<blink::WebURLRequest::FetchRequestMode>(mode);
-}
-
-blink::WebURLRequest::FetchCredentialsMode GetBlinkFetchCredentialsMode(
-    FetchCredentialsMode credentials_mode) {
-  return static_cast<blink::WebURLRequest::FetchCredentialsMode>(
-      credentials_mode);
-}
-
-blink::WebURLRequest::RequestContext GetBlinkRequestContext(
-    RequestContextType request_context_type) {
-  return static_cast<blink::WebURLRequest::RequestContext>(
-      request_context_type);
-}
-
-blink::WebURLRequest::FrameType GetBlinkFrameType(
-    RequestContextFrameType frame_type) {
-  return static_cast<blink::WebURLRequest::FrameType>(frame_type);
-}
-
-blink::WebServiceWorkerClientInfo
-ToWebServiceWorkerClientInfo(const ServiceWorkerClientInfo& client_info) {
-  DCHECK(client_info.IsValid());
-
-  blink::WebServiceWorkerClientInfo web_client_info;
-
-  web_client_info.uuid = base::UTF8ToUTF16(client_info.client_uuid);
-  web_client_info.pageVisibilityState = client_info.page_visibility_state;
-  web_client_info.isFocused = client_info.is_focused;
-  web_client_info.url = client_info.url;
-  web_client_info.frameType = GetBlinkFrameType(client_info.frame_type);
-  web_client_info.clientType = client_info.client_type;
-
-  return web_client_info;
-}
-
-}  // namespace
-
-ServiceWorkerScriptContext::ServiceWorkerScriptContext(
-    EmbeddedWorkerContextClient* embedded_context,
-    blink::WebServiceWorkerContextProxy* proxy)
-    : embedded_context_(embedded_context),
-      proxy_(proxy) {
-}
-
-ServiceWorkerScriptContext::~ServiceWorkerScriptContext() {}
-
-void ServiceWorkerScriptContext::OnMessageReceived(
-    const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(ServiceWorkerScriptContext, message)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ActivateEvent, OnActivateEvent)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FetchEvent, OnFetchEvent)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent, OnInstallEvent)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SyncEvent, OnSyncEvent)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_NotificationClickEvent,
-                        OnNotificationClickEvent)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_PushEvent, OnPushEvent)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_GeofencingEvent, OnGeofencingEvent)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CrossOriginConnectEvent,
-                        OnCrossOriginConnectEvent)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToWorker, OnPostMessage)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CrossOriginMessageToWorker,
-                        OnCrossOriginMessageToWorker)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SendStashedMessagePorts,
-                        OnSendStashedMessagePorts)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClients,
-                        OnDidGetClients)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_OpenWindowResponse,
-                        OnOpenWindowResponse)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_OpenWindowError,
-                        OnOpenWindowError)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FocusClientResponse,
-                        OnFocusClientResponse)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidSkipWaiting, OnDidSkipWaiting)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidClaimClients, OnDidClaimClients)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ClaimClientsError, OnClaimClientsError)
-    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_Ping, OnPing);
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-
-  DCHECK(handled);
-}
-
-void ServiceWorkerScriptContext::SetRegistrationInServiceWorkerGlobalScope(
-    scoped_ptr<WebServiceWorkerRegistrationImpl> registration) {
-  proxy_->setRegistration(registration.release());
-}
-
-void ServiceWorkerScriptContext::DidHandleActivateEvent(
-    int request_id,
-    blink::WebServiceWorkerEventResult result) {
-  UMA_HISTOGRAM_MEDIUM_TIMES(
-      "ServiceWorker.ActivateEvent.Time",
-      base::TimeTicks::Now() - activate_start_timings_[request_id]);
-  activate_start_timings_.erase(request_id);
-
-  Send(new ServiceWorkerHostMsg_ActivateEventFinished(
-      GetRoutingID(), request_id, result));
-}
-
-void ServiceWorkerScriptContext::DidHandleInstallEvent(
-    int request_id,
-    blink::WebServiceWorkerEventResult result) {
-  UMA_HISTOGRAM_MEDIUM_TIMES(
-      "ServiceWorker.InstallEvent.Time",
-      base::TimeTicks::Now() - install_start_timings_[request_id]);
-  install_start_timings_.erase(request_id);
-
-  Send(new ServiceWorkerHostMsg_InstallEventFinished(
-      GetRoutingID(), request_id, result));
-}
-
-void ServiceWorkerScriptContext::DidHandleFetchEvent(
-    int request_id,
-    ServiceWorkerFetchEventResult result,
-    const ServiceWorkerResponse& response) {
-  UMA_HISTOGRAM_MEDIUM_TIMES(
-      "ServiceWorker.FetchEvent.Time",
-      base::TimeTicks::Now() - fetch_start_timings_[request_id]);
-  fetch_start_timings_.erase(request_id);
-
-  Send(new ServiceWorkerHostMsg_FetchEventFinished(
-      GetRoutingID(), request_id, result, response));
-}
-
-void ServiceWorkerScriptContext::DidHandleNotificationClickEvent(
-    int request_id,
-    blink::WebServiceWorkerEventResult result) {
-  UMA_HISTOGRAM_MEDIUM_TIMES(
-      "ServiceWorker.NotificationClickEvent.Time",
-      base::TimeTicks::Now() - notification_click_start_timings_[request_id]);
-  notification_click_start_timings_.erase(request_id);
-
-  Send(new ServiceWorkerHostMsg_NotificationClickEventFinished(
-      GetRoutingID(), request_id));
-}
-
-void ServiceWorkerScriptContext::DidHandlePushEvent(
-    int request_id,
-    blink::WebServiceWorkerEventResult result) {
-  if (result == blink::WebServiceWorkerEventResultCompleted) {
-    UMA_HISTOGRAM_MEDIUM_TIMES(
-        "ServiceWorker.PushEvent.Time",
-        base::TimeTicks::Now() - push_start_timings_[request_id]);
-  }
-  push_start_timings_.erase(request_id);
-
-  Send(new ServiceWorkerHostMsg_PushEventFinished(
-      GetRoutingID(), request_id, result));
-}
-
-void ServiceWorkerScriptContext::DidHandleSyncEvent(
-    int request_id,
-    blink::WebServiceWorkerEventResult result) {
-  Send(new ServiceWorkerHostMsg_SyncEventFinished(GetRoutingID(), request_id,
-                                                  result));
-}
-
-void ServiceWorkerScriptContext::DidHandleCrossOriginConnectEvent(
-    int request_id,
-    bool accept_connection) {
-  Send(new ServiceWorkerHostMsg_CrossOriginConnectEventFinished(
-      GetRoutingID(), request_id, accept_connection));
-}
-
-void ServiceWorkerScriptContext::GetClients(
-    const blink::WebServiceWorkerClientQueryOptions& weboptions,
-    blink::WebServiceWorkerClientsCallbacks* callbacks) {
-  DCHECK(callbacks);
-  int request_id = pending_clients_callbacks_.Add(callbacks);
-  ServiceWorkerClientQueryOptions options;
-  options.client_type = weboptions.clientType;
-  options.include_uncontrolled = weboptions.includeUncontrolled;
-  Send(new ServiceWorkerHostMsg_GetClients(
-      GetRoutingID(), request_id, options));
-}
-
-void ServiceWorkerScriptContext::OpenWindow(
-    const GURL& url, blink::WebServiceWorkerClientCallbacks* callbacks) {
-  DCHECK(callbacks);
-  int request_id = pending_client_callbacks_.Add(callbacks);
-  Send(new ServiceWorkerHostMsg_OpenWindow(GetRoutingID(), request_id, url));
-}
-
-void ServiceWorkerScriptContext::SetCachedMetadata(const GURL& url,
-                                                   const char* data,
-                                                   size_t size) {
-  std::vector<char> copy(data, data + size);
-  Send(new ServiceWorkerHostMsg_SetCachedMetadata(GetRoutingID(), url, copy));
-}
-
-void ServiceWorkerScriptContext::ClearCachedMetadata(const GURL& url) {
-  Send(new ServiceWorkerHostMsg_ClearCachedMetadata(GetRoutingID(), url));
-}
-
-void ServiceWorkerScriptContext::PostMessageToClient(
-    const base::string16& uuid,
-    const base::string16& message,
-    scoped_ptr<blink::WebMessagePortChannelArray> channels) {
-  // This may send channels for MessagePorts, and all internal book-keeping
-  // messages for MessagePort (e.g. QueueMessages) are sent from main thread
-  // (with thread hopping), so we need to do the same thread hopping here not
-  // to overtake those messages.
-  embedded_context_->main_thread_task_runner()->PostTask(
-      FROM_HERE,
-      base::Bind(&SendPostMessageToClientOnMainThread,
-                 make_scoped_refptr(embedded_context_->thread_safe_sender()),
-                 GetRoutingID(),
-                 base::UTF16ToUTF8(uuid),
-                 message, base::Passed(&channels)));
-}
-
-void ServiceWorkerScriptContext::PostCrossOriginMessageToClient(
-    const blink::WebCrossOriginServiceWorkerClient& client,
-    const base::string16& message,
-    scoped_ptr<blink::WebMessagePortChannelArray> channels) {
-  // This may send channels for MessagePorts, and all internal book-keeping
-  // messages for MessagePort (e.g. QueueMessages) are sent from main thread
-  // (with thread hopping), so we need to do the same thread hopping here not
-  // to overtake those messages.
-  embedded_context_->main_thread_task_runner()->PostTask(
-      FROM_HERE,
-      base::Bind(&SendCrossOriginMessageToClientOnMainThread,
-                 make_scoped_refptr(embedded_context_->thread_safe_sender()),
-                 client.clientID, message, base::Passed(&channels)));
-}
-
-void ServiceWorkerScriptContext::FocusClient(
-    const base::string16& uuid,
-    blink::WebServiceWorkerClientCallbacks* callback) {
-  DCHECK(callback);
-  int request_id = pending_client_callbacks_.Add(callback);
-  Send(new ServiceWorkerHostMsg_FocusClient(GetRoutingID(), request_id,
-                                            base::UTF16ToUTF8(uuid)));
-}
-
-void ServiceWorkerScriptContext::ClaimClients(
-    blink::WebServiceWorkerClientsClaimCallbacks* callbacks) {
-  DCHECK(callbacks);
-  int request_id = pending_claim_clients_callbacks_.Add(callbacks);
-  Send(new ServiceWorkerHostMsg_ClaimClients(GetRoutingID(), request_id));
-}
-
-void ServiceWorkerScriptContext::SkipWaiting(
-    blink::WebServiceWorkerSkipWaitingCallbacks* callbacks) {
-  DCHECK(callbacks);
-  int request_id = pending_skip_waiting_callbacks_.Add(callbacks);
-  Send(new ServiceWorkerHostMsg_SkipWaiting(GetRoutingID(), request_id));
-}
-
-void ServiceWorkerScriptContext::StashMessagePort(
-    blink::WebMessagePortChannel* channel,
-    const base::string16& name) {
-  // All internal book-keeping messages for MessagePort are sent from main
-  // thread (with thread hopping), so we need to do the same thread hopping here
-  // not to overtake those messages.
-  WebMessagePortChannelImpl* channel_impl =
-      static_cast<WebMessagePortChannelImpl*>(channel);
-  embedded_context_->main_thread_task_runner()->PostTask(
-      FROM_HERE,
-      base::Bind(&StashMessagePortOnMainThread,
-                 make_scoped_refptr(embedded_context_->thread_safe_sender()),
-                 GetRoutingID(), base::Unretained(channel_impl), name));
-}
-
-void ServiceWorkerScriptContext::Send(IPC::Message* message) {
-  embedded_context_->Send(message);
-}
-
-int ServiceWorkerScriptContext::GetRoutingID() const {
-  return embedded_context_->embedded_worker_id();
-}
-
-void ServiceWorkerScriptContext::OnActivateEvent(int request_id) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnActivateEvent");
-  activate_start_timings_[request_id] = base::TimeTicks::Now();
-  proxy_->dispatchActivateEvent(request_id);
-}
-
-void ServiceWorkerScriptContext::OnInstallEvent(int request_id) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnInstallEvent");
-  install_start_timings_[request_id] = base::TimeTicks::Now();
-  proxy_->dispatchInstallEvent(request_id);
-}
-
-void ServiceWorkerScriptContext::OnFetchEvent(
-    int request_id,
-    const ServiceWorkerFetchRequest& request) {
-  blink::WebServiceWorkerRequest webRequest;
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnFetchEvent");
-  webRequest.setURL(blink::WebURL(request.url));
-  webRequest.setMethod(blink::WebString::fromUTF8(request.method));
-  for (ServiceWorkerHeaderMap::const_iterator it = request.headers.begin();
-       it != request.headers.end();
-       ++it) {
-    webRequest.setHeader(blink::WebString::fromUTF8(it->first),
-                         blink::WebString::fromUTF8(it->second));
-  }
-  if (!request.blob_uuid.empty()) {
-    webRequest.setBlob(blink::WebString::fromUTF8(request.blob_uuid),
-                       request.blob_size);
-  }
-  webRequest.setReferrer(
-      blink::WebString::fromUTF8(request.referrer.url.spec()),
-      request.referrer.policy);
-  webRequest.setMode(GetBlinkFetchRequestMode(request.mode));
-  webRequest.setCredentialsMode(
-      GetBlinkFetchCredentialsMode(request.credentials_mode));
-  webRequest.setRequestContext(
-      GetBlinkRequestContext(request.request_context_type));
-  webRequest.setFrameType(GetBlinkFrameType(request.frame_type));
-  webRequest.setIsReload(request.is_reload);
-  fetch_start_timings_[request_id] = base::TimeTicks::Now();
-  proxy_->dispatchFetchEvent(request_id, webRequest);
-}
-
-void ServiceWorkerScriptContext::OnSyncEvent(int request_id) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnSyncEvent");
-  proxy_->dispatchSyncEvent(request_id);
-}
-
-void ServiceWorkerScriptContext::OnNotificationClickEvent(
-    int request_id,
-    int64_t persistent_notification_id,
-    const PlatformNotificationData& notification_data) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnNotificationClickEvent");
-  notification_click_start_timings_[request_id] = base::TimeTicks::Now();
-  proxy_->dispatchNotificationClickEvent(
-      request_id,
-      persistent_notification_id,
-      ToWebNotificationData(notification_data));
-}
-
-void ServiceWorkerScriptContext::OnPushEvent(int request_id,
-                                             const std::string& data) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnPushEvent");
-  push_start_timings_[request_id] = base::TimeTicks::Now();
-  proxy_->dispatchPushEvent(request_id, blink::WebString::fromUTF8(data));
-}
-
-void ServiceWorkerScriptContext::OnGeofencingEvent(
-    int request_id,
-    blink::WebGeofencingEventType event_type,
-    const std::string& region_id,
-    const blink::WebCircularGeofencingRegion& region) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnGeofencingEvent");
-  proxy_->dispatchGeofencingEvent(
-      request_id, event_type, blink::WebString::fromUTF8(region_id), region);
-  Send(new ServiceWorkerHostMsg_GeofencingEventFinished(GetRoutingID(),
-                                                        request_id));
-}
-
-void ServiceWorkerScriptContext::OnCrossOriginConnectEvent(
-    int request_id,
-    const NavigatorConnectClient& client) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnCrossOriginConnectEvent");
-  blink::WebCrossOriginServiceWorkerClient web_client;
-  web_client.origin = client.origin;
-  web_client.targetURL = client.target_url;
-  web_client.clientID = client.message_port_id;
-  proxy_->dispatchCrossOriginConnectEvent(request_id, web_client);
-}
-
-void ServiceWorkerScriptContext::OnPostMessage(
-    const base::string16& message,
-    const std::vector<TransferredMessagePort>& sent_message_ports,
-    const std::vector<int>& new_routing_ids) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnPostEvent");
-  blink::WebMessagePortChannelArray ports =
-      WebMessagePortChannelImpl::CreatePorts(
-          sent_message_ports, new_routing_ids,
-          embedded_context_->main_thread_task_runner());
-
-  // dispatchMessageEvent is expected to execute onmessage function
-  // synchronously.
-  base::TimeTicks before = base::TimeTicks::Now();
-  proxy_->dispatchMessageEvent(message, ports);
-  UMA_HISTOGRAM_MEDIUM_TIMES(
-      "ServiceWorker.MessageEvent.Time",
-      base::TimeTicks::Now() - before);
-}
-
-void ServiceWorkerScriptContext::OnCrossOriginMessageToWorker(
-    const NavigatorConnectClient& client,
-    const base::string16& message,
-    const std::vector<TransferredMessagePort>& sent_message_ports,
-    const std::vector<int>& new_routing_ids) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnCrossOriginMessageToWorker");
-  blink::WebMessagePortChannelArray ports =
-      WebMessagePortChannelImpl::CreatePorts(
-          sent_message_ports, new_routing_ids,
-          embedded_context_->main_thread_task_runner());
-
-  blink::WebCrossOriginServiceWorkerClient web_client;
-  web_client.origin = client.origin;
-  web_client.targetURL = client.target_url;
-  web_client.clientID = client.message_port_id;
-  proxy_->dispatchCrossOriginMessageEvent(web_client, message, ports);
-}
-
-void ServiceWorkerScriptContext::OnSendStashedMessagePorts(
-    const std::vector<TransferredMessagePort>& stashed_message_ports,
-    const std::vector<int>& new_routing_ids,
-    const std::vector<base::string16>& port_names) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnSendStashedMessagePorts");
-  blink::WebMessagePortChannelArray ports =
-      WebMessagePortChannelImpl::CreatePorts(
-          stashed_message_ports, new_routing_ids,
-          embedded_context_->main_thread_task_runner());
-  for (blink::WebMessagePortChannel* port : ports)
-    static_cast<WebMessagePortChannelImpl*>(port)->set_is_stashed();
-  proxy_->addStashedMessagePorts(ports, port_names);
-}
-
-void ServiceWorkerScriptContext::OnDidGetClients(
-    int request_id, const std::vector<ServiceWorkerClientInfo>& clients) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnDidGetClients");
-  blink::WebServiceWorkerClientsCallbacks* callbacks =
-      pending_clients_callbacks_.Lookup(request_id);
-  if (!callbacks) {
-    NOTREACHED() << "Got stray response: " << request_id;
-    return;
-  }
-  scoped_ptr<blink::WebServiceWorkerClientsInfo> info(
-      new blink::WebServiceWorkerClientsInfo);
-  blink::WebVector<blink::WebServiceWorkerClientInfo> convertedClients(
-      clients.size());
-  for (size_t i = 0; i < clients.size(); ++i)
-    convertedClients[i] = ToWebServiceWorkerClientInfo(clients[i]);
-  info->clients.swap(convertedClients);
-  callbacks->onSuccess(info.release());
-  pending_clients_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerScriptContext::OnOpenWindowResponse(
-    int request_id,
-    const ServiceWorkerClientInfo& client) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnOpenWindowResponse");
-  blink::WebServiceWorkerClientCallbacks* callbacks =
-      pending_client_callbacks_.Lookup(request_id);
-  if (!callbacks) {
-    NOTREACHED() << "Got stray response: " << request_id;
-    return;
-  }
-  scoped_ptr<blink::WebServiceWorkerClientInfo> web_client;
-  if (!client.IsEmpty()) {
-    DCHECK(client.IsValid());
-    web_client.reset(new blink::WebServiceWorkerClientInfo(
-        ToWebServiceWorkerClientInfo(client)));
-  }
-  callbacks->onSuccess(web_client.release());
-  pending_client_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerScriptContext::OnOpenWindowError(
-    int request_id,
-    const std::string& message) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnOpenWindowError");
-  blink::WebServiceWorkerClientCallbacks* callbacks =
-      pending_client_callbacks_.Lookup(request_id);
-  if (!callbacks) {
-    NOTREACHED() << "Got stray response: " << request_id;
-    return;
-  }
-  scoped_ptr<blink::WebServiceWorkerError> error(
-      new blink::WebServiceWorkerError(
-          blink::WebServiceWorkerError::ErrorTypeUnknown,
-          blink::WebString::fromUTF8(message)));
-  callbacks->onError(error.release());
-  pending_client_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerScriptContext::OnFocusClientResponse(
-    int request_id, const ServiceWorkerClientInfo& client) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnFocusClientResponse");
-  blink::WebServiceWorkerClientCallbacks* callback =
-      pending_client_callbacks_.Lookup(request_id);
-  if (!callback) {
-    NOTREACHED() << "Got stray response: " << request_id;
-    return;
-  }
-  if (!client.IsEmpty()) {
-    DCHECK(client.IsValid());
-    scoped_ptr<blink::WebServiceWorkerClientInfo> web_client (
-        new blink::WebServiceWorkerClientInfo(
-            ToWebServiceWorkerClientInfo(client)));
-    callback->onSuccess(web_client.release());
-  } else {
-    scoped_ptr<blink::WebServiceWorkerError> error(
-        new blink::WebServiceWorkerError(
-            blink::WebServiceWorkerError::ErrorTypeNotFound,
-            "The WindowClient was not found."));
-    callback->onError(error.release());
-  }
-
-  pending_client_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerScriptContext::OnDidSkipWaiting(int request_id) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnDidSkipWaiting");
-  blink::WebServiceWorkerSkipWaitingCallbacks* callbacks =
-      pending_skip_waiting_callbacks_.Lookup(request_id);
-  if (!callbacks) {
-    NOTREACHED() << "Got stray response: " << request_id;
-    return;
-  }
-  callbacks->onSuccess();
-  pending_skip_waiting_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerScriptContext::OnDidClaimClients(int request_id) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnDidClaimClients");
-  blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
-      pending_claim_clients_callbacks_.Lookup(request_id);
-  if (!callbacks) {
-    NOTREACHED() << "Got stray response: " << request_id;
-    return;
-  }
-  callbacks->onSuccess();
-  pending_claim_clients_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerScriptContext::OnClaimClientsError(
-    int request_id,
-    blink::WebServiceWorkerError::ErrorType error_type,
-    const base::string16& message) {
-  TRACE_EVENT0("ServiceWorker",
-               "ServiceWorkerScriptContext::OnClaimClientsError");
-  blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
-      pending_claim_clients_callbacks_.Lookup(request_id);
-  if (!callbacks) {
-    NOTREACHED() << "Got stray response: " << request_id;
-    return;
-  }
-  scoped_ptr<blink::WebServiceWorkerError> error(
-      new blink::WebServiceWorkerError(error_type, message));
-  callbacks->onError(error.release());
-  pending_claim_clients_callbacks_.Remove(request_id);
-}
-
-void ServiceWorkerScriptContext::OnPing() {
-  Send(new ServiceWorkerHostMsg_Pong(GetRoutingID()));
-}
-
-}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_script_context.h b/content/renderer/service_worker/service_worker_script_context.h
deleted file mode 100644
index 9013795..0000000
--- a/content/renderer/service_worker/service_worker_script_context.h
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_SCRIPT_CONTEXT_H_
-#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_SCRIPT_CONTEXT_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/id_map.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string16.h"
-#include "base/time/time.h"
-#include "content/child/webmessageportchannel_impl.h"
-#include "content/common/service_worker/service_worker_types.h"
-#include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
-#include "third_party/WebKit/public/platform/WebMessagePortChannel.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerClientsClaimCallbacks.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerClientsInfo.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerSkipWaitingCallbacks.h"
-
-namespace blink {
-struct WebCircularGeofencingRegion;
-struct WebCrossOriginServiceWorkerClient;
-struct WebServiceWorkerClientQueryOptions;
-class WebServiceWorkerContextProxy;
-}
-
-namespace IPC {
-class Message;
-}
-
-namespace content {
-
-class EmbeddedWorkerContextClient;
-class WebServiceWorkerRegistrationImpl;
-struct NavigatorConnectClient;
-struct PlatformNotificationData;
-struct ServiceWorkerClientInfo;
-
-// TODO(kinuko): This should implement WebServiceWorkerContextClient
-// rather than having EmbeddedWorkerContextClient implement it.
-// See the header comment in embedded_worker_context_client.h for the
-// potential EW/SW layering concerns.
-class ServiceWorkerScriptContext {
- public:
-  ServiceWorkerScriptContext(
-      EmbeddedWorkerContextClient* embedded_context,
-      blink::WebServiceWorkerContextProxy* proxy);
-  ~ServiceWorkerScriptContext();
-
-  void OnMessageReceived(const IPC::Message& message);
-
-  void SetRegistrationInServiceWorkerGlobalScope(
-      scoped_ptr<WebServiceWorkerRegistrationImpl> registration);
-  void DidHandleActivateEvent(int request_id,
-                              blink::WebServiceWorkerEventResult);
-  void DidHandleInstallEvent(int request_id,
-                             blink::WebServiceWorkerEventResult result);
-  void DidHandleFetchEvent(int request_id,
-                           ServiceWorkerFetchEventResult result,
-                           const ServiceWorkerResponse& response);
-  void DidHandleNotificationClickEvent(
-      int request_id,
-      blink::WebServiceWorkerEventResult result);
-  void DidHandlePushEvent(int request_id,
-                          blink::WebServiceWorkerEventResult result);
-  void DidHandleSyncEvent(int request_id,
-                          blink::WebServiceWorkerEventResult result);
-  void DidHandleCrossOriginConnectEvent(int request_id, bool accept_connection);
-  void GetClients(
-      const blink::WebServiceWorkerClientQueryOptions& options,
-      blink::WebServiceWorkerClientsCallbacks* callbacks);
-  void OpenWindow(const GURL& url,
-                  blink::WebServiceWorkerClientCallbacks* callbacks);
-  void SetCachedMetadata(const GURL& url, const char* data, size_t size);
-  void ClearCachedMetadata(const GURL& url);
-  void PostMessageToClient(
-      const base::string16& uuid,
-      const base::string16& message,
-      scoped_ptr<blink::WebMessagePortChannelArray> channels);
-  void PostCrossOriginMessageToClient(
-      const blink::WebCrossOriginServiceWorkerClient& client,
-      const base::string16& message,
-      scoped_ptr<blink::WebMessagePortChannelArray> channels);
-  void FocusClient(const base::string16& uuid,
-                   blink::WebServiceWorkerClientCallbacks* callback);
-  void SkipWaiting(blink::WebServiceWorkerSkipWaitingCallbacks* callbacks);
-  void ClaimClients(blink::WebServiceWorkerClientsClaimCallbacks* callbacks);
-  void StashMessagePort(blink::WebMessagePortChannel* channel,
-                        const base::string16& name);
-
-  // Send a message to the browser. Takes ownership of |message|.
-  void Send(IPC::Message* message);
-
-  // Get routing_id for sending message to the ServiceWorkerVersion
-  // in the browser process.
-  int GetRoutingID() const;
-
- private:
-  typedef IDMap<blink::WebServiceWorkerClientsCallbacks, IDMapOwnPointer>
-      ClientsCallbacksMap;
-  typedef IDMap<blink::WebServiceWorkerClientsClaimCallbacks, IDMapOwnPointer>
-      ClaimClientsCallbacksMap;
-  typedef IDMap<blink::WebServiceWorkerClientCallbacks, IDMapOwnPointer>
-      ClientCallbacksMap;
-  typedef IDMap<blink::WebServiceWorkerSkipWaitingCallbacks, IDMapOwnPointer>
-      SkipWaitingCallbacksMap;
-
-  void OnActivateEvent(int request_id);
-  void OnInstallEvent(int request_id);
-  void OnFetchEvent(int request_id, const ServiceWorkerFetchRequest& request);
-  void OnSyncEvent(int request_id);
-  void OnNotificationClickEvent(
-      int request_id,
-      int64_t persistent_notification_id,
-      const PlatformNotificationData& notification_data);
-  void OnPushEvent(int request_id, const std::string& data);
-  void OnGeofencingEvent(int request_id,
-                         blink::WebGeofencingEventType event_type,
-                         const std::string& region_id,
-                         const blink::WebCircularGeofencingRegion& region);
-  void OnCrossOriginConnectEvent(int request_id,
-                                 const NavigatorConnectClient& client);
-  void OnPostMessage(
-      const base::string16& message,
-      const std::vector<TransferredMessagePort>& sent_message_ports,
-      const std::vector<int>& new_routing_ids);
-  void OnCrossOriginMessageToWorker(
-      const NavigatorConnectClient& client,
-      const base::string16& message,
-      const std::vector<TransferredMessagePort>& sent_message_ports,
-      const std::vector<int>& new_routing_ids);
-  void OnSendStashedMessagePorts(
-      const std::vector<TransferredMessagePort>& stashed_message_ports,
-      const std::vector<int>& new_routing_ids,
-      const std::vector<base::string16>& port_names);
-  void OnDidGetClients(
-      int request_id, const std::vector<ServiceWorkerClientInfo>& clients);
-  void OnOpenWindowResponse(int request_id,
-                            const ServiceWorkerClientInfo& client);
-  void OnOpenWindowError(int request_id, const std::string& message);
-  void OnFocusClientResponse(int request_id,
-                             const ServiceWorkerClientInfo& client);
-  void OnDidSkipWaiting(int request_id);
-  void OnDidClaimClients(int request_id);
-  void OnClaimClientsError(int request_id,
-                           blink::WebServiceWorkerError::ErrorType error_type,
-                           const base::string16& message);
-  void OnPing();
-
-  // Not owned; embedded_context_ owns this.
-  EmbeddedWorkerContextClient* embedded_context_;
-
-  // Not owned; this object is destroyed when proxy_ becomes invalid.
-  blink::WebServiceWorkerContextProxy* proxy_;
-
-  // Used for incoming messages from the browser for which an outgoing response
-  // back to the browser is expected, the id must be sent back with the
-  // response.
-  int current_request_id_;
-
-  // Pending callbacks for GetClientDocuments().
-  ClientsCallbacksMap pending_clients_callbacks_;
-
-  // Pending callbacks for OpenWindow() and FocusClient().
-  ClientCallbacksMap pending_client_callbacks_;
-
-  // Pending callbacks for SkipWaiting().
-  SkipWaitingCallbacksMap pending_skip_waiting_callbacks_;
-
-  // Pending callbacks for ClaimClients().
-  ClaimClientsCallbacksMap pending_claim_clients_callbacks_;
-
-  // Capture timestamps for UMA
-  std::map<int, base::TimeTicks> activate_start_timings_;
-  std::map<int, base::TimeTicks> fetch_start_timings_;
-  std::map<int, base::TimeTicks> install_start_timings_;
-  std::map<int, base::TimeTicks> notification_click_start_timings_;
-  std::map<int, base::TimeTicks> push_start_timings_;
-
-  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerScriptContext);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_SCRIPT_CONTEXT_H_
diff --git a/content/renderer/shared_worker/OWNERS b/content/renderer/shared_worker/OWNERS
index 61fc3fd..63d62763 100644
--- a/content/renderer/shared_worker/OWNERS
+++ b/content/renderer/shared_worker/OWNERS
@@ -1,3 +1,2 @@
 atwilson@chromium.org
-kinuko@chromium.org
 horo@chromium.org
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index d505da3..b736942 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -162,8 +162,6 @@
     "renderer/layout_test/leak_detector.h",
     "renderer/layout_test/test_media_stream_renderer_factory.cc",
     "renderer/layout_test/test_media_stream_renderer_factory.h",
-    "renderer/layout_test/test_plugin_placeholder.cc",
-    "renderer/layout_test/test_plugin_placeholder.h",
     "renderer/layout_test/test_video_frame_provider.cc",
     "renderer/layout_test/test_video_frame_provider.h",
     "renderer/shell_content_renderer_client.cc",
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellShellManagementTest.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellShellManagementTest.java
index a1ef2929..4140b539 100644
--- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellShellManagementTest.java
+++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellShellManagementTest.java
@@ -6,11 +6,12 @@
 
 import android.test.suitebuilder.annotation.SmallTest;
 
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content_shell.Shell;
 
+import java.util.concurrent.ExecutionException;
+
 /**
  * Test suite to verify the behavior of the shell management logic.
  */
@@ -23,7 +24,7 @@
 
     @SmallTest
     @Feature({"Main"})
-    public void testMultipleShellsLaunched() throws InterruptedException {
+    public void testMultipleShellsLaunched() throws InterruptedException, ExecutionException {
         final ContentShellActivity activity = launchContentShellWithUrl(TEST_PAGE_1);
         assertEquals(TEST_PAGE_1, activity.getActiveShell().getContentViewCore()
                 .getWebContents().getUrl());
@@ -31,13 +32,7 @@
         Shell previousActiveShell = activity.getActiveShell();
         assertFalse(previousActiveShell.isDestroyed());
 
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                activity.getShellManager().launchShell(TEST_PAGE_2);
-            }
-        });
-        waitForActiveShellToBeDoneLoading();
+        loadNewShell(TEST_PAGE_2);
         assertEquals(TEST_PAGE_2, activity.getActiveShell().getContentViewCore()
                 .getWebContents().getUrl());
 
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java
index 15d097d..93daeaa 100644
--- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java
+++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java
@@ -33,6 +33,8 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.lang.reflect.Method;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -140,9 +142,32 @@
     }
 
     /**
+     * Creates a new {@link Shell} and waits for it to finish loading.
+     * @param url The URL to create the new {@link Shell} with.
+     * @return A new instance of a {@link Shell}.
+     * @throws ExecutionException
+     * @throws InterruptedException
+     */
+    protected Shell loadNewShell(final String url) throws ExecutionException, InterruptedException {
+        Shell shell = ThreadUtils.runOnUiThreadBlocking(new Callable<Shell>() {
+            @Override
+            public Shell call() {
+                getActivity().getShellManager().launchShell(url);
+                return getActivity().getActiveShell();
+            }
+        });
+
+        assertNotNull("Unable to create shell.", shell);
+        assertEquals("Active shell unexpected.", shell, getActivity().getActiveShell());
+
+        waitForActiveShellToBeDoneLoading();
+
+        return shell;
+    }
+    /**
      * Loads a URL in the specified content view.
      *
-     * @param viewCore The content view core to load the URL in.
+     * @param navigationController The navigation controller to load the URL in.
      * @param callbackHelperContainer The callback helper container used to monitor progress.
      * @param params The URL params to use.
      */
diff --git a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java
index f13e348e..aa7a08a 100644
--- a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java
+++ b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java
@@ -24,7 +24,6 @@
 import org.chromium.content_shell.Shell;
 import org.chromium.content_shell.ShellManager;
 import org.chromium.ui.base.ActivityWindowAndroid;
-import org.chromium.ui.base.WindowAndroid;
 
 /**
  * Test activity used for verifying the different configuration options for the ContentLinker.
@@ -43,7 +42,7 @@
     private static final String LOW_MEMORY_DEVICE = "--low-memory-device";
 
     private ShellManager mShellManager;
-    private WindowAndroid mWindowAndroid;
+    private ActivityWindowAndroid mWindowAndroid;
 
     @Override
     public void onCreate(final Bundle savedInstanceState) {
@@ -63,21 +62,21 @@
         // reason, so parse the command-line differently here:
         boolean hasLowMemoryDeviceSwitch = false;
         String[] cmdline = CommandLine.getJavaSwitchesOrNull();
-        if (cmdline == null)
+        if (cmdline == null) {
             Log.i(TAG, "Command line is null");
-        else {
+        } else {
             Log.i(TAG, "Command line is:");
             for (int n = 0; n < cmdline.length; ++n) {
                 Log.i(TAG, "  '" + cmdline[n] + "'");
-                if (cmdline[n].equals(LOW_MEMORY_DEVICE))
-                    hasLowMemoryDeviceSwitch = true;
+                if (cmdline[n].equals(LOW_MEMORY_DEVICE)) hasLowMemoryDeviceSwitch = true;
             }
         }
 
         // Determine which kind of device to simulate from the command-line.
         int memoryDeviceConfig = Linker.MEMORY_DEVICE_CONFIG_NORMAL;
-        if (hasLowMemoryDeviceSwitch)
+        if (hasLowMemoryDeviceSwitch) {
             memoryDeviceConfig = Linker.MEMORY_DEVICE_CONFIG_LOW;
+        }
         Linker.setMemoryDeviceConfig(memoryDeviceConfig);
 
         // Register the test runner class by name.
@@ -185,12 +184,14 @@
      *         one is not showing.
      */
     public ContentViewCore getActiveContentViewCore() {
-        if (mShellManager == null)
+        if (mShellManager == null) {
             return null;
+        }
 
         Shell shell = mShellManager.getActiveShell();
-        if (shell == null)
+        if (shell == null) {
             return null;
+        }
 
         return shell.getContentViewCore();
     }
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
index ea0c4e6..a394a1b1 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
@@ -28,7 +28,6 @@
 import org.chromium.content_shell.Shell;
 import org.chromium.content_shell.ShellManager;
 import org.chromium.ui.base.ActivityWindowAndroid;
-import org.chromium.ui.base.WindowAndroid;
 
 /**
  * Activity for managing the Content Shell.
@@ -41,7 +40,7 @@
     public static final String COMMAND_LINE_ARGS_KEY = "commandLineArgs";
 
     private ShellManager mShellManager;
-    private WindowAndroid mWindowAndroid;
+    private ActivityWindowAndroid mWindowAndroid;
     private Intent mLastSentIntent;
 
     @Override
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
index 3c3dda08..7f3563f 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
@@ -23,6 +23,7 @@
 using device::MockBluetoothAdapter;
 using device::MockBluetoothDevice;
 using device::MockBluetoothDiscoverySession;
+using device::MockBluetoothGattCharacteristic;
 using device::MockBluetoothGattConnection;
 using device::MockBluetoothGattService;
 using testing::Between;
@@ -64,7 +65,8 @@
   }
   return NULL;
 }
-}
+
+}  // namespace
 
 namespace content {
 
@@ -174,10 +176,18 @@
   list.push_back(BluetoothUUID("1801"));
   ON_CALL(*empty_device, GetUUIDs()).WillByDefault(Return(list));
 
-  empty_device->AddMockService(
-      GetMockService(empty_device.get(), "1800" /* Generic Access */));
-  empty_device->AddMockService(
-      GetMockService(empty_device.get(), "1801" /* Generic Attribute */));
+  scoped_ptr<NiceMock<MockBluetoothGattService>> generic_access(
+      GetGattService(empty_device.get(), "1800" /* Generic Access */));
+  generic_access->AddMockCharacteristic(
+      GetGattCharacteristic(generic_access.get(), "2A00" /* Device Name */));
+
+  scoped_ptr<NiceMock<MockBluetoothGattService>> generic_attribute(
+      GetGattService(empty_device.get(), "1801" /* Generic Attribute */));
+  generic_attribute->AddMockCharacteristic(GetGattCharacteristic(
+      generic_attribute.get(), "2A05" /* Service Changed */));
+
+  empty_device->AddMockService(generic_access.Pass());
+  empty_device->AddMockService(generic_attribute.Pass());
 
   // Using Invoke allows the device returned from this method to be futher
   // modified and have more services added to it. The call to ::GetGattServices
@@ -187,6 +197,13 @@
       .WillByDefault(
           Invoke(empty_device.get(), &MockBluetoothDevice::GetMockServices));
 
+  // The call to BluetoothDevice::GetGattService will invoke ::GetMockService
+  // which returns a service matching the identifier provided if the service
+  // was added to the mock.
+  ON_CALL(*empty_device, GetGattService(_))
+      .WillByDefault(
+          Invoke(empty_device.get(), &MockBluetoothDevice::GetMockService));
+
   return empty_device.Pass();
 }
 
@@ -223,11 +240,27 @@
 
 // static
 scoped_ptr<NiceMock<MockBluetoothGattService>>
-LayoutTestBluetoothAdapterProvider::GetMockService(MockBluetoothDevice* device,
+LayoutTestBluetoothAdapterProvider::GetGattService(MockBluetoothDevice* device,
                                                    const std::string& uuid) {
-  return make_scoped_ptr(new NiceMock<MockBluetoothGattService>(
-      device, uuid /* identifier */, BluetoothUUID(uuid), true /* is_primary */,
-      false /* is_local */));
+  scoped_ptr<NiceMock<MockBluetoothGattService>> service(
+      new NiceMock<MockBluetoothGattService>(
+          device, uuid /* identifier */, BluetoothUUID(uuid),
+          true /* is_primary */, false /* is_local */));
+
+  ON_CALL(*service, GetCharacteristics())
+      .WillByDefault(Invoke(service.get(),
+                            &MockBluetoothGattService::GetMockCharacteristics));
+  return service.Pass();
+}
+
+// static
+scoped_ptr<NiceMock<MockBluetoothGattCharacteristic>>
+LayoutTestBluetoothAdapterProvider::GetGattCharacteristic(
+    MockBluetoothGattService* service,
+    const std::string& uuid) {
+  return make_scoped_ptr(new NiceMock<MockBluetoothGattCharacteristic>(
+      service, uuid /* identifier */, BluetoothUUID(uuid), false /* is_local */,
+      NULL /* properties */, NULL /* permissions */));
 }
 
 }  // namespace content
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
index fc8efb9..00580e4 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
@@ -10,7 +10,9 @@
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
 #include "device/bluetooth/test/mock_bluetooth_device.h"
 #include "device/bluetooth/test/mock_bluetooth_discovery_session.h"
+#include "device/bluetooth/test/mock_bluetooth_gatt_characteristic.h"
 #include "device/bluetooth/test/mock_bluetooth_gatt_service.h"
+
 namespace content {
 
 // Implements fake adapters with named mock data set for use in tests as a
@@ -71,7 +73,8 @@
   //  - |IsPaired| returns true.
   //  - |GetUUIDs| returns a list with two UUIDs: "1800" and "1801".
   //  - |GetGattServices| returns a list with two services "Generic Access" and
-  //    "Generic Attribute".
+  //    "Generic Attribute". "Generic Access" has a "Device Name" characteristic
+  //    and "Generic Attribute" has a "Service Changed" characteristic.
   static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>>
   GetEmptyDevice(device::MockBluetoothAdapter* adapter);
 
@@ -96,7 +99,18 @@
   // - |IsPrimary| returns true.
   // - |GetDevice| returns |device|.
   static scoped_ptr<testing::NiceMock<device::MockBluetoothGattService>>
-  GetMockService(device::MockBluetoothDevice* device, const std::string& uuid);
+  GetGattService(device::MockBluetoothDevice* device, const std::string& uuid);
+
+  // Returns a fake BluetoothGattCharacteristic with the following
+  // characteristics:
+  // - |GetIdentifier| returns |uuid|.
+  // - |GetUUID| returns BluetoothUUID(|uuid|).
+  // - |IsLocal| returns false.
+  // - |GetService| returns |service|.
+  // - |IsNotifying| returns false.
+  static scoped_ptr<testing::NiceMock<device::MockBluetoothGattCharacteristic>>
+  GetGattCharacteristic(device::MockBluetoothGattService* service,
+                        const std::string& uuid);
 };
 
 }  // namespace content
diff --git a/content/shell/browser/shell_platform_data_aura.cc b/content/shell/browser/shell_platform_data_aura.cc
index d0e806d..6a8423a 100644
--- a/content/shell/browser/shell_platform_data_aura.cc
+++ b/content/shell/browser/shell_platform_data_aura.cc
@@ -5,7 +5,6 @@
 #include "content/shell/browser/shell_platform_data_aura.h"
 
 #include "content/shell/browser/shell.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/default_capture_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/layout_manager.h"
@@ -56,54 +55,6 @@
   DISALLOW_COPY_AND_ASSIGN(FillLayout);
 };
 
-class MinimalInputEventFilter : public ui::internal::InputMethodDelegate,
-                                public ui::EventHandler {
- public:
-  explicit MinimalInputEventFilter(aura::WindowTreeHost* host)
-      : host_(host),
-        input_method_(ui::CreateInputMethod(this,
-                                            gfx::kNullAcceleratedWidget)) {
-    input_method_->OnFocus();
-    host_->window()->AddPreTargetHandler(this);
-    host_->window()->SetProperty(aura::client::kRootWindowInputMethodKey,
-                                 input_method_.get());
-  }
-
-  ~MinimalInputEventFilter() override {
-    host_->window()->RemovePreTargetHandler(this);
-    host_->window()->SetProperty(aura::client::kRootWindowInputMethodKey,
-                                 static_cast<ui::InputMethod*>(NULL));
-  }
-
- private:
-  // ui::EventHandler:
-  void OnKeyEvent(ui::KeyEvent* event) override {
-    // See the comment in InputMethodEventFilter::OnKeyEvent() for details.
-    if (event->IsTranslated()) {
-      event->SetTranslated(false);
-    } else {
-      if (input_method_->DispatchKeyEvent(*event))
-        event->StopPropagation();
-    }
-  }
-
-  // ui::internal::InputMethodDelegate:
-  bool DispatchKeyEventPostIME(const ui::KeyEvent& event) override {
-    // See the comment in InputMethodEventFilter::DispatchKeyEventPostIME() for
-    // details.
-    ui::KeyEvent aura_event(event);
-    aura_event.SetTranslated(true);
-    ui::EventDispatchDetails details =
-        host_->dispatcher()->OnEventFromSource(&aura_event);
-    return aura_event.handled() || details.dispatcher_destroyed;
-  }
-
-  aura::WindowTreeHost* host_;
-  scoped_ptr<ui::InputMethod> input_method_;
-
-  DISALLOW_COPY_AND_ASSIGN(MinimalInputEventFilter);
-};
-
 }
 
 ShellPlatformDataAura* Shell::platform_ = NULL;
@@ -122,7 +73,6 @@
       new aura::client::DefaultCaptureClient(host_->window()));
   window_tree_client_.reset(
       new aura::test::TestWindowTreeClient(host_->window()));
-  ime_filter_.reset(new MinimalInputEventFilter(host_.get()));
 }
 
 ShellPlatformDataAura::~ShellPlatformDataAura() {
diff --git a/content/shell/browser/shell_platform_data_aura.h b/content/shell/browser/shell_platform_data_aura.h
index bc45ec6..d5a2f34 100644
--- a/content/shell/browser/shell_platform_data_aura.h
+++ b/content/shell/browser/shell_platform_data_aura.h
@@ -41,7 +41,6 @@
   scoped_ptr<aura::client::FocusClient> focus_client_;
   scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;
   scoped_ptr<aura::client::WindowTreeClient> window_tree_client_;
-  scoped_ptr<ui::EventHandler> ime_filter_;
 
   DISALLOW_COPY_AND_ASSIGN(ShellPlatformDataAura);
 };
diff --git a/content/shell/renderer/layout_test/blink_test_runner.cc b/content/shell/renderer/layout_test/blink_test_runner.cc
index 009f475..ebba115 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.cc
+++ b/content/shell/renderer/layout_test/blink_test_runner.cc
@@ -23,6 +23,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "components/plugins/renderer/plugin_placeholder.h"
 #include "components/test_runner/app_banner_client.h"
 #include "components/test_runner/gamepad_controller.h"
 #include "components/test_runner/mock_screen_orientation_client.h"
@@ -46,7 +47,6 @@
 #include "content/shell/renderer/layout_test/gc_controller.h"
 #include "content/shell/renderer/layout_test/layout_test_render_process_observer.h"
 #include "content/shell/renderer/layout_test/leak_detector.h"
-#include "content/shell/renderer/layout_test/test_plugin_placeholder.h"
 #include "net/base/filename_util.h"
 #include "net/base/net_errors.h"
 #include "skia/ext/platform_canvas.h"
@@ -688,10 +688,13 @@
 
 blink::WebPlugin* BlinkTestRunner::CreatePluginPlaceholder(
     blink::WebLocalFrame* frame, const blink::WebPluginParams& params) {
-  if (params.mimeType == "application/x-plugin-placeholder-test")
-    return (new TestPluginPlaceholder(render_view()->GetMainRenderFrame(),
-                                      frame, params))->plugin();
-  return 0;
+  if (params.mimeType != "application/x-plugin-placeholder-test")
+    return nullptr;
+
+  plugins::PluginPlaceholder* placeholder =
+      new plugins::PluginPlaceholder(render_view()->GetMainRenderFrame(), frame,
+                                     params, "<div>Test content</div>");
+  return placeholder->plugin();
 }
 
 // RenderViewObserver  --------------------------------------------------------
diff --git a/content/shell/renderer/layout_test/blink_test_runner.h b/content/shell/renderer/layout_test/blink_test_runner.h
index 8f8386b..c2e5369 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.h
+++ b/content/shell/renderer/layout_test/blink_test_runner.h
@@ -15,7 +15,7 @@
 #include "content/public/renderer/render_view_observer.h"
 #include "content/public/renderer/render_view_observer_tracker.h"
 #include "content/shell/common/shell_test_configuration.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationType.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationType.h"
 #include "v8/include/v8.h"
 
 class SkBitmap;
diff --git a/content/shell/renderer/layout_test/test_plugin_placeholder.cc b/content/shell/renderer/layout_test/test_plugin_placeholder.cc
deleted file mode 100644
index 5b5a071..0000000
--- a/content/shell/renderer/layout_test/test_plugin_placeholder.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/shell/renderer/layout_test/test_plugin_placeholder.h"
-
-#include "gin/handle.h"
-#include "third_party/WebKit/public/web/WebKit.h"
-
-namespace content {
-
-TestPluginPlaceholder::TestPluginPlaceholder(
-    RenderFrame* render_frame,
-    blink::WebLocalFrame* frame,
-    const blink::WebPluginParams& params)
-    : PluginPlaceholder(render_frame,
-                        frame,
-                        params,
-                        "<div>Test content</div>",
-                        GURL("http://www.test.com")) {
-}
-
-void TestPluginPlaceholder::BindWebFrame(blink::WebFrame* frame) {
-  v8::Isolate* isolate = blink::mainThreadIsolate();
-  v8::HandleScope handle_scope(isolate);
-  v8::Local<v8::Context> context = frame->mainWorldScriptContext();
-  DCHECK(!context.IsEmpty());
-
-  v8::Context::Scope context_scope(context);
-  v8::Local<v8::Object> global = context->Global();
-  global->Set(gin::StringToV8(isolate, "plugin"),
-              gin::CreateHandle(isolate, this).ToV8());
-}
-
-}  // namespace content
diff --git a/content/shell/renderer/layout_test/test_plugin_placeholder.h b/content/shell/renderer/layout_test/test_plugin_placeholder.h
deleted file mode 100644
index 1424923f..0000000
--- a/content/shell/renderer/layout_test/test_plugin_placeholder.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#ifndef CONTENT_SHELL_RENDERER_TEST_RUNNER_TEST_PLUGIN_PLACEHOLDER_H_
-#define CONTENT_SHELL_RENDERER_TEST_RUNNER_TEST_PLUGIN_PLACEHOLDER_H_
-
-#include "components/plugins/renderer/plugin_placeholder.h"
-
-namespace content {
-
-// A subclass of PluginPlaceholder for use in Blink layout tests.
-class TestPluginPlaceholder : public plugins::PluginPlaceholder {
- public:
-  TestPluginPlaceholder(RenderFrame* render_frame,
-                        blink::WebLocalFrame* frame,
-                        const blink::WebPluginParams& params);
-
-  void BindWebFrame(blink::WebFrame* frame) override;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_RENDERER_TEST_RUNNER_TEST_PLUGIN_PLACEHOLDER_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index c254b4e..8375865 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -304,6 +304,7 @@
       "//third_party/WebKit/public:blink",
       "//third_party/leveldatabase",
       "//third_party/mesa:osmesa",
+      "//third_party/zlib",
       "//ui/accessibility",
       "//ui/accessibility:ax_gen",
       "//ui/base",
@@ -593,6 +594,7 @@
       "../browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc",
       "../browser/web_contents/aura/overscroll_window_animation_unittest.cc",
       "../browser/web_contents/aura/overscroll_window_delegate_unittest.cc",
+      "../browser/web_contents/web_contents_view_aura_unittest.cc",
     ]
   }
   if (use_aura || toolkit_views) {
diff --git a/content/test/content_test_suite.cc b/content/test/content_test_suite.cc
index 20db1eae..116bd0ce 100644
--- a/content/test/content_test_suite.cc
+++ b/content/test/content_test_suite.cc
@@ -4,11 +4,6 @@
 
 #include "content/test/content_test_suite.h"
 
-#if defined(OS_ANDROID)
-#include <android/native_window.h>
-#include <android/native_window_jni.h>
-#endif
-
 #include "base/base_paths.h"
 #include "base/logging.h"
 #include "content/public/common/content_client.h"
@@ -24,11 +19,8 @@
 #if defined(OS_MACOSX)
 #include "base/mac/scoped_nsautorelease_pool.h"
 #if !defined(OS_IOS)
-#include "base/containers/scoped_ptr_hash_map.h"
-#include "base/mac/scoped_mach_port.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/test/mock_chrome_application_mac.h"
-#include "content/common/mac/io_surface_manager.h"
+#include "content/browser/in_process_io_surface_manager_mac.h"
 #endif
 #endif
 
@@ -40,12 +32,7 @@
 #endif
 
 #if defined(OS_ANDROID)
-#include "base/android/jni_android.h"
-#include "base/containers/scoped_ptr_hash_map.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/common/android/surface_texture_manager.h"
-#include "ui/gl/android/scoped_java_surface.h"
-#include "ui/gl/android/surface_texture.h"
+#include "content/browser/android/in_process_surface_texture_manager.h"
 #endif
 
 namespace content {
@@ -71,60 +58,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestInitializationListener);
 };
 
-#if defined(OS_ANDROID)
-class TestSurfaceTextureManager : public SurfaceTextureManager {
- public:
-  // Overridden from SurfaceTextureManager:
-  void RegisterSurfaceTexture(int surface_texture_id,
-                              int client_id,
-                              gfx::SurfaceTexture* surface_texture) override {
-    surfaces_.add(surface_texture_id,
-                  make_scoped_ptr(new gfx::ScopedJavaSurface(surface_texture)));
-  }
-  void UnregisterSurfaceTexture(int surface_texture_id,
-                                int client_id) override {
-    surfaces_.erase(surface_texture_id);
-  }
-  gfx::AcceleratedWidget AcquireNativeWidgetForSurfaceTexture(
-      int surface_texture_id) override {
-    JNIEnv* env = base::android::AttachCurrentThread();
-    return ANativeWindow_fromSurface(
-        env, surfaces_.get(surface_texture_id)->j_surface().obj());
-  }
-
- private:
-  using SurfaceMap =
-      base::ScopedPtrHashMap<int, scoped_ptr<gfx::ScopedJavaSurface>>;
-  SurfaceMap surfaces_;
-};
-#endif
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-class TestIOSurfaceManager : public IOSurfaceManager {
- public:
-  // Overridden from IOSurfaceManager:
-  bool RegisterIOSurface(int io_surface_id,
-                         int client_id,
-                         IOSurfaceRef io_surface) override {
-    io_surfaces_.add(io_surface_id,
-                     make_scoped_ptr(new base::mac::ScopedMachSendRight(
-                         IOSurfaceCreateMachPort(io_surface))));
-    return true;
-  }
-  void UnregisterIOSurface(int io_surface_id, int client_id) override {
-    io_surfaces_.erase(io_surface_id);
-  }
-  IOSurfaceRef AcquireIOSurface(int io_surface_id) override {
-    return IOSurfaceLookupFromMachPort(io_surfaces_.get(io_surface_id)->get());
-  }
-
- private:
-  using IOSurfaceMap =
-      base::ScopedPtrHashMap<int, scoped_ptr<base::mac::ScopedMachSendRight>>;
-  IOSurfaceMap io_surfaces_;
-};
-#endif
-
 }  // namespace
 
 ContentTestSuite::ContentTestSuite(int argc, char** argv)
@@ -153,7 +86,7 @@
   }
   RegisterPathProvider();
 #if !defined(OS_IOS)
-  media::InitializeMediaLibraryForTesting();
+  media::InitializeMediaLibrary();
   // When running in a child process for Mac sandbox tests, the sandbox exists
   // to initialize GL, so don't do it here.
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -166,10 +99,11 @@
       testing::UnitTest::GetInstance()->listeners();
   listeners.Append(new TestInitializationListener);
 #if defined(OS_ANDROID)
-  SurfaceTextureManager::SetInstance(new TestSurfaceTextureManager);
+  SurfaceTextureManager::SetInstance(
+      InProcessSurfaceTextureManager::GetInstance());
 #endif
 #if defined(OS_MACOSX) && !defined(OS_IOS)
-  IOSurfaceManager::SetInstance(new TestIOSurfaceManager);
+  IOSurfaceManager::SetInstance(InProcessIOSurfaceManager::GetInstance());
 #endif
 }
 
diff --git a/content/test/data/navigation_controller/page_with_link_to_load_iframe.html b/content/test/data/navigation_controller/page_with_link_to_load_iframe.html
index 4a868e6..4c17eb8 100644
--- a/content/test/data/navigation_controller/page_with_link_to_load_iframe.html
+++ b/content/test/data/navigation_controller/page_with_link_to_load_iframe.html
@@ -2,6 +2,6 @@
 <head></head>
 <body>
   <p><a href="simple_page_1.html" id="link" target="frame">go</a>
-  <p><iframe src="about:blank" name="frame"></iframe>
+  <p><iframe src="data:text/html,initial" name="frame"></iframe>
 </body>
 </html>
diff --git a/content/test/data/web_ui_mojo_shell_test.html b/content/test/data/web_ui_mojo_shell_test.html
new file mode 100644
index 0000000..39a0e1ae
--- /dev/null
+++ b/content/test/data/web_ui_mojo_shell_test.html
@@ -0,0 +1,3 @@
+<html>
+<script src="web_ui_mojo_shell_test.js"></script>
+</html>
diff --git a/content/test/data/web_ui_mojo_shell_test.js b/content/test/data/web_ui_mojo_shell_test.js
new file mode 100644
index 0000000..1ed35993
--- /dev/null
+++ b/content/test/data/web_ui_mojo_shell_test.js
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+/**
+ * This URL is defined in content/public/test/test_mojo_app.cc. It identifies
+ * content_shell's out-of-process Mojo test app.
+ */
+var TEST_APP_URL = 'system:content_mojo_test';
+
+
+define('main', [
+  'mojo/application/public/interfaces/shell.mojom',
+  'mojo/public/js/core',
+  'mojo/public/js/router',
+  'mojo/services/network/public/interfaces/url_loader.mojom',
+  'content/public/renderer/service_provider',
+  'content/public/test/test_mojo_service.mojom',
+], function(shellMojom, core, router, urlMojom, serviceRegistry, testMojom) {
+
+  var connectToService = function(serviceProvider, iface) {
+    var pipe = core.createMessagePipe();
+    var service = new iface.proxyClass(new router.Router(pipe.handle0));
+    serviceProvider.connectToService(iface.name, pipe.handle1);
+    return service;
+  };
+
+  return function() {
+    domAutomationController.setAutomationId(0);
+    var shellPipe = serviceRegistry.connectToService(shellMojom.Shell.name);
+    var shell = new shellMojom.Shell.proxyClass(new router.Router(shellPipe));
+    var urlRequest = new urlMojom.URLRequest({ url: TEST_APP_URL });
+    shell.connectToApplication(urlRequest,
+        function (services) {
+          var test = connectToService(services, testMojom.TestMojoService);
+          test.getRequestorURL().then(function(response) {
+            // The requestor URL seen by the app should be localhost because the
+            // connection comes from this script hosted on the test server.
+            domAutomationController.send(response.url == 'http://127.0.0.1/');
+          });
+        },
+        function (exposedServices) {});
+  };
+});
diff --git a/content/test/fake_compositor_dependencies.cc b/content/test/fake_compositor_dependencies.cc
index 37ef965..e33554d 100644
--- a/content/test/fake_compositor_dependencies.cc
+++ b/content/test/fake_compositor_dependencies.cc
@@ -17,10 +17,6 @@
 FakeCompositorDependencies::~FakeCompositorDependencies() {
 }
 
-bool FakeCompositorDependencies::IsImplSidePaintingEnabled() {
-  return true;
-}
-
 bool FakeCompositorDependencies::IsGpuRasterizationForced() {
   return false;
 }
diff --git a/content/test/fake_compositor_dependencies.h b/content/test/fake_compositor_dependencies.h
index 463d8d6..9828a0b 100644
--- a/content/test/fake_compositor_dependencies.h
+++ b/content/test/fake_compositor_dependencies.h
@@ -19,7 +19,6 @@
   ~FakeCompositorDependencies() override;
 
   // CompositorDependencies implementation.
-  bool IsImplSidePaintingEnabled() override;
   bool IsGpuRasterizationForced() override;
   bool IsGpuRasterizationEnabled() override;
   int GetGpuRasterizationMSAASampleCount() override;
diff --git a/content/test/fake_renderer_scheduler.cc b/content/test/fake_renderer_scheduler.cc
index cc21750..2a3fe40 100644
--- a/content/test/fake_renderer_scheduler.cc
+++ b/content/test/fake_renderer_scheduler.cc
@@ -68,6 +68,9 @@
 void FakeRendererScheduler::OnRendererVisible() {
 }
 
+void FakeRendererScheduler::OnPageLoadStarted() {
+}
+
 bool FakeRendererScheduler::ShouldYieldForHighPriorityWork() {
   return false;
 }
diff --git a/content/test/fake_renderer_scheduler.h b/content/test/fake_renderer_scheduler.h
index a57e0f9..b4082767 100644
--- a/content/test/fake_renderer_scheduler.h
+++ b/content/test/fake_renderer_scheduler.h
@@ -32,6 +32,7 @@
   void DidAnimateForInputOnCompositorThread() override;
   void OnRendererHidden() override;
   void OnRendererVisible() override;
+  void OnPageLoadStarted() override;
   bool IsHighPriorityWorkAnticipated() override;
   bool CanExceedIdleDeadlineIfRequired() const override;
   bool ShouldYieldForHighPriorityWork() override;
diff --git a/content/test/gpu/gpu_tests/cloud_storage_test_base.py b/content/test/gpu/gpu_tests/cloud_storage_test_base.py
index ba5b380..2cfe4dc 100644
--- a/content/test/gpu/gpu_tests/cloud_storage_test_base.py
+++ b/content/test/gpu/gpu_tests/cloud_storage_test_base.py
@@ -9,11 +9,11 @@
 import re
 import tempfile
 
+from catapult_base import cloud_storage
 from telemetry import benchmark
-from telemetry.image_processing import image_util
-from telemetry.image_processing import rgba_color
 from telemetry.page import page_test
-from telemetry.util import cloud_storage
+from telemetry.util import image_util
+from telemetry.util import rgba_color
 
 
 test_data_dir = os.path.abspath(os.path.join(
diff --git a/content/test/gpu/gpu_tests/context_lost.py b/content/test/gpu/gpu_tests/context_lost.py
index c0c5b66..d41f404 100644
--- a/content/test/gpu/gpu_tests/context_lost.py
+++ b/content/test/gpu/gpu_tests/context_lost.py
@@ -334,7 +334,7 @@
   # options = {'page_repeat': 5}
   def CreatePageSet(self, options):
     ps = page_set.PageSet(
-      file_path=data_path,
+      base_dir=data_path,
       user_agent_type='desktop',
       serving_dirs=set(['']))
     ps.AddUserStory(GPUProcessCrashesExactlyOnce(ps, ps.base_dir))
diff --git a/content/test/gpu/gpu_tests/context_lost_expectations.py b/content/test/gpu/gpu_tests/context_lost_expectations.py
index e5c6a6c..c5b584d 100644
--- a/content/test/gpu/gpu_tests/context_lost_expectations.py
+++ b/content/test/gpu/gpu_tests/context_lost_expectations.py
@@ -19,3 +19,7 @@
     # Mac 10.8 (ideally should restrict this to Debug, too)
     self.Fail('ContextLost.WebGLContextLostFromSelectElement',
               ['mountainlion'], bug=497411)
+
+    # Flaky on Mac 10.7 (ideally should restrict this to Debug, too)
+    self.Fail('ContextLost.WebGLContextLostFromSelectElement',
+              ['lion'], bug=498149)
diff --git a/content/test/gpu/gpu_tests/gpu_rasterization.py b/content/test/gpu/gpu_tests/gpu_rasterization.py
index 9e72814f2..41d18b9 100644
--- a/content/test/gpu/gpu_tests/gpu_rasterization.py
+++ b/content/test/gpu/gpu_tests/gpu_rasterization.py
@@ -7,7 +7,7 @@
 import optparse
 import page_sets
 
-from telemetry.image_processing import image_util
+from telemetry.util import image_util
 
 
 test_harness_script = r"""
diff --git a/content/test/gpu/gpu_tests/gpu_rasterization_expectations.py b/content/test/gpu/gpu_tests/gpu_rasterization_expectations.py
index 9f9b68d..89ec4302 100644
--- a/content/test/gpu/gpu_tests/gpu_rasterization_expectations.py
+++ b/content/test/gpu/gpu_tests/gpu_rasterization_expectations.py
@@ -11,4 +11,7 @@
     # Sample Usage:
     # self.Fail('GpuRasterization.BlueBox',
     #     ['mac', 'amd', ('nvidia', 0x1234)], bug=123)
-    pass
+
+    # Failing on Nexus 5 and 6
+    self.Fail('GpuRasterization.ConcavePaths',
+              ['android', 'qualcomm'], bug=499555)
diff --git a/content/test/gpu/gpu_tests/gpu_test_expectations.py b/content/test/gpu/gpu_tests/gpu_test_expectations.py
index 9bb354172..464c7bc 100644
--- a/content/test/gpu/gpu_tests/gpu_test_expectations.py
+++ b/content/test/gpu/gpu_tests/gpu_test_expectations.py
@@ -15,7 +15,7 @@
 #     vivante
 #
 # Browser types:
-#     android-webview-shell
+#     android-webview-shell, android-content-shell
 #
 # ANGLE renderer:
 #     d3d9, d3d11, opengl
@@ -30,7 +30,7 @@
 
 ANGLE_MODIFIERS = ['d3d9', 'd3d11', 'opengl']
 
-BROWSER_TYPE_MODIFIERS = ['android-webview-shell']
+BROWSER_TYPE_MODIFIERS = ['android-webview-shell', 'android-content-shell']
 
 class GpuTestExpectations(test_expectations.TestExpectations):
   def IsValidUserDefinedCondition(self, condition):
diff --git a/content/test/gpu/gpu_tests/hardware_accelerated_feature.py b/content/test/gpu/gpu_tests/hardware_accelerated_feature.py
index af81c0d2..52dd131 100644
--- a/content/test/gpu/gpu_tests/hardware_accelerated_feature.py
+++ b/content/test/gpu/gpu_tests/hardware_accelerated_feature.py
@@ -59,7 +59,7 @@
   def CreatePageSet(self, options):
     features = ['WebGL', 'Canvas']
 
-    ps = page_set.PageSet(user_agent_type='desktop', file_path='')
+    ps = page_set.PageSet(user_agent_type='desktop')
 
     for feature in features:
       ps.AddUserStory(ChromeGpuPage(page_set=ps, feature=feature))
diff --git a/content/test/gpu/gpu_tests/maps.py b/content/test/gpu/gpu_tests/maps.py
index 430657d..8960c7a1 100644
--- a/content/test/gpu/gpu_tests/maps.py
+++ b/content/test/gpu/gpu_tests/maps.py
@@ -101,7 +101,7 @@
     page_set_path = os.path.join(
         util.GetChromiumSrcDir(), 'content', 'test', 'gpu', 'page_sets')
     ps = page_set.PageSet(archive_data_file='data/maps.json',
-                          file_path=page_set_path,
+                          base_dir=page_set_path,
                           bucket=page_set.PUBLIC_BUCKET)
     ps.AddUserStory(MapsPage(ps, ps.base_dir))
     return ps
diff --git a/content/test/gpu/gpu_tests/pixel.py b/content/test/gpu/gpu_tests/pixel.py
index 6db39cbe..f6d46811 100644
--- a/content/test/gpu/gpu_tests/pixel.py
+++ b/content/test/gpu/gpu_tests/pixel.py
@@ -11,10 +11,10 @@
 import page_sets
 import pixel_expectations
 
+from catapult_base import cloud_storage
 from telemetry import benchmark
-from telemetry.image_processing import image_util
 from telemetry.page import page_test
-from telemetry.util import cloud_storage
+from telemetry.util import image_util
 
 
 test_data_dir = os.path.abspath(os.path.join(
diff --git a/content/test/gpu/gpu_tests/screenshot_sync.py b/content/test/gpu/gpu_tests/screenshot_sync.py
index 1adfeed..942080a9 100644
--- a/content/test/gpu/gpu_tests/screenshot_sync.py
+++ b/content/test/gpu/gpu_tests/screenshot_sync.py
@@ -8,10 +8,10 @@
 
 from telemetry import benchmark
 from telemetry.core import util
-from telemetry.image_processing import image_util
 from telemetry.page import page
 from telemetry.page import page_set
 from telemetry.page import page_test
+from telemetry.util import image_util
 
 data_path = os.path.join(
     util.GetChromiumSrcDir(), 'content', 'test', 'data', 'gpu')
@@ -69,6 +69,6 @@
     return expectations.ScreenshotSyncExpectations()
 
   def CreatePageSet(self, options):
-    ps = page_set.PageSet(file_path=data_path, serving_dirs=[''])
+    ps = page_set.PageSet(base_dir=data_path, serving_dirs=[''])
     ps.AddUserStory(ScreenshotSyncPage(ps, ps.base_dir))
     return ps
diff --git a/content/test/gpu/gpu_tests/webgl_conformance.py b/content/test/gpu/gpu_tests/webgl_conformance.py
index 78030ce7..9f9f2f5 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance.py
@@ -9,6 +9,7 @@
 import webgl_conformance_expectations
 
 from telemetry import benchmark as benchmark_module
+from telemetry.core import browser_finder
 from telemetry.core import util
 from telemetry.page import page as page_module
 from telemetry.page import page_set
@@ -97,6 +98,11 @@
         '--disable-gpu-process-crash-limit',
         '--enable-unsafe-es3-apis'
     ])
+    target_os = browser_finder.FindBrowser(options.finder_options).target_os
+    if target_os.startswith('win'):
+      options.AppendExtraBrowserArgs([
+          '--use-gl=desktop'
+      ])
 
 
 class WebglConformancePage(page_module.Page):
@@ -145,7 +151,7 @@
     ps = page_set.PageSet(
       user_agent_type='desktop',
       serving_dirs=[''],
-      file_path=conformance_path)
+      base_dir=conformance_path)
 
     for test in tests:
       ps.AddUserStory(WebglConformancePage(ps, test))
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 4ec4450..ff4ccca8 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -147,6 +147,16 @@
         ['win', 'opengl'], bug=1007) # angle bug ID
     self.Fail('conformance/textures/tex-image-canvas-corruption.html',
         ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('deqp/data/gles2/shaders/conditionals.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('deqp/data/gles2/shaders/conversions.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('deqp/data/gles2/shaders/qualification_order.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+
+    # Skip all WebGL CTS on OpenGL+AMD/Intel
+    self.Skip('*', ['win', 'opengl', 'amd'], bug=1007) # angle bug ID
+    self.Skip('*', ['win', 'opengl', 'intel'], bug=1007) # angle bug ID
 
     # Mac failures
     self.Fail('conformance/glsl/misc/shaders-with-invariance.html',
@@ -319,7 +329,95 @@
         ['android', 'android-webview-shell'], bug=352645)
     self.Fail('conformance/textures/texture-npot-video.html',
         ['android', 'android-webview-shell'], bug=352645)
-
+    # Recent regressions have caused these to fail on multiple devices
+    self.Fail('conformance/textures/tex-image-and-sub-image-2d-with-video.html',
+        ['android', 'android-content-shell'], bug=499555)
+    self.Fail('conformance/textures/' +
+        'tex-image-and-sub-image-2d-with-video-rgb565.html',
+        ['android', 'android-content-shell'], bug=499555)
+    self.Fail('conformance/textures/' +
+        'tex-image-and-sub-image-2d-with-video-rgba4444.html',
+        ['android', 'android-content-shell'], bug=499555)
+    self.Fail('conformance/textures/' +
+        'tex-image-and-sub-image-2d-with-video-rgba5551.html',
+        ['android', 'android-content-shell'], bug=499555)
+    # These are failing on the Nexus 5 and 6
+    self.Fail('conformance/extensions/oes-texture-float-with-canvas.html',
+              ['android', 'qualcomm'], bug=499555)
+    self.Fail('conformance/extensions/oes-texture-float-with-video.html',
+              ['android', 'qualcomm'], bug=499555)
+    # Nexus 6 failures only
+    self.Fail('conformance/context/' +
+              'context-attributes-alpha-depth-stencil-antialias.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/context/premultiplyalpha-test.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/extensions/oes-texture-float-with-canvas.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/extensions/oes-texture-float-with-image-data.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/extensions/oes-texture-float-with-image.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/extensions/oes-texture-float-with-video.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/rendering/gl-scissor-test.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'copy-tex-image-and-sub-image-2d.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-array-buffer-view.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-canvas.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-canvas-rgb565.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-canvas-rgba4444.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-canvas-rgba5551.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-image-data.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-image-data-rgb565.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-image-data-rgba4444.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-image-data-rgba5551.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-image.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-image-rgb565.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-image-rgba4444.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-image-rgba5551.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-webgl-canvas.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-webgl-canvas-rgb565.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-webgl-canvas-rgba4444.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/' +
+              'tex-image-and-sub-image-2d-with-webgl-canvas-rgba5551.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
+    self.Fail('conformance/textures/texture-npot-video.html',
+              ['android', ('qualcomm', 'Adreno (TM) 420')], bug=499555)
 
     # The following test is very slow and therefore times out on Android bot.
     self.Skip('conformance/rendering/multisample-corruption.html',
@@ -480,15 +578,23 @@
     self.Fail('conformance2/textures/tex-mipmap-levels.html', bug=483282)
     self.Fail('conformance2/textures/tex-new-formats.html', bug=483282)
     self.Fail('conformance2/textures/tex-storage-2d.html', bug=483282)
+    self.Fail('conformance2/textures/tex-storage-and-subimage-3d.html',
+        bug=483282)
     self.Fail('conformance2/textures/texture-npot.html', bug=483282)
     self.Fail('conformance2/transform_feedback/transform_feedback.html',
         bug=483282)
 
     # Mac only.
+    self.Fail('conformance2/glsl3/array-as-return-value.html',
+        ['mac'], bug=483282)
+    self.Fail('conformance2/glsl3/array-assign.html',
+        ['mac'], bug=483282)
+    self.Fail('conformance2/glsl3/array-equality.html',
+        ['mac'], bug=483282)
+    self.Fail('conformance2/glsl3/array-in-complex-expression.html',
+        ['mac'], bug=483282)
     self.Fail('conformance2/renderbuffers/' +
         'multisampled-renderbuffer-initialization.html',
         ['mac'], bug=483282)
     self.Fail('conformance2/rendering/instanced-arrays.html',
         ['mac'], bug=483282)
-    self.Fail('conformance2/textures/tex-storage-and-subimage-3d.html',
-        ['mac'], bug=483282)
diff --git a/content/test/gpu/gpu_tests/webgl_robustness.py b/content/test/gpu/gpu_tests/webgl_robustness.py
index 464bbf7f..7660497 100644
--- a/content/test/gpu/gpu_tests/webgl_robustness.py
+++ b/content/test/gpu/gpu_tests/webgl_robustness.py
@@ -67,7 +67,7 @@
 
   def CreatePageSet(self, options):
     ps = page_set.PageSet(
-      file_path=conformance_path,
+      base_dir=conformance_path,
       user_agent_type='desktop',
       serving_dirs=[''])
     ps.AddUserStory(WebglRobustnessPage(ps, ps.base_dir))
diff --git a/content/test/gpu/page_sets/PRESUBMIT.py b/content/test/gpu/page_sets/PRESUBMIT.py
index c110e56d..5b8d0ad 100644
--- a/content/test/gpu/page_sets/PRESUBMIT.py
+++ b/content/test/gpu/page_sets/PRESUBMIT.py
@@ -18,7 +18,7 @@
     try:
       telemetry_path = _GetTelemetryPath(input_api)
       sys.path = [telemetry_path] + sys.path
-      from telemetry.util import cloud_storage
+      from catapult_base import cloud_storage
       globals()['cloud_storage'] = cloud_storage
     finally:
       sys.path = _old_sys_path
diff --git a/content/test/mock_webclipboard_impl.cc b/content/test/mock_webclipboard_impl.cc
index 8a6e7748..eb9677b8 100644
--- a/content/test/mock_webclipboard_impl.cc
+++ b/content/test/mock_webclipboard_impl.cc
@@ -176,11 +176,11 @@
     switch (item.storageType) {
       case WebDragData::Item::StorageTypeString: {
         ++m_sequenceNumber;
-        if (EqualsASCII(item.stringType, ui::Clipboard::kMimeTypeText)) {
+        if (base::EqualsASCII(item.stringType, ui::Clipboard::kMimeTypeText)) {
           m_plainText = item.stringData;
           continue;
         }
-        if (EqualsASCII(item.stringType, ui::Clipboard::kMimeTypeHTML)) {
+        if (base::EqualsASCII(item.stringType, ui::Clipboard::kMimeTypeHTML)) {
           m_htmlText = item.stringData;
           continue;
         }
diff --git a/content/test/net/url_request_abort_on_end_job.cc b/content/test/net/url_request_abort_on_end_job.cc
index 8bfd7f9..3fd494f 100644
--- a/content/test/net/url_request_abort_on_end_job.cc
+++ b/content/test/net/url_request_abort_on_end_job.cc
@@ -67,8 +67,8 @@
     net::HttpResponseInfo* info) const {
   // Send back mock headers.
   std::string raw_headers;
-  if (LowerCaseEqualsASCII(k400AbortOnEndUrl,
-                           request_->url().spec().c_str())) {
+  if (base::LowerCaseEqualsASCII(k400AbortOnEndUrl,
+                                 request_->url().spec().c_str())) {
     raw_headers.append(
       "HTTP/1.1 400 This is not OK\n"
       "Content-type: text/plain\n");
diff --git a/content/test/plugin/plugin_test.cc b/content/test/plugin/plugin_test.cc
index eb2d8640..84ad5ab 100644
--- a/content/test/plugin/plugin_test.cc
+++ b/content/test/plugin/plugin_test.cc
@@ -121,7 +121,7 @@
 
 void PluginTest::ExpectStringLowerCaseEqual(const std::string &val1,
                                             const std::string &val2) {
-  if (!LowerCaseEqualsASCII(val1, val2.c_str())) {
+  if (!base::LowerCaseEqualsASCII(val1, val2.c_str())) {
     std::string err;
     err = "Expected Equal for '";
     err.append(val1);
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc
index 0739137..177f7d6a 100644
--- a/content/test/test_blink_web_unit_test_support.cc
+++ b/content/test/test_blink_web_unit_test_support.cc
@@ -129,19 +129,9 @@
   blink::WebRuntimeFeatures::enableNotifications(true);
   blink::WebRuntimeFeatures::enableTouch(true);
 
-  // Load libraries for media and enable the media player.
-  bool enable_media = false;
-  base::FilePath module_path;
-  if (PathService::Get(base::DIR_MODULE, &module_path)) {
-#if defined(OS_MACOSX)
-    if (base::mac::AmIBundled())
-      module_path = module_path.DirName().DirName().DirName();
-#endif
-    if (media::InitializeMediaLibrary(module_path))
-      enable_media = true;
-  }
-  blink::WebRuntimeFeatures::enableMediaPlayer(enable_media);
-  LOG_IF(WARNING, !enable_media) << "Failed to initialize the media library.\n";
+  // Initialize libraries for media and enable the media player.
+  media::InitializeMediaLibrary();
+  blink::WebRuntimeFeatures::enableMediaPlayer(true);
 
   file_utilities_.set_sandbox_enabled(false);
 
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index b852b0b..73b8c06 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -28,7 +28,7 @@
 namespace content {
 
 TestWebContents::TestWebContents(BrowserContext* browser_context)
-    : WebContentsImpl(browser_context, NULL),
+    : WebContentsImpl(browser_context),
       delegate_view_override_(NULL),
       expect_set_history_offset_and_length_(false),
       expect_set_history_offset_and_length_history_length_(0) {
@@ -219,10 +219,7 @@
 }
 
 void TestWebContents::SetOpener(TestWebContents* opener) {
-  // This is normally only set in the WebContents constructor, which also
-  // registers an observer for when the opener gets closed.
-  opener_ = opener;
-  AddDestructionObserver(opener_);
+  frame_tree_.root()->SetOpener(opener->GetFrameTree()->root());
 }
 
 void TestWebContents::AddPendingContents(TestWebContents* contents) {
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index de3a103..b94aed6 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -79,7 +79,8 @@
     delegate_view_override_ = view;
   }
 
-  // Allows us to simulate this tab having an opener.
+  // Allows us to simulate this tab's main frame having an opener that points
+  // to the main frame of the |opener|.
   void SetOpener(TestWebContents* opener);
 
   // Allows us to simulate that a contents was created via CreateNewWindow.
diff --git a/crypto/crypto_unittests.isolate b/crypto/crypto_unittests.isolate
index 93272b43..e09095c 100644
--- a/crypto/crypto_unittests.isolate
+++ b/crypto/crypto_unittests.isolate
@@ -2,44 +2,18 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 {
+  'variables': {
+    'command': [
+      '../testing/test_env.py',
+      '<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)',
+      '--brave-new-test-launcher',
+      '--test-launcher-bot-mode',
+      '--asan=<(asan)',
+      '--msan=<(msan)',
+      '--tsan=<(tsan)',
+    ],
+  },
   'conditions': [
-    ['use_x11==0', {
-      'variables': {
-        'command': [
-          '../testing/test_env.py',
-          '<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)',
-          '--brave-new-test-launcher',
-          '--test-launcher-bot-mode',
-          '--asan=<(asan)',
-          '--msan=<(msan)',
-          '--tsan=<(tsan)',
-        ],
-      },
-    }],
-    ['use_x11==1', {
-      'variables': {
-        'command': [
-          '../testing/xvfb.py',
-          '<(PRODUCT_DIR)',
-          '<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)',
-          '--brave-new-test-launcher',
-          '--test-launcher-bot-mode',
-          '--asan=<(asan)',
-          '--msan=<(msan)',
-          '--tsan=<(tsan)',
-        ],
-        'files': [
-          '../testing/xvfb.py',
-        ],
-      },
-    }],
-    ['OS=="linux" and use_ozone==0', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
-        ],
-      },
-    }],
     ['OS=="linux" or OS=="mac" or OS=="win"', {
       'variables': {
         'files': [
diff --git a/crypto/nss_key_util_unittest.cc b/crypto/nss_key_util_unittest.cc
index f8de8e2..ff4d55a 100644
--- a/crypto/nss_key_util_unittest.cc
+++ b/crypto/nss_key_util_unittest.cc
@@ -50,7 +50,7 @@
   // Create an NSS keypair, which will put the keys in the user's NSSDB.
   ScopedSECKEYPublicKey public_key;
   ScopedSECKEYPrivateKey private_key;
-  ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 256,
+  ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 512,
                                     false /* not permanent */, &public_key,
                                     &private_key));
 
@@ -68,7 +68,7 @@
   // Create an NSS keypair, which will put the keys in the user's NSSDB.
   ScopedSECKEYPublicKey public_key;
   ScopedSECKEYPrivateKey private_key;
-  ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 256,
+  ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 512,
                                     false /* not permanent */, &public_key,
                                     &private_key));
 
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc
index df93160..125591c 100644
--- a/crypto/nss_util.cc
+++ b/crypto/nss_util.cc
@@ -37,7 +37,6 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram.h"
 #include "base/native_library.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
@@ -685,8 +684,6 @@
         initializing_tpm_token_(false),
         chaps_module_(NULL),
         root_(NULL) {
-    base::TimeTicks start_time = base::TimeTicks::Now();
-
     // It's safe to construct on any thread, since LazyInstance will prevent any
     // other threads from accessing until the constructor is done.
     thread_checker_.DetachFromThread();
@@ -783,14 +780,6 @@
     NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
     NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
                            0, NSS_USE_ALG_IN_CERT_SIGNATURE);
-
-    // The UMA bit is conditionally set for this histogram in
-    // components/startup_metric_utils.cc .
-    LOCAL_HISTOGRAM_CUSTOM_TIMES("Startup.SlowStartupNSSInit",
-                                 base::TimeTicks::Now() - start_time,
-                                 base::TimeDelta::FromMilliseconds(10),
-                                 base::TimeDelta::FromHours(1),
-                                 50);
   }
 
   // NOTE(willchan): We don't actually execute this code since we leak NSS to
diff --git a/crypto/rsa_private_key_unittest.cc b/crypto/rsa_private_key_unittest.cc
index b231cac..9e7f6ff5 100644
--- a/crypto/rsa_private_key_unittest.cc
+++ b/crypto/rsa_private_key_unittest.cc
@@ -447,7 +447,8 @@
 
 TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) {
   scoped_ptr<crypto::RSAPrivateKey> key_pair(
-      crypto::RSAPrivateKey::Create(256));
+      crypto::RSAPrivateKey::Create(512));
+  ASSERT_TRUE(key_pair.get());
 
   scoped_ptr<crypto::RSAPrivateKey> key_copy(
       crypto::RSAPrivateKey::CreateFromKey(key_pair->key()));
diff --git a/dbus/file_descriptor.cc b/dbus/file_descriptor.cc
index e607fc0..c67a9e1 100644
--- a/dbus/file_descriptor.cc
+++ b/dbus/file_descriptor.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <algorithm>
+
 #include "base/bind.h"
 #include "base/files/file.h"
 #include "base/location.h"
@@ -9,6 +11,8 @@
 #include "base/threading/worker_pool.h"
 #include "dbus/file_descriptor.h"
 
+using std::swap;
+
 namespace dbus {
 
 void CHROME_DBUS_EXPORT FileDescriptor::Deleter::operator()(
@@ -17,11 +21,21 @@
       FROM_HERE, base::Bind(&base::DeletePointer<FileDescriptor>, fd), false);
 }
 
+FileDescriptor::FileDescriptor(RValue other)
+    : value_(-1), owner_(false), valid_(false) {
+  Swap(other.object);
+}
+
 FileDescriptor::~FileDescriptor() {
   if (owner_)
     base::File auto_closer(value_);
 }
 
+FileDescriptor& FileDescriptor::operator=(RValue other) {
+  Swap(other.object);
+  return *this;
+}
+
 int FileDescriptor::value() const {
   CHECK(valid_);
   return value_;
@@ -41,4 +55,10 @@
   valid_ = (ok && !info.is_directory);
 }
 
+void FileDescriptor::Swap(FileDescriptor* other) {
+  swap(value_, other->value_);
+  swap(owner_, other->owner_);
+  swap(valid_, other->valid_);
+}
+
 }  // namespace dbus
diff --git a/dbus/file_descriptor.h b/dbus/file_descriptor.h
index a01ee6e..8a41097 100644
--- a/dbus/file_descriptor.h
+++ b/dbus/file_descriptor.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/move.h"
 #include "dbus/dbus_export.h"
 
 namespace dbus {
@@ -33,6 +34,8 @@
 // also allows the caller to do this work on the File thread to conform
 // with i/o restrictions.
 class CHROME_DBUS_EXPORT FileDescriptor {
+  MOVE_ONLY_TYPE_FOR_CPP_03(FileDescriptor, RValue);
+
  public:
   // This provides a simple way to pass around file descriptors since they must
   // be closed on a thread that is allowed to perform I/O.
@@ -46,8 +49,14 @@
   explicit FileDescriptor(int value) : value_(value), owner_(false),
       valid_(false) {}
 
+  // Move constructor for C++03 move emulation of this type.
+  FileDescriptor(RValue other);
+
   virtual ~FileDescriptor();
 
+  // Move operator= for C++03 move emulation of this type.
+  FileDescriptor& operator=(RValue other);
+
   // Retrieves value as an int without affecting ownership.
   int value() const;
 
@@ -70,11 +79,11 @@
   void CheckValidity();
 
  private:
+  void Swap(FileDescriptor* other);
+
   int value_;
   bool owner_;
   bool valid_;
-
-  DISALLOW_COPY_AND_ASSIGN(FileDescriptor);
 };
 
 using ScopedFileDescriptor =
diff --git a/dbus/string_util.cc b/dbus/string_util.cc
index f35c9b3a..0323e4a 100644
--- a/dbus/string_util.cc
+++ b/dbus/string_util.cc
@@ -14,7 +14,7 @@
   const bool kCaseSensitive = true;
 
   // A valid object path begins with '/'.
-  if (!StartsWithASCII(value, "/", kCaseSensitive))
+  if (!base::StartsWithASCII(value, "/", kCaseSensitive))
     return false;
 
   // Elements are pieces delimited by '/'. For instance, "org", "chromium",
diff --git a/device/BUILD.gn b/device/BUILD.gn
index ee53932..8bb5e11 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -90,9 +90,9 @@
   # USB does not compile on mobile platforms.
   if (!is_android && !is_ios) {
     sources += [
+      "devices_app/usb/device_impl_unittest.cc",
+      "devices_app/usb/device_manager_impl_unittest.cc",
       "test/usb_test_gadget_impl.cc",
-      "usb/device_impl_unittest.cc",
-      "usb/device_manager_impl_unittest.cc",
       "usb/usb_context_unittest.cc",
       "usb/usb_device_filter_unittest.cc",
       "usb/usb_device_handle_unittest.cc",
@@ -101,8 +101,9 @@
     ]
     deps += [
       "//device/core",
-      "//device/usb/public/cpp",
-      "//device/usb/public/interfaces",
+      "//device/devices_app:lib",
+      "//device/devices_app/usb/public/cpp",
+      "//device/devices_app/usb/public/interfaces",
       "//device/usb",
       "//device/usb:mocks",
       "//third_party/libusb",
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.h b/device/bluetooth/test/mock_bluetooth_adapter.h
index cd8b8a1b..547a9cf 100644
--- a/device/bluetooth/test/mock_bluetooth_adapter.h
+++ b/device/bluetooth/test/mock_bluetooth_adapter.h
@@ -102,7 +102,7 @@
       const ErrorCallback& error_callback);
 
   // BluetoothAdapter is supposed to manage the lifetime of BluetoothDevices.
-  // This methods takes ownership of the BluetoothDevices. This is only for
+  // This method takes ownership of the MockBluetoothDevice. This is only for
   // convenience as far testing is concerned and it's possible to write test
   // cases without using these functions.
   void AddMockDevice(scoped_ptr<MockBluetoothDevice> mock_device);
diff --git a/device/bluetooth/test/mock_bluetooth_device.cc b/device/bluetooth/test/mock_bluetooth_device.cc
index 928d98c..19b67a31 100644
--- a/device/bluetooth/test/mock_bluetooth_device.cc
+++ b/device/bluetooth/test/mock_bluetooth_device.cc
@@ -71,4 +71,13 @@
   return services;
 }
 
+BluetoothGattService* MockBluetoothDevice::GetMockService(
+    const std::string& identifier) const {
+  for (BluetoothGattService* service : mock_services_) {
+    if (service->GetIdentifier() == identifier)
+      return service;
+  }
+  return nullptr;
+}
+
 }  // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_device.h b/device/bluetooth/test/mock_bluetooth_device.h
index 2d16e469..b5948f65 100644
--- a/device/bluetooth/test/mock_bluetooth_device.h
+++ b/device/bluetooth/test/mock_bluetooth_device.h
@@ -83,15 +83,16 @@
   MOCK_CONST_METHOD1(GetGattService, BluetoothGattService*(const std::string&));
 
   // BluetoothDevice manages the lifetime of its BluetoothGATTServices.
-  // This methods takes ownership of the BluetoothGATTServices. This is only for
-  // convenience as far as testing is concerned, and it's possible to write test
-  // cases without using these functions.
+  // This method takes ownership of the MockBluetoothGATTServices. This is only
+  // for convenience as far as testing is concerned, and it's possible to write
+  // test cases without using these functions.
   // Example:
   // ON_CALL(*mock_device, GetGattServices))
   //   .WillByDefault(Invoke(*mock_device,
   //                         &MockBluetoothDevice::GetMockServices));
   void AddMockService(scoped_ptr<MockBluetoothGattService> mock_device);
   std::vector<BluetoothGattService*> GetMockServices() const;
+  BluetoothGattService* GetMockService(const std::string& identifier) const;
 
  private:
   uint32 bluetooth_class_;
diff --git a/device/bluetooth/test/mock_bluetooth_gatt_service.cc b/device/bluetooth/test/mock_bluetooth_gatt_service.cc
index 37392a6..faba596 100644
--- a/device/bluetooth/test/mock_bluetooth_gatt_service.cc
+++ b/device/bluetooth/test/mock_bluetooth_gatt_service.cc
@@ -33,4 +33,18 @@
 MockBluetoothGattService::~MockBluetoothGattService() {
 }
 
+void MockBluetoothGattService::AddMockCharacteristic(
+    scoped_ptr<MockBluetoothGattCharacteristic> mock_characteristic) {
+  mock_characteristics_.push_back(mock_characteristic.Pass());
+}
+
+std::vector<BluetoothGattCharacteristic*>
+MockBluetoothGattService::GetMockCharacteristics() const {
+  std::vector<BluetoothGattCharacteristic*> characteristics;
+  for (BluetoothGattCharacteristic* characteristic : mock_characteristics_) {
+    characteristics.push_back(characteristic);
+  }
+  return characteristics;
+}
+
 }  // namespace device
diff --git a/device/bluetooth/test/mock_bluetooth_gatt_service.h b/device/bluetooth/test/mock_bluetooth_gatt_service.h
index b03adfae..1ba3dea 100644
--- a/device/bluetooth/test/mock_bluetooth_gatt_service.h
+++ b/device/bluetooth/test/mock_bluetooth_gatt_service.h
@@ -8,8 +8,10 @@
 #include <string>
 #include <vector>
 
+#include "base/memory/scoped_vector.h"
 #include "device/bluetooth/bluetooth_gatt_service.h"
 #include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/test/mock_bluetooth_gatt_characteristic.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace device {
@@ -41,7 +43,23 @@
   MOCK_METHOD2(Register, void(const base::Closure&, const ErrorCallback&));
   MOCK_METHOD2(Unregister, void(const base::Closure&, const ErrorCallback&));
 
+  // BluetoothGattService manages the lifetime of its
+  // BluetoothGATTCharacteristics.
+  // This method takes ownership of the MockBluetoothGATTCharacteristics. This
+  // is only for convenience as far as testing is concerned, and it's possible
+  // to write test cases without using these functions.
+  // Example:
+  // ON_CALL(*mock_service, GetCharacteristics))
+  //   .WillByDefault(Invoke(
+  //     *mock_service,
+  //      &MockBluetoothGattService::GetMockCharacteristics));
+  void AddMockCharacteristic(
+      scoped_ptr<MockBluetoothGattCharacteristic> mock_characteristic);
+  std::vector<BluetoothGattCharacteristic*> GetMockCharacteristics() const;
+
  private:
+  ScopedVector<MockBluetoothGattCharacteristic> mock_characteristics_;
+
   DISALLOW_COPY_AND_ASSIGN(MockBluetoothGattService);
 };
 
diff --git a/device/core/BUILD.gn b/device/core/BUILD.gn
index 6b84cea..d931807 100644
--- a/device/core/BUILD.gn
+++ b/device/core/BUILD.gn
@@ -12,6 +12,5 @@
 
   public_deps = [
     "//base",
-    "//third_party/mojo/src/mojo/public/cpp/bindings",
   ]
 }
diff --git a/device/core/device_client.cc b/device/core/device_client.cc
index 2aca216..52021221 100644
--- a/device/core/device_client.cc
+++ b/device/core/device_client.cc
@@ -35,10 +35,6 @@
   return NULL;
 }
 
-void DeviceClient::ConnectToUSBDeviceManager(
-    mojo::InterfaceRequest<usb::DeviceManager> request) {
-}
-
 HidService* DeviceClient::GetHidService() {
   // This should never be called by clients which do not support the HID API.
   NOTREACHED();
diff --git a/device/core/device_client.h b/device/core/device_client.h
index 00fa179..d63471b 100644
--- a/device/core/device_client.h
+++ b/device/core/device_client.h
@@ -6,7 +6,6 @@
 #define DEVICE_CORE_DEVICE_CLIENT_H_
 
 #include "base/macros.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
 
 namespace device {
 
@@ -34,11 +33,6 @@
   // Returns the UsbService instance for this embedder.
   virtual UsbService* GetUsbService();
 
-  // Connects a USB DeviceManager client to a concrete implementation. If
-  // no such implementation is available the request is dropped.
-  virtual void ConnectToUSBDeviceManager(
-      mojo::InterfaceRequest<usb::DeviceManager> request);
-
   // Returns the HidService instance for this embedder.
   virtual HidService* GetHidService();
 
diff --git a/device/device_tests.gyp b/device/device_tests.gyp
index 7604cab..9300362 100644
--- a/device/device_tests.gyp
+++ b/device/device_tests.gyp
@@ -22,6 +22,7 @@
         'battery/battery.gyp:device_battery_mojo_bindings',
         'bluetooth/bluetooth.gyp:device_bluetooth',
         'bluetooth/bluetooth.gyp:device_bluetooth_mocks',
+        'devices_app/devices_app.gyp:devices_app_lib',
         'nfc/nfc.gyp:device_nfc',
         'usb/usb.gyp:device_usb',
         'usb/usb.gyp:device_usb_mocks',
@@ -52,6 +53,8 @@
         'bluetooth/bluetooth_uuid_unittest.cc',
         'bluetooth/test/test_bluetooth_adapter_observer.cc',
         'bluetooth/test/test_bluetooth_adapter_observer.h',
+        'devices_app/usb/device_impl_unittest.cc',
+        'devices_app/usb/device_manager_impl_unittest.cc',
         'hid/hid_connection_unittest.cc',
         'hid/hid_device_filter_unittest.cc',
         'hid/hid_report_descriptor_unittest.cc',
@@ -66,8 +69,6 @@
         'serial/serial_service_unittest.cc',
         'test/run_all_unittests.cc',
         'test/usb_test_gadget_impl.cc',
-        'usb/device_impl_unittest.cc',
-        'usb/device_manager_impl_unittest.cc',
         'usb/usb_context_unittest.cc',
         'usb/usb_device_filter_unittest.cc',
         'usb/usb_device_handle_unittest.cc',
@@ -89,6 +90,7 @@
         ['OS=="android"', {
           'dependencies!': [
             '../tools/usb_gadget/usb_gadget.gyp:usb_gadget',
+            'devices_app/devices_app.gyp:devices_app_lib',
             'usb/usb.gyp:device_usb',
             'usb/usb.gyp:device_usb_mocks',
             'serial/serial.gyp:device_serial',
diff --git a/device/devices_app/BUILD.gn b/device/devices_app/BUILD.gn
new file mode 100644
index 0000000..233d2633
--- /dev/null
+++ b/device/devices_app/BUILD.gn
@@ -0,0 +1,73 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/mojo_application.gni")
+
+source_set("lib") {
+  sources = [
+    "devices_app.cc",
+    "devices_app.h",
+    "usb/device_impl.cc",
+    "usb/device_impl.h",
+    "usb/device_manager_impl.cc",
+    "usb/device_manager_impl.h",
+    "usb/type_converters.cc",
+    "usb/type_converters.h",
+  ]
+
+  deps = [
+    "//device/core",
+    "//device/devices_app/usb/public/cpp",
+    "//device/devices_app/usb/public/interfaces",
+    "//device/usb",
+    "//net",
+    "//third_party/mojo/src/mojo/public/cpp/bindings",
+    "//third_party/mojo/src/mojo/public/cpp/bindings:callback",
+    "//url",
+  ]
+
+  public_deps = [
+    "//base",
+    "//mojo/application/public/cpp",
+    "//mojo/application/public/interfaces",
+  ]
+}
+
+mojo_native_application("devices") {
+  sources = [
+    "main.cc",
+  ]
+
+  deps = [
+    ":lib",
+    "//base",
+    "//mojo/application/public/cpp",
+  ]
+
+  public_deps = [
+    ":lib",
+  ]
+}
+
+mojo_native_application("apptests") {
+  output_name = "devices_apptests"
+
+  testonly = true
+
+  sources = [
+    "devices_apptest.cc",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/application/public/cpp:test_support",
+  ]
+
+  public_deps = [
+    ":lib",
+    "//device/devices_app/usb/public/interfaces",
+  ]
+
+  data_deps = [ ":devices" ]
+}
diff --git a/device/devices_app/DEPS b/device/devices_app/DEPS
new file mode 100644
index 0000000..8fbdc29
--- /dev/null
+++ b/device/devices_app/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+mojo/application/public",
+  "+mojo/common",
+]
diff --git a/device/devices_app/OWNERS b/device/devices_app/OWNERS
new file mode 100644
index 0000000..b16946a
--- /dev/null
+++ b/device/devices_app/OWNERS
@@ -0,0 +1,2 @@
+reillyg@chromium.org
+rockot@chromium.org
diff --git a/device/devices_app/devices_app.cc b/device/devices_app/devices_app.cc
new file mode 100644
index 0000000..318ebf62
--- /dev/null
+++ b/device/devices_app/devices_app.cc
@@ -0,0 +1,175 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/devices_app/devices_app.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/sequenced_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "device/core/device_client.h"
+#include "device/devices_app/usb/device_manager_impl.h"
+#include "device/devices_app/usb/public/cpp/device_manager_delegate.h"
+#include "device/usb/usb_service.h"
+#include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+#include "url/gurl.h"
+
+namespace device {
+
+const char kDevicesMojoAppUrl[] = "system:devices";
+
+namespace {
+
+// The number of seconds to wait without any bound DeviceManagers before
+// exiting the app.
+const int64 kIdleTimeoutInSeconds = 10;
+
+// A usb::DeviceManagerDelegate implementation which provides origin-based
+// device access control.
+class USBDeviceManagerDelegate : public usb::DeviceManagerDelegate {
+ public:
+  explicit USBDeviceManagerDelegate(const GURL& remote_url)
+      : remote_url_(remote_url) {}
+  ~USBDeviceManagerDelegate() override {}
+
+ private:
+  // usb::DeviceManagerDelegate:
+  bool IsDeviceAllowed(const usb::DeviceInfo& device) override {
+    // Limited set of conditions to allow localhost connection for testing. This
+    // does not presume to catch all common local host strings.
+    if (remote_url_.host() == "127.0.0.1" || remote_url_.host() == "localhost")
+      return true;
+
+    // Also let browser apps and mojo apptests talk to all devices.
+    if (remote_url_.SchemeIs("system") ||
+        remote_url_ == GURL("mojo://devices_apptests/"))
+      return true;
+
+    // TODO(rockot/reillyg): Implement origin-based device access control.
+    return false;
+  }
+
+  GURL remote_url_;
+
+  DISALLOW_COPY_AND_ASSIGN(USBDeviceManagerDelegate);
+};
+
+// A DeviceClient implementation to be constructed iff the app is not running
+// in an embedder that provides a DeviceClient (i.e. running as a standalone
+// Mojo app, not in Chrome).
+class AppDeviceClient : public DeviceClient {
+ public:
+  explicit AppDeviceClient(
+      scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
+      : usb_service_(UsbService::GetInstance(blocking_task_runner)) {}
+  ~AppDeviceClient() override {}
+
+ private:
+  // DeviceClient:
+  UsbService* GetUsbService() override { return usb_service_; }
+
+  UsbService* usb_service_;
+};
+
+}  // namespace
+
+// This class insures that a UsbService has been initialized and is accessible
+// via the DeviceClient interface.
+class DevicesApp::USBServiceInitializer {
+ public:
+  USBServiceInitializer()
+      : blocking_thread_("USB service blocking I/O thread") {
+    blocking_thread_.Start();
+    app_device_client_.reset(
+        new AppDeviceClient(blocking_thread_.task_runner()));
+  }
+
+  ~USBServiceInitializer() {}
+
+ private:
+  scoped_ptr<AppDeviceClient> app_device_client_;
+  base::Thread blocking_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(USBServiceInitializer);
+};
+
+DevicesApp::~DevicesApp() {
+}
+
+// static
+scoped_ptr<mojo::ApplicationDelegate> DevicesApp::CreateDelegate(
+    scoped_refptr<base::SequencedTaskRunner> service_task_runner) {
+  return scoped_ptr<mojo::ApplicationDelegate>(
+      new DevicesApp(service_task_runner));
+}
+
+DevicesApp::DevicesApp(
+    scoped_refptr<base::SequencedTaskRunner> service_task_runner)
+    : app_impl_(nullptr),
+      service_task_runner_(service_task_runner),
+      active_device_manager_count_(0) {
+}
+
+void DevicesApp::Initialize(mojo::ApplicationImpl* app) {
+  app_impl_ = app;
+  if (!service_task_runner_) {
+    service_initializer_.reset(new USBServiceInitializer);
+    service_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+  }
+  StartIdleTimer();
+}
+
+bool DevicesApp::ConfigureIncomingConnection(
+    mojo::ApplicationConnection* connection) {
+  connection->AddService<usb::DeviceManager>(this);
+  return true;
+}
+
+void DevicesApp::Quit() {
+  service_initializer_.reset();
+  app_impl_ = nullptr;
+}
+
+void DevicesApp::Create(mojo::ApplicationConnection* connection,
+                        mojo::InterfaceRequest<usb::DeviceManager> request) {
+  scoped_ptr<usb::DeviceManagerDelegate> delegate(new USBDeviceManagerDelegate(
+      GURL(connection->GetRemoteApplicationURL())));
+
+  // Owned by its message pipe.
+  usb::DeviceManagerImpl* device_manager = new usb::DeviceManagerImpl(
+      request.Pass(), delegate.Pass(), service_task_runner_);
+  device_manager->set_error_handler(this);
+
+  active_device_manager_count_++;
+  idle_timeout_callback_.Cancel();
+}
+
+void DevicesApp::OnConnectionError() {
+  DCHECK_GE(active_device_manager_count_, 0u);
+  active_device_manager_count_--;
+  if (active_device_manager_count_ == 0) {
+    // If the last DeviceManager connection has been dropped, kick off an idle
+    // timeout to shut ourselves down.
+    StartIdleTimer();
+  }
+}
+
+void DevicesApp::StartIdleTimer() {
+  // Passing unretained |app_impl_| is safe here because |app_impl_| is
+  // guaranteed to outlive |this|, and the callback is canceled if |this| is
+  // destroyed.
+  idle_timeout_callback_.Reset(base::Bind(&mojo::ApplicationImpl::Terminate,
+                                          base::Unretained(app_impl_)));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, idle_timeout_callback_.callback(),
+      base::TimeDelta::FromSeconds(kIdleTimeoutInSeconds));
+}
+
+}  // namespace device
diff --git a/device/devices_app/devices_app.gyp b/device/devices_app/devices_app.gyp
new file mode 100644
index 0000000..8cf952db
--- /dev/null
+++ b/device/devices_app/devices_app.gyp
@@ -0,0 +1,61 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'targets': [
+    {
+      'target_name': 'devices_app_lib',
+      'type': 'static_library',
+      'include_dirs': [
+        '../..',
+      ],
+      'sources': [
+        'devices_app.cc',
+        'devices_app.h',
+        'usb/device_impl.cc',
+        'usb/device_impl.h',
+        'usb/device_manager_impl.cc',
+        'usb/device_manager_impl.h',
+        'usb/public/cpp/device_manager_delegate.h',
+        'usb/type_converters.cc',
+        'usb/type_converters.h',
+      ],
+      'dependencies': [
+        '<(DEPTH)/device/usb/usb.gyp:device_usb',
+        'device_usb_mojo_bindings_lib',
+        '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_base',
+        '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings',
+        '<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+      ],
+      'export_dependent_settings': [
+        '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_base',
+        '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings',
+        '<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+      ],
+    },
+    {
+      'target_name': 'device_usb_mojo_bindings',
+      'type': 'none',
+      'variables': {
+        'mojom_files': [
+          'usb/public/interfaces/device.mojom',
+          'usb/public/interfaces/device_manager.mojom',
+        ],
+      },
+      'includes': [
+        '../../third_party/mojo/mojom_bindings_generator_explicit.gypi',
+      ],
+    },
+    {
+      'target_name': 'device_usb_mojo_bindings_lib',
+      'type': 'static_library',
+      'dependencies': [
+        'device_usb_mojo_bindings',
+      ],
+    },
+  ],
+}
diff --git a/device/devices_app/devices_app.h b/device/devices_app/devices_app.h
new file mode 100644
index 0000000..4b04568
--- /dev/null
+++ b/device/devices_app/devices_app.h
@@ -0,0 +1,81 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_DEVICES_DEVICES_APP_H_
+#define DEVICE_DEVICES_DEVICES_APP_H_
+
+#include "base/cancelable_callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/application/public/cpp/interface_factory.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace mojo {
+class ApplicationImpl;
+}
+
+namespace device {
+
+namespace usb {
+class DeviceManager;
+}
+
+extern const char kDevicesMojoAppUrl[];
+
+class DevicesApp : public mojo::ApplicationDelegate,
+                   public mojo::InterfaceFactory<usb::DeviceManager>,
+                   public mojo::ErrorHandler {
+ public:
+  ~DevicesApp() override;
+
+  // |service_task_runner| is the thread TaskRunner on which the UsbService
+  // lives. This argument should be removed once UsbService is owned by the
+  // USB device manager and no longer part of the public device API. If null,
+  // the app will construct its own DeviceClient and UsbService.
+  static scoped_ptr<mojo::ApplicationDelegate> CreateDelegate(
+      scoped_refptr<base::SequencedTaskRunner> service_task_runner);
+
+ private:
+  class USBServiceInitializer;
+
+  DevicesApp(scoped_refptr<base::SequencedTaskRunner> service_task_runner);
+
+  // mojo::ApplicationDelegate:
+  void Initialize(mojo::ApplicationImpl* app) override;
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override;
+  void Quit() override;
+
+  // mojo::InterfaceFactory<usb::DeviceManager>:
+  void Create(mojo::ApplicationConnection* connection,
+              mojo::InterfaceRequest<usb::DeviceManager> request) override;
+
+  // mojo::ErrorHandler:
+  void OnConnectionError() override;
+
+  // Sets the app for destruction after a period of idle time. If any top-level
+  // services (e.g. usb::DeviceManager) are bound before the timeout elapses,
+  // it's canceled.
+  void StartIdleTimer();
+
+  mojo::ApplicationImpl* app_impl_;
+  scoped_ptr<USBServiceInitializer> service_initializer_;
+  scoped_refptr<base::SequencedTaskRunner> service_task_runner_;
+  size_t active_device_manager_count_;
+
+  // Callback used to shut down the app after a period of inactivity.
+  base::CancelableClosure idle_timeout_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevicesApp);
+};
+
+}  // naespace device
+
+#endif  // DEVICE_DEVICES_DEVICES_APP_H_
diff --git a/device/devices_app/devices_apptest.cc b/device/devices_app/devices_apptest.cc
new file mode 100644
index 0000000..4416bda
--- /dev/null
+++ b/device/devices_app/devices_apptest.cc
@@ -0,0 +1,56 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "device/devices_app/devices_app.h"
+#include "device/devices_app/usb/public/interfaces/device_manager.mojom.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/application/public/cpp/application_test_base.h"
+
+namespace device {
+namespace {
+
+class DevicesAppTest : public mojo::test::ApplicationTestBase {
+ public:
+  DevicesAppTest() {}
+  ~DevicesAppTest() override {}
+
+  void SetUp() override {
+    ApplicationTestBase::SetUp();
+    mojo::URLRequestPtr request = mojo::URLRequest::New();
+    request->url = "mojo:devices";
+    application_impl()->ConnectToService(request.Pass(), &usb_device_manager_);
+  }
+
+  usb::DeviceManager* usb_device_manager() { return usb_device_manager_.get(); }
+
+ private:
+  usb::DeviceManagerPtr usb_device_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevicesAppTest);
+};
+
+void OnGetDevices(const base::Closure& continuation,
+                  mojo::Array<usb::DeviceInfoPtr> devices) {
+  continuation.Run();
+}
+
+}  // namespace
+
+// Simple test to verify that we can connect to the USB DeviceManager and get
+// a response.
+TEST_F(DevicesAppTest, GetUSBDevices) {
+  base::RunLoop loop;
+  usb::EnumerationOptionsPtr options = usb::EnumerationOptions::New();
+  options->filters = mojo::Array<usb::DeviceFilterPtr>(1);
+  options->filters[0] = usb::DeviceFilter::New();
+  usb_device_manager()->GetDevices(
+      options.Pass(), base::Bind(&OnGetDevices, loop.QuitClosure()));
+  loop.Run();
+}
+
+}  // namespace device
diff --git a/device/devices_app/main.cc b/device/devices_app/main.cc
new file mode 100644
index 0000000..e82edb34
--- /dev/null
+++ b/device/devices_app/main.cc
@@ -0,0 +1,14 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sequenced_task_runner.h"
+#include "device/devices_app/devices_app.h"
+#include "mojo/application/public/cpp/application_runner.h"
+#include "third_party/mojo/src/mojo/public/c/system/main.h"
+
+MojoResult MojoMain(MojoHandle shell_handle) {
+  mojo::ApplicationRunner runner(
+      device::DevicesApp::CreateDelegate(nullptr).release());
+  return runner.Run(shell_handle);
+}
diff --git a/device/devices_app/usb/DEPS b/device/devices_app/usb/DEPS
new file mode 100644
index 0000000..134e14a
--- /dev/null
+++ b/device/devices_app/usb/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "-net",
+  "+net/base",
+]
diff --git a/device/usb/device_impl.cc b/device/devices_app/usb/device_impl.cc
similarity index 98%
rename from device/usb/device_impl.cc
rename to device/devices_app/usb/device_impl.cc
index a86826b..e8b299b 100644
--- a/device/usb/device_impl.cc
+++ b/device/devices_app/usb/device_impl.cc
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "device/devices_app/usb/device_impl.h"
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/stl_util.h"
-#include "device/usb/device_impl.h"
-#include "device/usb/type_converters.h"
+#include "device/devices_app/usb/type_converters.h"
 #include "device/usb/usb_descriptors.h"
 #include "device/usb/usb_device.h"
 #include "net/base/io_buffer.h"
diff --git a/device/usb/device_impl.h b/device/devices_app/usb/device_impl.h
similarity index 98%
rename from device/usb/device_impl.h
rename to device/devices_app/usb/device_impl.h
index d3bf339..47f66c5 100644
--- a/device/usb/device_impl.h
+++ b/device/devices_app/usb/device_impl.h
@@ -9,7 +9,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "device/usb/public/interfaces/device.mojom.h"
+#include "device/devices_app/usb/public/interfaces/device.mojom.h"
 #include "device/usb/usb_device_handle.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/callback.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
diff --git a/device/usb/device_impl_unittest.cc b/device/devices_app/usb/device_impl_unittest.cc
similarity index 99%
rename from device/usb/device_impl_unittest.cc
rename to device/devices_app/usb/device_impl_unittest.cc
index 1b05305a..c62a12b 100644
--- a/device/usb/device_impl_unittest.cc
+++ b/device/devices_app/usb/device_impl_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
-#include "device/usb/device_impl.h"
+#include "device/devices_app/usb/device_impl.h"
 #include "device/usb/mock_usb_device.h"
 #include "device/usb/mock_usb_device_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/device/devices_app/usb/device_manager_impl.cc b/device/devices_app/usb/device_manager_impl.cc
new file mode 100644
index 0000000..6776438c
--- /dev/null
+++ b/device/devices_app/usb/device_manager_impl.cc
@@ -0,0 +1,159 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/devices_app/usb/device_manager_impl.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "device/core/device_client.h"
+#include "device/devices_app/usb/device_impl.h"
+#include "device/devices_app/usb/public/cpp/device_manager_delegate.h"
+#include "device/devices_app/usb/public/interfaces/device.mojom.h"
+#include "device/devices_app/usb/type_converters.h"
+#include "device/usb/usb_device.h"
+#include "device/usb/usb_device_filter.h"
+#include "device/usb/usb_service.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/array.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+
+namespace device {
+namespace usb {
+
+namespace {
+
+void OnGetDevicesOnServiceThread(
+    const UsbService::GetDevicesCallback& callback,
+    scoped_refptr<base::TaskRunner> callback_task_runner,
+    const std::vector<scoped_refptr<UsbDevice>>& devices) {
+  callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, devices));
+}
+
+void GetDevicesOnServiceThread(
+    const UsbService::GetDevicesCallback& callback,
+    scoped_refptr<base::TaskRunner> callback_task_runner) {
+  DCHECK(DeviceClient::Get());
+  UsbService* usb_service = DeviceClient::Get()->GetUsbService();
+  if (!usb_service) {
+    std::vector<scoped_refptr<UsbDevice>> no_devices;
+    callback_task_runner->PostTask(FROM_HERE, base::Bind(callback, no_devices));
+    return;
+  }
+  usb_service->GetDevices(
+      base::Bind(&OnGetDevicesOnServiceThread, callback, callback_task_runner));
+}
+
+void RunOpenDeviceCallback(const DeviceManager::OpenDeviceCallback& callback,
+                           OpenDeviceError error) {
+  callback.Run(error);
+}
+
+void OnOpenDeviceOnServiceThread(
+    mojo::InterfaceRequest<Device> device_request,
+    const DeviceManager::OpenDeviceCallback& callback,
+    scoped_refptr<base::TaskRunner> callback_task_runner,
+    scoped_refptr<UsbDeviceHandle> device_handle) {
+  if (!device_handle) {
+    callback_task_runner->PostTask(FROM_HERE,
+                                   base::Bind(&RunOpenDeviceCallback, callback,
+                                              OPEN_DEVICE_ERROR_ACCESS_DENIED));
+    return;
+  }
+
+  // Owned by its MessagePipe.
+  new DeviceImpl(device_handle, device_request.Pass());
+
+  callback_task_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&RunOpenDeviceCallback, callback, OPEN_DEVICE_ERROR_OK));
+}
+
+void OpenDeviceOnServiceThread(
+    const std::string& guid,
+    mojo::InterfaceRequest<Device> device_request,
+    const DeviceManager::OpenDeviceCallback& callback,
+    scoped_refptr<base::TaskRunner> callback_task_runner) {
+  DCHECK(DeviceClient::Get());
+  UsbService* usb_service = DeviceClient::Get()->GetUsbService();
+  if (!usb_service) {
+    callback_task_runner->PostTask(FROM_HERE,
+                                   base::Bind(&RunOpenDeviceCallback, callback,
+                                              OPEN_DEVICE_ERROR_NOT_FOUND));
+    return;
+  }
+  scoped_refptr<UsbDevice> device = usb_service->GetDevice(guid);
+  if (!device) {
+    callback_task_runner->PostTask(FROM_HERE,
+                                   base::Bind(&RunOpenDeviceCallback, callback,
+                                              OPEN_DEVICE_ERROR_NOT_FOUND));
+    return;
+  }
+  device->Open(base::Bind(&OnOpenDeviceOnServiceThread,
+                          base::Passed(&device_request), callback,
+                          callback_task_runner));
+}
+
+}  // namespace
+
+DeviceManagerImpl::DeviceManagerImpl(
+    mojo::InterfaceRequest<DeviceManager> request,
+    scoped_ptr<DeviceManagerDelegate> delegate,
+    scoped_refptr<base::SequencedTaskRunner> service_task_runner)
+    : binding_(this, request.Pass()),
+      delegate_(delegate.Pass()),
+      service_task_runner_(service_task_runner),
+      weak_factory_(this) {
+}
+
+DeviceManagerImpl::~DeviceManagerImpl() {
+}
+
+void DeviceManagerImpl::set_error_handler(mojo::ErrorHandler* error_handler) {
+  binding_.set_error_handler(error_handler);
+}
+
+void DeviceManagerImpl::GetDevices(EnumerationOptionsPtr options,
+                                   const GetDevicesCallback& callback) {
+  auto get_devices_callback =
+      base::Bind(&DeviceManagerImpl::OnGetDevices, weak_factory_.GetWeakPtr(),
+                 base::Passed(&options), callback);
+  service_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&GetDevicesOnServiceThread, get_devices_callback,
+                            base::ThreadTaskRunnerHandle::Get()));
+}
+
+void DeviceManagerImpl::OpenDevice(
+    const mojo::String& guid,
+    mojo::InterfaceRequest<Device> device_request,
+    const OpenDeviceCallback& callback) {
+  service_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&OpenDeviceOnServiceThread, guid,
+                            base::Passed(&device_request), callback,
+                            base::ThreadTaskRunnerHandle::Get()));
+}
+
+void DeviceManagerImpl::OnGetDevices(
+    EnumerationOptionsPtr options,
+    const GetDevicesCallback& callback,
+    const std::vector<scoped_refptr<UsbDevice>>& devices) {
+  auto filters = options->filters.To<std::vector<UsbDeviceFilter>>();
+  mojo::Array<DeviceInfoPtr> device_infos(0);
+  for (size_t i = 0; i < devices.size(); ++i) {
+    DeviceInfoPtr device_info = DeviceInfo::From(*devices[i]);
+    if (UsbDeviceFilter::MatchesAny(devices[i], filters) &&
+        delegate_->IsDeviceAllowed(*device_info)) {
+      const UsbConfigDescriptor* config = devices[i]->GetConfiguration();
+      device_info->configurations = mojo::Array<ConfigurationInfoPtr>::New(0);
+      if (config)
+        device_info->configurations.push_back(ConfigurationInfo::From(*config));
+      device_infos.push_back(device_info.Pass());
+    }
+  }
+  callback.Run(device_infos.Pass());
+}
+
+}  // namespace usb
+}  // namespace device
diff --git a/device/usb/device_manager_impl.h b/device/devices_app/usb/device_manager_impl.h
similarity index 67%
rename from device/usb/device_manager_impl.h
rename to device/devices_app/usb/device_manager_impl.h
index 5c77a65..5b0fb04 100644
--- a/device/usb/device_manager_impl.h
+++ b/device/devices_app/usb/device_manager_impl.h
@@ -11,10 +11,18 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "device/usb/public/interfaces/device_manager.mojom.h"
+#include "device/devices_app/usb/public/interfaces/device_manager.mojom.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
 
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace mojo {
+class ErrorHandler;
+}
+
 namespace device {
 
 class UsbDevice;
@@ -25,14 +33,18 @@
 
 class DeviceManagerDelegate;
 
-// Implementation of the public DeviceManager interface. Clients in the browser
-// can connect to this service via DeviceClient::ConnectToUSBDeviceManager.
+// Implementation of the public DeviceManager interface. This interface can be
+// requested from the devices app located at "system:devices", if available.
 class DeviceManagerImpl : public DeviceManager {
  public:
-  DeviceManagerImpl(mojo::InterfaceRequest<DeviceManager> request,
-                    scoped_ptr<DeviceManagerDelegate> delegate);
+  DeviceManagerImpl(
+      mojo::InterfaceRequest<DeviceManager> request,
+      scoped_ptr<DeviceManagerDelegate> delegate,
+      scoped_refptr<base::SequencedTaskRunner> service_task_runner);
   ~DeviceManagerImpl() override;
 
+  void set_error_handler(mojo::ErrorHandler* error_handler);
+
  private:
   // DeviceManager implementation:
   void GetDevices(EnumerationOptionsPtr options,
@@ -42,18 +54,14 @@
                   const OpenDeviceCallback& callback) override;
 
   // Callback to handle the async response from the underlying UsbService.
-  void OnGetDevices(const GetDevicesCallback& callback,
-                    const std::vector<UsbDeviceFilter>& filters,
+  void OnGetDevices(EnumerationOptionsPtr options,
+                    const GetDevicesCallback& callback,
                     const std::vector<scoped_refptr<UsbDevice>>& devices);
 
-  // Callback to handle the async Open response from a UsbDevice.
-  void OnOpenDevice(const OpenDeviceCallback& callback,
-                    mojo::InterfaceRequest<Device> device_request,
-                    scoped_refptr<UsbDeviceHandle> device_handle);
-
   mojo::StrongBinding<DeviceManager> binding_;
 
   scoped_ptr<DeviceManagerDelegate> delegate_;
+  scoped_refptr<base::SequencedTaskRunner> service_task_runner_;
 
   base::WeakPtrFactory<DeviceManagerImpl> weak_factory_;
 
diff --git a/device/usb/device_manager_impl_unittest.cc b/device/devices_app/usb/device_manager_impl_unittest.cc
similarity index 82%
rename from device/usb/device_manager_impl_unittest.cc
rename to device/devices_app/usb/device_manager_impl_unittest.cc
index f0ce167..0855b26 100644
--- a/device/usb/device_manager_impl_unittest.cc
+++ b/device/devices_app/usb/device_manager_impl_unittest.cc
@@ -10,14 +10,14 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "device/core/device_client.h"
-#include "device/usb/device_impl.h"
-#include "device/usb/device_manager_impl.h"
+#include "device/devices_app/usb/device_impl.h"
+#include "device/devices_app/usb/device_manager_impl.h"
+#include "device/devices_app/usb/public/cpp/device_manager_delegate.h"
 #include "device/usb/mock_usb_device.h"
 #include "device/usb/mock_usb_device_handle.h"
 #include "device/usb/mock_usb_service.h"
-#include "device/usb/public/cpp/device_manager_delegate.h"
-#include "device/usb/public/cpp/device_manager_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
@@ -30,51 +30,27 @@
 
 namespace {
 
-bool DefaultDelegateFilter(const DeviceInfo& device_info) {
-  return true;
-}
-
 class TestDeviceManagerDelegate : public DeviceManagerDelegate {
  public:
-  using Filter = base::Callback<bool(const DeviceInfo&)>;
-
-  TestDeviceManagerDelegate(const Filter& filter) : filter_(filter) {}
+  TestDeviceManagerDelegate() {}
   ~TestDeviceManagerDelegate() override {}
 
-  void set_filter(const Filter& filter) { filter_ = filter; }
-
  private:
   // DeviceManagerDelegate implementation:
-  bool IsDeviceAllowed(const DeviceInfo& device_info) override {
-    return filter_.Run(device_info);
-  }
-
-  Filter filter_;
+  bool IsDeviceAllowed(const DeviceInfo& device_info) override { return true; }
 };
 
 class TestDeviceClient : public DeviceClient {
  public:
-  TestDeviceClient() : delegate_filter_(base::Bind(&DefaultDelegateFilter)) {}
+  TestDeviceClient() {}
   ~TestDeviceClient() override {}
 
   MockUsbService& mock_usb_service() { return mock_usb_service_; }
 
-  void SetDelegateFilter(const TestDeviceManagerDelegate::Filter& filter) {
-    delegate_filter_ = filter;
-  }
-
  private:
   // DeviceClient implementation:
   UsbService* GetUsbService() override { return &mock_usb_service_; }
 
-  void ConnectToUSBDeviceManager(
-      mojo::InterfaceRequest<DeviceManager> request) override {
-    new DeviceManagerImpl(request.Pass(),
-                          scoped_ptr<DeviceManagerDelegate>(
-                              new TestDeviceManagerDelegate(delegate_filter_)));
-  }
-
-  TestDeviceManagerDelegate::Filter delegate_filter_;
   MockUsbService mock_usb_service_;
 };
 
@@ -90,8 +66,13 @@
     return device_client_->mock_usb_service();
   }
 
-  void SetDelegateFilter(const TestDeviceManagerDelegate::Filter& filter) {
-    device_client_->SetDelegateFilter(filter);
+  DeviceManagerPtr ConnectToDeviceManager() {
+    DeviceManagerPtr device_manager;
+    new DeviceManagerImpl(
+        mojo::GetProxy(&device_manager),
+        scoped_ptr<DeviceManagerDelegate>(new TestDeviceManagerDelegate),
+        base::ThreadTaskRunnerHandle::Get());
+    return device_manager.Pass();
   }
 
  private:
@@ -175,9 +156,7 @@
   mock_usb_service().AddDevice(device1);
   mock_usb_service().AddDevice(device2);
 
-  DeviceManagerPtr device_manager;
-  DeviceClient::Get()->ConnectToUSBDeviceManager(
-      mojo::GetProxy(&device_manager));
+  DeviceManagerPtr device_manager = ConnectToDeviceManager();
 
   EnumerationOptionsPtr options = EnumerationOptions::New();
   options->filters = mojo::Array<DeviceFilterPtr>::New(1);
@@ -209,9 +188,7 @@
 
   mock_usb_service().AddDevice(mock_device);
 
-  DeviceManagerPtr device_manager;
-  DeviceClient::Get()->ConnectToUSBDeviceManager(
-      mojo::GetProxy(&device_manager));
+  DeviceManagerPtr device_manager = ConnectToDeviceManager();
 
   // Should be called on the mock as a result of OpenDevice() below.
   EXPECT_CALL(*mock_device.get(), Open(_));
diff --git a/device/usb/public/cpp/BUILD.gn b/device/devices_app/usb/public/cpp/BUILD.gn
similarity index 82%
rename from device/usb/public/cpp/BUILD.gn
rename to device/devices_app/usb/public/cpp/BUILD.gn
index 43cea68..9ca3cce 100644
--- a/device/usb/public/cpp/BUILD.gn
+++ b/device/devices_app/usb/public/cpp/BUILD.gn
@@ -5,12 +5,11 @@
 source_set("cpp") {
   sources = [
     "device_manager_delegate.h",
-    "device_manager_factory.h",
   ]
 
   public_deps = [
     "//base",
-    "//device/usb/public/interfaces",
+    "//device/devices_app/usb/public/interfaces",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
   ]
 }
diff --git a/device/usb/public/cpp/device_manager_delegate.h b/device/devices_app/usb/public/cpp/device_manager_delegate.h
similarity index 68%
rename from device/usb/public/cpp/device_manager_delegate.h
rename to device/devices_app/usb/public/cpp/device_manager_delegate.h
index 306be18..6400591 100644
--- a/device/usb/public/cpp/device_manager_delegate.h
+++ b/device/devices_app/usb/public/cpp/device_manager_delegate.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef DEVICE_USB_PUBLIC_CPP_DEVICE_MANAGER_DELEGATE_H_
-#define DEVICE_USB_PUBLIC_CPP_DEVICE_MANAGER_DELEGATE_H_
+#ifndef DEVICE_DEVICES_APP_USB_PUBLIC_CPP_DEVICE_MANAGER_DELEGATE_H_
+#define DEVICE_DEVICES_APP_USB_PUBLIC_CPP_DEVICE_MANAGER_DELEGATE_H_
 
-#include "device/usb/public/interfaces/device.mojom.h"
+#include "device/devices_app/usb/public/interfaces/device.mojom.h"
 
 namespace device {
 namespace usb {
@@ -24,4 +24,4 @@
 }  // namespace usb
 }  // namespace device
 
-#endif  // DEVICE_USB_PUBLIC_CPP_DEVICE_MANAGER_DELEGATE_H_
+#endif  // DEVICE_DEVICES_APP_USB_PUBLIC_CPP_DEVICE_MANAGER_DELEGATE_H_
diff --git a/device/usb/public/interfaces/BUILD.gn b/device/devices_app/usb/public/interfaces/BUILD.gn
similarity index 100%
rename from device/usb/public/interfaces/BUILD.gn
rename to device/devices_app/usb/public/interfaces/BUILD.gn
diff --git a/device/usb/public/interfaces/device.mojom b/device/devices_app/usb/public/interfaces/device.mojom
similarity index 100%
rename from device/usb/public/interfaces/device.mojom
rename to device/devices_app/usb/public/interfaces/device.mojom
diff --git a/device/usb/public/interfaces/device_manager.mojom b/device/devices_app/usb/public/interfaces/device_manager.mojom
similarity index 100%
rename from device/usb/public/interfaces/device_manager.mojom
rename to device/devices_app/usb/public/interfaces/device_manager.mojom
diff --git a/device/usb/type_converters.cc b/device/devices_app/usb/type_converters.cc
similarity index 98%
rename from device/usb/type_converters.cc
rename to device/devices_app/usb/type_converters.cc
index 456f1701..ee1f072 100644
--- a/device/usb/type_converters.cc
+++ b/device/devices_app/usb/type_converters.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/usb/type_converters.h"
+#include "device/devices_app/usb/type_converters.h"
 
 #include <map>
 #include <utility>
diff --git a/device/usb/type_converters.h b/device/devices_app/usb/type_converters.h
similarity index 91%
rename from device/usb/type_converters.h
rename to device/devices_app/usb/type_converters.h
index b8e1a73..32d5b601 100644
--- a/device/usb/type_converters.h
+++ b/device/devices_app/usb/type_converters.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef DEVICE_USB_TYPE_CONVERTERS_H_
-#define DEVICE_USB_TYPE_CONVERTERS_H_
+#ifndef DEVICE_DEVICES_APP_USB_TYPE_CONVERTERS_H_
+#define DEVICE_DEVICES_APP_USB_TYPE_CONVERTERS_H_
 
 #include <vector>
 
-#include "device/usb/public/interfaces/device.mojom.h"
-#include "device/usb/public/interfaces/device_manager.mojom.h"
+#include "device/devices_app/usb/public/interfaces/device.mojom.h"
+#include "device/devices_app/usb/public/interfaces/device_manager.mojom.h"
 #include "device/usb/usb_descriptors.h"
 #include "device/usb/usb_device_filter.h"
 #include "device/usb/usb_device_handle.h"
@@ -101,4 +101,4 @@
 
 }  // namespace mojo
 
-#endif  // DEVICE_USB_TYPE_CONVERTERS_H_
+#endif  // DEVICE_DEVICES_APP_USB_TYPE_CONVERTERS_H_
diff --git a/device/serial/serial_io_handler.h b/device/serial/serial_io_handler.h
index 1b2a8c4..bd8255e 100644
--- a/device/serial/serial_io_handler.h
+++ b/device/serial/serial_io_handler.h
@@ -83,6 +83,14 @@
   // successfully retrieved.
   virtual serial::ConnectionInfoPtr GetPortInfo() const = 0;
 
+  // Initiates a BREAK signal. Places the transmission line in a break state
+  // until the |ClearBreak| is called.
+  virtual bool SetBreak() = 0;
+
+  // Terminates the BREAK signal. Places the transmission line in a nonbreak
+  // state.
+  virtual bool ClearBreak() = 0;
+
  protected:
   explicit SerialIoHandler(
       scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner,
diff --git a/device/serial/serial_io_handler_posix.cc b/device/serial/serial_io_handler_posix.cc
index 52aad17..91cd110c 100644
--- a/device/serial/serial_io_handler_posix.cc
+++ b/device/serial/serial_io_handler_posix.cc
@@ -472,6 +472,23 @@
   return info.Pass();
 }
 
+bool SerialIoHandlerPosix::SetBreak() {
+  if (ioctl(file().GetPlatformFile(), TIOCSBRK, 0) != 0) {
+    VPLOG(1) << "Failed to set break";
+    return false;
+  }
+
+  return true;
+}
+
+bool SerialIoHandlerPosix::ClearBreak() {
+  if (ioctl(file().GetPlatformFile(), TIOCCBRK, 0) != 0) {
+    VPLOG(1) << "Failed to clear break";
+    return false;
+  }
+  return true;
+}
+
 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) {
   return port_name;
 }
diff --git a/device/serial/serial_io_handler_posix.h b/device/serial/serial_io_handler_posix.h
index 9a5b832..6d744c7b 100644
--- a/device/serial/serial_io_handler_posix.h
+++ b/device/serial/serial_io_handler_posix.h
@@ -26,6 +26,8 @@
   bool SetControlSignals(
       const serial::HostControlSignals& control_signals) override;
   serial::ConnectionInfoPtr GetPortInfo() const override;
+  bool SetBreak() override;
+  bool ClearBreak() override;
   void RequestAccess(
       const std::string& port,
       scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
diff --git a/device/serial/serial_io_handler_win.cc b/device/serial/serial_io_handler_win.cc
index 60a2a33..15165f6 100644
--- a/device/serial/serial_io_handler_win.cc
+++ b/device/serial/serial_io_handler_win.cc
@@ -391,6 +391,22 @@
   return info.Pass();
 }
 
+bool SerialIoHandlerWin::SetBreak() {
+  if (!SetCommBreak(file().GetPlatformFile())) {
+    VPLOG(1) << "Failed to set break";
+    return false;
+  }
+  return true;
+}
+
+bool SerialIoHandlerWin::ClearBreak() {
+  if (!ClearCommBreak(file().GetPlatformFile())) {
+    VPLOG(1) << "Failed to clear break";
+    return false;
+  }
+  return true;
+}
+
 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) {
   // For COM numbers less than 9, CreateFile is called with a string such as
   // "COM1". For numbers greater than 9, a prefix of "\\\\.\\" must be added.
diff --git a/device/serial/serial_io_handler_win.h b/device/serial/serial_io_handler_win.h
index d2c14212..7f438b5 100644
--- a/device/serial/serial_io_handler_win.h
+++ b/device/serial/serial_io_handler_win.h
@@ -27,6 +27,8 @@
   bool SetControlSignals(
       const serial::HostControlSignals& control_signals) override;
   serial::ConnectionInfoPtr GetPortInfo() const override;
+  bool SetBreak() override;
+  bool ClearBreak() override;
   bool PostOpen() override;
 
  private:
diff --git a/device/serial/test_serial_io_handler.cc b/device/serial/test_serial_io_handler.cc
index 9713c07..0dcb048 100644
--- a/device/serial/test_serial_io_handler.cc
+++ b/device/serial/test_serial_io_handler.cc
@@ -101,6 +101,14 @@
   return true;
 }
 
+bool TestSerialIoHandler::SetBreak() {
+  return true;
+}
+
+bool TestSerialIoHandler::ClearBreak() {
+  return true;
+}
+
 TestSerialIoHandler::~TestSerialIoHandler() {
 }
 
diff --git a/device/serial/test_serial_io_handler.h b/device/serial/test_serial_io_handler.h
index 52cb16a..edded0e 100644
--- a/device/serial/test_serial_io_handler.h
+++ b/device/serial/test_serial_io_handler.h
@@ -32,6 +32,8 @@
   serial::ConnectionInfoPtr GetPortInfo() const override;
   bool Flush() const override;
   bool SetControlSignals(const serial::HostControlSignals& signals) override;
+  bool SetBreak() override;
+  bool ClearBreak() override;
 
   serial::ConnectionInfo* connection_info() { return &info_; }
   serial::DeviceControlSignals* device_control_signals() {
diff --git a/device/usb/BUILD.gn b/device/usb/BUILD.gn
index ea0248a..aa74a106 100644
--- a/device/usb/BUILD.gn
+++ b/device/usb/BUILD.gn
@@ -9,12 +9,6 @@
 
 source_set("usb") {
   sources = [
-    "device_impl.cc",
-    "device_impl.h",
-    "device_manager_impl.cc",
-    "device_manager_impl.h",
-    "type_converters.cc",
-    "type_converters.h",
     "usb_context.cc",
     "usb_context.h",
     "usb_descriptors.cc",
@@ -45,17 +39,8 @@
     "//base/third_party/dynamic_annotations",
     "//components/device_event_log",
     "//device/core",
-    "//device/usb/public/cpp",
-    "//mojo/environment:chromium",
     "//net",
     "//third_party/libusb",
-    "//third_party/mojo/src/mojo/edk/system",
-  ]
-
-  public_deps = [
-    "//device/usb/public/interfaces",
-    "//third_party/mojo/src/mojo/public/cpp/bindings",
-    "//third_party/mojo/src/mojo/public/cpp/bindings:callback",
   ]
 
   if (is_linux) {
diff --git a/device/usb/device_manager_impl.cc b/device/usb/device_manager_impl.cc
deleted file mode 100644
index bf444a4a..0000000
--- a/device/usb/device_manager_impl.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "device/usb/device_manager_impl.h"
-
-#include "base/bind.h"
-#include "base/memory/scoped_ptr.h"
-#include "device/core/device_client.h"
-#include "device/usb/device_impl.h"
-#include "device/usb/public/cpp/device_manager_delegate.h"
-#include "device/usb/public/cpp/device_manager_factory.h"
-#include "device/usb/public/interfaces/device.mojom.h"
-#include "device/usb/type_converters.h"
-#include "device/usb/usb_device.h"
-#include "device/usb/usb_device_filter.h"
-#include "device/usb/usb_service.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/array.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
-
-namespace device {
-namespace usb {
-
-// static
-void DeviceManagerFactory::Build(mojo::InterfaceRequest<DeviceManager> request,
-                                 scoped_ptr<DeviceManagerDelegate> delegate) {
-  // Owned by its MessagePipe.
-  new DeviceManagerImpl(request.Pass(), delegate.Pass());
-}
-
-DeviceManagerImpl::DeviceManagerImpl(
-    mojo::InterfaceRequest<DeviceManager> request,
-    scoped_ptr<DeviceManagerDelegate> delegate)
-    : binding_(this, request.Pass()),
-      delegate_(delegate.Pass()),
-      weak_factory_(this) {
-}
-
-DeviceManagerImpl::~DeviceManagerImpl() {
-}
-
-void DeviceManagerImpl::GetDevices(EnumerationOptionsPtr options,
-                                   const GetDevicesCallback& callback) {
-  DCHECK(DeviceClient::Get());
-  UsbService* usb_service = DeviceClient::Get()->GetUsbService();
-  if (!usb_service) {
-    mojo::Array<DeviceInfoPtr> results(0);
-    callback.Run(results.Pass());
-    return;
-  }
-  std::vector<UsbDeviceFilter> filters =
-      options->filters.To<std::vector<UsbDeviceFilter>>();
-  usb_service->GetDevices(base::Bind(&DeviceManagerImpl::OnGetDevices,
-                                     weak_factory_.GetWeakPtr(), callback,
-                                     filters));
-}
-
-void DeviceManagerImpl::OpenDevice(
-    const mojo::String& guid,
-    mojo::InterfaceRequest<Device> device_request,
-    const OpenDeviceCallback& callback) {
-  DCHECK(DeviceClient::Get());
-  UsbService* usb_service = DeviceClient::Get()->GetUsbService();
-  if (!usb_service) {
-    callback.Run(OPEN_DEVICE_ERROR_NOT_FOUND);
-    return;
-  }
-  scoped_refptr<UsbDevice> device = usb_service->GetDevice(guid);
-  if (!device) {
-    callback.Run(OPEN_DEVICE_ERROR_NOT_FOUND);
-    return;
-  }
-  device->Open(base::Bind(&DeviceManagerImpl::OnOpenDevice,
-                          weak_factory_.GetWeakPtr(), callback,
-                          base::Passed(&device_request)));
-}
-
-void DeviceManagerImpl::OnGetDevices(
-    const GetDevicesCallback& callback,
-    const std::vector<UsbDeviceFilter>& filters,
-    const std::vector<scoped_refptr<UsbDevice>>& devices) {
-  mojo::Array<DeviceInfoPtr> device_infos(0);
-  for (size_t i = 0; i < devices.size(); ++i) {
-    DeviceInfoPtr device_info = DeviceInfo::From(*devices[i]);
-    if (UsbDeviceFilter::MatchesAny(devices[i], filters) &&
-        delegate_->IsDeviceAllowed(*device_info)) {
-      const UsbConfigDescriptor* config = devices[i]->GetConfiguration();
-      device_info->configurations = mojo::Array<ConfigurationInfoPtr>::New(0);
-      if (config)
-        device_info->configurations.push_back(ConfigurationInfo::From(*config));
-      device_infos.push_back(device_info.Pass());
-    }
-  }
-  callback.Run(device_infos.Pass());
-}
-
-void DeviceManagerImpl::OnOpenDevice(
-    const OpenDeviceCallback& callback,
-    mojo::InterfaceRequest<Device> device_request,
-    scoped_refptr<UsbDeviceHandle> device_handle) {
-  if (!device_handle) {
-    callback.Run(OPEN_DEVICE_ERROR_ACCESS_DENIED);
-    return;
-  }
-
-  // Owned by its MessagePipe.
-  new DeviceImpl(device_handle, device_request.Pass());
-
-  callback.Run(OPEN_DEVICE_ERROR_OK);
-}
-
-}  // namespace usb
-}  // namespace device
diff --git a/device/usb/public/cpp/device_manager_factory.h b/device/usb/public/cpp/device_manager_factory.h
deleted file mode 100644
index 51f9727..0000000
--- a/device/usb/public/cpp/device_manager_factory.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef DEVICE_USB_PUBLIC_CPP_DEVICE_MANAGER_FACTORY_H_
-#define DEVICE_USB_PUBLIC_CPP_DEVICE_MANAGER_FACTORY_H_
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "device/usb/public/interfaces/device_manager.mojom.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
-
-namespace device {
-namespace usb {
-
-class DeviceManagerDelegate;
-
-// Public interface to construct an implementation of the DeviceManager service.
-class DeviceManagerFactory {
- public:
-  // Builds a new DeviceManager instance to fulfill a request. The service is
-  // bound to the lifetime of |request|'s MessagePipe, and it takes ownership of
-  // |delegate|.
-  static void Build(mojo::InterfaceRequest<DeviceManager> request,
-                    scoped_ptr<DeviceManagerDelegate> delegate);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DeviceManagerFactory);
-};
-
-}  // namespace usb
-}  // namespace device
-
-#endif  // DEVICE_USB_PUBLIC_CPP_DEVICE_MANAGER_FACTORY_H_
diff --git a/device/usb/usb.gyp b/device/usb/usb.gyp
index dc3ebd0..f1afd8c 100644
--- a/device/usb/usb.gyp
+++ b/device/usb/usb.gyp
@@ -11,26 +11,14 @@
       'target_name': 'device_usb',
       'type': 'static_library',
       'dependencies': [
-        'device_usb_mojo_bindings_lib',
         '../../components/components.gyp:device_event_log_component',
         '../../net/net.gyp:net',
         '../../third_party/libusb/libusb.gyp:libusb',
-        '../../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
       ],
       'include_dirs': [
         '../..',
       ],
       'sources': [
-        'device_impl.cc',
-        'device_impl.h',
-        'device_manager_impl.cc',
-        'device_manager_impl.h',
-        # TODO(rockot/reillyg): Split out public sources into their own target
-        # once all device/usb consumers have transitioned to the new public API.
-        'public/cpp/device_manager_delegate.h',
-        'public/cpp/device_manager_factory.h',
-        'type_converters.cc',
-        'type_converters.h',
         'usb_context.cc',
         'usb_context.h',
         'usb_descriptors.cc',
@@ -90,26 +78,6 @@
       ]
     },
     {
-      'target_name': 'device_usb_mojo_bindings',
-      'type': 'none',
-      'variables': {
-        'mojom_files': [
-          'public/interfaces/device.mojom',
-          'public/interfaces/device_manager.mojom',
-        ],
-      },
-      'includes': [
-        '../../third_party/mojo/mojom_bindings_generator_explicit.gypi',
-      ],
-    },
-    {
-      'target_name': 'device_usb_mojo_bindings_lib',
-      'type': 'static_library',
-      'dependencies': [
-        'device_usb_mojo_bindings',
-      ],
-    },
-    {
       'target_name': 'device_usb_mocks',
       'type': 'static_library',
       'include_dirs': [
diff --git a/device/usb/usb_context.cc b/device/usb/usb_context.cc
index 7661469..99b76ab 100644
--- a/device/usb/usb_context.cc
+++ b/device/usb/usb_context.cc
@@ -63,6 +63,7 @@
 void UsbContext::UsbEventHandler::Stop() {
   base::subtle::Release_Store(&running_, 0);
   libusb_interrupt_handle_event(context_);
+  base::PlatformThread::Join(thread_handle_);
 }
 
 UsbContext::UsbContext(PlatformUsbContext context) : context_(context) {
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn
index 4ced0d5..ea66ab16 100644
--- a/extensions/BUILD.gn
+++ b/extensions/BUILD.gn
@@ -59,6 +59,7 @@
   ]
 
   deps = [
+    "//chrome/browser/media/router:mojo_bindings__generator",
     "//device/serial:serial_mojo__generator",
     "//extensions/common:mojo__generator",
     "//extensions/common/api:mojom__generator",
diff --git a/extensions/browser/api/api_resource_manager.h b/extensions/browser/api/api_resource_manager.h
index e90cb33c..29040d0 100644
--- a/extensions/browser/api/api_resource_manager.h
+++ b/extensions/browser/api/api_resource_manager.h
@@ -10,6 +10,7 @@
 #include "base/containers/hash_tables.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/scoped_observer.h"
 #include "base/threading/non_thread_safe.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -119,13 +120,12 @@
     process_manager_observer_.Add(ProcessManager::Get(context));
   }
   // For Testing.
-  static ApiResourceManager<T, TestThreadTraits<T> >*
+  static scoped_ptr<ApiResourceManager<T, TestThreadTraits<T>>>
   CreateApiResourceManagerForTest(content::BrowserContext* context,
                                   content::BrowserThread::ID thread_id) {
     TestThreadTraits<T>::thread_id_ = thread_id;
-    ApiResourceManager<T, TestThreadTraits<T> >* manager =
-        new ApiResourceManager<T, TestThreadTraits<T> >(context);
-    return manager;
+    return make_scoped_ptr(
+        new ApiResourceManager<T, TestThreadTraits<T>>(context));
   }
 
   virtual ~ApiResourceManager() {
diff --git a/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc b/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc
index 0248f4ba..55774999 100644
--- a/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc
+++ b/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc
@@ -375,11 +375,6 @@
 
 bool AppCurrentWindowInternalSetVisibleOnAllWorkspacesFunction::RunWithWindow(
     AppWindow* window) {
-  if (AppWindowClient::Get()->IsCurrentChannelOlderThanDev()) {
-    error_ = kDevChannelOnly;
-    return false;
-  }
-
   scoped_ptr<SetVisibleOnAllWorkspaces::Params> params(
       SetVisibleOnAllWorkspaces::Params::Create(*args_));
   CHECK(params.get());
diff --git a/extensions/browser/api/cast_channel/cast_auth_ica.cc b/extensions/browser/api/cast_channel/cast_auth_ica.cc
index 0b570df..1e9f0cae 100644
--- a/extensions/browser/api/cast_channel/cast_auth_ica.cc
+++ b/extensions/browser/api/cast_channel/cast_auth_ica.cc
@@ -17,545 +17,13 @@
 namespace cast_channel {
 namespace {
 
-// Fingerprints and public keys of the allowed / trusted ICAs.
-static const net::SHA256HashValue kFingerprintICA1 = { {
+// Fingerprint of the default ICA.
+static const net::SHA256HashValue kDefaultFingerprintICA = { {
     0x52, 0x9D, 0x9C, 0xD6, 0x7F, 0xE5, 0xEB, 0x69, 0x8E, 0x70, 0xDD, 0x26,
     0xD7, 0xD8, 0xF1, 0x26, 0x59, 0xF1, 0xE6, 0xE5, 0x23, 0x48, 0xBF, 0x6A,
     0x5C, 0xF7, 0x16, 0xE1, 0x3F, 0x41, 0x0E, 0x73
 } };
 
-static const unsigned char kPublicKeyICA1[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xBC, 0x22, 0x80,
-    0xBD, 0x80, 0xF6, 0x3A, 0x21, 0x00, 0x3B, 0xAE, 0x76, 0x5E, 0x35, 0x7F,
-    0x3D, 0xC3, 0x64, 0x5C, 0x55, 0x94, 0x86, 0x34, 0x2F, 0x05, 0x87, 0x28,
-    0xCD, 0xF7, 0x69, 0x8C, 0x17, 0xB3, 0x50, 0xA7, 0xB8, 0x82, 0xFA, 0xDF,
-    0xC7, 0x43, 0x2D, 0xD6, 0x7E, 0xAB, 0xA0, 0x6F, 0xB7, 0x13, 0x72, 0x80,
-    0xA4, 0x47, 0x15, 0xC1, 0x20, 0x99, 0x50, 0xCD, 0xEC, 0x14, 0x62, 0x09,
-    0x5B, 0xA4, 0x98, 0xCD, 0xD2, 0x41, 0xB6, 0x36, 0x4E, 0xFF, 0xE8, 0x2E,
-    0x32, 0x30, 0x4A, 0x81, 0xA8, 0x42, 0xA3, 0x6C, 0x9B, 0x33, 0x6E, 0xCA,
-    0xB2, 0xF5, 0x53, 0x66, 0xE0, 0x27, 0x53, 0x86, 0x1A, 0x85, 0x1E, 0xA7,
-    0x39, 0x3F, 0x4A, 0x77, 0x8E, 0xFB, 0x54, 0x66, 0x66, 0xFB, 0x58, 0x54,
-    0xC0, 0x5E, 0x39, 0xC7, 0xF5, 0x50, 0x06, 0x0B, 0xE0, 0x8A, 0xD4, 0xCE,
-    0xE1, 0x6A, 0x55, 0x1F, 0x8B, 0x17, 0x00, 0xE6, 0x69, 0xA3, 0x27, 0xE6,
-    0x08, 0x25, 0x69, 0x3C, 0x12, 0x9D, 0x8D, 0x05, 0x2C, 0xD6, 0x2E, 0xA2,
-    0x31, 0xDE, 0xB4, 0x52, 0x50, 0xD6, 0x20, 0x49, 0xDE, 0x71, 0xA0, 0xF9,
-    0xAD, 0x20, 0x40, 0x12, 0xF1, 0xDD, 0x25, 0xEB, 0xD5, 0xE6, 0xB8, 0x36,
-    0xF4, 0xD6, 0x8F, 0x7F, 0xCA, 0x43, 0xDC, 0xD7, 0x10, 0x5B, 0xE6, 0x3F,
-    0x51, 0x8A, 0x85, 0xB3, 0xF3, 0xFF, 0xF6, 0x03, 0x2D, 0xCB, 0x23, 0x4F,
-    0x9C, 0xAD, 0x18, 0xE7, 0x93, 0x05, 0x8C, 0xAC, 0x52, 0x9A, 0xF7, 0x4C,
-    0xE9, 0x99, 0x7A, 0xBE, 0x6E, 0x7E, 0x4D, 0x0A, 0xE3, 0xC6, 0x1C, 0xA9,
-    0x93, 0xFA, 0x3A, 0xA5, 0x91, 0x5D, 0x1C, 0xBD, 0x66, 0xEB, 0xCC, 0x60,
-    0xDC, 0x86, 0x74, 0xCA, 0xCF, 0xF8, 0x92, 0x1C, 0x98, 0x7D, 0x57, 0xFA,
-    0x61, 0x47, 0x9E, 0xAB, 0x80, 0xB7, 0xE4, 0x48, 0x80, 0x2A, 0x92, 0xC5,
-    0x1B, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA2 = {{
-    0x98, 0xD6, 0x6D, 0xE8, 0x1C, 0x56, 0x47, 0x84, 0x4D, 0x96, 0x43, 0x4D,
-    0x37, 0xC4, 0x8D, 0xC2, 0xCE, 0x7F, 0x08, 0x72, 0x50, 0x19, 0xE7, 0xB6,
-    0xE8, 0x92, 0x7F, 0x56, 0xD6, 0x81, 0xAA, 0x18
-}};
-
-static const unsigned char kPublicKeyICA2[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xBC, 0x22, 0x80,
-    0xBD, 0x80, 0xF6, 0x3A, 0x21, 0x00, 0x3B, 0xAE, 0x76, 0x5E, 0x35, 0x7F,
-    0x3D, 0xC3, 0x64, 0x5C, 0x55, 0x94, 0x86, 0x34, 0x2F, 0x05, 0x87, 0x28,
-    0xCD, 0xF7, 0x69, 0x8C, 0x17, 0xB3, 0x50, 0xA7, 0xB8, 0x82, 0xFA, 0xDF,
-    0xC7, 0x43, 0x2D, 0xD6, 0x7E, 0xAB, 0xA0, 0x6F, 0xB7, 0x13, 0x72, 0x80,
-    0xA4, 0x47, 0x15, 0xC1, 0x20, 0x99, 0x50, 0xCD, 0xEC, 0x14, 0x62, 0x09,
-    0x5B, 0xA4, 0x98, 0xCD, 0xD2, 0x41, 0xB6, 0x36, 0x4E, 0xFF, 0xE8, 0x2E,
-    0x32, 0x30, 0x4A, 0x81, 0xA8, 0x42, 0xA3, 0x6C, 0x9B, 0x33, 0x6E, 0xCA,
-    0xB2, 0xF5, 0x53, 0x66, 0xE0, 0x27, 0x53, 0x86, 0x1A, 0x85, 0x1E, 0xA7,
-    0x39, 0x3F, 0x4A, 0x77, 0x8E, 0xFB, 0x54, 0x66, 0x66, 0xFB, 0x58, 0x54,
-    0xC0, 0x5E, 0x39, 0xC7, 0xF5, 0x50, 0x06, 0x0B, 0xE0, 0x8A, 0xD4, 0xCE,
-    0xE1, 0x6A, 0x55, 0x1F, 0x8B, 0x17, 0x00, 0xE6, 0x69, 0xA3, 0x27, 0xE6,
-    0x08, 0x25, 0x69, 0x3C, 0x12, 0x9D, 0x8D, 0x05, 0x2C, 0xD6, 0x2E, 0xA2,
-    0x31, 0xDE, 0xB4, 0x52, 0x50, 0xD6, 0x20, 0x49, 0xDE, 0x71, 0xA0, 0xF9,
-    0xAD, 0x20, 0x40, 0x12, 0xF1, 0xDD, 0x25, 0xEB, 0xD5, 0xE6, 0xB8, 0x36,
-    0xF4, 0xD6, 0x8F, 0x7F, 0xCA, 0x43, 0xDC, 0xD7, 0x10, 0x5B, 0xE6, 0x3F,
-    0x51, 0x8A, 0x85, 0xB3, 0xF3, 0xFF, 0xF6, 0x03, 0x2D, 0xCB, 0x23, 0x4F,
-    0x9C, 0xAD, 0x18, 0xE7, 0x93, 0x05, 0x8C, 0xAC, 0x52, 0x9A, 0xF7, 0x4C,
-    0xE9, 0x99, 0x7A, 0xBE, 0x6E, 0x7E, 0x4D, 0x0A, 0xE3, 0xC6, 0x1C, 0xA9,
-    0x93, 0xFA, 0x3A, 0xA5, 0x91, 0x5D, 0x1C, 0xBD, 0x66, 0xEB, 0xCC, 0x60,
-    0xDC, 0x86, 0x74, 0xCA, 0xCF, 0xF8, 0x92, 0x1C, 0x98, 0x7D, 0x57, 0xFA,
-    0x61, 0x47, 0x9E, 0xAB, 0x80, 0xB7, 0xE4, 0x48, 0x80, 0x2A, 0x92, 0xC5,
-    0x1B, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA3 = {{
-    0xA2, 0x48, 0xC2, 0xE8, 0x54, 0xE6, 0x56, 0xA5, 0x6D, 0xE8, 0x23, 0x1F,
-    0x1E, 0xE1, 0x75, 0x6F, 0xDB, 0xE4, 0x07, 0xF9, 0xFE, 0xD4, 0x65, 0x0D,
-    0x60, 0xCC, 0x5A, 0xCB, 0x65, 0x11, 0xC7, 0x20
-}};
-
-static const unsigned char kPublicKeyICA3[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB0, 0x0E, 0x5E,
-    0x07, 0x3A, 0xDF, 0xA4, 0x5F, 0x68, 0xF7, 0x21, 0xC7, 0x64, 0xDB, 0xB6,
-    0x76, 0xEF, 0xEE, 0x8B, 0x93, 0xF8, 0xF6, 0x1B, 0x88, 0xE1, 0x93, 0xB7,
-    0x17, 0xF0, 0x15, 0x1E, 0x7E, 0x52, 0x55, 0x77, 0x3C, 0x02, 0x8D, 0x7B,
-    0x4A, 0x6C, 0xD3, 0xBD, 0xD6, 0xC1, 0x9C, 0x72, 0xC8, 0xB3, 0x15, 0xCF,
-    0x11, 0xC1, 0xF5, 0x46, 0xC4, 0xD5, 0x20, 0x47, 0xFB, 0x30, 0xF4, 0xE4,
-    0x61, 0x0C, 0x68, 0xF0, 0x5E, 0xAB, 0x37, 0x8E, 0x9B, 0xE1, 0xBC, 0x81,
-    0xC3, 0x70, 0x8A, 0x78, 0xD6, 0x83, 0x34, 0x32, 0x9C, 0x19, 0x62, 0xEB,
-    0xE4, 0x9C, 0xED, 0xE3, 0x64, 0x6C, 0x41, 0x1D, 0x9C, 0xD2, 0x8B, 0x48,
-    0x4C, 0x23, 0x90, 0x95, 0xB3, 0xE7, 0x52, 0xEA, 0x05, 0x57, 0xCC, 0x60,
-    0xB3, 0xBA, 0x14, 0xE4, 0xBA, 0x00, 0x39, 0xE4, 0x46, 0x55, 0x74, 0xCE,
-    0x5A, 0x8E, 0x7A, 0x67, 0x23, 0xDA, 0x68, 0x0A, 0xFA, 0xC4, 0x84, 0x1E,
-    0xB4, 0xC5, 0xA1, 0xA2, 0x6A, 0x73, 0x1F, 0x6E, 0xC8, 0x2E, 0x2F, 0x9A,
-    0x9E, 0xA8, 0xB1, 0x0E, 0xFD, 0x87, 0xA6, 0x8F, 0x4D, 0x3D, 0x4B, 0x05,
-    0xD5, 0x35, 0x5A, 0x74, 0x4D, 0xBC, 0x8E, 0x82, 0x44, 0x96, 0xF4, 0xB5,
-    0x95, 0x60, 0x4E, 0xA5, 0xDF, 0x27, 0x3D, 0x41, 0x5C, 0x07, 0xA3, 0xB4,
-    0x35, 0x5A, 0xB3, 0x9E, 0xF2, 0x05, 0x24, 0xCA, 0xCD, 0x31, 0x5A, 0x0D,
-    0x26, 0x4C, 0xD4, 0xD3, 0xFD, 0x50, 0xE1, 0x34, 0xE9, 0x4C, 0x81, 0x58,
-    0x30, 0xB2, 0xC7, 0x7A, 0xDD, 0x81, 0x89, 0xA6, 0xD4, 0x3A, 0x38, 0x84,
-    0x03, 0xB7, 0x34, 0x9E, 0x77, 0x3F, 0xFF, 0x78, 0x07, 0x5B, 0x99, 0xC1,
-    0xB2, 0x1F, 0x35, 0x56, 0x6E, 0x3A, 0x3C, 0x0C, 0x25, 0xE1, 0x57, 0xF6,
-    0x8A, 0x7E, 0x49, 0xC0, 0xCC, 0x83, 0x11, 0x35, 0xE7, 0x91, 0x6D, 0x2E,
-    0x65, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA4 = {{
-    0x2B, 0x9B, 0xC7, 0x92, 0xCD, 0x2A, 0x20, 0xB3, 0x65, 0x5E, 0x57, 0xFB,
-    0x10, 0x1A, 0x95, 0x93, 0x62, 0x53, 0x69, 0x50, 0x52, 0xA2, 0x71, 0x42,
-    0x2B, 0xFE, 0xB5, 0xB4, 0x5D, 0xC5, 0xA5, 0xE9
-}};
-
-static const unsigned char kPublicKeyICA4[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB7, 0xE8, 0xC3,
-    0xE4, 0x2C, 0xDE, 0x74, 0x53, 0xF2, 0x49, 0x95, 0x6D, 0xD1, 0xDA, 0x69,
-    0x57, 0x0D, 0x86, 0xE5, 0xED, 0xB4, 0xB9, 0xE6, 0x73, 0x9F, 0x6C, 0xAD,
-    0x3B, 0x64, 0x85, 0x03, 0x0D, 0x08, 0x44, 0xAF, 0x18, 0x69, 0x82, 0xAD,
-    0xA9, 0x74, 0x64, 0x37, 0x47, 0xE1, 0xE7, 0x26, 0x19, 0x33, 0x3C, 0xE2,
-    0xD0, 0xB5, 0x84, 0x3C, 0xD7, 0xAC, 0x63, 0xAE, 0xC4, 0x32, 0x23, 0xF6,
-    0xDC, 0x14, 0x10, 0x4B, 0x95, 0x7F, 0xE8, 0x98, 0xD7, 0x7A, 0x9E, 0x43,
-    0x3D, 0x68, 0x8B, 0x2A, 0x70, 0xF7, 0x1E, 0x43, 0x70, 0xBA, 0xA5, 0xA5,
-    0x93, 0xAD, 0x8A, 0xD4, 0x9F, 0xAC, 0x83, 0x16, 0xF3, 0x48, 0x5F, 0xC5,
-    0xE0, 0xA5, 0x44, 0xB8, 0x4F, 0xD9, 0xD8, 0x75, 0x90, 0x25, 0x8B, 0xE3,
-    0x1C, 0x6C, 0xDA, 0x88, 0xFF, 0x09, 0x2B, 0xCA, 0x1E, 0x48, 0xDD, 0x76,
-    0x0F, 0x68, 0x56, 0x7B, 0x15, 0x9D, 0xCA, 0x6B, 0x1C, 0xF7, 0x48, 0xC2,
-    0x89, 0xC6, 0x93, 0x0A, 0x31, 0xF2, 0x78, 0x27, 0x45, 0x3D, 0xF1, 0x0D,
-    0x5B, 0x6E, 0x55, 0x32, 0xEF, 0x49, 0xA0, 0xD6, 0xAF, 0xA6, 0x30, 0x91,
-    0xF2, 0x21, 0x2F, 0xDB, 0xA4, 0x29, 0xB9, 0x9B, 0x22, 0xBC, 0xCD, 0x0B,
-    0xA6, 0x8B, 0xA6, 0x22, 0x79, 0xFD, 0xCF, 0x95, 0x93, 0x96, 0xB3, 0x23,
-    0xC9, 0xC6, 0x30, 0x8E, 0xC0, 0xE9, 0x1F, 0xEC, 0xFB, 0xF5, 0x88, 0xDD,
-    0x97, 0x72, 0x16, 0x29, 0x08, 0xFA, 0x42, 0xE7, 0x4F, 0xCA, 0xAE, 0xD7,
-    0x0F, 0x23, 0x48, 0x9B, 0x82, 0xA7, 0x37, 0x4A, 0xDD, 0x60, 0x04, 0x75,
-    0xDC, 0xDE, 0x09, 0x98, 0xD2, 0x16, 0x23, 0x04, 0x70, 0x4D, 0x99, 0x9F,
-    0x4A, 0x82, 0x28, 0xE6, 0xBE, 0x8F, 0x9D, 0xBF, 0xA1, 0x4B, 0xA2, 0xBA,
-    0xF5, 0xB2, 0x51, 0x1E, 0x4E, 0xE7, 0x80, 0x9E, 0x7A, 0x38, 0xA1, 0xC7,
-    0x09, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA5 = {{
-    0xFD, 0xCD, 0x0D, 0x59, 0x29, 0xF8, 0x7A, 0x62, 0xD2, 0xFE, 0x0F, 0xD8,
-    0x94, 0xB8, 0x32, 0xF1, 0xD4, 0x9C, 0x73, 0xF9, 0xD3, 0x51, 0x8B, 0x64,
-    0x67, 0x3E, 0x04, 0x97, 0x0B, 0x0A, 0x4F, 0xAD
-}};
-
-static const unsigned char kPublicKeyICA5[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xC2, 0xF6, 0xD5,
-    0x91, 0xDC, 0x37, 0xB4, 0x9A, 0x73, 0x4A, 0xE7, 0x74, 0x6D, 0x03, 0xAE,
-    0x27, 0x24, 0x41, 0x99, 0x96, 0x1B, 0x05, 0x0E, 0xC7, 0xCF, 0x09, 0xCD,
-    0x65, 0x56, 0x02, 0xFC, 0x98, 0x59, 0xB4, 0xBB, 0x95, 0x71, 0xD7, 0x88,
-    0x66, 0xC8, 0x08, 0xCB, 0xBF, 0x5B, 0x85, 0x65, 0x7E, 0xDE, 0xC4, 0xB5,
-    0xE3, 0x71, 0x24, 0xA2, 0xFD, 0x92, 0x2C, 0x77, 0xC5, 0x08, 0xE0, 0xF0,
-    0xB1, 0x8A, 0x8A, 0x54, 0xCA, 0xA6, 0xAF, 0x87, 0xB8, 0xCB, 0x7D, 0x83,
-    0x28, 0x59, 0x9C, 0x01, 0xF5, 0x7B, 0x10, 0xD0, 0xF3, 0x52, 0x09, 0x3F,
-    0xF5, 0x7D, 0xDA, 0x21, 0x63, 0x8F, 0xAC, 0x8B, 0x60, 0x67, 0x22, 0xEF,
-    0x6B, 0x66, 0x91, 0xFC, 0x97, 0x30, 0x8D, 0xCC, 0xFE, 0xDE, 0x5C, 0xF9,
-    0x19, 0xBB, 0x1C, 0x25, 0x29, 0x2C, 0x99, 0x48, 0x41, 0xC2, 0xFC, 0x5B,
-    0x66, 0xD6, 0x79, 0x84, 0x16, 0x8D, 0x0D, 0x4F, 0x75, 0x01, 0x40, 0xC5,
-    0x50, 0x69, 0xFA, 0xA4, 0x88, 0xF1, 0xD2, 0x3B, 0xD1, 0x23, 0xDF, 0xC5,
-    0xBA, 0xE3, 0xE8, 0xBA, 0xCC, 0x1E, 0x93, 0x17, 0xF7, 0x97, 0xE2, 0x71,
-    0x42, 0x75, 0x5B, 0x99, 0x55, 0x98, 0x22, 0x23, 0x98, 0xDC, 0x10, 0x89,
-    0xF4, 0xE8, 0x26, 0xBB, 0x98, 0x66, 0xFD, 0xBB, 0x9A, 0x21, 0x62, 0xA2,
-    0xDF, 0x90, 0xDB, 0x48, 0x6F, 0xDB, 0x2A, 0xEF, 0xDE, 0x53, 0x59, 0x31,
-    0x5D, 0x38, 0xCD, 0x80, 0xA8, 0x0C, 0x6E, 0x4E, 0x37, 0x65, 0xEB, 0x36,
-    0x1C, 0x13, 0xBA, 0x53, 0xD3, 0x8F, 0xCC, 0x43, 0x86, 0x02, 0x70, 0xD2,
-    0x91, 0xF6, 0x96, 0x25, 0x6C, 0xA4, 0xE8, 0x1F, 0xD8, 0xB3, 0x74, 0x20,
-    0xEB, 0x60, 0x9D, 0x3D, 0xD3, 0x3D, 0x2E, 0x36, 0x0F, 0xF1, 0x94, 0x10,
-    0xF9, 0x7A, 0x03, 0x52, 0x7E, 0xA4, 0xEF, 0xE3, 0x40, 0x9E, 0x74, 0x0E,
-    0xDF, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA6 = {{
-    0xD6, 0xA1, 0xC4, 0xBC, 0x74, 0x5B, 0xC8, 0xE9, 0xED, 0xF8, 0x9C, 0x0D,
-    0x55, 0xCC, 0xB2, 0xC9, 0xF3, 0x04, 0xF6, 0x6E, 0x4D, 0x3D, 0x27, 0x4C,
-    0xA3, 0xFC, 0x0F, 0x4B, 0x95, 0x55, 0x10, 0x7E
-}};
-
-static const unsigned char kPublicKeyICA6[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB5, 0xC8, 0x14,
-    0x5B, 0x94, 0x2E, 0x8E, 0x40, 0xBC, 0x8A, 0xAB, 0x1F, 0x48, 0xEE, 0xA5,
-    0x5C, 0x5D, 0xA9, 0x44, 0x23, 0x33, 0xE5, 0x09, 0xDD, 0x84, 0xDD, 0xA6,
-    0x08, 0x95, 0xB0, 0xEA, 0x64, 0xEB, 0xC1, 0xCA, 0x02, 0x60, 0xFF, 0x83,
-    0xF9, 0x17, 0x71, 0x2C, 0xC7, 0xAB, 0x06, 0x0F, 0xE4, 0xAD, 0x39, 0x24,
-    0xFB, 0x1F, 0xED, 0xFA, 0xB2, 0x4D, 0x14, 0x5A, 0x6E, 0x5B, 0x06, 0x10,
-    0x13, 0xE7, 0x77, 0x22, 0xAA, 0xE5, 0xD1, 0x2C, 0x05, 0xC4, 0x06, 0x05,
-    0xB1, 0xCD, 0xBE, 0xCB, 0x4B, 0xAF, 0x11, 0x3E, 0xA0, 0x77, 0xBA, 0x6D,
-    0xE4, 0xA7, 0xBA, 0xC9, 0x9D, 0x3F, 0x47, 0xE0, 0xD6, 0x20, 0x75, 0x1C,
-    0xE9, 0x89, 0xD3, 0x88, 0x56, 0x4F, 0x29, 0xF6, 0x7D, 0x49, 0x96, 0xBE,
-    0xE8, 0x41, 0xAB, 0x35, 0x08, 0xAD, 0x07, 0x22, 0x90, 0xA3, 0x4A, 0x98,
-    0xBA, 0xC3, 0xE2, 0x29, 0xDA, 0x2E, 0xBD, 0x34, 0xF5, 0x41, 0xBC, 0x27,
-    0x7D, 0xE0, 0x02, 0xBF, 0xB7, 0xAE, 0x8B, 0x1E, 0xEE, 0xE9, 0xC1, 0x59,
-    0x92, 0xEA, 0xE3, 0x76, 0x0E, 0xE7, 0x77, 0xEF, 0x10, 0x7E, 0x4F, 0xD8,
-    0xAD, 0xC4, 0x5D, 0xBB, 0xB7, 0x9F, 0x23, 0x0B, 0x34, 0x89, 0xF7, 0x97,
-    0x9A, 0x40, 0x79, 0x00, 0xDD, 0x10, 0x9E, 0x01, 0xA7, 0xF0, 0xD8, 0xC4,
-    0x37, 0xF1, 0x6A, 0xD7, 0xC2, 0xE9, 0x75, 0x94, 0x55, 0xA9, 0x81, 0xA8,
-    0xF8, 0xC6, 0xF9, 0xD2, 0xCF, 0x26, 0xA0, 0x74, 0x58, 0x2E, 0xD0, 0xCB,
-    0x16, 0x58, 0x1B, 0x1E, 0x2B, 0x94, 0x80, 0x26, 0x82, 0x3F, 0x01, 0x36,
-    0x01, 0x97, 0x1E, 0xA6, 0x94, 0x14, 0xC0, 0xB2, 0x55, 0x95, 0x2E, 0x30,
-    0x9C, 0x7B, 0xC6, 0x79, 0xF8, 0x12, 0xB3, 0xB4, 0x11, 0x93, 0x73, 0x9C,
-    0xD4, 0x3F, 0x29, 0x6E, 0x6A, 0xAA, 0xA8, 0xE9, 0xA2, 0xF3, 0x20, 0x4E,
-    0xE9, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA7 = {{
-    0xB6, 0xB3, 0x4F, 0x73, 0x23, 0x9D, 0xA6, 0xDD, 0x9A, 0x26, 0xF7, 0xD5,
-    0x9E, 0x26, 0x3B, 0xF0, 0x0C, 0x01, 0x6B, 0x21, 0x17, 0x41, 0xE5, 0xAD,
-    0x92, 0xA5, 0xA0, 0x0B, 0xD7, 0x31, 0x26, 0x11
-}};
-
-static const unsigned char kPublicKeyICA7[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xCC, 0xE2, 0xB6,
-    0x2F, 0x11, 0xAB, 0xFF, 0xD0, 0x5D, 0x63, 0x97, 0x59, 0xFA, 0x5F, 0x26,
-    0xD7, 0x91, 0xE9, 0x90, 0x86, 0x31, 0x91, 0x8E, 0x2D, 0x29, 0x5F, 0x7A,
-    0x2F, 0x12, 0x77, 0x21, 0xD9, 0x0E, 0x99, 0x0F, 0x11, 0x08, 0x69, 0x3C,
-    0x9C, 0x58, 0xD4, 0xCE, 0x44, 0xB3, 0x8E, 0x46, 0x6C, 0xC1, 0x8E, 0x60,
-    0x63, 0x3E, 0x99, 0x24, 0x72, 0x69, 0x07, 0xC2, 0x30, 0x0F, 0xD5, 0x74,
-    0x06, 0xC6, 0x09, 0x94, 0x13, 0xD7, 0x34, 0x34, 0x75, 0x73, 0x4F, 0x4A,
-    0x01, 0xFE, 0x1E, 0x3C, 0x91, 0x86, 0x9C, 0x63, 0xF8, 0xEF, 0x15, 0x79,
-    0xE5, 0x5A, 0xC1, 0xF2, 0x05, 0xDC, 0xE0, 0x76, 0xDE, 0x69, 0x46, 0xDF,
-    0x12, 0x3D, 0xF4, 0xD9, 0x05, 0xE2, 0x9E, 0xAD, 0x07, 0xCC, 0x69, 0x5F,
-    0x1D, 0x42, 0x5E, 0x6C, 0x4A, 0xB4, 0x89, 0x7C, 0xDB, 0xBC, 0x69, 0x4E,
-    0x23, 0x70, 0x9A, 0x67, 0xC5, 0xFA, 0x29, 0x88, 0x7C, 0x30, 0xFA, 0x61,
-    0x98, 0x3C, 0x43, 0x4A, 0x1E, 0xCA, 0xAE, 0xA8, 0x7B, 0x65, 0x68, 0xA3,
-    0xFB, 0x38, 0xB4, 0x4F, 0xCA, 0x49, 0x60, 0x85, 0xA0, 0xC1, 0x55, 0xA1,
-    0xCE, 0x67, 0x78, 0x9F, 0x53, 0x81, 0xD7, 0x92, 0xC9, 0x6D, 0x44, 0xF1,
-    0x97, 0x95, 0xA5, 0x7C, 0x83, 0xEC, 0xD3, 0xEB, 0x7D, 0xD7, 0x0A, 0x06,
-    0xFE, 0xBA, 0xFC, 0x56, 0x5F, 0xF0, 0x70, 0xE4, 0x82, 0xBE, 0x69, 0x6D,
-    0x95, 0x00, 0xDF, 0xB5, 0xE5, 0xBF, 0x9E, 0xF1, 0x12, 0x47, 0x14, 0x9C,
-    0x7D, 0xE5, 0xA0, 0xB8, 0x70, 0x29, 0x6B, 0xC8, 0x8A, 0xF2, 0xBA, 0x35,
-    0xD8, 0xC4, 0xD3, 0xB4, 0xB5, 0xEB, 0xDF, 0x2D, 0x27, 0x46, 0xA5, 0xFF,
-    0x35, 0xB5, 0x5F, 0x85, 0x72, 0xEB, 0xCF, 0xAD, 0x09, 0x18, 0x05, 0x95,
-    0x56, 0x88, 0x95, 0x22, 0xD7, 0x60, 0x47, 0xC9, 0x1F, 0xFA, 0x2D, 0x51,
-    0x3F, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA8 = {{
-    0xE9, 0xD4, 0x83, 0xD3, 0x78, 0x01, 0xB1, 0x1A, 0xB8, 0x8E, 0xE1, 0x87,
-    0xB1, 0x88, 0xD5, 0xE2, 0xF0, 0xFE, 0x18, 0xE7, 0xCE, 0xB8, 0x10, 0x06,
-    0x3E, 0xA5, 0x05, 0x4A, 0x1A, 0x9D, 0x1C, 0x11
-}};
-
-static const unsigned char kPublicKeyICA8[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xBF, 0x3A, 0x31,
-    0xFC, 0xF8, 0xE6, 0xEE, 0xC0, 0x48, 0x00, 0xB4, 0x05, 0x65, 0x36, 0x23,
-    0x6D, 0x34, 0xD6, 0x00, 0xD5, 0x43, 0x89, 0x6A, 0x90, 0xCB, 0x7D, 0x1B,
-    0x39, 0xFE, 0x2E, 0x83, 0x84, 0x29, 0xBE, 0x51, 0xEF, 0x98, 0x66, 0x48,
-    0x59, 0x8E, 0x7E, 0x10, 0x14, 0x1D, 0x9F, 0xAA, 0x52, 0xFD, 0x6B, 0xBF,
-    0xC6, 0x13, 0xF2, 0xE9, 0x79, 0x62, 0xE2, 0xA0, 0x3B, 0xC6, 0x44, 0x70,
-    0x94, 0x98, 0xAF, 0x92, 0x9E, 0x66, 0x3F, 0xA4, 0x6C, 0xC1, 0x2F, 0x6D,
-    0xA2, 0x08, 0x8A, 0x47, 0x1B, 0xFA, 0x6D, 0x09, 0xCF, 0x94, 0xDB, 0x20,
-    0xCE, 0xA2, 0xBF, 0xEA, 0x06, 0xF4, 0xD3, 0x4D, 0xF7, 0x62, 0xAE, 0x1A,
-    0x64, 0xEC, 0x1F, 0xA5, 0x40, 0x2D, 0x15, 0xE7, 0xF7, 0x26, 0xFB, 0x08,
-    0xD9, 0x5B, 0xFC, 0x86, 0x7E, 0xC7, 0x94, 0x18, 0x08, 0x2A, 0xF5, 0x83,
-    0x44, 0x06, 0x15, 0x12, 0x5A, 0x1F, 0xBB, 0x47, 0xE3, 0x2C, 0x61, 0x64,
-    0xDF, 0xFE, 0x74, 0x0E, 0x78, 0xA4, 0x65, 0xB8, 0x70, 0xC1, 0xDB, 0x3D,
-    0xCA, 0x26, 0x33, 0xBD, 0x4A, 0x14, 0xDA, 0x0B, 0xEC, 0xEC, 0xB3, 0x34,
-    0x23, 0x59, 0xD2, 0x11, 0xF9, 0xB0, 0x53, 0x1C, 0x75, 0x76, 0xF5, 0x65,
-    0x00, 0x6C, 0xF0, 0x7F, 0xFA, 0x1A, 0x59, 0xFE, 0xF8, 0x9D, 0x1A, 0x4E,
-    0x42, 0x35, 0xEE, 0x2F, 0xE3, 0xA1, 0xE2, 0xDF, 0xDB, 0x7A, 0x6B, 0x5E,
-    0x6B, 0x21, 0xFF, 0xA5, 0xE1, 0x87, 0xDF, 0xB8, 0xE7, 0x52, 0xAD, 0x99,
-    0xCD, 0x47, 0x88, 0xE0, 0xBA, 0xF0, 0x3D, 0x9D, 0x87, 0x93, 0xAD, 0xA7,
-    0x45, 0x67, 0xF0, 0x1E, 0x46, 0xD7, 0x83, 0x9A, 0xE5, 0x49, 0x76, 0x21,
-    0x82, 0xCB, 0x82, 0x67, 0xA5, 0xFF, 0x63, 0xD8, 0x97, 0x51, 0xB4, 0x44,
-    0xA0, 0x76, 0xBA, 0x40, 0xD8, 0xAB, 0xA6, 0xEB, 0x70, 0xD5, 0xA4, 0x38,
-    0xB9, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA9 = {{
-    0x7A, 0x96, 0xE1, 0xA4, 0xDE, 0xEB, 0x04, 0x23, 0xD6, 0xC4, 0xFD, 0x98,
-    0xDF, 0x25, 0x83, 0x25, 0x2C, 0x3E, 0xE0, 0x23, 0x35, 0x9F, 0x4B, 0x92,
-    0x08, 0xAB, 0xE8, 0x7C, 0xB1, 0xD8, 0x4D, 0x85
-}};
-
-static const unsigned char kPublicKeyICA9[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xE5, 0x44, 0x79,
-    0xD4, 0x75, 0x3A, 0xBD, 0x25, 0x6F, 0x89, 0xF7, 0x94, 0xE9, 0x23, 0xAE,
-    0x19, 0x38, 0x09, 0xA7, 0x75, 0x9C, 0x5A, 0x08, 0x4A, 0xC2, 0xC6, 0xA4,
-    0x95, 0x13, 0x96, 0x95, 0x4E, 0xFA, 0xF1, 0xC3, 0xD2, 0x7A, 0xBC, 0x4A,
-    0xEE, 0x65, 0x2D, 0xE2, 0xB1, 0x57, 0x49, 0x02, 0x84, 0x7C, 0x35, 0x31,
-    0x8A, 0xBB, 0xCB, 0x75, 0x9C, 0x14, 0x84, 0x52, 0x85, 0x40, 0xD2, 0x1D,
-    0x03, 0xAE, 0x2B, 0x38, 0xA2, 0x7F, 0xEE, 0xE8, 0x3C, 0x51, 0x5B, 0x82,
-    0x11, 0x9E, 0xE2, 0xC9, 0x0B, 0x7B, 0x66, 0xF2, 0xE5, 0x35, 0x64, 0x4B,
-    0xF1, 0x98, 0xD9, 0x60, 0x0A, 0xA2, 0x8B, 0xB2, 0xD3, 0x96, 0x35, 0xBE,
-    0x2D, 0xB4, 0x7E, 0xAC, 0x75, 0x73, 0x5F, 0xC0, 0x78, 0xC1, 0x91, 0x3E,
-    0xB7, 0xB2, 0x53, 0x4F, 0x78, 0x7D, 0x58, 0x93, 0x12, 0x3B, 0xA9, 0xB3,
-    0x8F, 0xA7, 0xF6, 0x7F, 0x4C, 0x2F, 0x7B, 0xFA, 0x41, 0xCA, 0xF5, 0x5A,
-    0xF4, 0x8A, 0x5B, 0xFE, 0x82, 0x18, 0x90, 0xE5, 0x15, 0x01, 0xD3, 0xD8,
-    0x83, 0x6B, 0x02, 0xA3, 0xAE, 0x54, 0x5C, 0xD9, 0x0B, 0x65, 0x00, 0xD6,
-    0x06, 0xF6, 0x4E, 0x52, 0x2C, 0x9C, 0x06, 0x1B, 0x11, 0x53, 0xA5, 0x7E,
-    0xBE, 0xAC, 0x5E, 0x01, 0xF1, 0x50, 0xF2, 0xC0, 0x26, 0xC6, 0xF9, 0xDD,
-    0x89, 0x8C, 0x1D, 0xD4, 0x7A, 0x59, 0xC2, 0xD7, 0xF8, 0x7A, 0x03, 0x6A,
-    0xBD, 0xC5, 0x75, 0x04, 0xED, 0x29, 0x90, 0xD8, 0x24, 0x75, 0x12, 0x38,
-    0x24, 0xF2, 0x56, 0xB4, 0x87, 0xB2, 0x55, 0x0F, 0x26, 0x1D, 0xD0, 0x6B,
-    0x32, 0xDF, 0x05, 0xFA, 0x73, 0x94, 0xB0, 0x6B, 0x41, 0xE7, 0x2D, 0xF0,
-    0x24, 0x48, 0xA8, 0x5B, 0x03, 0x34, 0xE7, 0x48, 0x92, 0x4E, 0x99, 0x3A,
-    0x6B, 0x96, 0x8E, 0x8E, 0x48, 0x52, 0xA5, 0xE8, 0x13, 0x54, 0xCF, 0x8D,
-    0xA1, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA10 = {{
-    0x61, 0x79, 0xBE, 0x64, 0x83, 0xD6, 0x71, 0xCE, 0x4F, 0xEE, 0x95, 0x5B,
-    0xF3, 0x6A, 0x1D, 0xDB, 0xC9, 0x51, 0x2F, 0xF4, 0x0C, 0xF8, 0xA5, 0x1C,
-    0x4F, 0x31, 0x2A, 0x93, 0x9A, 0x94, 0x07, 0xF7
-}};
-
-static const unsigned char kPublicKeyICA10[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xAF, 0xA1, 0x27,
-    0x5B, 0x18, 0x01, 0xF9, 0x16, 0x7C, 0xB9, 0x1D, 0xBB, 0x34, 0xC4, 0x45,
-    0xCF, 0x7A, 0x7B, 0x7A, 0xB7, 0xC9, 0x52, 0xC6, 0xC1, 0xBE, 0x14, 0x57,
-    0xF5, 0xDC, 0xF7, 0xA3, 0xB9, 0x1F, 0x63, 0x5B, 0xDE, 0x95, 0x36, 0x23,
-    0x3A, 0xD4, 0xDF, 0x33, 0xA5, 0x75, 0xF6, 0x2B, 0x70, 0x6B, 0xE6, 0x46,
-    0xA9, 0x94, 0x84, 0x22, 0xD0, 0xC7, 0xF4, 0x2C, 0x8D, 0x20, 0xBC, 0x2F,
-    0x8E, 0x08, 0x44, 0xA4, 0x99, 0x30, 0xE2, 0x2B, 0x37, 0x1E, 0x1A, 0xB7,
-    0x0D, 0x98, 0x20, 0x40, 0x18, 0xEC, 0x7E, 0x7C, 0x65, 0xD7, 0xF7, 0x1E,
-    0x7A, 0x50, 0x1C, 0x27, 0xFE, 0x82, 0x5F, 0xFA, 0xDF, 0xAC, 0xA6, 0x4E,
-    0xB4, 0x91, 0x2F, 0x73, 0xFB, 0x20, 0xFC, 0x70, 0x3F, 0x5E, 0x58, 0x7B,
-    0xAC, 0xC6, 0x1C, 0xAD, 0xEF, 0x0A, 0xB1, 0xB3, 0x12, 0x2E, 0xB8, 0xC3,
-    0x60, 0xCB, 0xF7, 0x71, 0x5F, 0x18, 0xDD, 0x85, 0x64, 0x06, 0xA7, 0x17,
-    0x60, 0x81, 0x72, 0x6D, 0xE2, 0x24, 0x57, 0xCA, 0x3D, 0x1D, 0x87, 0x75,
-    0x05, 0x95, 0xDE, 0x38, 0x8A, 0xE0, 0xC2, 0xF7, 0xCB, 0x2F, 0xA6, 0xB9,
-    0x24, 0x50, 0x14, 0x17, 0x12, 0x77, 0xFB, 0x41, 0xA8, 0xA1, 0x79, 0xBC,
-    0xC0, 0x87, 0x06, 0x34, 0xF2, 0xAF, 0x87, 0x12, 0xB6, 0x66, 0x24, 0xDD,
-    0x3E, 0xBA, 0x4E, 0x34, 0x02, 0xF2, 0x1B, 0xAB, 0x1D, 0x79, 0x72, 0x41,
-    0x16, 0x0E, 0x1F, 0x9B, 0x35, 0x40, 0xD0, 0xC6, 0x07, 0xA7, 0x91, 0x53,
-    0x55, 0x19, 0x0C, 0xB1, 0x1B, 0x42, 0x20, 0x41, 0xC5, 0x2A, 0xA8, 0x26,
-    0x8D, 0x44, 0x50, 0x1B, 0x0B, 0x21, 0xB2, 0x16, 0xA2, 0x1B, 0xF3, 0xBD,
-    0xC2, 0x1D, 0xAF, 0x4F, 0x41, 0x43, 0xAD, 0x3A, 0x76, 0x45, 0x3C, 0x2B,
-    0xD3, 0x71, 0x31, 0x43, 0x37, 0xB6, 0x68, 0xA6, 0x5D, 0x8C, 0x50, 0x2B,
-    0x8F, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA11 = {{
-    0x9C, 0x1E, 0xB3, 0xEA, 0x88, 0xAA, 0x1C, 0x1E, 0x0A, 0xE7, 0x9C, 0x2B,
-    0x43, 0xFF, 0x46, 0xD4, 0xC8, 0xF5, 0xF4, 0xFF, 0x43, 0x71, 0xFB, 0x83,
-    0xE4, 0x81, 0x13, 0x8D, 0xAD, 0x82, 0x42, 0xE8
-}};
-
-static const unsigned char kPublicKeyICA11[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xA8, 0xB2, 0x65,
-    0xFB, 0x07, 0xB0, 0x21, 0xBE, 0x11, 0xD1, 0xDA, 0x5D, 0x89, 0xB5, 0xAA,
-    0xC2, 0xFD, 0xD3, 0x27, 0x8D, 0x3A, 0x29, 0x2F, 0x3E, 0xD4, 0x87, 0xC1,
-    0x1B, 0x51, 0x39, 0x48, 0x73, 0x4A, 0xD5, 0x52, 0x5D, 0x59, 0x93, 0x8B,
-    0xF3, 0x3D, 0x57, 0x6A, 0x77, 0x7D, 0x43, 0x3A, 0xED, 0xE5, 0xC2, 0x0E,
-    0xFB, 0xE0, 0xFB, 0x0C, 0x65, 0x65, 0x74, 0xA9, 0x1F, 0x3C, 0x56, 0x77,
-    0xC8, 0x5C, 0x8F, 0xA3, 0xCB, 0xB4, 0x68, 0xBC, 0xE9, 0x0F, 0xE4, 0x52,
-    0x46, 0x1B, 0xB2, 0x23, 0x6F, 0x66, 0x9D, 0xB7, 0xCF, 0xD9, 0x48, 0xE2,
-    0x7D, 0x17, 0x26, 0x45, 0x4F, 0xA5, 0x14, 0x10, 0x08, 0xCE, 0xEC, 0x18,
-    0xE0, 0x78, 0x8E, 0x25, 0xB7, 0xAE, 0x23, 0xBD, 0xAE, 0x56, 0x33, 0x1F,
-    0x5B, 0x02, 0x41, 0xE1, 0x22, 0x6D, 0x85, 0x8E, 0xB0, 0x87, 0x73, 0xF8,
-    0xBF, 0x3A, 0x06, 0xF7, 0xDA, 0x70, 0xCB, 0x14, 0x1F, 0x1E, 0xFF, 0x78,
-    0x9D, 0xC4, 0x7A, 0xFF, 0x76, 0x32, 0x35, 0x28, 0x16, 0xD4, 0xBF, 0xBC,
-    0x2B, 0x4E, 0xD2, 0x86, 0x50, 0x14, 0x7A, 0x8D, 0x3F, 0x8F, 0x9E, 0x53,
-    0x0B, 0xB5, 0x83, 0x6E, 0x00, 0x82, 0xB0, 0x08, 0x6F, 0x22, 0xF4, 0x26,
-    0x33, 0x19, 0xCC, 0x82, 0xC7, 0x4C, 0xA0, 0x1B, 0xD2, 0x62, 0x33, 0xF7,
-    0x75, 0x0B, 0x57, 0x4A, 0xDF, 0xDD, 0x68, 0xCB, 0xFD, 0x6F, 0xB8, 0xB3,
-    0x8F, 0x8E, 0x45, 0x8D, 0xEE, 0xF2, 0xA2, 0xFD, 0x71, 0xF5, 0xE0, 0x1B,
-    0x3E, 0x62, 0x00, 0x35, 0x98, 0x19, 0x6B, 0xA3, 0x1B, 0x1A, 0xA3, 0x5D,
-    0xDE, 0x49, 0xB9, 0x20, 0x0D, 0x44, 0x8F, 0x58, 0x3C, 0xDD, 0x52, 0x6D,
-    0x03, 0x7A, 0x33, 0xB3, 0x06, 0x7A, 0xC7, 0x49, 0x23, 0xC5, 0x2A, 0x24,
-    0xB6, 0x96, 0x12, 0x4C, 0x16, 0xB3, 0x3A, 0xFC, 0x46, 0x03, 0xEC, 0xBB,
-    0xF9, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA12 = {{
-    0xFF, 0xFA, 0x45, 0x0D, 0x1D, 0xB6, 0x31, 0x13, 0xA7, 0x43, 0x70, 0x19,
-    0x6E, 0xCB, 0xDB, 0xA4, 0x3F, 0x74, 0xF4, 0xBD, 0x63, 0xAD, 0x8E, 0xFD,
-    0x35, 0x62, 0xB3, 0xF9, 0xE8, 0x69, 0x1F, 0xDB
-}};
-
-static const unsigned char kPublicKeyICA12[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xD9, 0xE3, 0x76,
-    0x97, 0x6A, 0xEF, 0x2D, 0x16, 0xD5, 0xF9, 0xDC, 0x9D, 0x0E, 0x65, 0x12,
-    0x65, 0x72, 0xC0, 0xE9, 0x11, 0x12, 0x37, 0x09, 0x5D, 0x54, 0xF4, 0x8F,
-    0x3C, 0xDB, 0xF2, 0xE9, 0x42, 0x9F, 0x4E, 0xF2, 0xD0, 0x4E, 0xC8, 0x10,
-    0x31, 0xE8, 0x1B, 0xFE, 0x5B, 0xFB, 0xC8, 0xD3, 0xFB, 0x77, 0x25, 0xC4,
-    0x69, 0xFA, 0x53, 0x03, 0x16, 0x12, 0x7F, 0x23, 0x9F, 0x4C, 0xFB, 0x35,
-    0x60, 0xAE, 0xFB, 0xA5, 0x94, 0xD3, 0x5A, 0x97, 0x38, 0x91, 0x6E, 0x87,
-    0xE4, 0xB5, 0xA1, 0x6E, 0x23, 0x1C, 0x7A, 0x41, 0x55, 0x27, 0xA3, 0x9E,
-    0x6E, 0xF3, 0xD0, 0xA7, 0x19, 0x52, 0x0C, 0x7C, 0xBC, 0xEC, 0xB6, 0xB8,
-    0x54, 0x40, 0x77, 0x0E, 0x67, 0x14, 0x0D, 0x19, 0x1B, 0x74, 0xD4, 0x2C,
-    0x16, 0x01, 0xE5, 0x57, 0x6C, 0x03, 0x1E, 0xE3, 0x9E, 0xA3, 0x8E, 0x72,
-    0xA6, 0x63, 0x3A, 0xED, 0x25, 0xEC, 0x15, 0x2F, 0xE8, 0xCE, 0x52, 0x1E,
-    0xCB, 0x50, 0x39, 0x36, 0x7E, 0xC2, 0xEC, 0x7C, 0xCA, 0x4A, 0xB8, 0x73,
-    0x91, 0xC8, 0x88, 0x98, 0x31, 0x0F, 0x2E, 0x68, 0x45, 0x53, 0x22, 0x66,
-    0xF1, 0xF5, 0xBF, 0xF9, 0x11, 0x88, 0xB6, 0x36, 0x8E, 0xAA, 0x1A, 0xB8,
-    0xC9, 0x18, 0x90, 0x44, 0xBE, 0xBD, 0xDD, 0xB1, 0x81, 0x98, 0xBE, 0xEB,
-    0x1F, 0xF6, 0x28, 0x85, 0xB3, 0xA4, 0xA1, 0xAE, 0x14, 0xD2, 0x91, 0x9D,
-    0xD3, 0xB1, 0x0B, 0xEC, 0x72, 0x3D, 0x43, 0xEB, 0xD3, 0x79, 0x2A, 0x7D,
-    0xAD, 0x79, 0xA5, 0xB5, 0xA0, 0xDD, 0x88, 0x89, 0x6E, 0xB4, 0xC8, 0x11,
-    0xB6, 0x11, 0xED, 0x18, 0x50, 0x43, 0x2E, 0xD7, 0xCE, 0x18, 0x58, 0xEB,
-    0xCE, 0x2E, 0xE9, 0x9E, 0x20, 0x86, 0xFE, 0x97, 0xCD, 0xB2, 0x9C, 0xC1,
-    0xAF, 0x24, 0x02, 0x38, 0x60, 0x6B, 0xCC, 0x66, 0xC3, 0x04, 0x72, 0xD3,
-    0xF1, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA13 = {{
-    0xE0, 0x2C, 0x66, 0xCD, 0x6F, 0x96, 0xFC, 0x1B, 0x5A, 0x43, 0xC4, 0xA5,
-    0x19, 0xB6, 0x6F, 0x0B, 0xFE, 0xA7, 0x58, 0x0D, 0xC1, 0x02, 0x3E, 0xFE,
-    0xFF, 0x9C, 0xE4, 0x9E, 0xB1, 0x7E, 0x3F, 0x79
-}};
-
-static const unsigned char kPublicKeyICA13[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xBB, 0xE5, 0x0F,
-    0xD2, 0x1C, 0x6B, 0xBA, 0x23, 0xA9, 0x2F, 0x87, 0xEC, 0xDB, 0x92, 0x3F,
-    0xAF, 0xC8, 0xD4, 0xB2, 0x59, 0x24, 0x2E, 0xC8, 0xCD, 0x00, 0xEF, 0x09,
-    0xFB, 0xF6, 0x19, 0xE7, 0x6C, 0x8A, 0x1A, 0x3B, 0xB6, 0xCC, 0xEF, 0x3A,
-    0x40, 0x6C, 0x93, 0xF8, 0xE3, 0x1B, 0xB7, 0xE5, 0x1C, 0x92, 0x65, 0xE8,
-    0x5E, 0x64, 0x83, 0x90, 0xF1, 0x24, 0x4A, 0xD1, 0xC5, 0x3D, 0x8C, 0x3B,
-    0x71, 0x66, 0x31, 0x58, 0xD8, 0x55, 0xC2, 0xCC, 0xD3, 0xEA, 0x0E, 0x66,
-    0x88, 0x59, 0x14, 0x77, 0xED, 0x12, 0xC5, 0x96, 0x54, 0x7F, 0x97, 0x28,
-    0x3B, 0x5E, 0xCA, 0xF7, 0x1B, 0xD3, 0x4B, 0x10, 0xC3, 0x45, 0x3A, 0x4D,
-    0xCA, 0x36, 0x5A, 0xFF, 0x4F, 0x86, 0xDD, 0x9E, 0x69, 0xDF, 0xD5, 0x4A,
-    0xD0, 0xB8, 0x9F, 0x8D, 0x31, 0x70, 0x76, 0x63, 0x33, 0xB0, 0xB8, 0xF4,
-    0xB0, 0x45, 0x28, 0xB3, 0x5D, 0xF2, 0x2F, 0xC5, 0xA4, 0xD9, 0x30, 0x6F,
-    0x9F, 0x69, 0x23, 0x42, 0x6D, 0x7D, 0x73, 0x29, 0x56, 0x61, 0xCC, 0x56,
-    0xC9, 0xAE, 0xED, 0x13, 0x33, 0xB4, 0x0E, 0xD0, 0x25, 0xE3, 0x06, 0xC1,
-    0x9A, 0x26, 0xDB, 0x8E, 0x89, 0xA6, 0xA0, 0xF9, 0x30, 0xE6, 0x92, 0xD0,
-    0xEC, 0x77, 0xB9, 0xA8, 0x0C, 0x8E, 0x83, 0x5D, 0x6B, 0xB9, 0x49, 0xF2,
-    0xFB, 0x1C, 0xE4, 0x79, 0xC8, 0xB3, 0x90, 0x88, 0xE9, 0x92, 0x24, 0x8A,
-    0x18, 0x7E, 0xE3, 0x5C, 0xEF, 0xC0, 0x4B, 0xDD, 0xFD, 0x09, 0x14, 0x4C,
-    0x9C, 0x7A, 0xB3, 0x56, 0x84, 0x96, 0xDB, 0x08, 0xA8, 0xE1, 0xCD, 0x40,
-    0x94, 0xF5, 0x12, 0xF4, 0x63, 0x38, 0x0C, 0x51, 0xE4, 0x03, 0x63, 0xC4,
-    0x76, 0x54, 0xB7, 0x59, 0x25, 0xCE, 0x62, 0xDE, 0x73, 0x3F, 0xAB, 0x15,
-    0x56, 0xC5, 0xBC, 0x99, 0x8C, 0x3A, 0x46, 0x3F, 0x13, 0x0E, 0xF4, 0x53,
-    0x1D, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA14 = {{
-    0x3B, 0x60, 0x2E, 0xE9, 0x9F, 0x75, 0x7C, 0x18, 0xE3, 0x08, 0x1E, 0xC0,
-    0x72, 0xE9, 0x20, 0x05, 0x0B, 0x83, 0xD7, 0xB7, 0x5E, 0x25, 0x47, 0xE7,
-    0xE6, 0x44, 0x2C, 0x40, 0xF4, 0xA9, 0xA1, 0xD0
-}};
-
-static const unsigned char kPublicKeyICA14[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xAD, 0x16, 0x57,
-    0x87, 0xD7, 0x0D, 0xA3, 0xA2, 0x7E, 0x8B, 0xAE, 0x45, 0x7A, 0x1F, 0xCA,
-    0xFE, 0xB9, 0x15, 0xB7, 0x5B, 0x9F, 0x7D, 0x16, 0xA5, 0xA5, 0x63, 0xB1,
-    0xF5, 0x6E, 0x17, 0x7F, 0x35, 0xD8, 0x4A, 0x8C, 0x97, 0xBF, 0x77, 0x84,
-    0x5E, 0xC6, 0x21, 0x81, 0xAF, 0x72, 0xEF, 0xCF, 0xDE, 0x46, 0xB7, 0xE7,
-    0x49, 0x61, 0x8E, 0xFC, 0x84, 0x12, 0xBC, 0x30, 0xEA, 0xF8, 0x5B, 0x78,
-    0x6C, 0x3E, 0x12, 0x23, 0x33, 0x29, 0x80, 0x34, 0x6A, 0x1E, 0x8D, 0x3C,
-    0x15, 0xE9, 0x47, 0x9E, 0x33, 0x27, 0x90, 0x73, 0x52, 0xD0, 0xBF, 0xCE,
-    0x0D, 0x68, 0xE5, 0x5A, 0x90, 0x71, 0xB2, 0xF2, 0xBD, 0x7E, 0x69, 0xE0,
-    0x92, 0xDC, 0x44, 0x9F, 0x4B, 0xA3, 0xC2, 0x58, 0x16, 0x1A, 0x35, 0x18,
-    0x88, 0x3A, 0x82, 0x15, 0xFC, 0x41, 0x8C, 0x72, 0x11, 0x2E, 0xC4, 0xED,
-    0xD3, 0x7E, 0x68, 0xF2, 0x00, 0x01, 0xE2, 0x71, 0xC3, 0x91, 0x91, 0xFD,
-    0xF3, 0xBE, 0x11, 0xE7, 0x62, 0xB4, 0xAF, 0xC8, 0xF0, 0x12, 0xBC, 0xB2,
-    0x0E, 0x58, 0x5C, 0xFF, 0x08, 0xCB, 0xCB, 0x91, 0xD2, 0xD0, 0x11, 0x87,
-    0x72, 0x04, 0x99, 0x63, 0x12, 0xA6, 0x6F, 0x7D, 0x40, 0x76, 0xB7, 0xE8,
-    0x89, 0xCE, 0xCD, 0x5A, 0x73, 0x18, 0x8A, 0x73, 0xAF, 0xFD, 0x21, 0x68,
-    0xE5, 0x26, 0x74, 0x12, 0x2C, 0xC3, 0xE6, 0x7D, 0x1D, 0x9A, 0xC8, 0x12,
-    0xCD, 0x38, 0xCB, 0x47, 0xA6, 0x54, 0x8F, 0xAD, 0x9F, 0xFA, 0xB1, 0xDF,
-    0xB0, 0xBF, 0xE7, 0x12, 0x32, 0x76, 0xA7, 0xA5, 0xD7, 0x46, 0xF8, 0x62,
-    0x15, 0x54, 0x78, 0xBA, 0x9E, 0x4D, 0xD8, 0x99, 0x62, 0x9E, 0xE8, 0x45,
-    0x93, 0x8C, 0x14, 0x7E, 0x9C, 0xE9, 0xF7, 0x2A, 0x7E, 0x56, 0xE3, 0xBD,
-    0xF1, 0x65, 0xC8, 0x6B, 0xB9, 0xE5, 0x16, 0x1E, 0x22, 0x29, 0xEC, 0xCA,
-    0xD9, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA15 = {{
-    0x09, 0xA7, 0x9F, 0x65, 0xE5, 0x55, 0x72, 0xAA, 0xFD, 0xDB, 0x74, 0xE9,
-    0xF8, 0xFA, 0x01, 0x45, 0x1D, 0x8E, 0xA4, 0x17, 0x48, 0xAB, 0x50, 0x75,
-    0xF9, 0xB1, 0x12, 0xB0, 0x6F, 0xC8, 0x08, 0xAE
-}};
-
-static const unsigned char kPublicKeyICA15[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xDD, 0xFE, 0x56,
-    0x5F, 0x53, 0x05, 0x59, 0x8F, 0x7C, 0xF4, 0x8B, 0x90, 0x38, 0xED, 0x51,
-    0xE6, 0x8A, 0xAC, 0x78, 0x1F, 0x7B, 0x33, 0x74, 0x7F, 0x33, 0xAA, 0x6A,
-    0x13, 0x6F, 0x7C, 0xDF, 0x82, 0x8F, 0x7B, 0xC4, 0x11, 0xAE, 0x5C, 0x2B,
-    0x1A, 0xDB, 0x9A, 0x95, 0x13, 0xE8, 0x64, 0x48, 0x37, 0x6C, 0x6B, 0x8C,
-    0xDD, 0x42, 0xE1, 0xCE, 0xE4, 0x0C, 0xDF, 0xA2, 0x41, 0x9E, 0x78, 0x8B,
-    0x26, 0xBF, 0xA1, 0x6E, 0x59, 0x8E, 0x10, 0xF8, 0x31, 0xAD, 0x13, 0xD2,
-    0x1F, 0x84, 0xCC, 0xE0, 0x88, 0x59, 0x5D, 0x0C, 0xD0, 0xAB, 0x24, 0xC8,
-    0x1F, 0xCB, 0xE0, 0x13, 0x72, 0xD3, 0xF3, 0x90, 0xFB, 0xB0, 0x1D, 0x36,
-    0x4E, 0xB6, 0xDC, 0x42, 0xC2, 0x87, 0xD8, 0x38, 0x6D, 0x18, 0x23, 0x3F,
-    0xDF, 0x95, 0x8B, 0xF1, 0x40, 0x89, 0xEE, 0x43, 0xD5, 0x09, 0x1F, 0xBB,
-    0xDA, 0x96, 0x4C, 0xB7, 0x23, 0x33, 0xE9, 0x48, 0xEA, 0x9E, 0x1D, 0x30,
-    0xFD, 0x72, 0x90, 0x81, 0x74, 0x1C, 0xE7, 0x8A, 0xA9, 0x8C, 0xD9, 0x4B,
-    0x30, 0x35, 0x47, 0x60, 0xDC, 0x28, 0x34, 0x92, 0x39, 0xD6, 0xEA, 0x3E,
-    0x1F, 0x70, 0x1B, 0xCA, 0x28, 0x64, 0xA5, 0x2E, 0x90, 0x3E, 0x25, 0x90,
-    0xE7, 0x70, 0x10, 0x55, 0x1E, 0xAE, 0x9B, 0x5C, 0xB3, 0x88, 0xB7, 0x00,
-    0x76, 0x7B, 0xF7, 0xB6, 0x4A, 0xD3, 0x69, 0x1E, 0x00, 0xDF, 0xB1, 0xE6,
-    0x4D, 0xD1, 0x18, 0x3A, 0xAD, 0x7E, 0xB9, 0x6C, 0x6D, 0x51, 0x81, 0x75,
-    0xFE, 0xC4, 0xAA, 0xE6, 0x17, 0x37, 0xBA, 0x2B, 0x3B, 0xD4, 0x4E, 0xFC,
-    0xEC, 0xE6, 0x60, 0x7B, 0x20, 0x7F, 0xC3, 0x74, 0xD9, 0xA3, 0x67, 0x80,
-    0x8B, 0x4A, 0x34, 0xDC, 0x25, 0x6E, 0x9B, 0xA5, 0x67, 0x97, 0x54, 0xAC,
-    0x6C, 0x8E, 0x7A, 0x64, 0x20, 0xDA, 0xD6, 0xAA, 0x59, 0x6B, 0x27, 0x28,
-    0x99, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-static const net::SHA256HashValue kFingerprintICA16 = {{
-    0x49, 0x0D, 0xC9, 0x48, 0xA1, 0x6B, 0x02, 0xEA, 0xC6, 0xDA, 0x47, 0x99,
-    0x36, 0x4D, 0xD2, 0xAF, 0x04, 0xF7, 0xEA, 0x46, 0x30, 0xCF, 0x33, 0x79,
-    0x73, 0x10, 0xAC, 0x4C, 0x07, 0xB4, 0x67, 0xAD
-}};
-
-static const unsigned char kPublicKeyICA16[] = {
-    0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xD2, 0xB0, 0xC9,
-    0xB3, 0x88, 0xCD, 0x93, 0x23, 0x6A, 0x46, 0xD3, 0x69, 0x0A, 0xD7, 0xFF,
-    0xE1, 0x51, 0x7E, 0x29, 0xA9, 0x6B, 0x71, 0x68, 0xC0, 0xCF, 0x69, 0xA3,
-    0xE8, 0xAD, 0xA9, 0x58, 0x22, 0x18, 0x45, 0x9F, 0x04, 0x86, 0x7F, 0xBA,
-    0x1B, 0xC8, 0x1C, 0x3A, 0x99, 0x80, 0xFF, 0x73, 0x8C, 0x65, 0xE7, 0xDA,
-    0x76, 0x5F, 0xCE, 0xD6, 0xB8, 0x28, 0xCA, 0xC9, 0x20, 0x7A, 0x4B, 0xB9,
-    0xC2, 0xCE, 0x89, 0x46, 0x40, 0x68, 0x60, 0x7E, 0x3B, 0xE0, 0x88, 0x1C,
-    0x1B, 0xDC, 0xEE, 0xDC, 0x06, 0x42, 0x5B, 0x28, 0x1A, 0xCD, 0xCB, 0x3E,
-    0x4E, 0xF3, 0x19, 0x0D, 0x83, 0xE2, 0x2A, 0x9D, 0x8C, 0xA3, 0x78, 0xE8,
-    0x1D, 0x6B, 0x79, 0x7C, 0x48, 0xA9, 0xE1, 0x8B, 0x56, 0x8B, 0x66, 0x63,
-    0xCE, 0x54, 0xA7, 0xD2, 0x1F, 0xE6, 0x81, 0x5B, 0x0C, 0x63, 0xB9, 0xF0,
-    0x94, 0xBD, 0xC1, 0xB2, 0x5A, 0x7F, 0xEC, 0x9A, 0x09, 0x4F, 0xB8, 0x02,
-    0x6D, 0x7F, 0x59, 0x64, 0xBE, 0x01, 0xF8, 0x83, 0xD4, 0xF0, 0x0E, 0x96,
-    0x78, 0xDC, 0xF4, 0x9D, 0x4C, 0x91, 0x4C, 0x08, 0xB3, 0xFA, 0x28, 0x55,
-    0xB7, 0xF6, 0x06, 0x1E, 0x34, 0xC3, 0x79, 0x90, 0xAB, 0x2C, 0x4E, 0x2E,
-    0xD9, 0xE4, 0x78, 0x87, 0xCF, 0xF2, 0xAA, 0x83, 0x2D, 0x74, 0x8F, 0xE4,
-    0xDA, 0xEE, 0xD0, 0x24, 0x06, 0xDE, 0x40, 0xE7, 0xC9, 0xC0, 0x02, 0xF5,
-    0x8D, 0x7D, 0xDE, 0x28, 0x03, 0x8A, 0xAE, 0x21, 0xBD, 0xF1, 0x29, 0x36,
-    0xEB, 0xD7, 0xC9, 0x3B, 0x34, 0xE3, 0x08, 0x8C, 0xCA, 0x25, 0xEE, 0x3C,
-    0xE4, 0x07, 0x49, 0xB9, 0xB8, 0xDB, 0x35, 0x90, 0x99, 0x50, 0x99, 0xC2,
-    0x7D, 0x6A, 0x3A, 0x33, 0x31, 0xC7, 0x61, 0x13, 0xB7, 0x71, 0x10, 0x80,
-    0xC1, 0x8C, 0xE0, 0x69, 0xA2, 0xDD, 0xA3, 0xE5, 0x52, 0x8A, 0xF5, 0xEF,
-    0x63, 0x02, 0x03, 0x01, 0x00, 0x01
-};
-
-// Info for trusted ICA certs.
-struct ICACertInfo {
-  const net::SHA256HashValue* fingerprint;
-  const unsigned char* public_key;
-  size_t public_key_size;
-};
-
-// Default list of allowed / trusted ICAs.
-static const ICACertInfo kAllowedICAs[] = {
-    {&kFingerprintICA1, kPublicKeyICA1, sizeof(kPublicKeyICA1)},
-    {&kFingerprintICA2, kPublicKeyICA2, sizeof(kPublicKeyICA2)},
-    {&kFingerprintICA3, kPublicKeyICA3, sizeof(kPublicKeyICA3)},
-    {&kFingerprintICA4, kPublicKeyICA4, sizeof(kPublicKeyICA4)},
-    {&kFingerprintICA5, kPublicKeyICA5, sizeof(kPublicKeyICA5)},
-    {&kFingerprintICA6, kPublicKeyICA6, sizeof(kPublicKeyICA6)},
-    {&kFingerprintICA7, kPublicKeyICA7, sizeof(kPublicKeyICA7)},
-    {&kFingerprintICA8, kPublicKeyICA8, sizeof(kPublicKeyICA8)},
-    {&kFingerprintICA9, kPublicKeyICA9, sizeof(kPublicKeyICA9)},
-    {&kFingerprintICA10, kPublicKeyICA10, sizeof(kPublicKeyICA10)},
-    {&kFingerprintICA11, kPublicKeyICA11, sizeof(kPublicKeyICA11)},
-    {&kFingerprintICA12, kPublicKeyICA12, sizeof(kPublicKeyICA12)},
-    {&kFingerprintICA13, kPublicKeyICA13, sizeof(kPublicKeyICA13)},
-    {&kFingerprintICA14, kPublicKeyICA14, sizeof(kPublicKeyICA14)},
-    {&kFingerprintICA15, kPublicKeyICA15, sizeof(kPublicKeyICA15)},
-    {&kFingerprintICA16, kPublicKeyICA16, sizeof(kPublicKeyICA16)}};
-
 // Built in public key for verifying trusted authorities data.
 const uint8 kPublicKey[] = {
     0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
@@ -615,13 +83,6 @@
 }  // namespace
 
 AuthorityKeyStore::AuthorityKeyStore() {
-  for (size_t i = 0; i < arraysize(kAllowedICAs); i++) {
-    certificate_authorities_.insert(
-        make_pair(*(kAllowedICAs[i].fingerprint),
-                  base::StringPiece(
-                      reinterpret_cast<const char*>(kAllowedICAs[i].public_key),
-                      kAllowedICAs[i].public_key_size)));
-  }
 }
 
 AuthorityKeyStore::~AuthorityKeyStore() {
@@ -636,7 +97,7 @@
 }
 
 base::StringPiece AuthorityKeyStore::GetDefaultICAPublicKey() {
-  return GetICAPublicKeyFromFingerprint(kFingerprintICA1);
+  return GetICAPublicKeyFromFingerprint(kDefaultFingerprintICA);
 }
 
 bool AuthorityKeyStore::Load(const std::string& keys) {
diff --git a/extensions/browser/api/cast_channel/cast_auth_ica_unittest.cc b/extensions/browser/api/cast_channel/cast_auth_ica_unittest.cc
index 8e1b6a5..31f6980 100644
--- a/extensions/browser/api/cast_channel/cast_auth_ica_unittest.cc
+++ b/extensions/browser/api/cast_channel/cast_auth_ica_unittest.cc
@@ -61,7 +61,8 @@
 }
 
 TEST_F(CastChannelAuthorityKeysTest, TestDefaultKeys) {
-  ExpectKeysLoaded();
+  base::StringPiece key = authority_keys_store_.GetDefaultICAPublicKey();
+  EXPECT_TRUE(key.empty());
 }
 
 TEST_F(CastChannelAuthorityKeysTest, TestInvalidProtobuf) {
diff --git a/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc b/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc
index 6d56f683..77ac762 100644
--- a/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc
+++ b/extensions/browser/api/cast_channel/cast_auth_util_unittest.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "extensions/browser/api/cast_channel/cast_auth_ica.h"
 #include "extensions/common/api/cast_channel/cast_channel.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -318,6 +319,27 @@
 
  protected:
   static AuthResponse CreateAuthResponse() {
+    std::string keys =
+        "CrMCCiBSnZzWf+XraY5w3SbX2PEmWfHm5SNIv2pc9xbhP0EOcxKOAjCCAQoCggEBALwigL"
+        "2A9johADuudl41fz3DZFxVlIY0LwWHKM33aYwXs1CnuIL638dDLdZ+q6BvtxNygKRHFcEg"
+        "mVDN7BRiCVukmM3SQbY2Tv/oLjIwSoGoQqNsmzNuyrL1U2bgJ1OGGoUepzk/SneO+1RmZv"
+        "tYVMBeOcf1UAYL4IrUzuFqVR+LFwDmaaMn5gglaTwSnY0FLNYuojHetFJQ1iBJ3nGg+a0g"
+        "QBLx3SXr1ea4NvTWj3/KQ9zXEFvmP1GKhbPz//YDLcsjT5ytGOeTBYysUpr3TOmZer5ufk"
+        "0K48YcqZP6OqWRXRy9ZuvMYNyGdMrP+JIcmH1X+mFHnquAt+RIgCqSxRsCAwEAAQqzAgog"
+        "mNZt6BxWR4RNlkNNN8SNws5/CHJQGee26JJ/VtaBqhgSjgIwggEKAoIBAQC8IoC9gPY6IQ"
+        "A7rnZeNX89w2RcVZSGNC8FhyjN92mMF7NQp7iC+t/HQy3Wfqugb7cTcoCkRxXBIJlQzewU"
+        "YglbpJjN0kG2Nk7/6C4yMEqBqEKjbJszbsqy9VNm4CdThhqFHqc5P0p3jvtUZmb7WFTAXj"
+        "nH9VAGC+CK1M7halUfixcA5mmjJ+YIJWk8Ep2NBSzWLqIx3rRSUNYgSd5xoPmtIEAS8d0l"
+        "69XmuDb01o9/ykPc1xBb5j9RioWz8//2Ay3LI0+crRjnkwWMrFKa90zpmXq+bn5NCuPGHK"
+        "mT+jqlkV0cvWbrzGDchnTKz/iSHJh9V/phR56rgLfkSIAqksUbAgMBAAE=";
+    std::string signature =
+        "eHMoa7dP2ByNtDnxM/Q6yV3ZyUyihBFgOthq937yuiu2uwW2X/i8h1YrJFaWrA0iTTfSLA"
+        "a6PBAN1hhnwXlWYy8MvViJ9eJqf5FfCCkOjdRN0QIFPpmIJm/EcIv91bNMWnOGANgSW1Ho"
+        "ns+sC0/kROPbPABPLLwfgGizBDSZNapxgj8G+iDvi1JRRvvNdmjUs2AUIPNrSp3Knt3FyZ"
+        "5F2SmkKhpo7XVTWgSuWOzUJu6zNHn2krm64Ymd2HxRDyKTm1DBzy1MoXv4/8mbLYdj+KAv"
+        "hqKJfRcrGkUXVK++wCHERwxcvfk7e6lN6adcCVYP9pZPMhE/UyAJY6/uE1X0cw==";
+    EXPECT_TRUE(SetTrustedCertificateAuthorities(keys, signature));
+
     AuthResponse response;
     response.add_intermediate_certificate(
         std::string(reinterpret_cast<const char*>(kIntermediateCertificate),
diff --git a/extensions/browser/api/cast_channel/cast_transport.cc b/extensions/browser/api/cast_channel/cast_transport.cc
index 777b1685..6022a9f2 100644
--- a/extensions/browser/api/cast_channel/cast_transport.cc
+++ b/extensions/browser/api/cast_channel/cast_transport.cc
@@ -274,7 +274,6 @@
   int rv = socket_->Write(
       request.io_buffer.get(), request.io_buffer->BytesRemaining(),
       base::Bind(&CastTransportImpl::OnWriteResult, base::Unretained(this)));
-  logger_->LogSocketEventWithRv(channel_id_, proto::SOCKET_WRITE, rv);
   return rv;
 }
 
diff --git a/extensions/browser/api/cast_channel/logger.cc b/extensions/browser/api/cast_channel/logger.cc
index 9390210..38d8e61 100644
--- a/extensions/browser/api/cast_channel/logger.cc
+++ b/extensions/browser/api/cast_channel/logger.cc
@@ -251,7 +251,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   SocketEvent event = CreateEvent(event_type);
-  if (StartsWithASCII(message_namespace, kInternalNamespacePrefix, false))
+  if (base::StartsWithASCII(message_namespace, kInternalNamespacePrefix, false))
     event.set_message_namespace(message_namespace);
   event.set_details(details);
 
diff --git a/extensions/browser/api/declarative_content/content_rules_registry.h b/extensions/browser/api/declarative_content/content_rules_registry.h
index f7f08bd..6063942f 100644
--- a/extensions/browser/api/declarative_content/content_rules_registry.h
+++ b/extensions/browser/api/declarative_content/content_rules_registry.h
@@ -23,6 +23,12 @@
 // to allow RulesRegistryService to be moved to //extensions.
 // TODO(wjmaclean): Remove this once ContentRulesRegistry moves to
 // //extensions.
+//
+// Note: when dealing with WebContents associated with OffTheRecord contexts,
+// functions on this interface must be invoked for BOTH the Original and
+// OffTheRecord ContentRulesRegistry instances. This is necessary because the
+// Original ContentRulesRegistry instance handles spanning-mode incognito
+// extensions.
 class ContentRulesRegistry : public RulesRegistry {
  public:
   ContentRulesRegistry(content::BrowserContext* browser_context,
@@ -36,11 +42,9 @@
                       cache_delegate,
                       rules_registry_id) {}
 
-  // Applies all content rules given an update (CSS match change or
-  // page navigation, for now) from the renderer.
-  virtual void Apply(
-      content::WebContents* contents,
-      const std::vector<std::string>& matching_css_selectors) = 0;
+  // Notifies the registry that it should evaluate rules for |contents|.
+  virtual void MonitorWebContentsForRuleEvaluation(
+      content::WebContents* contents) = 0;
 
   // Applies all content rules given that a tab was just navigated.
   virtual void DidNavigateMainFrame(
@@ -48,13 +52,6 @@
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) = 0;
 
-  // Applies all content rules given that a tab was just navigated on the
-  // original context. Only invoked on the OffTheRecord registry instance.
-  virtual void DidNavigateMainFrameOfOriginalContext(
-      content::WebContents* tab,
-      const content::LoadCommittedDetails& details,
-      const content::FrameNavigateParams& params) = 0;
-
  protected:
   ~ContentRulesRegistry() override {}
 
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc b/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc
index 49680add6..c428af9e 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc
+++ b/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc
@@ -422,12 +422,12 @@
     const std::string& str) const {
   switch (type_) {
     case kPrefix:
-      return StartsWithASCII(str, data_, case_sensitive_);
+      return base::StartsWithASCII(str, data_, case_sensitive_);
     case kSuffix:
       return EndsWith(str, data_, case_sensitive_);
     case kEquals:
       return str.size() == data_.size() &&
-             StartsWithASCII(str, data_, case_sensitive_);
+             base::StartsWithASCII(str, data_, case_sensitive_);
     case kContains:
       if (!case_sensitive_) {
         return std::search(str.begin(), str.end(), data_.begin(), data_.end(),
diff --git a/extensions/browser/api/extensions_api_client.cc b/extensions/browser/api/extensions_api_client.cc
index adf9090b..5fc571c0 100644
--- a/extensions/browser/api/extensions_api_client.cc
+++ b/extensions/browser/api/extensions_api_client.cc
@@ -33,6 +33,10 @@
     std::map<settings_namespace::Namespace, ValueStoreCache*>* caches) {
 }
 
+void ExtensionsAPIClient::AttachWebContentsHelpers(
+    content::WebContents* web_contents) const {
+}
+
 AppViewGuestDelegate* ExtensionsAPIClient::CreateAppViewGuestDelegate() const {
   return NULL;
 }
@@ -43,12 +47,6 @@
   return NULL;
 }
 
-ExtensionViewGuestDelegate*
-ExtensionsAPIClient::CreateExtensionViewGuestDelegate(
-    ExtensionViewGuest* guest) const {
-  return NULL;
-}
-
 scoped_ptr<MimeHandlerViewGuestDelegate>
 ExtensionsAPIClient::CreateMimeHandlerViewGuestDelegate(
     MimeHandlerViewGuest* guest) const {
diff --git a/extensions/browser/api/extensions_api_client.h b/extensions/browser/api/extensions_api_client.h
index 4800040e..35f0114 100644
--- a/extensions/browser/api/extensions_api_client.h
+++ b/extensions/browser/api/extensions_api_client.h
@@ -31,8 +31,6 @@
 class DevicePermissionsPrompt;
 class ExtensionOptionsGuest;
 class ExtensionOptionsGuestDelegate;
-class ExtensionViewGuest;
-class ExtensionViewGuestDelegate;
 class ManagementAPIDelegate;
 class MimeHandlerViewGuest;
 class MimeHandlerViewGuestDelegate;
@@ -72,6 +70,11 @@
           observers,
       std::map<settings_namespace::Namespace, ValueStoreCache*>* caches);
 
+  // Attaches any extra web contents helpers (like ExtensionWebContentsObserver)
+  // to |web_contents|.
+  virtual void AttachWebContentsHelpers(content::WebContents* web_contents)
+      const;
+
   // Creates the AppViewGuestDelegate.
   virtual AppViewGuestDelegate* CreateAppViewGuestDelegate() const;
 
@@ -80,11 +83,6 @@
   virtual ExtensionOptionsGuestDelegate* CreateExtensionOptionsGuestDelegate(
       ExtensionOptionsGuest* guest) const;
 
-  // Returns a delegate for ExtensionViewGuest. The caller owns the returned
-  // ExtensionViewGuestDelegate.
-  virtual ExtensionViewGuestDelegate* CreateExtensionViewGuestDelegate(
-      ExtensionViewGuest* guest) const;
-
   // Creates a delegate for MimeHandlerViewGuest.
   virtual scoped_ptr<MimeHandlerViewGuestDelegate>
       CreateMimeHandlerViewGuestDelegate(MimeHandlerViewGuest* guest) const;
diff --git a/extensions/browser/api/idle/idle_api_unittest.cc b/extensions/browser/api/idle/idle_api_unittest.cc
index 2e0a6041..31535bc 100644
--- a/extensions/browser/api/idle/idle_api_unittest.cc
+++ b/extensions/browser/api/idle/idle_api_unittest.cc
@@ -7,6 +7,7 @@
 #include <limits.h>
 #include <string>
 
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "extensions/browser/api/idle/idle_api_constants.h"
 #include "extensions/browser/api/idle/idle_manager_factory.h"
@@ -111,8 +112,9 @@
   idle_manager_->OnListenerRemoved(details);
 }
 
-KeyedService* IdleManagerTestFactory(content::BrowserContext* context) {
-  return new IdleManager(context);
+scoped_ptr<KeyedService> IdleManagerTestFactory(
+    content::BrowserContext* context) {
+  return make_scoped_ptr(new IdleManager(context));
 }
 
 }  // namespace
diff --git a/extensions/browser/api/management/management_api.cc b/extensions/browser/api/management/management_api.cc
index 7b2e68783..1000e64e 100644
--- a/extensions/browser/api/management/management_api.cc
+++ b/extensions/browser/api/management/management_api.cc
@@ -541,39 +541,14 @@
     return RespondNow(Error(keys::kGestureNeededForUninstallError));
 
   if (show_confirm_dialog) {
-    switch (auto_confirm_for_test) {
-      case DO_NOT_SKIP: {
-        // We show the programmatic uninstall ui for extensions uninstalling
-        // other extensions.
-        bool show_programmatic_uninstall_ui = !self_uninstall && extension();
-        AddRef();  // Balanced in OnExtensionUninstallDialogClosed.
-        // TODO(devlin): A method called "UninstallFunctionDelegate" does not in
-        // any way imply that this actually creates a dialog and runs it.
-        uninstall_dialog_ =
-            delegate->UninstallFunctionDelegate(
-                this,
-                target_extension,
-                show_programmatic_uninstall_ui);
-        break;
-      }
-      case PROCEED: {
-        // Skip the confirm dialog for testing.
-        base::MessageLoop::current()->PostTask(
-            FROM_HERE,
-            base::Bind(&ManagementUninstallFunctionBase::UninstallExtension,
-                       this));
-        break;
-      }
-      case ABORT: {
-        // Fake the user canceling.
-        base::MessageLoop::current()->PostTask(
-            FROM_HERE,
-            base::Bind(
-                &ManagementUninstallFunctionBase::Finish, this, false,
-                ErrorUtils::FormatErrorMessage(keys::kUninstallCanceledError,
-                                               target_extension_id_)));
-      }
-    }
+    // We show the programmatic uninstall ui for extensions uninstalling
+    // other extensions.
+    bool show_programmatic_uninstall_ui = !self_uninstall && extension();
+    AddRef();  // Balanced in OnExtensionUninstallDialogClosed.
+    // TODO(devlin): A method called "UninstallFunctionDelegate" does not in
+    // any way imply that this actually creates a dialog and runs it.
+    uninstall_dialog_ = delegate->UninstallFunctionDelegate(
+        this, target_extension, show_programmatic_uninstall_ui);
   } else {  // No confirm dialog.
     base::MessageLoop::current()->PostTask(
         FROM_HERE,
@@ -591,7 +566,9 @@
 void ManagementUninstallFunctionBase::OnExtensionUninstallDialogClosed(
     bool did_start_uninstall,
     const base::string16& error) {
-  Finish(did_start_uninstall, base::UTF16ToUTF8(error));
+  Finish(did_start_uninstall,
+         ErrorUtils::FormatErrorMessage(keys::kUninstallCanceledError,
+                                        target_extension_id_));
   Release();  // Balanced in Uninstall().
 }
 
@@ -621,12 +598,6 @@
   Finish(success, error);
 }
 
-// static
-void ManagementUninstallFunctionBase::SetAutoConfirmForTest(
-    bool should_proceed) {
-  auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
-}
-
 ManagementUninstallFunction::ManagementUninstallFunction() {
 }
 
diff --git a/extensions/browser/api/management/management_api.h b/extensions/browser/api/management/management_api.h
index c8687c2de..8b77ff6 100644
--- a/extensions/browser/api/management/management_api.h
+++ b/extensions/browser/api/management/management_api.h
@@ -135,8 +135,6 @@
  public:
   ManagementUninstallFunctionBase();
 
-  static void SetAutoConfirmForTest(bool should_proceed);
-
   void OnExtensionUninstallDialogClosed(bool did_start_uninstall,
                                         const base::string16& error);
 
diff --git a/extensions/browser/api/mime_handler_private/mime_handler_private_unittest.cc b/extensions/browser/api/mime_handler_private/mime_handler_private_unittest.cc
index 9b7cee42..7f36a399 100644
--- a/extensions/browser/api/mime_handler_private/mime_handler_private_unittest.cc
+++ b/extensions/browser/api/mime_handler_private/mime_handler_private_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
 #include "content/public/browser/stream_handle.h"
 #include "content/public/browser/stream_info.h"
 #include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
diff --git a/extensions/browser/api/runtime/runtime_apitest.cc b/extensions/browser/api/runtime/runtime_apitest.cc
index 49614d08..c3161893 100644
--- a/extensions/browser/api/runtime/runtime_apitest.cc
+++ b/extensions/browser/api/runtime/runtime_apitest.cc
@@ -8,8 +8,8 @@
 #include "chrome/browser/extensions/test_extension_dir.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_service.h"
-#include "extensions/browser/api/management/management_api.h"
 #include "extensions/browser/api/runtime/runtime_api.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/test/result_catcher.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -34,7 +34,8 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeRuntimeUninstallURL) {
   // Auto-confirm the uninstall dialog.
-  extensions::ManagementUninstallFunction::SetAutoConfirmForTest(true);
+  extensions::ScopedTestDialogAutoConfirm auto_confirm(
+      extensions::ScopedTestDialogAutoConfirm::ACCEPT);
   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("runtime")
                                 .AppendASCII("uninstall_url")
                                 .AppendASCII("sets_uninstall_url")));
diff --git a/extensions/browser/api/serial/serial_api.cc b/extensions/browser/api/serial/serial_api.cc
index d2eead81..8b425a33 100644
--- a/extensions/browser/api/serial/serial_api.cc
+++ b/extensions/browser/api/serial/serial_api.cc
@@ -422,6 +422,53 @@
   results_ = serial::SetControlSignals::Results::Create(success);
 }
 
+SerialSetBreakFunction::SerialSetBreakFunction() {
+}
+
+SerialSetBreakFunction::~SerialSetBreakFunction() {
+}
+
+bool SerialSetBreakFunction::Prepare() {
+  params_ = serial::SetBreak::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+
+  return true;
+}
+
+void SerialSetBreakFunction::Work() {
+  SerialConnection* connection = GetSerialConnection(params_->connection_id);
+  if (!connection) {
+    error_ = kErrorSerialConnectionNotFound;
+    return;
+  }
+  bool success = connection->SetBreak();
+  results_ = serial::SetBreak::Results::Create(success);
+}
+
+SerialClearBreakFunction::SerialClearBreakFunction() {
+}
+
+SerialClearBreakFunction::~SerialClearBreakFunction() {
+}
+
+bool SerialClearBreakFunction::Prepare() {
+  params_ = serial::ClearBreak::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+
+  return true;
+}
+
+void SerialClearBreakFunction::Work() {
+  SerialConnection* connection = GetSerialConnection(params_->connection_id);
+  if (!connection) {
+    error_ = kErrorSerialConnectionNotFound;
+    return;
+  }
+
+  bool success = connection->ClearBreak();
+  results_ = serial::ClearBreak::Results::Create(success);
+}
+
 }  // namespace core_api
 
 }  // namespace extensions
diff --git a/extensions/browser/api/serial/serial_api.h b/extensions/browser/api/serial/serial_api.h
index 4a84ffa..ea943d31 100644
--- a/extensions/browser/api/serial/serial_api.h
+++ b/extensions/browser/api/serial/serial_api.h
@@ -239,6 +239,38 @@
   scoped_ptr<serial::SetControlSignals::Params> params_;
 };
 
+class SerialSetBreakFunction : public SerialAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("serial.setBreak", SERIAL_SETBREAK)
+  SerialSetBreakFunction();
+
+ protected:
+  ~SerialSetBreakFunction() override;
+
+  // AsyncApiFunction:
+  bool Prepare() override;
+  void Work() override;
+
+ private:
+  scoped_ptr<serial::SetBreak::Params> params_;
+};
+
+class SerialClearBreakFunction : public SerialAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("serial.clearBreak", SERIAL_CLEARBREAK)
+  SerialClearBreakFunction();
+
+ protected:
+  ~SerialClearBreakFunction() override;
+
+  // AsyncApiFunction:
+  bool Prepare() override;
+  void Work() override;
+
+ private:
+  scoped_ptr<serial::ClearBreak::Params> params_;
+};
+
 }  // namespace core_api
 
 }  // namespace extensions
diff --git a/extensions/browser/api/serial/serial_connection.cc b/extensions/browser/api/serial/serial_connection.cc
index ef25885..ebe3f9b5 100644
--- a/extensions/browser/api/serial/serial_connection.cc
+++ b/extensions/browser/api/serial/serial_connection.cc
@@ -360,6 +360,14 @@
       *device::serial::HostControlSignals::From(control_signals));
 }
 
+bool SerialConnection::SetBreak() {
+  return io_handler_->SetBreak();
+}
+
+bool SerialConnection::ClearBreak() {
+  return io_handler_->ClearBreak();
+}
+
 void SerialConnection::OnReceiveTimeout() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   io_handler_->CancelRead(device::serial::RECEIVE_ERROR_TIMEOUT);
diff --git a/extensions/browser/api/serial/serial_connection.h b/extensions/browser/api/serial/serial_connection.h
index 7fc5535..0537c38 100644
--- a/extensions/browser/api/serial/serial_connection.h
+++ b/extensions/browser/api/serial/serial_connection.h
@@ -112,6 +112,12 @@
   bool SetControlSignals(
       const core_api::serial::HostControlSignals& control_signals);
 
+  // Suspend character transmission. Known as setting/sending 'Break' signal.
+  bool SetBreak();
+
+  // Restore character transmission. Known as clear/stop sending 'Break' signal.
+  bool ClearBreak();
+
   // Overrides |io_handler_| for testing.
   void SetIoHandlerForTest(scoped_refptr<device::SerialIoHandler> handler);
 
diff --git a/extensions/browser/api/sockets_tcp/sockets_tcp_api_unittest.cc b/extensions/browser/api/sockets_tcp/sockets_tcp_api_unittest.cc
index de1afc3..6bd9fe1 100644
--- a/extensions/browser/api/sockets_tcp/sockets_tcp_api_unittest.cc
+++ b/extensions/browser/api/sockets_tcp/sockets_tcp_api_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "content/public/test/test_browser_context.h"
 #include "extensions/browser/api/api_resource_manager.h"
@@ -15,7 +16,7 @@
 namespace extensions {
 namespace core_api {
 
-static KeyedService* ApiResourceManagerTestFactory(
+static scoped_ptr<KeyedService> ApiResourceManagerTestFactory(
     content::BrowserContext* context) {
   content::BrowserThread::ID id;
   CHECK(content::BrowserThread::GetCurrentThreadIdentifier(&id));
diff --git a/extensions/browser/api/sockets_udp/sockets_udp_api_unittest.cc b/extensions/browser/api/sockets_udp/sockets_udp_api_unittest.cc
index 7fbc871..bf924e77 100644
--- a/extensions/browser/api/sockets_udp/sockets_udp_api_unittest.cc
+++ b/extensions/browser/api/sockets_udp/sockets_udp_api_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "extensions/browser/api/api_resource_manager.h"
 #include "extensions/browser/api/socket/socket.h"
@@ -14,7 +15,7 @@
 namespace extensions {
 namespace core_api {
 
-static KeyedService* ApiResourceManagerTestFactory(
+static scoped_ptr<KeyedService> ApiResourceManagerTestFactory(
     content::BrowserContext* context) {
   content::BrowserThread::ID id;
   CHECK(content::BrowserThread::GetCurrentThreadIdentifier(&id));
diff --git a/extensions/browser/api/storage/storage_api_unittest.cc b/extensions/browser/api/storage/storage_api_unittest.cc
index 0d2dc4d..e8d309b 100644
--- a/extensions/browser/api/storage/storage_api_unittest.cc
+++ b/extensions/browser/api/storage/storage_api_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/stringprintf.h"
 #include "content/public/test/test_browser_context.h"
 #include "extensions/browser/api/extensions_api_client.h"
@@ -29,14 +30,14 @@
 namespace {
 
 // Caller owns the returned object.
-KeyedService* CreateStorageFrontendForTesting(
+scoped_ptr<KeyedService> CreateStorageFrontendForTesting(
     content::BrowserContext* context) {
   return StorageFrontend::CreateForTesting(new LeveldbSettingsStorageFactory(),
                                            context);
 }
 
-KeyedService* BuildEventRouter(content::BrowserContext* profile) {
-  return new extensions::EventRouter(profile, nullptr);
+scoped_ptr<KeyedService> BuildEventRouter(content::BrowserContext* context) {
+  return make_scoped_ptr(new extensions::EventRouter(context, nullptr));
 }
 
 }  // namespace
diff --git a/extensions/browser/api/storage/storage_frontend.cc b/extensions/browser/api/storage/storage_frontend.cc
index e94ecd8..dccd5e1 100644
--- a/extensions/browser/api/storage/storage_frontend.cc
+++ b/extensions/browser/api/storage/storage_frontend.cc
@@ -65,10 +65,10 @@
 }
 
 // static
-StorageFrontend* StorageFrontend::CreateForTesting(
+scoped_ptr<StorageFrontend> StorageFrontend::CreateForTesting(
     const scoped_refptr<SettingsStorageFactory>& storage_factory,
     BrowserContext* context) {
-  return new StorageFrontend(storage_factory, context);
+  return make_scoped_ptr(new StorageFrontend(storage_factory, context));
 }
 
 StorageFrontend::StorageFrontend(BrowserContext* context)
diff --git a/extensions/browser/api/storage/storage_frontend.h b/extensions/browser/api/storage/storage_frontend.h
index 5e11b82..f1c82874 100644
--- a/extensions/browser/api/storage/storage_frontend.h
+++ b/extensions/browser/api/storage/storage_frontend.h
@@ -28,8 +28,8 @@
   // Returns the current instance for |context|.
   static StorageFrontend* Get(content::BrowserContext* context);
 
-  // Creates with a specific |storage_factory|. Caller owns the object.
-  static StorageFrontend* CreateForTesting(
+  // Creates with a specific |storage_factory|.
+  static scoped_ptr<StorageFrontend> CreateForTesting(
       const scoped_refptr<SettingsStorageFactory>& storage_factory,
       content::BrowserContext* context);
 
diff --git a/extensions/browser/api/storage/storage_frontend_unittest.cc b/extensions/browser/api/storage/storage_frontend_unittest.cc
index b292244..75982ea 100644
--- a/extensions/browser/api/storage/storage_frontend_unittest.cc
+++ b/extensions/browser/api/storage/storage_frontend_unittest.cc
@@ -60,8 +60,8 @@
  protected:
   void ResetFrontend() {
     storage_factory_->Reset(new LeveldbSettingsStorageFactory());
-    frontend_.reset(
-        StorageFrontend::CreateForTesting(storage_factory_, browser_context()));
+    frontend_ = StorageFrontend::CreateForTesting(storage_factory_,
+                                                  browser_context()).Pass();
   }
 
   base::ScopedTempDir temp_dir_;
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index f6c7527..082e3ef 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -137,8 +137,8 @@
 
 bool IsWebRequestEvent(const std::string& event_name) {
   std::string web_request_event_name(event_name);
-  if (StartsWithASCII(
-          web_request_event_name, webview::kWebViewEventPrefix, true)) {
+  if (base::StartsWithASCII(web_request_event_name,
+                            webview::kWebViewEventPrefix, true)) {
     web_request_event_name.replace(
         0, strlen(webview::kWebViewEventPrefix), kWebRequestEventPrefix);
   }
@@ -1346,7 +1346,6 @@
 
 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
     void* browser_context,
-    const std::string& extension_id,
     int embedder_process_id,
     int web_view_instance_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -1370,7 +1369,7 @@
     for (const auto& listener : listeners_to_delete) {
       RemoveEventListenerOnIOThread(
           browser_context,
-          extension_id,
+          listener.extension_id,
           listener.sub_event_name,
           listener.embedder_process_id,
           listener.web_view_instance_id);
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h
index 7ae6012..3a692ea 100644
--- a/extensions/browser/api/web_request/web_request_api.h
+++ b/extensions/browser/api/web_request/web_request_api.h
@@ -296,7 +296,6 @@
   // Removes the listeners for a given <webview>.
   void RemoveWebViewEventListeners(
       void* browser_context,
-      const std::string& extension_id,
       int embedder_process_id,
       int web_view_instance_id);
 
diff --git a/extensions/browser/api/web_request/web_request_api_helpers.cc b/extensions/browser/api/web_request/web_request_api_helpers.cc
index 020aa4f..fb6908f 100644
--- a/extensions/browser/api/web_request/web_request_api_helpers.cc
+++ b/extensions/browser/api/web_request/web_request_api_helpers.cc
@@ -350,7 +350,7 @@
       bool header_found = false;
       for (ResponseHeaders::const_iterator i = new_response_headers->begin();
            i != new_response_headers->end(); ++i) {
-        if (LowerCaseEqualsASCII(i->first, name_lowercase.c_str()) &&
+        if (base::LowerCaseEqualsASCII(i->first, name_lowercase.c_str()) &&
             value == i->second) {
           header_found = true;
           break;
diff --git a/extensions/browser/api/web_request/web_request_permissions.cc b/extensions/browser/api/web_request/web_request_permissions.cc
index ea463073..19d85b8 100644
--- a/extensions/browser/api/web_request/web_request_permissions.cc
+++ b/extensions/browser/api/web_request/web_request_permissions.cc
@@ -35,7 +35,7 @@
     // This protects requests to several internal services such as sync,
     // extension update pings, captive portal detection, fraudulent certificate
     // reporting, autofill and others.
-    if (StartsWithASCII(host, kClient, true)) {
+    if (base::StartsWithASCII(host, kClient, true)) {
       bool match = true;
       for (std::string::const_iterator i = host.begin() + strlen(kClient),
                end = host.end() - strlen(kGoogleCom); i != end; ++i) {
@@ -48,11 +48,12 @@
     }
     // This protects requests to safe browsing, link doctor, and possibly
     // others.
-    sensitive_chrome_url = sensitive_chrome_url ||
+    sensitive_chrome_url =
+        sensitive_chrome_url ||
         EndsWith(url.host(), ".clients.google.com", true) ||
         url.host() == "sb-ssl.google.com" ||
-        (url.host() ==  "chrome.google.com" &&
-             StartsWithASCII(url.path(), "/webstore", true));
+        (url.host() == "chrome.google.com" &&
+         base::StartsWithASCII(url.path(), "/webstore", true));
   }
   GURL::Replacements replacements;
   replacements.ClearQuery();
diff --git a/extensions/browser/api/webcam_private/visca_webcam.cc b/extensions/browser/api/webcam_private/visca_webcam.cc
new file mode 100644
index 0000000..b6bbfb05
--- /dev/null
+++ b/extensions/browser/api/webcam_private/visca_webcam.cc
@@ -0,0 +1,399 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/webcam_private/visca_webcam.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace {
+
+// Message terminator:
+const char VISCA_TERMINATOR = 0xFF;
+
+// Response types:
+const char VISCA_RESPONSE_NETWORK_CHANGE = 0x38;
+const char VISCA_RESPONSE_ACK = 0x40;
+const char VISCA_RESPONSE_ERROR = 0x60;
+
+// Pan-Tilt-Zoom movement comands from http://www.manualslib.com/manual/...
+// 557364/Cisco-Precisionhd-1080p12x.html?page=31#manual
+
+// Reset the address of each device in the VISCA chain (broadcast). This is used
+// when resetting the VISCA network.
+const std::vector<char> kSetAddressCommand = {0x88, 0x30, 0x01, 0xFF};
+
+// Clear all of the devices, halting any pending commands in the VISCA chain
+// (broadcast). This is used when resetting the VISCA network.
+const std::vector<char> kClearAllCommand = {0x88, 0x01, 0x00, 0x01, 0xFF};
+
+// Clear the command buffer in the target device and cancel the command
+// currently being executed. Command: {0x8X, 0x01, 0x00, 0x01, 0xFF}, X = 1 to
+// 7: target device address.
+const std::vector<char> kClearCommand = {0x81, 0x01, 0x00, 0x01, 0xFF};
+
+// Command: {0x8X, 0x09, 0x06, 0x12, 0xFF}, X = 1 to 7: target device address.
+// Response: {0xY0, 0x50, 0x0p, 0x0q, 0x0r, 0x0s, 0x0t, 0x0u, 0x0v, 0x0w, 0xFF},
+// Y = socket number; pqrs: pan position; tuvw: tilt position.
+const std::vector<char> kGetPanTiltCommand = {0x81, 0x09, 0x06, 0x12, 0xFF};
+
+// Command: {0x8X, 0x01, 0x06, 0x20, 0x0p, 0x0t, 0x0q, 0x0r, 0x0s, 0x0u, 0x0v,
+// 0x0w, 0x0y, 0x0z, 0xFF}, X = 1 to 7: target device address; p = pan speed;
+// t = tilt speed; qrsu = pan position; vwyz = tilt position.
+const std::vector<char> kSetPanTiltCommand = {0x81, 0x01, 0x06, 0x02, 0x05,
+    0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF};
+
+// Command: {0x8X, 0x01, 0x06, 0x05, 0xFF}, X = 1 to 7: target device address.
+const std::vector<char> kResetPanTiltCommand = {0x81, 0x01, 0x06, 0x05, 0xFF};
+
+// Command: {0x8X, 0x09, 0x04, 0x47, 0xFF}, X = 1 to 7: target device address.
+// Response: {0xY0, 0x50, 0x0p, 0x0q, 0x0r, 0x0s, 0xFF}, Y = socket number;
+// pqrs: zoom position.
+const std::vector<char> kGetZoomCommand = {0x81, 0x09, 0x04, 0x47, 0xFF};
+
+// Command: {0x8X, 0x01, 0x04, 0x47, 0x0p, 0x0q, 0x0r, 0x0s, 0xFF}, X = 1 to 7:
+// target device address; pqrs: zoom position;
+const std::vector<char> kSetZoomCommand =
+    {0x81, 0x01, 0x04, 0x47, 0x00, 0x00, 0x00, 0x00, 0xFF};
+
+// Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x03, 0x01, 0xFF}, X = 1 to 7:
+// target device address; p: pan speed; t: tilt speed.
+const std::vector<char> kPTUpCommand =
+    {0x81, 0x01, 0x06, 0x01, 0x05, 0x05, 0x03, 0x01, 0xFF};
+
+// Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x03, 0x02, 0xFF}, X = 1 to 7:
+// target device address; p: pan speed; t: tilt speed.
+const std::vector<char> kPTDownCommand =
+    {0x81, 0x01, 0x06, 0x01, 0x05, 0x05, 0x03, 0x02, 0xFF};
+
+// Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x0, 0x03, 0xFF}, X = 1 to 7:
+// target device address; p: pan speed; t: tilt speed.
+const std::vector<char> kPTLeftCommand =
+    {0x81, 0x01, 0x06, 0x01, 0x05, 0x05, 0x01, 0x03, 0xFF};
+
+// Command: {0x8X, 0x01, 0x06, 0x01, 0x0p, 0x0t, 0x02, 0x03, 0xFF}, X = 1 to 7:
+// target device address; p: pan speed; t: tilt speed.
+const std::vector<char> kPTRightCommand =
+    {0x81, 0x01, 0x06, 0x01, 0x05, 0x05, 0x02, 0x03, 0xFF};
+
+// Command: {0x8X, 0x01, 0x06, 0x01, 0x03, 0x03, 0x03, 0x03, 0xFF}, X = 1 to 7:
+// target device address.
+const std::vector<char> kPTStopCommand =
+    {0x81, 0x01, 0x06, 0x01, 0x03, 0x03, 0x03, 0x03, 0xFF};
+
+}  // namespace
+
+namespace extensions {
+
+ViscaWebcam::ViscaWebcam(const std::string& path,
+                         const std::string& extension_id)
+    : path_(path),
+      extension_id_(extension_id),
+      pan_(0),
+      tilt_(0),
+      weak_ptr_factory_(this) {
+}
+
+ViscaWebcam::~ViscaWebcam() {
+}
+
+void ViscaWebcam::Open(const OpenCompleteCallback& open_callback) {
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&ViscaWebcam::OpenOnIOThread, weak_ptr_factory_.GetWeakPtr(),
+                 open_callback));
+}
+
+void ViscaWebcam::OpenOnIOThread(const OpenCompleteCallback& open_callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  core_api::serial::ConnectionOptions options;
+
+  // Set the receive buffer size to receive the response data 1 by 1.
+  options.buffer_size.reset(new int(1));
+  options.persistent.reset(new bool(false));
+  options.bitrate.reset(new int(9600));
+  options.cts_flow_control.reset(new bool(false));
+  options.receive_timeout.reset(new int(0));
+  options.send_timeout.reset(new int(0));
+  options.data_bits = core_api::serial::DATA_BITS_EIGHT;
+  options.parity_bit = core_api::serial::PARITY_BIT_NO;
+  options.stop_bits = core_api::serial::STOP_BITS_ONE;
+
+  serial_connection_.reset(new SerialConnection(path_, extension_id_));
+  serial_connection_->Open(
+      options, base::Bind(&ViscaWebcam::OnConnected,
+                          weak_ptr_factory_.GetWeakPtr(), open_callback));
+}
+
+void ViscaWebcam::OnConnected(const OpenCompleteCallback& open_callback,
+                              bool success) {
+  if (!success) {
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(open_callback, false));
+  } else {
+    Send(kSetAddressCommand,
+         base::Bind(&ViscaWebcam::OnAddressSetCompleted,
+                    weak_ptr_factory_.GetWeakPtr(), open_callback));
+  }
+}
+
+void ViscaWebcam::OnAddressSetCompleted(
+    const OpenCompleteCallback& open_callback,
+    bool success,
+    const std::vector<char>& response) {
+  if (!success) {
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(open_callback, false));
+  } else {
+    Send(kClearAllCommand,
+         base::Bind(&ViscaWebcam::OnClearAllCompleted,
+                    weak_ptr_factory_.GetWeakPtr(), open_callback));
+  }
+}
+
+void ViscaWebcam::OnClearAllCompleted(const OpenCompleteCallback& open_callback,
+                                      bool success,
+                                      const std::vector<char>& response) {
+  if (!success) {
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(open_callback, false));
+  } else {
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(open_callback, true));
+    // Get the current pan and tilt position to initilize |pan| and |tilt|.
+    int value;
+    Send(kGetPanTiltCommand,
+         base::Bind(&ViscaWebcam::OnCommandCompleted,
+                    weak_ptr_factory_.GetWeakPtr(), INQUIRY_PAN_TILT, &value));
+  }
+}
+
+void ViscaWebcam::Send(const std::vector<char>& command,
+                       const CommandCompleteCallback& callback) {
+  if (!commands_.empty() ||
+      !serial_connection_->Send(
+          command, base::Bind(&ViscaWebcam::OnSendCompleted,
+                              weak_ptr_factory_.GetWeakPtr(), callback))) {
+    commands_.push_back(std::make_pair(command, callback));
+  }
+}
+
+void ViscaWebcam::OnSendCompleted(const CommandCompleteCallback& callback,
+                                  int bytes_sent,
+                                  core_api::serial::SendError error) {
+  if (error == core_api::serial::SEND_ERROR_NONE) {
+    ReceiveLoop(callback);
+  } else {
+    const std::vector<char> response;
+    callback.Run(false, response);
+  }
+}
+
+void ViscaWebcam::ReceiveLoop(const CommandCompleteCallback& callback) {
+  serial_connection_->Receive(base::Bind(&ViscaWebcam::OnReceiveCompleted,
+                                         weak_ptr_factory_.GetWeakPtr(),
+                                         callback));
+}
+
+void ViscaWebcam::OnReceiveCompleted(const CommandCompleteCallback& callback,
+                                     const std::vector<char>& data,
+                                     core_api::serial::ReceiveError error) {
+  data_buffer_.insert(data_buffer_.end(), data.begin(), data.end());
+
+  if (error == core_api::serial::RECEIVE_ERROR_NONE) {
+    // Loop until encounter the terminator.
+    if (int(data_buffer_.back()) != VISCA_TERMINATOR) {
+      base::MessageLoop::current()->PostTask(
+          FROM_HERE, base::Bind(&ViscaWebcam::ReceiveLoop,
+                                weak_ptr_factory_.GetWeakPtr(), callback));
+    } else {
+      // Clear |data_buffer_|.
+      std::vector<char> response;
+      response.swap(data_buffer_);
+
+      if ((int(response[1]) & 0xF0) == VISCA_RESPONSE_ERROR) {
+        callback.Run(false, response);
+      } else if ((int(response[1]) & 0xF0) != VISCA_RESPONSE_ACK &&
+                 (int(response[1]) & 0xFF) != VISCA_RESPONSE_NETWORK_CHANGE) {
+        callback.Run(true, response);
+      } else {
+        base::MessageLoop::current()->PostTask(
+            FROM_HERE, base::Bind(&ViscaWebcam::ReceiveLoop,
+                                  weak_ptr_factory_.GetWeakPtr(), callback));
+      }
+    }
+  } else {
+    // Clear |data_buffer_|.
+    std::vector<char> response;
+    response.swap(data_buffer_);
+    callback.Run(false, response);
+  }
+}
+
+void ViscaWebcam::OnCommandCompleted(CommandType type,
+                                     int* value,
+                                     bool success,
+                                     const std::vector<char>& response) {
+  // TODO(xdai): Error handling according to |response|.
+  if (!success)
+    return;
+
+  switch (type) {
+    case COMMAND:
+      break;
+    case INQUIRY_PAN:
+      pan_ = ((int(response[2]) & 0x0F) << 12) +
+             ((int(response[3]) & 0x0F) << 8) +
+             ((int(response[4]) & 0x0F) << 4) + (int(response[5]) & 0x0F);
+      *value = pan_;
+      break;
+    case INQUIRY_TILT:
+      tilt_ = ((int(response[6]) & 0x0F) << 12) +
+              ((int(response[7]) & 0x0F) << 8) +
+              ((int(response[8]) & 0x0F) << 4) + (int(response[9]) & 0x0F);
+      *value = tilt_;
+      break;
+    case INQUIRY_PAN_TILT:
+      pan_ = ((int(response[2]) & 0x0F) << 12) +
+             ((int(response[3]) & 0x0F) << 8) +
+             ((int(response[4]) & 0x0F) << 4) + (int(response[5]) & 0x0F);
+      tilt_ = ((int(response[6]) & 0x0F) << 12) +
+              ((int(response[7]) & 0x0F) << 8) +
+              ((int(response[8]) & 0x0F) << 4) + (int(response[9]) & 0x0F);
+      break;
+    case INQUIRY_ZOOM:
+      *value = ((int(response[2]) & 0x0F) << 12) +
+               ((int(response[3]) & 0x0F) << 8) +
+               ((int(response[4]) & 0x0F) << 4) + (int(response[5]) & 0x0F);
+      break;
+  }
+
+  // If there are pending commands, process the next one.
+  if (!commands_.empty()) {
+    const std::vector<char> command = commands_.front().first;
+    const CommandCompleteCallback callback = commands_.front().second;
+    commands_.pop_front();
+    serial_connection_->Send(
+        command, base::Bind(&ViscaWebcam::OnSendCompleted,
+                            weak_ptr_factory_.GetWeakPtr(), callback));
+  }
+}
+
+void ViscaWebcam::Reset(bool pan, bool tilt, bool zoom) {
+  int value;
+  // pan and tilt are always reset together in Visca Webcams.
+  if (pan || tilt) {
+    Send(kResetPanTiltCommand,
+         base::Bind(&ViscaWebcam::OnCommandCompleted,
+                    weak_ptr_factory_.GetWeakPtr(), COMMAND, &value));
+  }
+  if (zoom) {
+    const int default_zoom = 1;
+    SetZoom(default_zoom);
+  }
+}
+
+bool ViscaWebcam::GetPan(int* value) {
+  Send(kGetPanTiltCommand,
+       base::Bind(&ViscaWebcam::OnCommandCompleted,
+                  weak_ptr_factory_.GetWeakPtr(), INQUIRY_PAN, value));
+  return true;
+}
+
+bool ViscaWebcam::GetTilt(int* value) {
+  Send(kGetPanTiltCommand,
+       base::Bind(&ViscaWebcam::OnCommandCompleted,
+                  weak_ptr_factory_.GetWeakPtr(), INQUIRY_TILT, value));
+  return true;
+}
+
+bool ViscaWebcam::GetZoom(int* value) {
+  Send(kGetZoomCommand,
+       base::Bind(&ViscaWebcam::OnCommandCompleted,
+                  weak_ptr_factory_.GetWeakPtr(), INQUIRY_ZOOM, value));
+  return true;
+}
+
+bool ViscaWebcam::SetPan(int value) {
+  pan_ = value;
+  std::vector<char> command = kSetPanTiltCommand;
+  command[6] |= ((pan_ & 0xF000) >> 12);
+  command[7] |= ((pan_ & 0x0F00) >> 8);
+  command[8] |= ((pan_ & 0x00F0) >> 4);
+  command[9] |= (pan_ & 0x000F);
+  command[10] |= ((tilt_ & 0xF000) >> 12);
+  command[11] |= ((tilt_ & 0x0F00) >> 8);
+  command[12] |= ((tilt_ & 0x00F0) >> 4);
+  command[13] |= (tilt_ & 0x000F);
+  Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
+                           weak_ptr_factory_.GetWeakPtr(), COMMAND, &value));
+  return true;
+}
+
+bool ViscaWebcam::SetTilt(int value) {
+  tilt_ = value;
+  std::vector<char> command = kSetPanTiltCommand;
+  command[6] |= ((pan_ & 0xF000) >> 12);
+  command[7] |= ((pan_ & 0x0F00) >> 8);
+  command[8] |= ((pan_ & 0x00F0) >> 4);
+  command[9] |= (pan_ & 0x000F);
+  command[10] |= ((tilt_ & 0xF000) >> 12);
+  command[11] |= ((tilt_ & 0x0F00) >> 8);
+  command[12] |= ((tilt_ & 0x00F0) >> 4);
+  command[13] |= (tilt_ & 0x000F);
+  Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
+                           weak_ptr_factory_.GetWeakPtr(), COMMAND, &value));
+  return true;
+}
+
+bool ViscaWebcam::SetZoom(int value) {
+  std::vector<char> command = kSetZoomCommand;
+  command[4] |= ((value & 0xF000) >> 12);
+  command[5] |= ((value & 0x0F00) >> 8);
+  command[6] |= ((value & 0x00F0) >> 4);
+  command[7] |= (value & 0x000F);
+  Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
+                           weak_ptr_factory_.GetWeakPtr(), COMMAND, &value));
+  return true;
+}
+
+bool ViscaWebcam::SetPanDirection(PanDirection direction) {
+  std::vector<char> command = kPTStopCommand;
+  switch (direction) {
+    case PAN_STOP:
+      break;
+    case PAN_RIGHT:
+      command = kPTRightCommand;
+      break;
+    case PAN_LEFT:
+      command = kPTLeftCommand;
+      break;
+  }
+  Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
+                           weak_ptr_factory_.GetWeakPtr(), COMMAND, &pan_));
+  return true;
+}
+
+bool ViscaWebcam::SetTiltDirection(TiltDirection direction) {
+  std::vector<char> command = kPTStopCommand;
+  switch (direction) {
+    case TILT_STOP:
+      break;
+    case TILT_UP:
+      command = kPTUpCommand;
+      break;
+    case TILT_DOWN:
+      command = kPTDownCommand;
+      break;
+  }
+  Send(command, base::Bind(&ViscaWebcam::OnCommandCompleted,
+                           weak_ptr_factory_.GetWeakPtr(), COMMAND, &tilt_));
+  return true;
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/api/webcam_private/visca_webcam.h b/extensions/browser/api/webcam_private/visca_webcam.h
new file mode 100644
index 0000000..cd904da3
--- /dev/null
+++ b/extensions/browser/api/webcam_private/visca_webcam.h
@@ -0,0 +1,109 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_WEBCAM_PRIVATE_VISCA_WEBCAM_H_
+#define EXTENSIONS_BROWSER_API_WEBCAM_PRIVATE_VISCA_WEBCAM_H_
+
+#include <deque>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "extensions/browser/api/serial/serial_connection.h"
+#include "extensions/browser/api/webcam_private/webcam.h"
+#include "extensions/common/api/serial.h"
+
+namespace extensions {
+
+class ViscaWebcam : public Webcam {
+ public:
+  ViscaWebcam(const std::string& path, const std::string& extension_id);
+  ~ViscaWebcam() override;
+
+  using OpenCompleteCallback = base::Callback<void(bool)>;
+
+  // Open and initialize the web camera. This is done by the following three
+  // steps (in order): 1. Open the serial port;  2. Request address; 3. Clear
+  // the command buffer. After these three steps completes, |open_callback| will
+  // be called.
+  void Open(const OpenCompleteCallback& open_callback);
+
+ private:
+  enum CommandType {
+    COMMAND,
+    INQUIRY_PAN,
+    INQUIRY_TILT,
+    INQUIRY_PAN_TILT,
+    INQUIRY_ZOOM,
+  };
+
+  using CommandCompleteCallback =
+      base::Callback<void(bool, const std::vector<char>&)>;
+
+  void OpenOnIOThread(const OpenCompleteCallback& open_callback);
+  // Callback function that will be called after the serial connection has been
+  // opened successfully.
+  void OnConnected(const OpenCompleteCallback& open_callback, bool success);
+  // Callback function that will be called after the address has been set
+  // successfully.
+  void OnAddressSetCompleted(const OpenCompleteCallback& open_callback,
+                             bool success,
+                             const std::vector<char>& response);
+  // Callback function that will be called after the command buffer has been
+  // cleared successfully.
+  void OnClearAllCompleted(const OpenCompleteCallback& open_callback,
+                           bool success,
+                           const std::vector<char>& response);
+
+  // Send or queue a command and wait for the camera's response.
+  void Send(const std::vector<char>& command,
+            const CommandCompleteCallback& callback);
+  void OnSendCompleted(const CommandCompleteCallback& callback,
+                       int bytes_sent,
+                       core_api::serial::SendError error);
+  void ReceiveLoop(const CommandCompleteCallback& callback);
+  void OnReceiveCompleted(const CommandCompleteCallback& callback,
+                          const std::vector<char>& data,
+                          core_api::serial::ReceiveError error);
+  // Callback function that will be called after the send and reply of a command
+  // are both completed. Update |value| according to |type| and |response| if
+  // necessory.
+  void OnCommandCompleted(CommandType type,
+                          int* value,
+                          bool success,
+                          const std::vector<char>& response);
+
+  // Webcam Overrides:
+  void Reset(bool pan, bool tilt, bool zoom) override;
+  bool GetPan(int* value) override;
+  bool GetTilt(int* value) override;
+  bool GetZoom(int* value) override;
+  bool SetPan(int value) override;
+  bool SetTilt(int value) override;
+  bool SetZoom(int value) override;
+  bool SetPanDirection(PanDirection direction) override;
+  bool SetTiltDirection(TiltDirection direction) override;
+
+  const std::string path_;
+  const std::string extension_id_;
+
+  scoped_ptr<SerialConnection> serial_connection_;
+
+  // Stores the response for the current command.
+  std::vector<char> data_buffer_;
+  // Queues commands till the current command completes.
+  std::deque<std::pair<std::vector<char>, CommandCompleteCallback>> commands_;
+
+  // Visca webcam always get/set pan-tilt together. |pan| and |tilt| are used to
+  // store the current value of pan and tilt positions.
+  int pan_;
+  int tilt_;
+
+  base::WeakPtrFactory<ViscaWebcam> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViscaWebcam);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_WEBCAM_PRIVATE_VISCA_WEBCAM_H_
diff --git a/extensions/browser/api/webcam_private/webcam_private_api.h b/extensions/browser/api/webcam_private/webcam_private_api.h
index 3c64e6c8..4e1f0b8 100644
--- a/extensions/browser/api/webcam_private/webcam_private_api.h
+++ b/extensions/browser/api/webcam_private/webcam_private_api.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/scoped_observer.h"
+#include "extensions/browser/api/webcam_private/webcam.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/extension_function.h"
 #include "extensions/browser/process_manager_observer.h"
@@ -18,7 +19,6 @@
 namespace extensions {
 
 class ProcessManager;
-class Webcam;
 
 class WebcamPrivateAPI : public BrowserContextKeyedAPI,
                          public ProcessManagerObserver {
@@ -32,14 +32,31 @@
   ~WebcamPrivateAPI() override;
 
   Webcam* GetWebcam(const std::string& extension_id,
-                    const std::string& webcam_id);
+                    const std::string& device_id);
+
+  bool OpenSerialWebcam(
+      const std::string& extension_id,
+      const std::string& device_id,
+      const base::Callback<void(const std::string&, bool)>& callback);
+  bool CloseWebcam(const std::string& extension_id,
+                   const std::string& device_id);
 
  private:
   friend class BrowserContextKeyedAPIFactory<WebcamPrivateAPI>;
 
+  void OnOpenSerialWebcam(
+      const std::string& extension_id,
+      const std::string& device_id,
+      const base::Callback<void(const std::string&, bool)>& callback,
+      bool success);
+
+  // Todo(xdai): This function doesn't work for serial devices. It can't get the
+  // correct |device_id| for given |extension_id| and |webcam_id|. (why?)
   bool GetDeviceId(const std::string& extension_id,
                    const std::string& webcam_id,
                    std::string* device_id);
+  std::string GetWebcamId(const std::string& extension_id,
+                          const std::string& device_id);
 
   // ProcessManagerObserver:
   void OnBackgroundHostClose(const std::string& extension_id) override;
@@ -64,6 +81,40 @@
 void BrowserContextKeyedAPIFactory<WebcamPrivateAPI>
     ::DeclareFactoryDependencies();
 
+class WebcamPrivateOpenSerialWebcamFunction : public AsyncExtensionFunction {
+ public:
+  WebcamPrivateOpenSerialWebcamFunction();
+  DECLARE_EXTENSION_FUNCTION("webcamPrivate.openSerialWebcam",
+                             WEBCAMPRIVATE_OPENSERIALWEBCAM);
+
+ protected:
+  ~WebcamPrivateOpenSerialWebcamFunction() override;
+
+  // AsyncExtensionFunction:
+  bool RunAsync() override;
+
+ private:
+  void OnOpenWebcam(const std::string& webcam_id, bool success);
+
+  DISALLOW_COPY_AND_ASSIGN(WebcamPrivateOpenSerialWebcamFunction);
+};
+
+class WebcamPrivateCloseWebcamFunction : public AsyncExtensionFunction {
+ public:
+  WebcamPrivateCloseWebcamFunction();
+  DECLARE_EXTENSION_FUNCTION("webcamPrivate.closeWebcam",
+                             WEBCAMPRIVATE_CLOSEWEBCAM);
+
+ protected:
+  ~WebcamPrivateCloseWebcamFunction() override;
+
+  // AsyncApiFunction:
+  bool RunAsync() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebcamPrivateCloseWebcamFunction);
+};
+
 class WebcamPrivateSetFunction : public SyncExtensionFunction {
  public:
   WebcamPrivateSetFunction();
diff --git a/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc b/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
index 4b0f0d3..bcb0bea 100644
--- a/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
+++ b/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
@@ -10,7 +10,7 @@
 #include "content/public/browser/resource_context.h"
 #include "content/public/common/media_stream_request.h"
 #include "extensions/browser/api/webcam_private/v4l2_webcam.h"
-#include "extensions/browser/api/webcam_private/webcam.h"
+#include "extensions/browser/api/webcam_private/visca_webcam.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/browser/process_manager_factory.h"
 #include "extensions/common/api/webcam_private.h"
@@ -22,6 +22,7 @@
 }  // namespace content
 
 namespace {
+const char kPathInUse[] = "Path in use";
 const char kUnknownWebcam[] = "Unknown webcam id";
 }  // namespace
 
@@ -42,12 +43,7 @@
 WebcamPrivateAPI::~WebcamPrivateAPI() {}
 
 Webcam* WebcamPrivateAPI::GetWebcam(const std::string& extension_id,
-                                    const std::string& webcam_id) {
-  std::string device_id;
-  if (!GetDeviceId(extension_id, webcam_id, &device_id)) {
-    return nullptr;
-  }
-
+                                    const std::string& device_id) {
   auto ix = webcams_.find(device_id);
   if (ix != webcams_.end()) {
     ix->second->AddExtensionRef(extension_id);
@@ -67,6 +63,51 @@
   return webcam.get();
 }
 
+bool WebcamPrivateAPI::OpenSerialWebcam(
+    const std::string& extension_id,
+    const std::string& device_id,
+    const base::Callback<void(const std::string&, bool)>& callback) {
+  auto ix = webcams_.find(device_id);
+  if (ix != webcams_.end()) {
+    return false;
+  }
+
+  ViscaWebcam* visca_webcam(new ViscaWebcam(device_id, extension_id));
+  visca_webcam->AddExtensionRef(extension_id);
+  webcams_[device_id] = linked_ptr<Webcam>(visca_webcam);
+
+  visca_webcam->Open(base::Bind(&WebcamPrivateAPI::OnOpenSerialWebcam,
+                                weak_ptr_factory_.GetWeakPtr(), extension_id,
+                                device_id, callback));
+  return true;
+}
+
+bool WebcamPrivateAPI::CloseWebcam(const std::string& extension_id,
+                                   const std::string& device_id) {
+  auto webcam = webcams_.find(device_id);
+  if (webcam == webcams_.end())
+    return false;
+
+  webcam->second->RemoveExtensionRef(extension_id);
+  if (webcam->second->ShouldDelete())
+    webcams_.erase(webcam);
+  return true;
+}
+
+void WebcamPrivateAPI::OnOpenSerialWebcam(
+    const std::string& extension_id,
+    const std::string& device_id,
+    const base::Callback<void(const std::string&, bool)>& callback,
+    bool success) {
+  if (success) {
+    std::string webcam_id = GetWebcamId(extension_id, device_id);
+    callback.Run(webcam_id, true);
+  } else {
+    webcams_.erase(device_id);
+    callback.Run("", false);
+  }
+}
+
 bool WebcamPrivateAPI::GetDeviceId(const std::string& extension_id,
                                    const std::string& webcam_id,
                                    std::string* device_id) {
@@ -81,6 +122,16 @@
       device_id);
 }
 
+std::string WebcamPrivateAPI::GetWebcamId(const std::string& extension_id,
+                                          const std::string& device_id) {
+  GURL security_origin =
+      extensions::Extension::GetBaseURLFromExtensionId(extension_id);
+
+  return content::GetHMACForMediaDeviceID(
+      browser_context_->GetResourceContext()->GetMediaDeviceIDSalt(),
+      security_origin, device_id);
+}
+
 void WebcamPrivateAPI::OnBackgroundHostClose(const std::string& extension_id) {
   for (auto webcam = webcams_.begin();
        webcam != webcams_.end(); /* No increment */ ) {
@@ -92,6 +143,57 @@
   }
 }
 
+WebcamPrivateOpenSerialWebcamFunction::WebcamPrivateOpenSerialWebcamFunction() {
+}
+
+WebcamPrivateOpenSerialWebcamFunction::
+    ~WebcamPrivateOpenSerialWebcamFunction() {
+}
+
+bool WebcamPrivateOpenSerialWebcamFunction::RunAsync() {
+  scoped_ptr<webcam_private::OpenSerialWebcam::Params> params(
+      webcam_private::OpenSerialWebcam::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  if (WebcamPrivateAPI::Get(browser_context())
+          ->OpenSerialWebcam(
+              extension_id(), params->path,
+              base::Bind(&WebcamPrivateOpenSerialWebcamFunction::OnOpenWebcam,
+                         this))) {
+    return true;
+  } else {
+    SetError(kPathInUse);
+    return false;
+  }
+}
+
+void WebcamPrivateOpenSerialWebcamFunction::OnOpenWebcam(
+    const std::string& webcam_id,
+    bool success) {
+  if (success) {
+    SetResult(new base::StringValue(webcam_id));
+    SendResponse(true);
+  } else {
+    SetError(kUnknownWebcam);
+    SendResponse(false);
+  }
+}
+
+WebcamPrivateCloseWebcamFunction::WebcamPrivateCloseWebcamFunction() {
+}
+
+WebcamPrivateCloseWebcamFunction::~WebcamPrivateCloseWebcamFunction() {
+}
+
+bool WebcamPrivateCloseWebcamFunction::RunAsync() {
+  scoped_ptr<webcam_private::CloseWebcam::Params> params(
+      webcam_private::CloseWebcam::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  return WebcamPrivateAPI::Get(browser_context())
+      ->CloseWebcam(extension_id(), params->path);
+}
+
 WebcamPrivateSetFunction::WebcamPrivateSetFunction() {
 }
 
@@ -99,13 +201,12 @@
 }
 
 bool WebcamPrivateSetFunction::RunSync() {
-  // Get parameters
   scoped_ptr<webcam_private::Set::Params> params(
       webcam_private::Set::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  Webcam* webcam = WebcamPrivateAPI::Get(browser_context())->
-      GetWebcam(extension_id(), params->webcam_id);
+  Webcam* webcam = WebcamPrivateAPI::Get(browser_context())
+                       ->GetWebcam(extension_id(), params->path);
   if (!webcam) {
     SetError(kUnknownWebcam);
     return false;
@@ -172,13 +273,12 @@
 }
 
 bool WebcamPrivateGetFunction::RunSync() {
-  // Get parameters
   scoped_ptr<webcam_private::Get::Params> params(
       webcam_private::Get::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  Webcam* webcam = WebcamPrivateAPI::Get(browser_context())->
-      GetWebcam(extension_id(), params->webcam_id);
+  Webcam* webcam = WebcamPrivateAPI::Get(browser_context())
+                       ->GetWebcam(extension_id(), params->path);
   if (!webcam) {
     SetError(kUnknownWebcam);
     return false;
@@ -210,13 +310,12 @@
 }
 
 bool WebcamPrivateResetFunction::RunSync() {
-  // Get parameters
   scoped_ptr<webcam_private::Reset::Params> params(
       webcam_private::Reset::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  Webcam* webcam = WebcamPrivateAPI::Get(browser_context())->
-      GetWebcam(extension_id(), params->webcam_id);
+  Webcam* webcam = WebcamPrivateAPI::Get(browser_context())
+                       ->GetWebcam(extension_id(), params->path);
   if (!webcam) {
     SetError(kUnknownWebcam);
     return false;
diff --git a/extensions/browser/api_test_utils.cc b/extensions/browser/api_test_utils.cc
index 4affb862..587f8e29 100644
--- a/extensions/browser/api_test_utils.cc
+++ b/extensions/browser/api_test_utils.cc
@@ -19,17 +19,6 @@
 
 namespace {
 
-class TestFunctionDispatcherDelegate
-    : public ExtensionFunctionDispatcher::Delegate {
- public:
-  TestFunctionDispatcherDelegate() {}
-  ~TestFunctionDispatcherDelegate() override {}
-
-  // NULL implementation.
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestFunctionDispatcherDelegate);
-};
-
 scoped_ptr<base::Value> ParseJSON(const std::string& data) {
   return base::JSONReader::Read(data);
 }
@@ -185,9 +174,8 @@
     const std::string& args,
     content::BrowserContext* context,
     RunFunctionFlags flags) {
-  TestFunctionDispatcherDelegate delegate;
   scoped_ptr<ExtensionFunctionDispatcher> dispatcher(
-      new ExtensionFunctionDispatcher(context, &delegate));
+      new ExtensionFunctionDispatcher(context));
 
   return RunFunctionWithDelegateAndReturnSingleResult(
       function, args, context, dispatcher.Pass(), flags);
@@ -203,9 +191,8 @@
                                       const std::string& args,
                                       content::BrowserContext* context,
                                       RunFunctionFlags flags) {
-  TestFunctionDispatcherDelegate delegate;
   scoped_ptr<ExtensionFunctionDispatcher> dispatcher(
-      new ExtensionFunctionDispatcher(context, &delegate));
+      new ExtensionFunctionDispatcher(context));
   scoped_refptr<ExtensionFunction> function_owner(function);
   // Without a callback the function will not generate a result.
   function->set_has_callback(true);
@@ -217,9 +204,8 @@
 bool RunFunction(UIThreadExtensionFunction* function,
                  const std::string& args,
                  content::BrowserContext* context) {
-  TestFunctionDispatcherDelegate delegate;
   scoped_ptr<ExtensionFunctionDispatcher> dispatcher(
-      new ExtensionFunctionDispatcher(context, &delegate));
+      new ExtensionFunctionDispatcher(context));
   return RunFunction(function, args, context, dispatcher.Pass(), NONE);
 }
 
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc
index c1959a9..77da594 100644
--- a/extensions/browser/app_window/app_window.cc
+++ b/extensions/browser/app_window/app_window.cc
@@ -30,6 +30,7 @@
 #include "extensions/browser/app_window/size_constraints.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_web_contents_observer.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/browser/process_manager.h"
@@ -258,6 +259,9 @@
   SetViewType(web_contents(), VIEW_TYPE_APP_WINDOW);
   app_delegate_->InitWebContents(web_contents());
 
+  ExtensionWebContentsObserver::GetForWebContents(web_contents())->
+      dispatcher()->set_delegate(this);
+
   WebContentsModalDialogManager::CreateForWebContents(web_contents());
 
   web_contents()->SetDelegate(this);
@@ -454,17 +458,35 @@
 }
 
 void AppWindow::OnNativeWindowChanged() {
+  // This may be called during Init before |native_app_window_| is set.
+  if (!native_app_window_)
+    return;
+
+#if defined(OS_MACOSX)
+  // On Mac the user can change the window's fullscreen state. If that has
+  // happened, update AppWindow's internal state.
+  if (native_app_window_->IsFullscreen()) {
+    if (!IsFullscreen())
+      fullscreen_types_ = FULLSCREEN_TYPE_OS;
+  } else {
+    fullscreen_types_ = FULLSCREEN_TYPE_NONE;
+  }
+
+  if (cached_always_on_top_)
+    UpdateNativeAlwaysOnTop();  // Same as in SetNativeWindowFullscreen.
+#endif
+
   SaveWindowPosition();
 
 #if defined(OS_WIN)
-  if (native_app_window_ && cached_always_on_top_ && !IsFullscreen() &&
+  if (cached_always_on_top_ && !IsFullscreen() &&
       !native_app_window_->IsMaximized() &&
       !native_app_window_->IsMinimized()) {
     UpdateNativeAlwaysOnTop();
   }
 #endif
 
-  if (app_window_contents_ && native_app_window_)
+  if (app_window_contents_)
     app_window_contents_->NativeWindowChanged(native_app_window_.get());
 }
 
@@ -922,6 +944,14 @@
                         : blink::WebDisplayModeStandalone;
 }
 
+WindowController* AppWindow::GetExtensionWindowController() const {
+  return app_window_contents_->GetWindowController();
+}
+
+content::WebContents* AppWindow::GetAssociatedWebContents() const {
+  return web_contents();
+}
+
 void AppWindow::OnExtensionUnloaded(BrowserContext* browser_context,
                                     const Extension* extension,
                                     UnloadedExtensionInfo::Reason reason) {
@@ -952,10 +982,9 @@
 }
 
 void AppWindow::SaveWindowPosition() {
+  DCHECK(native_app_window_);
   if (window_key_.empty())
     return;
-  if (!native_app_window_)
-    return;
 
   AppWindowGeometryCache* cache =
       AppWindowGeometryCache::Get(browser_context());
diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h
index 1112d38a..10267f6 100644
--- a/extensions/browser/app_window/app_window.h
+++ b/extensions/browser/app_window/app_window.h
@@ -15,6 +15,7 @@
 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "extensions/browser/extension_function_dispatcher.h"
 #include "extensions/browser/extension_icon_image.h"
 #include "extensions/browser/extension_registry_observer.h"
 #include "ui/base/ui_base_types.h"  // WindowShowState
@@ -70,6 +71,8 @@
 
   virtual content::WebContents* GetWebContents() const = 0;
 
+  virtual extensions::WindowController* GetWindowController() const = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(AppWindowContents);
 };
@@ -80,6 +83,7 @@
                   public content::WebContentsObserver,
                   public web_modal::WebContentsModalDialogManagerDelegate,
                   public IconImage::Observer,
+                  public ExtensionFunctionDispatcher::Delegate,
                   public ExtensionRegistryObserver {
  public:
   enum WindowType {
@@ -408,6 +412,10 @@
   void RenderViewCreated(content::RenderViewHost* render_view_host) override;
   void DidFirstVisuallyNonEmptyPaint() override;
 
+  // ExtensionFunctionDispatcher::Delegate implementation.
+  WindowController* GetExtensionWindowController() const override;
+  content::WebContents* GetAssociatedWebContents() const override;
+
   // ExtensionRegistryObserver implementation.
   void OnExtensionUnloaded(content::BrowserContext* browser_context,
                            const Extension* extension,
diff --git a/extensions/browser/app_window/app_window_contents.cc b/extensions/browser/app_window/app_window_contents.cc
index 6c3909a..396a638 100644
--- a/extensions/browser/app_window/app_window_contents.cc
+++ b/extensions/browser/app_window/app_window_contents.cc
@@ -28,9 +28,6 @@
                                        const GURL& url) {
   url_ = url;
 
-  extension_function_dispatcher_.reset(
-      new ExtensionFunctionDispatcher(context, this));
-
   web_contents_.reset(
       content::WebContents::Create(content::WebContents::CreateParams(
           context, content::SiteInstance::CreateForURL(context, url_))));
@@ -96,10 +93,13 @@
   return web_contents_.get();
 }
 
+WindowController* AppWindowContentsImpl::GetWindowController() const {
+  return nullptr;
+}
+
 bool AppWindowContentsImpl::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(AppWindowContentsImpl, message)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_UpdateDraggableRegions,
                         UpdateDraggableRegions)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -107,20 +107,6 @@
   return handled;
 }
 
-WindowController* AppWindowContentsImpl::GetExtensionWindowController() const {
-  return NULL;
-}
-
-content::WebContents* AppWindowContentsImpl::GetAssociatedWebContents() const {
-  return web_contents_.get();
-}
-
-void AppWindowContentsImpl::OnRequest(
-    const ExtensionHostMsg_Request_Params& params) {
-  extension_function_dispatcher_->Dispatch(
-      params, web_contents_->GetRenderViewHost());
-}
-
 void AppWindowContentsImpl::UpdateDraggableRegions(
     const std::vector<DraggableRegion>& regions) {
   host_->UpdateDraggableRegions(regions);
diff --git a/extensions/browser/app_window/app_window_contents.h b/extensions/browser/app_window/app_window_contents.h
index ab07ca6a..56c16647 100644
--- a/extensions/browser/app_window/app_window_contents.h
+++ b/extensions/browser/app_window/app_window_contents.h
@@ -10,7 +10,6 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "extensions/browser/app_window/app_window.h"
-#include "extensions/browser/extension_function_dispatcher.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -25,8 +24,7 @@
 // WebContents instance and observes it for the purpose of passing
 // messages to the extensions system.
 class AppWindowContentsImpl : public AppWindowContents,
-                              public content::WebContentsObserver,
-                              public ExtensionFunctionDispatcher::Delegate {
+                              public content::WebContentsObserver {
  public:
   explicit AppWindowContentsImpl(AppWindow* host);
   ~AppWindowContentsImpl() override;
@@ -38,23 +36,18 @@
   void NativeWindowClosed() override;
   void DispatchWindowShownForTests() const override;
   content::WebContents* GetWebContents() const override;
+  WindowController* GetWindowController() const override;
 
  private:
   // content::WebContentsObserver
   bool OnMessageReceived(const IPC::Message& message) override;
 
-  // ExtensionFunctionDispatcher::Delegate
-  WindowController* GetExtensionWindowController() const override;
-  content::WebContents* GetAssociatedWebContents() const override;
-
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
   void UpdateDraggableRegions(const std::vector<DraggableRegion>& regions);
   void SuspendRenderViewHost(content::RenderViewHost* rvh);
 
   AppWindow* host_;  // This class is owned by |host_|
   GURL url_;
   scoped_ptr<content::WebContents> web_contents_;
-  scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
 
   DISALLOW_COPY_AND_ASSIGN(AppWindowContentsImpl);
 };
diff --git a/extensions/browser/app_window/test_app_window_contents.cc b/extensions/browser/app_window/test_app_window_contents.cc
index 4cc856d6..18401e7 100644
--- a/extensions/browser/app_window/test_app_window_contents.cc
+++ b/extensions/browser/app_window/test_app_window_contents.cc
@@ -36,4 +36,8 @@
   return web_contents_.get();
 }
 
+WindowController* TestAppWindowContents::GetWindowController() const {
+  return nullptr;
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/app_window/test_app_window_contents.h b/extensions/browser/app_window/test_app_window_contents.h
index 018b33e..d52fb97 100644
--- a/extensions/browser/app_window/test_app_window_contents.h
+++ b/extensions/browser/app_window/test_app_window_contents.h
@@ -28,6 +28,7 @@
   void NativeWindowClosed() override;
   void DispatchWindowShownForTests() const override;
   content::WebContents* GetWebContents() const override;
+  WindowController* GetWindowController() const override;
 
  private:
   scoped_ptr<content::WebContents> web_contents_;
diff --git a/extensions/browser/browser_context_keyed_service_factories.cc b/extensions/browser/browser_context_keyed_service_factories.cc
index ee2a901..ceda9f3 100644
--- a/extensions/browser/browser_context_keyed_service_factories.cc
+++ b/extensions/browser/browser_context_keyed_service_factories.cc
@@ -7,11 +7,16 @@
 #include "extensions/browser/api/alarms/alarm_manager.h"
 #include "extensions/browser/api/api_resource_manager.h"
 #include "extensions/browser/api/audio/audio_api.h"
+#include "extensions/browser/api/bluetooth/bluetooth_api.h"
+#include "extensions/browser/api/bluetooth/bluetooth_private_api.h"
+#include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
+#include "extensions/browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h"
 #include "extensions/browser/api/hid/hid_device_manager.h"
 #include "extensions/browser/api/idle/idle_manager_factory.h"
 #include "extensions/browser/api/management/management_api.h"
 #include "extensions/browser/api/networking_config/networking_config_service_factory.h"
 #include "extensions/browser/api/networking_private/networking_private_event_router_factory.h"
+#include "extensions/browser/api/power/power_api.h"
 #include "extensions/browser/api/runtime/runtime_api.h"
 #include "extensions/browser/api/serial/serial_connection.h"
 #include "extensions/browser/api/socket/socket.h"
@@ -25,8 +30,11 @@
 #include "extensions/browser/api/usb/usb_device_resource.h"
 #include "extensions/browser/api/usb/usb_event_router.h"
 #include "extensions/browser/api/usb/usb_guid_map.h"
+#include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_private_api.h"
 #include "extensions/browser/api/vpn_provider/vpn_service_factory.h"
+#include "extensions/browser/api/web_request/web_request_api.h"
 #include "extensions/browser/api/webcam_private/webcam_private_api.h"
+#include "extensions/browser/declarative_user_script_manager_factory.h"
 #include "extensions/browser/event_router_factory.h"
 #include "extensions/browser/extension_message_filter.h"
 #include "extensions/browser/extension_prefs_factory.h"
@@ -44,12 +52,17 @@
   ApiResourceManager<Socket>::GetFactoryInstance();
   ApiResourceManager<UsbDeviceResource>::GetFactoryInstance();
   AudioAPI::GetFactoryInstance();
+  BluetoothAPI::GetFactoryInstance();
+  BluetoothLowEnergyAPI::GetFactoryInstance();
+  BluetoothPrivateAPI::GetFactoryInstance();
 #if defined(OS_CHROMEOS)
   chromeos::VpnServiceFactory::GetInstance();
 #endif
+  core_api::BluetoothSocketEventDispatcher::GetFactoryInstance();
   core_api::TCPServerSocketEventDispatcher::GetFactoryInstance();
   core_api::TCPSocketEventDispatcher::GetFactoryInstance();
   core_api::UDPSocketEventDispatcher::GetFactoryInstance();
+  DeclarativeUserScriptManagerFactory::GetInstance();
   EventRouterFactory::GetInstance();
   ExtensionMessageFilter::EnsureShutdownNotifierFactoryBuilt();
   ExtensionPrefsFactory::GetInstance();
@@ -62,6 +75,7 @@
 #if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_MACOSX)
   NetworkingPrivateEventRouterFactory::GetInstance();
 #endif
+  PowerAPI::GetFactoryInstance();
   ProcessManagerFactory::GetInstance();
   RendererStartupHelperFactory::GetInstance();
   RuntimeAPI::GetFactoryInstance();
@@ -70,8 +84,10 @@
   UsbEventRouter::GetFactoryInstance();
   UsbGuidMap::GetFactoryInstance();
 #if defined(OS_CHROMEOS)
+  VirtualKeyboardAPI::GetFactoryInstance();
   WebcamPrivateAPI::GetFactoryInstance();
 #endif
+  WebRequestAPI::GetFactoryInstance();
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/content_hash_fetcher.cc b/extensions/browser/content_hash_fetcher.cc
index eefc991..8f8b496 100644
--- a/extensions/browser/content_hash_fetcher.cc
+++ b/extensions/browser/content_hash_fetcher.cc
@@ -458,15 +458,11 @@
   DCHECK(extension->version());
   GURL url =
       delegate_->GetSignatureFetchUrl(extension->id(), *extension->version());
-  ContentHashFetcherJob* job =
-      new ContentHashFetcherJob(context_->GetRequestContext(),
-                                delegate_->PublicKey(),
-                                extension->id(),
-                                extension->path(),
-                                url,
-                                force,
-                                base::Bind(&ContentHashFetcher::JobFinished,
-                                           weak_ptr_factory_.GetWeakPtr()));
+  ContentHashFetcherJob* job = new ContentHashFetcherJob(
+      context_->GetRequestContext(), delegate_->GetPublicKey(), extension->id(),
+      extension->path(), url, force,
+      base::Bind(&ContentHashFetcher::JobFinished,
+                 weak_ptr_factory_.GetWeakPtr()));
   jobs_.insert(std::make_pair(key, job));
   job->Start();
 }
diff --git a/extensions/browser/content_verifier.cc b/extensions/browser/content_verifier.cc
index 8c05f12..3bbe4a9 100644
--- a/extensions/browser/content_verifier.cc
+++ b/extensions/browser/content_verifier.cc
@@ -70,11 +70,8 @@
   // TODO(asargent) - we can probably get some good performance wins by having
   // a cache of ContentHashReader's that we hold onto past the end of each job.
   return new ContentVerifyJob(
-      new ContentHashReader(extension_id,
-                            data->version,
-                            extension_root,
-                            relative_path,
-                            delegate_->PublicKey()),
+      new ContentHashReader(extension_id, data->version, extension_root,
+                            relative_path, delegate_->GetPublicKey()),
       base::Bind(&ContentVerifier::VerifyFailed, this, extension_id));
 }
 
diff --git a/extensions/browser/content_verifier_delegate.h b/extensions/browser/content_verifier_delegate.h
index fbeb7a7..2feb7b79 100644
--- a/extensions/browser/content_verifier_delegate.h
+++ b/extensions/browser/content_verifier_delegate.h
@@ -61,9 +61,8 @@
   virtual Mode ShouldBeVerified(const Extension& extension) = 0;
 
   // Should return the public key to use for validating signatures via the two
-  // out parameters. NOTE: the pointer returned *must* remain valid for the
-  // lifetime of this object.
-  virtual const ContentVerifierKey& PublicKey() = 0;
+  // out parameters.
+  virtual ContentVerifierKey GetPublicKey() = 0;
 
   // This should return a URL that can be used to fetch the
   // verified_contents.json containing signatures for the given extension
diff --git a/extensions/browser/event_router.h b/extensions/browser/event_router.h
index 6cd7df6..b9af93a 100644
--- a/extensions/browser/event_router.h
+++ b/extensions/browser/event_router.h
@@ -76,8 +76,6 @@
   };
 
   // Gets the EventRouter for |browser_context|.
-  // Shorthand for ExtensionSystem::Get(browser_context)->event_router(); it's
-  // a very common operation.
   static EventRouter* Get(content::BrowserContext* browser_context);
 
   // Converts event names like "foo.onBar/123" into "foo.onBar". Event names
diff --git a/extensions/browser/extension_dialog_auto_confirm.cc b/extensions/browser/extension_dialog_auto_confirm.cc
new file mode 100644
index 0000000..e17fa6a
--- /dev/null
+++ b/extensions/browser/extension_dialog_auto_confirm.cc
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/extension_dialog_auto_confirm.h"
+
+namespace extensions {
+
+namespace {
+ScopedTestDialogAutoConfirm::AutoConfirm g_extension_dialog_auto_confirm =
+    ScopedTestDialogAutoConfirm::NONE;
+}
+
+ScopedTestDialogAutoConfirm::ScopedTestDialogAutoConfirm(
+    ScopedTestDialogAutoConfirm::AutoConfirm override_value)
+    : old_value_(g_extension_dialog_auto_confirm) {
+  g_extension_dialog_auto_confirm = override_value;
+}
+
+ScopedTestDialogAutoConfirm::~ScopedTestDialogAutoConfirm() {
+  g_extension_dialog_auto_confirm = old_value_;
+}
+
+ScopedTestDialogAutoConfirm::AutoConfirm
+ScopedTestDialogAutoConfirm::GetAutoConfirmValue() {
+  return g_extension_dialog_auto_confirm;
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/extension_dialog_auto_confirm.h b/extensions/browser/extension_dialog_auto_confirm.h
new file mode 100644
index 0000000..5b4303e0
--- /dev/null
+++ b/extensions/browser/extension_dialog_auto_confirm.h
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_EXTENSION_DIALOG_AUTO_CONFIRM_H_
+#define EXTENSIONS_BROWSER_EXTENSION_DIALOG_AUTO_CONFIRM_H_
+
+#include "base/auto_reset.h"
+
+namespace extensions {
+
+class ScopedTestDialogAutoConfirm {
+ public:
+  enum AutoConfirm {
+    NONE,    // The prompt will show normally.
+    ACCEPT,  // The prompt will always accept.
+    CANCEL,  // The prompt will always cancel.
+  };
+
+  explicit ScopedTestDialogAutoConfirm(AutoConfirm override_value);
+  ~ScopedTestDialogAutoConfirm();
+
+  static AutoConfirm GetAutoConfirmValue();
+
+ private:
+  AutoConfirm old_value_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTestDialogAutoConfirm);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_EXTENSION_DIALOG_AUTO_CONFIRM_H_
diff --git a/extensions/browser/extension_function.cc b/extensions/browser/extension_function.cc
index 46e3ba1..624bfe78 100644
--- a/extensions/browser/extension_function.cc
+++ b/extensions/browser/extension_function.cc
@@ -237,7 +237,8 @@
       bad_message_(false),
       histogram_value_(extensions::functions::UNKNOWN),
       source_tab_id_(-1),
-      source_context_type_(Feature::UNSPECIFIED_CONTEXT) {
+      source_context_type_(Feature::UNSPECIFIED_CONTEXT),
+      source_process_id_(-1) {
 }
 
 ExtensionFunction::~ExtensionFunction() {
@@ -463,7 +464,7 @@
 content::WebContents* UIThreadExtensionFunction::GetAssociatedWebContents() {
   content::WebContents* web_contents = NULL;
   if (dispatcher())
-    web_contents = dispatcher()->delegate()->GetAssociatedWebContents();
+    web_contents = dispatcher()->GetAssociatedWebContents();
 
   return web_contents;
 }
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h
index 3f6f9ce..23ffedf 100644
--- a/extensions/browser/extension_function.h
+++ b/extensions/browser/extension_function.h
@@ -278,6 +278,13 @@
     return source_context_type_;
   }
 
+  void set_source_process_id(int source_process_id) {
+    source_process_id_ = source_process_id;
+  }
+  int source_process_id() const {
+    return source_process_id_;
+  }
+
  protected:
   friend struct ExtensionFunctionDeleteTraits;
 
@@ -424,6 +431,10 @@
   // The type of the JavaScript context where this call originated.
   extensions::Feature::Context source_context_type_;
 
+  // The process ID of the page that triggered this function call, or -1
+  // if unknown.
+  int source_process_id_;
+
  private:
   void OnRespondingLater(ResponseValue response);
 
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc
index e682701..9a30d2e 100644
--- a/extensions/browser/extension_function_dispatcher.cc
+++ b/extensions/browser/extension_function_dispatcher.cc
@@ -205,12 +205,12 @@
 
 WindowController*
 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() const {
-  return NULL;
+  return nullptr;
 }
 
 content::WebContents*
 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const {
-  return NULL;
+  return nullptr;
 }
 
 content::WebContents*
@@ -301,10 +301,8 @@
 }
 
 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
-    content::BrowserContext* browser_context,
-    Delegate* delegate)
-    : browser_context_(browser_context),
-      delegate_(delegate) {
+    content::BrowserContext* browser_context)
+    : browser_context_(browser_context) {
 }
 
 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
@@ -440,6 +438,22 @@
   }
 }
 
+WindowController*
+ExtensionFunctionDispatcher::GetExtensionWindowController() const {
+  return delegate_ ? delegate_->GetExtensionWindowController() : nullptr;
+}
+
+content::WebContents*
+ExtensionFunctionDispatcher::GetAssociatedWebContents() const {
+  return delegate_ ? delegate_->GetAssociatedWebContents() : nullptr;
+}
+
+content::WebContents*
+ExtensionFunctionDispatcher::GetVisibleWebContents() const {
+  return delegate_ ? delegate_->GetVisibleWebContents() :
+      GetAssociatedWebContents();
+}
+
 // static
 bool ExtensionFunctionDispatcher::CheckPermissions(
     ExtensionFunction* function,
@@ -481,6 +495,7 @@
   function->set_source_tab_id(params.source_tab_id);
   function->set_source_context_type(
       process_map.GetMostLikelyContextType(extension, requesting_process_id));
+  function->set_source_process_id(requesting_process_id);
 
   return function;
 }
diff --git a/extensions/browser/extension_function_dispatcher.h b/extensions/browser/extension_function_dispatcher.h
index 9224bbde..2764449 100644
--- a/extensions/browser/extension_function_dispatcher.h
+++ b/extensions/browser/extension_function_dispatcher.h
@@ -90,16 +90,12 @@
       const ExtensionHostMsg_Request_Params& params);
 
   // Public constructor. Callers must ensure that:
-  // - |delegate| outlives this object.
   // - This object outlives any RenderViewHost's passed to created
   //   ExtensionFunctions.
-  ExtensionFunctionDispatcher(content::BrowserContext* browser_context,
-                              Delegate* delegate);
-
+  explicit ExtensionFunctionDispatcher(
+      content::BrowserContext* browser_context);
   ~ExtensionFunctionDispatcher();
 
-  Delegate* delegate() { return delegate_; }
-
   // Message handlers.
   // The response is sent to the corresponding render view in an
   // ExtensionMsg_Response message.
@@ -111,9 +107,18 @@
   // a response (if any) to the extension.
   void OnExtensionFunctionCompleted(const Extension* extension);
 
+  // See the Delegate class for documentation on these methods.
+  // TODO(devlin): None of these belong here. We should kill
+  // ExtensionFunctionDispatcher::Delegate.
+  WindowController* GetExtensionWindowController() const;
+  content::WebContents* GetAssociatedWebContents() const;
+  content::WebContents* GetVisibleWebContents() const;
+
   // The BrowserContext that this dispatcher is associated with.
   content::BrowserContext* browser_context() { return browser_context_; }
 
+  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
  private:
   // For a given RenderViewHost instance, UIThreadResponseCallbackWrapper
   // creates ExtensionFunction::ResponseCallback instances which send responses
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 9538f45..924cd1d 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1109,6 +1109,10 @@
   USERSPRIVATE_ISCURRENTUSEROWNER,
   USERSPRIVATE_ISWHITELISTMANAGED,
   PRINTERPROVIDERINTERNAL_REPORTUSBPRINTERINFO,
+  WEBCAMPRIVATE_OPENSERIALWEBCAM,
+  WEBCAMPRIVATE_CLOSEWEBCAM,
+  SERIAL_SETBREAK,
+  SERIAL_CLEARBREAK,
   // Last entry: Add new entries above and ensure to update
   // tools/metrics/histograms/histograms.xml.
   ENUM_BOUNDARY
diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc
index 124a8fd..c3e041a 100644
--- a/extensions/browser/extension_host.cc
+++ b/extensions/browser/extension_host.cc
@@ -27,6 +27,7 @@
 #include "extensions/browser/extension_host_queue.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_web_contents_observer.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/load_monitoring_extension_host_queue.h"
 #include "extensions/browser/notification_types.h"
@@ -62,7 +63,6 @@
       has_loaded_once_(false),
       document_element_available_(false),
       initial_url_(url),
-      extension_function_dispatcher_(browser_context_, this),
       extension_host_type_(host_type) {
   // Not used for panels, see PanelHost.
   DCHECK(host_type == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
@@ -82,6 +82,9 @@
 
   // Set up web contents observers and pref observers.
   delegate_->OnExtensionHostCreated(host_contents());
+
+  ExtensionWebContentsObserver::GetForWebContents(host_contents())->
+      dispatcher()->set_delegate(this);
 }
 
 ExtensionHost::~ExtensionHost() {
@@ -321,7 +324,6 @@
 bool ExtensionHost::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(ExtensionHost, message)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_EventAck, OnEventAck)
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_IncrementLazyKeepaliveCount,
                         OnIncrementLazyKeepaliveCount)
@@ -332,10 +334,6 @@
   return handled;
 }
 
-void ExtensionHost::OnRequest(const ExtensionHostMsg_Request_Params& params) {
-  extension_function_dispatcher_.Dispatch(params, render_view_host());
-}
-
 void ExtensionHost::OnEventAck(int event_id) {
   EventRouter* router = EventRouter::Get(browser_context_);
   if (router)
diff --git a/extensions/browser/extension_host.h b/extensions/browser/extension_host.h
index 846eb50..d82c427 100644
--- a/extensions/browser/extension_host.h
+++ b/extensions/browser/extension_host.h
@@ -151,7 +151,6 @@
       DeferredStartRenderHostObserver* observer) override;
 
   // Message handlers.
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
   void OnEventAck(int event_id);
   void OnIncrementLazyKeepaliveCount();
   void OnDecrementLazyKeepaliveCount();
@@ -193,8 +192,6 @@
   // Messages sent out to the renderer that have not been acknowledged yet.
   std::set<int> unacked_messages_;
 
-  ExtensionFunctionDispatcher extension_function_dispatcher_;
-
   // The type of view being hosted.
   ViewType extension_host_type_;
 
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index 460e0de7..79bd547 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -83,9 +83,6 @@
 // run of this profile.
 const char kPrefExternalInstallFirstRun[] = "external_first_run";
 
-// Indicates whether to show an install warning when the user enables.
-const char kExtensionDidEscalatePermissions[] = "install_warning_on_enable";
-
 // DO NOT USE, use kPrefDisableReasons instead.
 // Indicates whether the extension was updated while it was disabled.
 const char kDeprecatedPrefDisableReason[] = "disable_reason";
@@ -729,14 +726,9 @@
 
 bool ExtensionPrefs::DidExtensionEscalatePermissions(
     const std::string& extension_id) const {
-  return ReadPrefAsBooleanAndReturn(extension_id,
-                                    kExtensionDidEscalatePermissions);
-}
-
-void ExtensionPrefs::SetDidExtensionEscalatePermissions(
-    const Extension* extension, bool did_escalate) {
-  UpdateExtensionPref(extension->id(), kExtensionDidEscalatePermissions,
-                      new base::FundamentalValue(did_escalate));
+  return HasDisableReason(extension_id,
+                          Extension::DISABLE_PERMISSIONS_INCREASE) ||
+         HasDisableReason(extension_id, Extension::DISABLE_REMOTE_INSTALL);
 }
 
 int ExtensionPrefs::GetDisableReasons(const std::string& extension_id) const {
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h
index 9cd810e..8050789 100644
--- a/extensions/browser/extension_prefs.h
+++ b/extensions/browser/extension_prefs.h
@@ -251,12 +251,6 @@
   // Did the extension ask to escalate its permission during an upgrade?
   bool DidExtensionEscalatePermissions(const std::string& id) const;
 
-  // If |did_escalate| is true, the preferences for |extension| will be set to
-  // require the install warning when the user tries to enable.
-  void SetDidExtensionEscalatePermissions(
-      const Extension* extension,
-      bool did_escalate);
-
   // Getters and setters for disabled reason.
   int GetDisableReasons(const std::string& extension_id) const;
   bool HasDisableReason(const std::string& extension_id,
diff --git a/extensions/browser/extension_prefs_factory.cc b/extensions/browser/extension_prefs_factory.cc
index c07229cb..9e1d3ec 100644
--- a/extensions/browser/extension_prefs_factory.cc
+++ b/extensions/browser/extension_prefs_factory.cc
@@ -28,8 +28,9 @@
 }
 
 void ExtensionPrefsFactory::SetInstanceForTesting(
-    content::BrowserContext* context, ExtensionPrefs* prefs) {
-  Associate(context, prefs);
+    content::BrowserContext* context,
+    scoped_ptr<ExtensionPrefs> prefs) {
+  Associate(context, prefs.Pass());
 }
 
 ExtensionPrefsFactory::ExtensionPrefsFactory()
diff --git a/extensions/browser/extension_prefs_factory.h b/extensions/browser/extension_prefs_factory.h
index a83b4f3d..9a6d921 100644
--- a/extensions/browser/extension_prefs_factory.h
+++ b/extensions/browser/extension_prefs_factory.h
@@ -19,8 +19,8 @@
 
   static ExtensionPrefsFactory* GetInstance();
 
-  void SetInstanceForTesting(
-      content::BrowserContext* context, ExtensionPrefs* prefs);
+  void SetInstanceForTesting(content::BrowserContext* context,
+                             scoped_ptr<ExtensionPrefs> prefs);
 
  private:
   friend struct DefaultSingletonTraits<ExtensionPrefsFactory>;
diff --git a/extensions/browser/extension_web_contents_observer.cc b/extensions/browser/extension_web_contents_observer.cc
index 1b1cad8..779f9a0 100644
--- a/extensions/browser/extension_web_contents_observer.cc
+++ b/extensions/browser/extension_web_contents_observer.cc
@@ -45,19 +45,33 @@
 
 }  // namespace
 
+// static
+ExtensionWebContentsObserver* ExtensionWebContentsObserver::GetForWebContents(
+    content::WebContents* web_contents) {
+  return ExtensionsBrowserClient::Get()->GetExtensionWebContentsObserver(
+      web_contents);
+}
+
 ExtensionWebContentsObserver::ExtensionWebContentsObserver(
     content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
-      browser_context_(web_contents->GetBrowserContext()) {
+      browser_context_(web_contents->GetBrowserContext()),
+      dispatcher_(browser_context_) {
   NotifyRenderViewType(web_contents->GetRenderViewHost());
   content::RenderFrameHost* host = web_contents->GetMainFrame();
   if (host)
     RenderFrameHostChanged(nullptr, host);
+  dispatcher_.set_delegate(this);
 }
 
 ExtensionWebContentsObserver::~ExtensionWebContentsObserver() {
 }
 
+content::WebContents* ExtensionWebContentsObserver::GetAssociatedWebContents()
+    const {
+  return web_contents();
+}
+
 void ExtensionWebContentsObserver::RenderViewCreated(
     content::RenderViewHost* render_view_host) {
   NotifyRenderViewType(render_view_host);
@@ -110,6 +124,16 @@
   }
 }
 
+bool ExtensionWebContentsObserver::OnMessageReceived(
+    const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(ExtensionWebContentsObserver, message)
+    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
 void ExtensionWebContentsObserver::FrameDeleted(
     content::RenderFrameHost* render_frame_host) {
   ProcessManager::Get(browser_context_)->UnregisterRenderFrameHost(
@@ -189,4 +213,9 @@
   return site.host();
 }
 
+void ExtensionWebContentsObserver::OnRequest(
+    const ExtensionHostMsg_Request_Params& params) {
+  dispatcher_.Dispatch(params, web_contents()->GetRenderViewHost());
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/extension_web_contents_observer.h b/extensions/browser/extension_web_contents_observer.h
index d36d782..2989e05 100644
--- a/extensions/browser/extension_web_contents_observer.h
+++ b/extensions/browser/extension_web_contents_observer.h
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "extensions/browser/extension_function_dispatcher.h"
 
 namespace content {
 class BrowserContext;
@@ -28,13 +29,25 @@
 // WebContents. It must be a subclass so that creating an instance via
 // content::WebContentsUserData::CreateForWebContents() provides an object of
 // the correct type. For an example, see ChromeExtensionWebContentsObserver.
-class ExtensionWebContentsObserver : public content::WebContentsObserver {
+class ExtensionWebContentsObserver
+    : public content::WebContentsObserver,
+      public ExtensionFunctionDispatcher::Delegate {
+ public:
+  // Returns the ExtensionWebContentsObserver for the given |web_contents|.
+  static ExtensionWebContentsObserver* GetForWebContents(
+      content::WebContents* web_contents);
+
+  ExtensionFunctionDispatcher* dispatcher() { return &dispatcher_; }
+
  protected:
   explicit ExtensionWebContentsObserver(content::WebContents* web_contents);
   ~ExtensionWebContentsObserver() override;
 
   content::BrowserContext* browser_context() { return browser_context_; }
 
+  // ExtensionFunctionDispatcher::Delegate overrides.
+  content::WebContents* GetAssociatedWebContents() const override;
+
   // content::WebContentsObserver overrides.
 
   // A subclass should invoke this method to finish extension process setup.
@@ -42,6 +55,9 @@
 
   void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
 
+  // Subclasses should call this first before doing their own message handling.
+  bool OnMessageReceived(const IPC::Message& message) override;
+
   // Per the documentation in WebContentsObserver, these two methods are
   // appropriate to track the set of current RenderFrameHosts.
   // NOTE: FrameDeleted() != RenderFrameDeleted().
@@ -66,9 +82,13 @@
   static std::string GetExtensionId(content::RenderViewHost* render_view_host);
 
  private:
+  void OnRequest(const ExtensionHostMsg_Request_Params& params);
+
   // The BrowserContext associated with the WebContents being observed.
   content::BrowserContext* browser_context_;
 
+  ExtensionFunctionDispatcher dispatcher_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionWebContentsObserver);
 };
 
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h
index 49d00db..6e99f7f 100644
--- a/extensions/browser/extensions_browser_client.h
+++ b/extensions/browser/extensions_browser_client.h
@@ -44,6 +44,7 @@
 class ExtensionPrefsObserver;
 class ExtensionSystem;
 class ExtensionSystemProvider;
+class ExtensionWebContentsObserver;
 class InfoMap;
 class ProcessManagerDelegate;
 class RuntimeAPIDelegate;
@@ -212,6 +213,10 @@
   // is left up to the embedder.
   virtual bool IsMinBrowserVersionSupported(const std::string& min_version) = 0;
 
+  // Returns the ExtensionWebContentsObserver for the given |web_contents|.
+  virtual ExtensionWebContentsObserver* GetExtensionWebContentsObserver(
+      content::WebContents* web_contents) = 0;
+
   // Returns the single instance of |this|.
   static ExtensionsBrowserClient* Get();
 
diff --git a/extensions/browser/guest_view/app_view/app_view_guest.cc b/extensions/browser/guest_view/app_view/app_view_guest.cc
index 9c157d04..108b9b3 100644
--- a/extensions/browser/guest_view/app_view/app_view_guest.cc
+++ b/extensions/browser/guest_view/app_view/app_view_guest.cc
@@ -104,23 +104,6 @@
 AppViewGuest::~AppViewGuest() {
 }
 
-WindowController* AppViewGuest::GetExtensionWindowController() const {
-  return nullptr;
-}
-
-content::WebContents* AppViewGuest::GetAssociatedWebContents() const {
-  return web_contents();
-}
-
-bool AppViewGuest::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(AppViewGuest, message)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
 bool AppViewGuest::HandleContextMenu(const content::ContextMenuParams& params) {
   if (app_view_guest_delegate_) {
     return app_view_guest_delegate_->HandleContextMenu(web_contents(), params);
@@ -226,8 +209,7 @@
 }
 
 void AppViewGuest::DidInitialize(const base::DictionaryValue& create_params) {
-  extension_function_dispatcher_.reset(
-      new ExtensionFunctionDispatcher(browser_context(), this));
+  ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents());
 
   if (!url_.is_valid())
     return;
@@ -244,11 +226,6 @@
   return IDS_EXTENSION_TASK_MANAGER_APPVIEW_TAG_PREFIX;
 }
 
-void AppViewGuest::OnRequest(const ExtensionHostMsg_Request_Params& params) {
-  extension_function_dispatcher_->Dispatch(params,
-                                           web_contents()->GetRenderViewHost());
-}
-
 void AppViewGuest::CompleteCreateWebContents(
     const GURL& url,
     const Extension* guest_extension,
diff --git a/extensions/browser/guest_view/app_view/app_view_guest.h b/extensions/browser/guest_view/app_view/app_view_guest.h
index 4b05d1a..81cf44de 100644
--- a/extensions/browser/guest_view/app_view/app_view_guest.h
+++ b/extensions/browser/guest_view/app_view/app_view_guest.h
@@ -7,7 +7,6 @@
 
 #include "base/id_map.h"
 #include "components/guest_view/browser/guest_view.h"
-#include "extensions/browser/extension_function_dispatcher.h"
 #include "extensions/browser/guest_view/app_view/app_view_guest_delegate.h"
 
 namespace extensions {
@@ -18,8 +17,7 @@
 // AppViewGuest is created on attachment. That is, when a guest WebContents is
 // associated with a particular embedder WebContents. This happens on calls to
 // the connect API.
-class AppViewGuest : public guest_view::GuestView<AppViewGuest>,
-                     public ExtensionFunctionDispatcher::Delegate {
+class AppViewGuest : public guest_view::GuestView<AppViewGuest> {
  public:
   static const char Type[];
 
@@ -33,13 +31,6 @@
 
   static GuestViewBase* Create(content::WebContents* owner_web_contents);
 
-  // ExtensionFunctionDispatcher::Delegate implementation.
-  WindowController* GetExtensionWindowController() const override;
-  content::WebContents* GetAssociatedWebContents() const override;
-
-  // content::WebContentsObserver implementation.
-  bool OnMessageReceived(const IPC::Message& message) override;
-
   // content::WebContentsDelegate implementation.
   bool HandleContextMenu(const content::ContextMenuParams& params) override;
   void RequestMediaAccessPermission(
@@ -66,8 +57,6 @@
 
   ~AppViewGuest() override;
 
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
-
   void CompleteCreateWebContents(const GURL& url,
                                  const Extension* guest_extension,
                                  const WebContentsCreatedCallback& callback);
@@ -78,7 +67,6 @@
 
   GURL url_;
   std::string guest_extension_id_;
-  scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
   scoped_ptr<AppViewGuestDelegate> app_view_guest_delegate_;
   scoped_ptr<AppDelegate> app_delegate_;
 
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.cc b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
index c882315..339906a 100644
--- a/extensions/browser/guest_view/extension_options/extension_options_guest.cc
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
@@ -17,7 +17,6 @@
 #include "extensions/browser/bad_message.h"
 #include "extensions/browser/extension_function_dispatcher.h"
 #include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_web_contents_observer.h"
 #include "extensions/browser/guest_view/extension_options/extension_options_constants.h"
 #include "extensions/browser/guest_view/extension_options/extension_options_guest_delegate.h"
 #include "extensions/common/api/extension_options_internal.h"
@@ -117,11 +116,7 @@
 
 void ExtensionOptionsGuest::DidInitialize(
     const base::DictionaryValue& create_params) {
-  extension_function_dispatcher_.reset(
-      new extensions::ExtensionFunctionDispatcher(browser_context(), this));
-  if (extension_options_guest_delegate_) {
-    extension_options_guest_delegate_->DidInitialize();
-  }
+  ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents());
   web_contents()->GetController().LoadURL(options_page_,
                                           content::Referrer(),
                                           ui::PAGE_TRANSITION_LINK,
@@ -160,10 +155,6 @@
       options.ToValue()));
 }
 
-content::WebContents* ExtensionOptionsGuest::GetAssociatedWebContents() const {
-  return web_contents();
-}
-
 content::WebContents* ExtensionOptionsGuest::OpenURLFromTab(
     content::WebContents* source,
     const content::OpenURLParams& params) {
@@ -244,19 +235,4 @@
   }
 }
 
-bool ExtensionOptionsGuest::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(ExtensionOptionsGuest, message)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void ExtensionOptionsGuest::OnRequest(
-    const ExtensionHostMsg_Request_Params& params) {
-  extension_function_dispatcher_->Dispatch(params,
-                                           web_contents()->GetRenderViewHost());
-}
-
 }  // namespace extensions
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.h b/extensions/browser/guest_view/extension_options/extension_options_guest.h
index b62d81a..088c78b 100644
--- a/extensions/browser/guest_view/extension_options/extension_options_guest.h
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest.h
@@ -7,7 +7,6 @@
 
 #include "base/macros.h"
 #include "components/guest_view/browser/guest_view.h"
-#include "extensions/browser/extension_function_dispatcher.h"
 #include "extensions/browser/guest_view/extension_options/extension_options_guest_delegate.h"
 #include "url/gurl.h"
 
@@ -18,8 +17,7 @@
 namespace extensions {
 
 class ExtensionOptionsGuest
-    : public guest_view::GuestView<ExtensionOptionsGuest>,
-      public extensions::ExtensionFunctionDispatcher::Delegate {
+    : public guest_view::GuestView<ExtensionOptionsGuest> {
  public:
   static const char Type[];
   static guest_view::GuestViewBase* Create(
@@ -37,9 +35,6 @@
   bool IsDragAndDropEnabled() const override;
   void OnPreferredSizeChanged(const gfx::Size& pref_size) override;
 
-  // ExtensionFunctionDispatcher::Delegate implementation.
-  content::WebContents* GetAssociatedWebContents() const override;
-
   // content::WebContentsDelegate implementation.
   content::WebContents* OpenURLFromTab(
       content::WebContents* source,
@@ -60,15 +55,11 @@
   void DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) override;
-  bool OnMessageReceived(const IPC::Message& message) override;
 
  private:
   explicit ExtensionOptionsGuest(content::WebContents* owner_web_contents);
   ~ExtensionOptionsGuest() override;
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
 
-  scoped_ptr<extensions::ExtensionFunctionDispatcher>
-      extension_function_dispatcher_;
   scoped_ptr<extensions::ExtensionOptionsGuestDelegate>
       extension_options_guest_delegate_;
   GURL options_page_;
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest_delegate.h b/extensions/browser/guest_view/extension_options/extension_options_guest_delegate.h
index bbeed907..4052c8b 100644
--- a/extensions/browser/guest_view/extension_options/extension_options_guest_delegate.h
+++ b/extensions/browser/guest_view/extension_options/extension_options_guest_delegate.h
@@ -24,9 +24,6 @@
   explicit ExtensionOptionsGuestDelegate(ExtensionOptionsGuest* guest);
   virtual ~ExtensionOptionsGuestDelegate();
 
-  // Called from ExtensionOptionsGuest::DidInitialize().
-  virtual void DidInitialize() = 0;
-
   // Shows the context menu for the guest.
   // Returns true if the context menu was handled.
   virtual bool HandleContextMenu(const content::ContextMenuParams& params) = 0;
diff --git a/extensions/browser/guest_view/extension_view/extension_view_guest.cc b/extensions/browser/guest_view/extension_view/extension_view_guest.cc
index b9f73f4..ff2bcf9 100644
--- a/extensions/browser/guest_view/extension_view/extension_view_guest.cc
+++ b/extensions/browser/guest_view/extension_view/extension_view_guest.cc
@@ -28,10 +28,7 @@
 
 ExtensionViewGuest::ExtensionViewGuest(
     content::WebContents* owner_web_contents)
-    : GuestView<ExtensionViewGuest>(owner_web_contents),
-      extension_view_guest_delegate_(
-          extensions::ExtensionsAPIClient::Get()
-              ->CreateExtensionViewGuestDelegate(this)) {
+    : GuestView<ExtensionViewGuest>(owner_web_contents) {
 }
 
 ExtensionViewGuest::~ExtensionViewGuest() {
@@ -104,11 +101,7 @@
 
 void ExtensionViewGuest::DidInitialize(
     const base::DictionaryValue& create_params) {
-  extension_function_dispatcher_.reset(
-      new extensions::ExtensionFunctionDispatcher(browser_context(), this));
-
-  if (extension_view_guest_delegate_)
-    extension_view_guest_delegate_->DidInitialize();
+  ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents());
 
   ApplyAttributes(create_params);
 }
@@ -157,22 +150,6 @@
   }
 }
 
-bool ExtensionViewGuest::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(ExtensionViewGuest, message)
-  IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-  IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-// Private
-void ExtensionViewGuest::OnRequest(
-    const ExtensionHostMsg_Request_Params& params) {
-  extension_function_dispatcher_->Dispatch(params,
-                                           web_contents()->GetRenderViewHost());
-}
-
 void ExtensionViewGuest::ApplyAttributes(const base::DictionaryValue& params) {
   std::string src;
   params.GetString(extensionview::kAttributeSrc, &src);
diff --git a/extensions/browser/guest_view/extension_view/extension_view_guest.h b/extensions/browser/guest_view/extension_view/extension_view_guest.h
index 8a3fd7d..ffd72a4 100644
--- a/extensions/browser/guest_view/extension_view/extension_view_guest.h
+++ b/extensions/browser/guest_view/extension_view/extension_view_guest.h
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "components/guest_view/browser/guest_view.h"
 #include "extensions/browser/extension_function_dispatcher.h"
-#include "extensions/browser/guest_view/extension_view/extension_view_guest_delegate.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -18,8 +17,7 @@
 namespace extensions {
 
 class ExtensionViewGuest
-    : public guest_view::GuestView<ExtensionViewGuest>,
-      public ExtensionFunctionDispatcher::Delegate {
+    : public guest_view::GuestView<ExtensionViewGuest> {
  public:
   static const char Type[];
   static guest_view::GuestViewBase* Create(
@@ -45,20 +43,14 @@
   void DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) override;
-  bool OnMessageReceived(const IPC::Message& message) override;
 
  private:
   ExtensionViewGuest(content::WebContents* owner_web_contents);
   ~ExtensionViewGuest() override;
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
 
   // Applies attributes to the extensionview.
   void ApplyAttributes(const base::DictionaryValue& params);
 
-  scoped_ptr<extensions::ExtensionFunctionDispatcher>
-      extension_function_dispatcher_;
-  scoped_ptr<extensions::ExtensionViewGuestDelegate>
-      extension_view_guest_delegate_;
   GURL view_page_;
   GURL extension_url_;
 
diff --git a/extensions/browser/guest_view/extension_view/extension_view_guest_delegate.cc b/extensions/browser/guest_view/extension_view/extension_view_guest_delegate.cc
deleted file mode 100644
index 26fcbb2..0000000
--- a/extensions/browser/guest_view/extension_view/extension_view_guest_delegate.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/browser/guest_view/extension_view/extension_view_guest_delegate.h"
-
-namespace extensions {
-
-ExtensionViewGuestDelegate::ExtensionViewGuestDelegate(
-    ExtensionViewGuest* guest)
-    : guest_(guest) {
-}
-
-ExtensionViewGuestDelegate::~ExtensionViewGuestDelegate() {
-}
-
-}  // namespace extensions
diff --git a/extensions/browser/guest_view/extension_view/extension_view_guest_delegate.h b/extensions/browser/guest_view/extension_view/extension_view_guest_delegate.h
deleted file mode 100644
index 6f5a2daf..0000000
--- a/extensions/browser/guest_view/extension_view/extension_view_guest_delegate.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_BROWSER_GUEST_VIEW_EXTENSION_VIEW_EXTENSION_VIEW_GUEST_DELEGATE_H_
-#define EXTENSIONS_BROWSER_GUEST_VIEW_EXTENSION_VIEW_EXTENSION_VIEW_GUEST_DELEGATE_H_
-
-#include "base/macros.h"
-
-namespace extensions {
-
-class ExtensionViewGuest;
-
-// Interface to handle communication between ExtensionViewGuest and
-// the browser.
-class ExtensionViewGuestDelegate {
- public:
-  explicit ExtensionViewGuestDelegate(ExtensionViewGuest* guest);
-  virtual ~ExtensionViewGuestDelegate();
-
-  // Called from ExtensionViewGuest::DidInitialize().
-  virtual void DidInitialize() = 0;
-
-  ExtensionViewGuest* extension_view_guest() const { return guest_; }
-
- private:
-  ExtensionViewGuest* const guest_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionViewGuestDelegate);
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_BROWSER_GUEST_VIEW_EXTENSION_VIEW_EXTENSION_VIEW_GUEST_DELEGATE_H_
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
index 61fd142..2f446623 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
@@ -82,14 +82,6 @@
 MimeHandlerViewGuest::~MimeHandlerViewGuest() {
 }
 
-WindowController* MimeHandlerViewGuest::GetExtensionWindowController() const {
-  return nullptr;
-}
-
-WebContents* MimeHandlerViewGuest::GetAssociatedWebContents() const {
-  return web_contents();
-}
-
 const char* MimeHandlerViewGuest::GetAPINamespace() const {
   return "mimeHandlerViewGuestInternal";
 }
@@ -155,10 +147,7 @@
 
 void MimeHandlerViewGuest::DidInitialize(
     const base::DictionaryValue& create_params) {
-  extension_function_dispatcher_.reset(
-      new ExtensionFunctionDispatcher(browser_context(), this));
-  if (delegate_)
-    delegate_->AttachHelpers();
+  ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents());
 }
 
 bool MimeHandlerViewGuest::ZoomPropagatesFromEmbedderToGuest() const {
@@ -251,27 +240,10 @@
           element_instance_id()));
 }
 
-bool MimeHandlerViewGuest::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(MimeHandlerViewGuest, message)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
 base::WeakPtr<StreamContainer> MimeHandlerViewGuest::GetStream() const {
   if (!stream_)
     return base::WeakPtr<StreamContainer>();
   return stream_->GetWeakPtr();
 }
 
-void MimeHandlerViewGuest::OnRequest(
-    const ExtensionHostMsg_Request_Params& params) {
-  if (extension_function_dispatcher_) {
-    extension_function_dispatcher_->Dispatch(
-        params, web_contents()->GetRenderViewHost());
-  }
-}
-
 }  // namespace extensions
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
index f95aab78..33ff28e 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
@@ -7,7 +7,6 @@
 
 #include "base/memory/weak_ptr.h"
 #include "components/guest_view/browser/guest_view.h"
-#include "extensions/browser/extension_function_dispatcher.h"
 
 namespace content {
 class WebContents;
@@ -50,18 +49,14 @@
   base::WeakPtrFactory<StreamContainer> weak_factory_;
 };
 
-class MimeHandlerViewGuest : public guest_view::GuestView<MimeHandlerViewGuest>,
-                             public ExtensionFunctionDispatcher::Delegate {
+class MimeHandlerViewGuest :
+    public guest_view::GuestView<MimeHandlerViewGuest> {
  public:
   static guest_view::GuestViewBase* Create(
       content::WebContents* owner_web_contents);
 
   static const char Type[];
 
-  // ExtensionFunctionDispatcher::Delegate implementation.
-  WindowController* GetExtensionWindowController() const override;
-  content::WebContents* GetAssociatedWebContents() const override;
-
   // GuestViewBase implementation.
   const char* GetAPINamespace() const override;
   int GetTaskPrefix() const override;
@@ -96,7 +91,6 @@
 
   // content::WebContentsObserver implementation.
   void DocumentOnLoadCompletedInMainFrame() override;
-  bool OnMessageReceived(const IPC::Message& message) override;
 
   std::string view_id() const { return view_id_; }
   base::WeakPtr<StreamContainer> GetStream() const;
@@ -106,10 +100,7 @@
   ~MimeHandlerViewGuest() override;
 
  private:
-  void OnRequest(const ExtensionHostMsg_Request_Params& params);
-
   scoped_ptr<MimeHandlerViewGuestDelegate> delegate_;
-  scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
   scoped_ptr<StreamContainer> stream_;
   std::string view_id_;
 
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h
index b9a6fe3..e065104d 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h
@@ -19,12 +19,9 @@
 // A delegate class of MimeHandlerViewGuest that are not a part of chrome.
 class MimeHandlerViewGuestDelegate {
  public:
-  explicit MimeHandlerViewGuestDelegate(MimeHandlerViewGuest* guest) {}
+  MimeHandlerViewGuestDelegate() {}
   virtual ~MimeHandlerViewGuestDelegate() {}
 
-  // Attaches helpers upon initializing the WebContents.
-  virtual void AttachHelpers() {}
-
   // Handles context menu, or returns false if unhandled.
   virtual bool HandleContextMenu(content::WebContents* web_contents,
                                  const content::ContextMenuParams& params);
diff --git a/extensions/browser/guest_view/web_view/web_view_apitest.cc b/extensions/browser/guest_view/web_view/web_view_apitest.cc
index 369bc73..26e91b1 100644
--- a/extensions/browser/guest_view/web_view/web_view_apitest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_apitest.cc
@@ -58,13 +58,13 @@
     const std::string& path,
     const GURL& redirect_target,
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(path, request.relative_url, true))
+  if (!base::StartsWithASCII(path, request.relative_url, true))
     return scoped_ptr<net::test_server::HttpResponse>();
 
   std::map<std::string, std::string>::const_iterator it =
         request.headers.find("User-Agent");
   EXPECT_TRUE(it != request.headers.end());
-  if (!StartsWithASCII("foobar", it->second, true))
+  if (!base::StartsWithASCII("foobar", it->second, true))
     return scoped_ptr<net::test_server::HttpResponse>();
 
   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
@@ -103,7 +103,7 @@
     const std::string& path,
     const GURL& redirect_target,
     const net::test_server::HttpRequest& request) {
-  if (!StartsWithASCII(path, request.relative_url, true))
+  if (!base::StartsWithASCII(path, request.relative_url, true))
     return scoped_ptr<net::test_server::HttpResponse>();
 
   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
@@ -117,7 +117,7 @@
 scoped_ptr<net::test_server::HttpResponse> EmptyResponseHandler(
     const std::string& path,
     const net::test_server::HttpRequest& request) {
-  if (StartsWithASCII(path, request.relative_url, true)) {
+  if (base::StartsWithASCII(path, request.relative_url, true)) {
     return scoped_ptr<net::test_server::HttpResponse>(new EmptyHttpResponse);
   }
 
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index 8960f4c..add40d7 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -147,11 +147,11 @@
     return;
   }
 
-  // Since the "persist:" prefix is in ASCII, StartsWith will work fine on
+  // Since the "persist:" prefix is in ASCII, base::StartsWith will work fine on
   // UTF-8 encoded |partition_id|. If the prefix is a match, we can safely
   // remove the prefix without splicing in the middle of a multi-byte codepoint.
   // We can use the rest of the string as UTF-8 encoded one.
-  if (StartsWithASCII(partition_str, "persist:", true)) {
+  if (base::StartsWithASCII(partition_str, "persist:", true)) {
     size_t index = partition_str.find(":");
     CHECK(index != std::string::npos);
     // It is safe to do index + 1, since we tested for the full prefix above.
@@ -170,13 +170,11 @@
 
 void RemoveWebViewEventListenersOnIOThread(
     void* profile,
-    const std::string& extension_id,
     int embedder_process_id,
     int view_instance_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   ExtensionWebRequestEventRouter::GetInstance()->RemoveWebViewEventListeners(
       profile,
-      extension_id,
       embedder_process_id,
       view_instance_id);
 }
@@ -189,9 +187,51 @@
   return zoom_factor;
 }
 
+using WebViewKey = std::pair<int, int>;
+using WebViewKeyToIDMap = std::map<WebViewKey, int>;
+static base::LazyInstance<WebViewKeyToIDMap> web_view_key_to_id_map =
+    LAZY_INSTANCE_INITIALIZER;
+
 }  // namespace
 
 // static
+void WebViewGuest::CleanUp(int embedder_process_id, int view_instance_id) {
+  GuestViewBase::CleanUp(embedder_process_id, view_instance_id);
+
+  auto rph = content::RenderProcessHost::FromID(embedder_process_id);
+  // TODO(paulmeyer): It should be impossible for rph to be nullptr here, but
+  // this check is needed here for now as there seems to be occasional crashes
+  // because of this (http//crbug.com/499438). This should be removed once the
+  // cause is discovered and fixed.
+  DCHECK(rph != nullptr)
+      << "Cannot find RenderProcessHost for embedder process ID# "
+      << embedder_process_id;
+  if (rph == nullptr)
+    return;
+  auto browser_context = rph->GetBrowserContext();
+
+  // Clean up rules registries for the WebView.
+  WebViewKey key(embedder_process_id, view_instance_id);
+  auto it = web_view_key_to_id_map.Get().find(key);
+  if (it != web_view_key_to_id_map.Get().end()) {
+    auto rules_registry_id = it->second;
+    web_view_key_to_id_map.Get().erase(it);
+    RulesRegistryService::Get(browser_context)
+        ->RemoveRulesRegistriesByID(rules_registry_id);
+  }
+
+  // Clean up web request event listeners for the WebView.
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(
+          &RemoveWebViewEventListenersOnIOThread,
+          browser_context,
+          embedder_process_id,
+          view_instance_id));
+}
+
+// static
 GuestViewBase* WebViewGuest::Create(content::WebContents* owner_web_contents) {
   return new WebViewGuest(owner_web_contents);
 }
@@ -222,11 +262,6 @@
 // static
 const char WebViewGuest::Type[] = "webview";
 
-using WebViewKey = std::pair<int, int>;
-using WebViewKeyToIDMap = std::map<WebViewKey, int>;
-static base::LazyInstance<WebViewKeyToIDMap> web_view_key_to_id_map =
-    LAZY_INSTANCE_INITIALIZER;
-
 // static
 int WebViewGuest::GetOrGenerateRulesRegistryID(
     int embedder_process_id,
@@ -334,7 +369,10 @@
                               content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
                               content::Source<WebContents>(web_contents()));
 
-  AttachWebViewHelpers(web_contents());
+  if (web_view_guest_delegate_)
+    web_view_guest_delegate_->OnDidInitialize();
+  ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents());
+  web_view_permission_helper_.reset(new WebViewPermissionHelper(this));
 
   rules_registry_id_ = GetOrGenerateRulesRegistryID(
       owner_web_contents()->GetRenderProcessHost()->GetID(),
@@ -348,12 +386,6 @@
   ApplyAttributes(create_params);
 }
 
-void WebViewGuest::AttachWebViewHelpers(WebContents* contents) {
-  if (web_view_guest_delegate_)
-    web_view_guest_delegate_->OnAttachWebViewHelpers(contents);
-  web_view_permission_helper_.reset(new WebViewPermissionHelper(this));
-}
-
 void WebViewGuest::ClearDataInternal(base::Time remove_since,
                                      uint32 removal_mask,
                                      const base::Closure& callback) {
@@ -388,25 +420,6 @@
     SetFullscreenState(false);
 }
 
-void WebViewGuest::EmbedderWillBeDestroyed() {
-  // Clean up rules registries for the webview.
-  RulesRegistryService::Get(browser_context())
-      ->RemoveRulesRegistriesByID(rules_registry_id_);
-  WebViewKey key(owner_web_contents()->GetRenderProcessHost()->GetID(),
-                 view_instance_id());
-  web_view_key_to_id_map.Get().erase(key);
-
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(
-          &RemoveWebViewEventListenersOnIOThread,
-          browser_context(),
-          owner_host(),
-          owner_web_contents()->GetRenderProcessHost()->GetID(),
-          view_instance_id()));
-}
-
 const char* WebViewGuest::GetAPINamespace() const {
   return webview::kAPINamespace;
 }
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.h b/extensions/browser/guest_view/web_view/web_view_guest.h
index 517c1db..ea7b4f6 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.h
+++ b/extensions/browser/guest_view/web_view/web_view_guest.h
@@ -36,6 +36,10 @@
 class WebViewGuest : public guest_view::GuestView<WebViewGuest>,
                      public content::NotificationObserver {
  public:
+  // Clean up state when this GuestView is being destroyed. See
+  // GuestViewBase::CleanUp().
+  static void CleanUp(int embedder_process_id, int view_instance_id);
+
   static GuestViewBase* Create(content::WebContents* owner_web_contents);
 
   // For WebViewGuest, we create special guest processes, which host the
@@ -110,7 +114,6 @@
   void DidInitialize(const base::DictionaryValue& create_params) override;
   void GuestViewDidStopLoading() override;
   void EmbedderFullscreenToggled(bool entered_fullscreen) override;
-  void EmbedderWillBeDestroyed() override;
   const char* GetAPINamespace() const override;
   int GetTaskPrefix() const override;
   void GuestDestroyed() override;
@@ -265,8 +268,6 @@
 
   ~WebViewGuest() override;
 
-  void AttachWebViewHelpers(content::WebContents* contents);
-
   void ClearDataInternal(const base::Time remove_since,
                          uint32 removal_mask,
                          const base::Closure& callback);
diff --git a/extensions/browser/guest_view/web_view/web_view_guest_delegate.h b/extensions/browser/guest_view/web_view/web_view_guest_delegate.h
index 0ab06150..1fbabf8e 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest_delegate.h
+++ b/extensions/browser/guest_view/web_view/web_view_guest_delegate.h
@@ -35,8 +35,8 @@
   // Called when context menu operation was handled.
   virtual bool HandleContextMenu(const content::ContextMenuParams& params) = 0;
 
-  // Called to attach helpers just after additional initialization is performed.
-  virtual void OnAttachWebViewHelpers(content::WebContents* contents) = 0;
+  // Called just after additional initialization is performed.
+  virtual void OnDidInitialize() = 0;
 
   // Called immediately after the guest WebContents has been destroyed.
   virtual void OnGuestDestroyed() = 0;
diff --git a/extensions/browser/lazy_background_task_queue_unittest.cc b/extensions/browser/lazy_background_task_queue_unittest.cc
index dbe0794..917967d1 100644
--- a/extensions/browser/lazy_background_task_queue_unittest.cc
+++ b/extensions/browser/lazy_background_task_queue_unittest.cc
@@ -5,6 +5,7 @@
 #include "extensions/browser/lazy_background_task_queue.h"
 
 #include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/prefs/testing_pref_service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/user_prefs/user_prefs.h"
@@ -52,8 +53,8 @@
   DISALLOW_COPY_AND_ASSIGN(TestProcessManager);
 };
 
-KeyedService* CreateTestProcessManager(BrowserContext* context) {
-  return new TestProcessManager(context);
+scoped_ptr<KeyedService> CreateTestProcessManager(BrowserContext* context) {
+  return make_scoped_ptr(new TestProcessManager(context));
 }
 
 }  // namespace
diff --git a/extensions/browser/test_extensions_browser_client.cc b/extensions/browser/test_extensions_browser_client.cc
index 30e39b0..6f2821d 100644
--- a/extensions/browser/test_extensions_browser_client.cc
+++ b/extensions/browser/test_extensions_browser_client.cc
@@ -198,4 +198,10 @@
   return true;
 }
 
+ExtensionWebContentsObserver*
+TestExtensionsBrowserClient::GetExtensionWebContentsObserver(
+    content::WebContents* web_contents) {
+  return nullptr;
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/test_extensions_browser_client.h b/extensions/browser/test_extensions_browser_client.h
index 84a4ed3..9adf4d55 100644
--- a/extensions/browser/test_extensions_browser_client.h
+++ b/extensions/browser/test_extensions_browser_client.h
@@ -94,6 +94,8 @@
   ExtensionCache* GetExtensionCache() override;
   bool IsBackgroundUpdateAllowed() override;
   bool IsMinBrowserVersionSupported(const std::string& min_version) override;
+  ExtensionWebContentsObserver* GetExtensionWebContentsObserver(
+      content::WebContents* web_contents) override;
 
  private:
   content::BrowserContext* main_context_;       // Not owned.
diff --git a/extensions/browser/warning_set.cc b/extensions/browser/warning_set.cc
index 54c1c8b..5cd7190 100644
--- a/extensions/browser/warning_set.cc
+++ b/extensions/browser/warning_set.cc
@@ -195,7 +195,7 @@
   std::vector<base::string16> final_parameters;
   for (size_t i = 0; i < message_parameters_.size(); ++i) {
     std::string message = message_parameters_[i];
-    if (StartsWithASCII(message, kTranslate, true)) {
+    if (base::StartsWithASCII(message, kTranslate, true)) {
       std::string extension_id = message.substr(sizeof(kTranslate) - 1);
       const extensions::Extension* extension =
           extensions->GetByID(extension_id);
diff --git a/extensions/common/PRESUBMIT.py b/extensions/common/PRESUBMIT.py
index cc49fc0..16c1946 100644
--- a/extensions/common/PRESUBMIT.py
+++ b/extensions/common/PRESUBMIT.py
@@ -10,26 +10,5 @@
 
 import sys
 
-def _CreateAPIPermissionIDChecker(input_api, output_api):
-  original_sys_path = sys.path
-
-  try:
-    sys.path.append(input_api.os_path.join(
-        input_api.PresubmitLocalPath(), '..', '..', 'tools',
-        'strict_enum_value_checker'))
-    from strict_enum_value_checker import StrictEnumValueChecker
-  finally:
-    sys.path = original_sys_path
-
-  return StrictEnumValueChecker(input_api, output_api,
-      start_marker='  enum ID {', end_marker='    // Last entry:',
-      path='extensions/common/permissions/api_permission.h')
-
 def CheckChangeOnUpload(input_api, output_api):
-  results = []
-  results += _CreateAPIPermissionIDChecker(input_api, output_api).Run()
-  results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
-  return results
-
-def CheckChangeOnCommit(input_api, output_api):
-  return _CreateAPIPermissionIDChecker(input_api, output_api).Run()
+  return input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json
index 2897a81..7b392d52 100644
--- a/extensions/common/api/_permission_features.json
+++ b/extensions/common/api/_permission_features.json
@@ -125,10 +125,18 @@
         // http://crbug.com/292856
         "3F50C3A83839D9C76334BCE81CDEC06174F266AF",
         "39BE69F11F68E4EED080DA3DC2394F7885B7AFF9",
-        "FF78670081967CE21DB86A04AD94A0498F01E20A",
+        "FF78670081967CE21DB86A04AD94A0498F01E20A",  // http://crbug.com/409192
         // Hotword component extension
-        "62CCAAD339E6451BBF97C4BBDF758E934A05AD0B"
-      ]
+        "62CCAAD339E6451BBF97C4BBDF758E934A05AD0B",
+        "0C0426C12F94156F330FFAF346A976BA8878DE78",  // http://crbug.com/496954
+        "AC4538682FCECD28587C7A0F80849F78F4872BC2",  // http://crbug.com/496954
+        "CCA4D85A67ADD65DA6C02E49EE3C080C54A8211C",  // http://crbug.com/496954
+        "05EBA3051DFCA6AF17070AEE5FE8C66322FF4738",  // http://crbug.com/431978
+        "11B478CEC461C766A2DC1E5BEEB7970AE06DC9C2",  // http://crbug.com/458218
+        "0EFB879311E9EFBB7C45251F89EC655711B1F6ED",  // http://crbug.com/458218
+        "9193D3A51E2FE33B496CDA53EA330423166E7F02",  // http://crbug.com/458218
+        "F9119B8B18C7C82B51E7BC6FF816B694F2EC3E89"   // http://crbug.com/458218
+     ]
     }
   ],
   "bluetoothPrivate": {
diff --git a/extensions/common/api/app_window.idl b/extensions/common/api/app_window.idl
index 825611dc..618918f7 100644
--- a/extensions/common/api/app_window.idl
+++ b/extensions/common/api/app_window.idl
@@ -271,7 +271,8 @@
     // If true, the window will be focused when created. Defaults to true.
     boolean? focused;
 
-    // If true, the window will be visible on all workspaces.
+    // If true, and supported by the platform, the window will be visible on all
+    // workspaces.
     boolean? visibleOnAllWorkspaces;
   };
 
@@ -380,8 +381,8 @@
     // TODO(jackhou): Document this properly before going to stable.
     [nodoc] static boolean alphaEnabled();
 
-    // For platforms that support multiple workspaces, is this window visible on
-    // all of them?
+    // Set whether the window is visible on all workspaces. (Only for platforms
+    // that support this).
     static void setVisibleOnAllWorkspaces(boolean alwaysVisible);
 
     // Set whether the window should get all keyboard events including system
@@ -448,8 +449,8 @@
     // exists null is returned. This method is new in Chrome 33.
     [nocompile] static AppWindow get(DOMString id);
 
-    // Does the current platform support windows being visible on all
-    // workspaces?
+    // Whether the current platform supports windows being visible on all
+    // workspaces.
     [nocompile] static boolean canSetVisibleOnAllWorkspaces();
   };
 
diff --git a/extensions/common/api/serial.idl b/extensions/common/api/serial.idl
index d5bbc02ac..dae1135 100644
--- a/extensions/common/api/serial.idl
+++ b/extensions/common/api/serial.idl
@@ -171,6 +171,10 @@
 
   callback FlushCallback = void (boolean result);
 
+  callback SetBreakCallback = void (boolean result);
+
+  callback ClearBreakCallback = void (boolean result);
+
   // The set of control signals which may be sent to a connected serial device
   // using <code>setControlSignals</code>. Note that support for these signals
   // is device-dependent.
@@ -307,6 +311,16 @@
     static void setControlSignals(long connectionId,
                                   HostControlSignals signals,
                                   SetControlSignalsCallback callback);
+
+    // Suspends character transmission on a given connection and places the
+    // transmission line in a break state until the clearBreak is called.
+    // |connectionId| : The id of the connection.
+    static void setBreak(long connectionId, SetBreakCallback callback);
+
+    // Restore character transmission on a given connection and place the
+    // transmission line in a nonbreak state.
+    // |connectionId| : The id of the connection.
+    static void clearBreak(long connectionId, ClearBreakCallback callback);
   };
 
   interface Events {
diff --git a/extensions/common/api/webcam_private.idl b/extensions/common/api/webcam_private.idl
index 757e5b3..d6b5c85 100644
--- a/extensions/common/api/webcam_private.idl
+++ b/extensions/common/api/webcam_private.idl
@@ -6,6 +6,11 @@
 namespace webcamPrivate {
   enum PanDirection { stop, right, left };
   enum TiltDirection { stop, up, down };
+  enum Protocol { visca };
+
+  dictionary ProtocolConfiguration {
+    Protocol? protocol;
+  };
 
   dictionary WebcamConfiguration {
     double? pan;
@@ -15,13 +20,21 @@
     double? zoom;
   };
 
+  callback WebcamIdCallback = void(DOMString webcamId);
   callback WebcamConfigurationCallback =
       void(WebcamConfiguration configuration);
 
   interface Functions {
-    static void get(DOMString webcamId, WebcamConfigurationCallback callback);
-    static void set(DOMString webcamId, WebcamConfiguration config);
-    static void reset(DOMString webcamId, WebcamConfiguration config);
+    // Open a serial port that controls a webcam.
+    static void openSerialWebcam(DOMString path, ProtocolConfiguration protocol,
+                                 WebcamIdCallback callback);
+
+    // Close a serial port connection to a webcam.
+    static void closeWebcam(DOMString path);
+
+    static void get(DOMString path, WebcamConfigurationCallback callback);
+    static void set(DOMString path, WebcamConfiguration config);
+    static void reset(DOMString path, WebcamConfiguration config);
   };
 };
 
diff --git a/extensions/common/cast/cast_cert_validator.cc b/extensions/common/cast/cast_cert_validator.cc
index e4f0440..d4832579 100644
--- a/extensions/common/cast/cast_cert_validator.cc
+++ b/extensions/common/cast/cast_cert_validator.cc
@@ -4,6 +4,8 @@
 
 #include "extensions/common/cast/cast_cert_validator.h"
 
+#include "extensions/browser/api/cast_channel/cast_auth_ica.h"
+
 namespace extensions {
 namespace core_api {
 namespace cast_crypto {
@@ -25,6 +27,12 @@
       library_error_code(in_error_code) {
 }
 
+bool SetTrustedCertificateAuthoritiesForTest(const std::string& keys,
+                                             const std::string& signature) {
+  return extensions::core_api::cast_channel::SetTrustedCertificateAuthorities(
+      keys, signature);
+}
+
 }  // namespace cast_crypto
 }  // namespace core_api
 }  // namespace extensions
diff --git a/extensions/common/cast/cast_cert_validator.h b/extensions/common/cast/cast_cert_validator.h
index b9d2cf66..9b15b6e2 100644
--- a/extensions/common/cast/cast_cert_validator.h
+++ b/extensions/common/cast/cast_cert_validator.h
@@ -89,6 +89,10 @@
     const std::vector<std::string>& ica_certs,
     scoped_ptr<CertVerificationContext>* context);
 
+// Sets trusted certificate authorities. Only exposed for tests.
+bool SetTrustedCertificateAuthoritiesForTest(const std::string& keys,
+                                             const std::string& signature);
+
 }  // namespace cast_crypto
 }  // namespace core_api
 }  // namespace extensions
diff --git a/extensions/common/csp_validator.cc b/extensions/common/csp_validator.cc
index 371d7f8d..ced436e 100644
--- a/extensions/common/csp_validator.cc
+++ b/extensions/common/csp_validator.cc
@@ -57,7 +57,7 @@
 bool isNonWildcardTLD(const std::string& url,
                       const std::string& scheme_and_separator,
                       bool should_check_rcd) {
-  if (!StartsWithASCII(url, scheme_and_separator, true))
+  if (!base::StartsWithASCII(url, scheme_and_separator, true))
     return false;
 
   size_t start_of_host = scheme_and_separator.length();
@@ -128,21 +128,19 @@
     bool is_secure_csp_token = false;
 
     // We might need to relax this whitelist over time.
-    if (source == "'self'" ||
-        source == "'none'" ||
+    if (source == "'self'" || source == "'none'" ||
         source == "http://127.0.0.1" ||
-        LowerCaseEqualsASCII(source, "blob:") ||
-        LowerCaseEqualsASCII(source, "filesystem:") ||
-        LowerCaseEqualsASCII(source, "http://localhost") ||
-        StartsWithASCII(source, "http://127.0.0.1:", true) ||
-        StartsWithASCII(source, "http://localhost:", true) ||
+        base::LowerCaseEqualsASCII(source, "blob:") ||
+        base::LowerCaseEqualsASCII(source, "filesystem:") ||
+        base::LowerCaseEqualsASCII(source, "http://localhost") ||
+        base::StartsWithASCII(source, "http://127.0.0.1:", true) ||
+        base::StartsWithASCII(source, "http://localhost:", true) ||
         isNonWildcardTLD(source, "https://", true) ||
         isNonWildcardTLD(source, "chrome://", false) ||
-        isNonWildcardTLD(source,
-                         std::string(extensions::kExtensionScheme) +
-                         url::kStandardSchemeSeparator,
+        isNonWildcardTLD(source, std::string(extensions::kExtensionScheme) +
+                                     url::kStandardSchemeSeparator,
                          false) ||
-        StartsWithASCII(source, "chrome-extension-resource:", true)) {
+        base::StartsWithASCII(source, "chrome-extension-resource:", true)) {
       is_secure_csp_token = true;
     } else if ((options & OPTIONS_ALLOW_UNSAFE_EVAL) &&
                source == "'unsafe-eval'") {
@@ -209,7 +207,7 @@
     base::StringTokenizer tokenizer(input, " \t\r\n");
     if (!tokenizer.GetNext())
       continue;
-    if (!LowerCaseEqualsASCII(tokenizer.token(), kPluginTypes))
+    if (!base::LowerCaseEqualsASCII(tokenizer.token(), kPluginTypes))
       continue;
     while (tokenizer.GetNext()) {
       if (!PluginTypeAllowed(tokenizer.token()))
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc
index 1e973fc..d42fce6 100644
--- a/extensions/common/extension.cc
+++ b/extensions/common/extension.cc
@@ -154,7 +154,7 @@
     path = relative_path.substr(1);
 
   GURL ret_val = GURL(extension_url.spec() + path);
-  DCHECK(StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
+  DCHECK(base::StartsWithASCII(ret_val.spec(), extension_url.spec(), false));
 
   return ret_val;
 }
@@ -205,7 +205,7 @@
     return false;
 
   std::string working = input;
-  if (StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
+  if (base::StartsWithASCII(working, kKeyBeginHeaderMarker, true)) {
     working = base::CollapseWhitespaceASCII(working, true);
     size_t header_pos = working.find(kKeyInfoEndMarker,
       sizeof(kKeyBeginHeaderMarker) - 1);
diff --git a/extensions/common/extension_urls.cc b/extensions/common/extension_urls.cc
index eeb1798..2b34178b 100644
--- a/extensions/common/extension_urls.cc
+++ b/extensions/common/extension_urls.cc
@@ -20,9 +20,8 @@
 
 bool IsSourceFromAnExtension(const base::string16& source) {
   return GURL(source).SchemeIs(kExtensionScheme) ||
-         StartsWith(source,
-                    base::ASCIIToUTF16("extensions::"),
-                    true /* case-sensitive */);
+         base::StartsWith(source, base::ASCIIToUTF16("extensions::"),
+                          true /* case-sensitive */);
 }
 
 }  // namespace extensions
diff --git a/extensions/common/permissions/PRESUBMIT.py b/extensions/common/permissions/PRESUBMIT.py
index 20d6ddd..421841c3 100644
--- a/extensions/common/permissions/PRESUBMIT.py
+++ b/extensions/common/permissions/PRESUBMIT.py
@@ -12,7 +12,7 @@
 def GetPreferredTrySlaves():
   return ['linux_chromeos']
 
-def _CreatePermissionMessageEnumChecker(input_api, output_api):
+def _CreateAPIPermissionIDChecker(input_api, output_api):
   original_sys_path = sys.path
 
   try:
@@ -24,9 +24,12 @@
     sys.path = original_sys_path
 
   return StrictEnumValueChecker(input_api, output_api,
-      start_marker='  enum ID {', end_marker='    kEnumBoundary',
-      path='extensions/common/permissions/permission_message.h')
+      start_marker='  enum ID {', end_marker='    // Last entry:',
+      path='extensions/common/permissions/api_permission.h')
 
 def CheckChangeOnUpload(input_api, output_api):
-    return _CreatePermissionMessageEnumChecker(input_api, output_api).Run()
+  return _CreateAPIPermissionIDChecker(input_api, output_api).Run()
+
+def CheckChangeOnCommit(input_api, output_api):
+  return _CreateAPIPermissionIDChecker(input_api, output_api).Run()
 
diff --git a/extensions/common/permissions/permission_message.h b/extensions/common/permissions/permission_message.h
index a4e62b56..d95af255 100644
--- a/extensions/common/permissions/permission_message.h
+++ b/extensions/common/permissions/permission_message.h
@@ -109,9 +109,7 @@
     kAutofillPrivate,
     kPasswordsPrivate,
     kUsersPrivate,
-    // Last entry: Add new entries above and ensure to update the
-    // "ExtensionPermission2" enum in tools/metrics/histograms/histograms.xml
-    // (by running update_extension_permission.py).
+    // Last entry: Add new entries above.
     kEnumBoundary,
   };
   static_assert(PermissionMessage::kNone > PermissionMessage::kUnknown,
diff --git a/extensions/common/permissions/permission_set.cc b/extensions/common/permissions/permission_set.cc
index 65236ac..f987411 100644
--- a/extensions/common/permissions/permission_set.cc
+++ b/extensions/common/permissions/permission_set.cc
@@ -141,6 +141,10 @@
       explicit_hosts_ == rhs.explicit_hosts_;
 }
 
+bool PermissionSet::operator!=(const PermissionSet& rhs) const {
+  return !(*this == rhs);
+}
+
 bool PermissionSet::Contains(const PermissionSet& set) const {
   return apis_.Contains(set.apis()) &&
          manifest_permissions_.Contains(set.manifest_permissions()) &&
diff --git a/extensions/common/permissions/permission_set.h b/extensions/common/permissions/permission_set.h
index 5321eda..e7b5311d 100644
--- a/extensions/common/permissions/permission_set.h
+++ b/extensions/common/permissions/permission_set.h
@@ -56,6 +56,7 @@
       const PermissionSet* set1, const PermissionSet* set2);
 
   bool operator==(const PermissionSet& rhs) const;
+  bool operator!=(const PermissionSet& rhs) const;
 
   // Returns true if every API or host permission available to |set| is also
   // available to this. In other words, if the API permissions of |set| are a
diff --git a/extensions/common/permissions/permissions_info.cc b/extensions/common/permissions/permissions_info.cc
index 44a80149..ad64fd5c 100644
--- a/extensions/common/permissions/permissions_info.cc
+++ b/extensions/common/permissions/permissions_info.cc
@@ -64,7 +64,7 @@
 bool PermissionsInfo::HasChildPermissions(const std::string& name) const {
   NameMap::const_iterator i = name_map_.lower_bound(name + '.');
   if (i == name_map_.end()) return false;
-  return StartsWithASCII(i->first, name + '.', true);
+  return base::StartsWithASCII(i->first, name + '.', true);
 }
 
 PermissionsInfo::PermissionsInfo()
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi
index de96657..0470f0a 100644
--- a/extensions/extensions.gypi
+++ b/extensions/extensions.gypi
@@ -567,6 +567,8 @@
       'browser/event_router.h',
       'browser/event_router_factory.cc',
       'browser/event_router_factory.h',
+      'browser/extension_dialog_auto_confirm.cc',
+      'browser/extension_dialog_auto_confirm.h',
       'browser/extension_error.cc',
       'browser/extension_error.h',
       'browser/extension_function.cc',
@@ -645,8 +647,6 @@
       'browser/guest_view/extension_view/extension_view_constants.h',
       'browser/guest_view/extension_view/extension_view_guest.cc',
       'browser/guest_view/extension_view/extension_view_guest.h',
-      'browser/guest_view/extension_view/extension_view_guest_delegate.cc',
-      'browser/guest_view/extension_view/extension_view_guest_delegate.h',
       'browser/guest_view/extensions_guest_view_manager_delegate.cc',
       'browser/guest_view/extensions_guest_view_manager_delegate.h',
       'browser/guest_view/extensions_guest_view_message_filter.cc',
@@ -811,6 +811,8 @@
       'browser/api/vpn_provider/vpn_service_factory.h',
       'browser/api/webcam_private/v4l2_webcam.h',
       'browser/api/webcam_private/v4l2_webcam.cc',
+      'browser/api/webcam_private/visca_webcam.h',
+      'browser/api/webcam_private/visca_webcam.cc',
       'browser/api/webcam_private/webcam.h',
       'browser/api/webcam_private/webcam.cc',
       'browser/api/webcam_private/webcam_private_api.h',
@@ -951,6 +953,7 @@
       'renderer/resources/guest_view/surface_view/surface_view.js',
       'renderer/resources/guest_view/web_view/web_view.js',
       'renderer/resources/guest_view/web_view/web_view_events.js',
+      'renderer/resources/guest_view/web_view/web_view_iframe.js',
       'renderer/resources/web_request_custom_bindings.js',
       'renderer/resources/web_request_internal_custom_bindings.js',
       'renderer/runtime_custom_bindings.cc',
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index cf4bb57..17c6dbea 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -472,6 +472,15 @@
   resources.push_back(std::make_pair("guestViewDeny", IDR_GUEST_VIEW_DENY_JS));
   resources.push_back(std::make_pair("guestViewEvents",
                                      IDR_GUEST_VIEW_EVENTS_JS));
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          ::switches::kSitePerProcess)) {
+    resources.push_back(std::make_pair("guestViewIframe",
+                                       IDR_GUEST_VIEW_IFRAME_JS));
+    resources.push_back(std::make_pair("guestViewIframeContainer",
+                                       IDR_GUEST_VIEW_IFRAME_CONTAINER_JS));
+  }
+
   resources.push_back(std::make_pair("imageUtil", IDR_IMAGE_UTIL_JS));
   resources.push_back(std::make_pair("json_schema", IDR_JSON_SCHEMA_JS));
   resources.push_back(std::make_pair("lastError", IDR_LAST_ERROR_JS));
@@ -509,6 +518,11 @@
   resources.push_back(std::make_pair("webViewEvents", IDR_WEB_VIEW_EVENTS_JS));
   resources.push_back(std::make_pair("webViewInternal",
                                      IDR_WEB_VIEW_INTERNAL_CUSTOM_BINDINGS_JS));
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          ::switches::kSitePerProcess)) {
+    resources.push_back(std::make_pair("webViewIframe",
+                                       IDR_WEB_VIEW_IFRAME_JS));
+  }
   resources.push_back(
       std::make_pair(mojo::kBindingsModuleName, IDR_MOJO_BINDINGS_JS));
   resources.push_back(
@@ -590,6 +604,14 @@
   // Platform app sources that are not API-specific..
   resources.push_back(std::make_pair("platformApp", IDR_PLATFORM_APP_JS));
 
+#if defined(ENABLE_MEDIA_ROUTER)
+  resources.push_back(
+      std::make_pair("chrome/browser/media/router/media_router.mojom",
+                     IDR_MEDIA_ROUTER_MOJOM_JS));
+  resources.push_back(
+      std::make_pair("media_router_bindings", IDR_MEDIA_ROUTER_BINDINGS_JS));
+#endif  // defined(ENABLE_MEDIA_ROUTER)
+
   return resources;
 }
 
@@ -1409,6 +1431,11 @@
     module_system->Require("webView");
     module_system->Require("webViewApiMethods");
     module_system->Require("webViewAttributes");
+
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            ::switches::kSitePerProcess)) {
+      module_system->Require("webViewIframe");
+    }
   }
 
   // The "guestViewDeny" module must always be loaded last. It registers
diff --git a/extensions/renderer/guest_view/extensions_guest_view_container.cc b/extensions/renderer/guest_view/extensions_guest_view_container.cc
index 1bd8575..96650d8 100644
--- a/extensions/renderer/guest_view/extensions_guest_view_container.cc
+++ b/extensions/renderer/guest_view/extensions_guest_view_container.cc
@@ -19,6 +19,15 @@
 }
 
 ExtensionsGuestViewContainer::~ExtensionsGuestViewContainer() {
+}
+
+void ExtensionsGuestViewContainer::OnDestroy(bool embedder_frame_destroyed) {
+  // Do not attempt to run |destruction_callback_| if the embedder frame was
+  // destroyed. Trying to invoke callback on RenderFrame destruction results in
+  // assertion failure when calling WebScopedMicrotaskSuppression.
+  if (embedder_frame_destroyed)
+    return;
+
   // Call the destruction callback, if one is registered.
   if (!destruction_callback_.IsEmpty()) {
     v8::HandleScope handle_scope(destruction_isolate_);
diff --git a/extensions/renderer/guest_view/extensions_guest_view_container.h b/extensions/renderer/guest_view/extensions_guest_view_container.h
index 4e3f3e9..aabb47e6 100644
--- a/extensions/renderer/guest_view/extensions_guest_view_container.h
+++ b/extensions/renderer/guest_view/extensions_guest_view_container.h
@@ -19,7 +19,6 @@
 class ExtensionsGuestViewContainer : public guest_view::GuestViewContainer {
  public:
   explicit ExtensionsGuestViewContainer(content::RenderFrame* render_frame);
-  ~ExtensionsGuestViewContainer() override;
 
   void RegisterDestructionCallback(v8::Local<v8::Function> callback,
                                    v8::Isolate* isolate);
@@ -29,9 +28,15 @@
   // BrowserPluginDelegate implementation.
   void DidResizeElement(const gfx::Size& new_size) override;
 
+ protected:
+  ~ExtensionsGuestViewContainer() override;
+
  private:
   void CallElementResizeCallback(const gfx::Size& new_size);
 
+  // GuestViewContainer implementation.
+  void OnDestroy(bool embedder_frame_destroyed) override;
+
   v8::Global<v8::Function> destruction_callback_;
   v8::Isolate* destruction_isolate_;
 
diff --git a/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc b/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc
index 5a240f8..82fbd27 100644
--- a/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc
+++ b/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc
@@ -47,6 +47,9 @@
   RouteFunction("DetachGuest",
                 base::Bind(&GuestViewInternalCustomBindings::DetachGuest,
                            base::Unretained(this)));
+  RouteFunction("DestroyContainer",
+                base::Bind(&GuestViewInternalCustomBindings::DestroyContainer,
+                           base::Unretained(this)));
   RouteFunction("GetContentWindow",
                 base::Bind(&GuestViewInternalCustomBindings::GetContentWindow,
                            base::Unretained(this)));
@@ -174,6 +177,30 @@
   args.GetReturnValue().Set(v8::Boolean::New(context()->isolate(), true));
 }
 
+void GuestViewInternalCustomBindings::DestroyContainer(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  args.GetReturnValue().SetNull();
+
+  if (args.Length() != 1)
+    return;
+
+  // Element Instance ID.
+  if (!args[0]->IsInt32())
+    return;
+
+  int element_instance_id = args[0]->Int32Value();
+  auto* guest_view_container =
+      guest_view::GuestViewContainer::FromID(element_instance_id);
+  if (!guest_view_container)
+    return;
+
+  // Note: |guest_view_container| is deleted.
+  // GuestViewContainer::DidDestroyElement() currently also destroys
+  // a GuestViewContainer. That won't be necessary once GuestViewContainer
+  // always runs w/o plugin.
+  guest_view_container->Destroy(false /* embedder_frame_destroyed */);
+}
+
 void GuestViewInternalCustomBindings::GetContentWindow(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   // Default to returning null.
@@ -267,26 +294,34 @@
 
 void GuestViewInternalCustomBindings::RegisterView(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
-  // There are two parameters.
-  CHECK(args.Length() == 2);
+  // There are three parameters.
+  CHECK(args.Length() == 3);
   // View Instance ID.
   CHECK(args[0]->IsInt32());
   // View element.
   CHECK(args[1]->IsObject());
+  // View type (e.g. "webview").
+  CHECK(args[2]->IsString());
 
   // A reference to the view object is stored in |weak_view_map| using its view
   // ID as the key. The reference is made weak so that it will not extend the
   // lifetime of the object.
-  int view_id = args[0]->Int32Value();
+  int view_instance_id = args[0]->Int32Value();
   auto object =
       new v8::Global<v8::Object>(args.GetIsolate(), args[1].As<v8::Object>());
-  weak_view_map.Get().insert(std::make_pair(view_id, object));
+  weak_view_map.Get().insert(std::make_pair(view_instance_id, object));
 
-  // The view_id is given to the SetWeak callback so that that view's entry in
-  // |weak_view_map| can be cleared when the view object is garbage collected.
-  object->SetWeak(new int(view_id),
+  // The |view_instance_id| is given to the SetWeak callback so that that view's
+  // entry in |weak_view_map| can be cleared when the view object is garbage
+  // collected.
+  object->SetWeak(new int(view_instance_id),
                   &GuestViewInternalCustomBindings::ResetMapEntry,
                   v8::WeakCallbackType::kParameter);
+
+  // Let the GuestViewManager know that a GuestView has been created.
+  const std::string& view_type = *v8::String::Utf8Value(args[2]);
+  content::RenderThread::Get()->Send(
+      new GuestViewHostMsg_ViewCreated(view_instance_id, view_type));
 }
 
 void GuestViewInternalCustomBindings::RunWithGesture(
diff --git a/extensions/renderer/guest_view/guest_view_internal_custom_bindings.h b/extensions/renderer/guest_view/guest_view_internal_custom_bindings.h
index 0f84a39..6a6d6c3 100644
--- a/extensions/renderer/guest_view/guest_view_internal_custom_bindings.h
+++ b/extensions/renderer/guest_view/guest_view_internal_custom_bindings.h
@@ -51,6 +51,9 @@
   // Window JavaScript object for that RenderView.
   void GetContentWindow(const v8::FunctionCallbackInfo<v8::Value>& args);
 
+  // Destroys the GuestViewContainer given an element instance ID in |args|.
+  void DestroyContainer(const v8::FunctionCallbackInfo<v8::Value>& args);
+
   // GetViewFromID takes a view ID, and returns the GuestView element associated
   // with that ID, if one exists. Otherwise, null is returned.
   void GetViewFromID(const v8::FunctionCallbackInfo<v8::Value>& args);
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
index c39bf93..796358ef 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.h
@@ -41,7 +41,6 @@
   MimeHandlerViewContainer(content::RenderFrame* render_frame,
                            const std::string& mime_type,
                            const GURL& original_url);
-  ~MimeHandlerViewContainer() override;
 
   static std::vector<MimeHandlerViewContainer*> FromRenderFrame(
       content::RenderFrame* render_frame);
@@ -74,6 +73,9 @@
   // Post |message| to the guest.
   void PostMessageFromValue(const base::Value& message);
 
+ protected:
+  ~MimeHandlerViewContainer() override;
+
  private:
   // Message handlers.
   void OnCreateMimeHandlerViewGuestACK(int element_instance_id);
diff --git a/extensions/renderer/resources/OWNERS b/extensions/renderer/resources/OWNERS
new file mode 100644
index 0000000..8ab4ab3
--- /dev/null
+++ b/extensions/renderer/resources/OWNERS
@@ -0,0 +1,3 @@
+per-file media_router_bindings.js=mfoltz@chromium.org
+per-file media_router_bindings.js=kmarshall@chromium.org
+
diff --git a/extensions/renderer/resources/extensions_renderer_resources.grd b/extensions/renderer/resources/extensions_renderer_resources.grd
index c9c6299..ee74db3 100644
--- a/extensions/renderer/resources/extensions_renderer_resources.grd
+++ b/extensions/renderer/resources/extensions_renderer_resources.grd
@@ -28,11 +28,13 @@
       <include name="IDR_EXTENSION_VIEW_CONSTANTS_JS" file="guest_view/extension_view/extension_view_constants.js" type="BINDATA" />
       <include name="IDR_EXTENSION_VIEW_EVENTS_JS" file="guest_view/extension_view/extension_view_events.js" type="BINDATA" />
       <include name="IDR_EXTENSION_VIEW_INTERNAL_CUSTOM_BINDINGS_JS" file="guest_view/extension_view/extension_view_internal.js" type="BINDATA" />
-      <include name="IDR_GUEST_VIEW_JS" file="guest_view/guest_view.js" type="BINDATA" />
       <include name="IDR_GUEST_VIEW_ATTRIBUTES_JS" file="guest_view/guest_view_attributes.js" type="BINDATA" />
       <include name="IDR_GUEST_VIEW_CONTAINER_JS" file="guest_view/guest_view_container.js" type="BINDATA" />
       <include name="IDR_GUEST_VIEW_DENY_JS" file="guest_view/guest_view_deny.js" type="BINDATA" />
       <include name="IDR_GUEST_VIEW_EVENTS_JS" file="guest_view/guest_view_events.js" type="BINDATA" />
+      <include name="IDR_GUEST_VIEW_IFRAME_CONTAINER_JS" file="guest_view/guest_view_iframe_container.js" type="BINDATA" />
+      <include name="IDR_GUEST_VIEW_IFRAME_JS" file="guest_view/guest_view_iframe.js" type="BINDATA" />
+      <include name="IDR_GUEST_VIEW_JS" file="guest_view/guest_view.js" type="BINDATA" />
       <include name="IDR_IMAGE_UTIL_JS" file="image_util.js" type="BINDATA" />
       <include name="IDR_JSON_SCHEMA_JS" file="json_schema.js" type="BINDATA" />
       <include name="IDR_KEEP_ALIVE_JS" file="keep_alive.js" type="BINDATA" />
@@ -61,6 +63,7 @@
       <include name="IDR_WEB_VIEW_ATTRIBUTES_JS" file="guest_view/web_view/web_view_attributes.js" type="BINDATA" />
       <include name="IDR_WEB_VIEW_CONSTANTS_JS" file="guest_view/web_view/web_view_constants.js" type="BINDATA" />
       <include name="IDR_WEB_VIEW_EVENTS_JS" file="guest_view/web_view/web_view_events.js" type="BINDATA" />
+      <include name="IDR_WEB_VIEW_IFRAME_JS" file="guest_view/web_view/web_view_iframe.js" type="BINDATA" />
       <include name="IDR_WEB_VIEW_INTERNAL_CUSTOM_BINDINGS_JS" file="guest_view/web_view/web_view_internal.js" type="BINDATA" />
       <include name="IDR_WEB_VIEW_JS" file="guest_view/web_view/web_view.js" type="BINDATA" />
 
@@ -93,6 +96,12 @@
 
       <!-- Extension styles. -->
       <include name="IDR_EXTENSION_FONTS_CSS" file="extension_fonts.css" type="BINDATA"/>
+
+      <!-- Media Router Mojo service and bindings. -->
+      <if expr="enable_media_router">
+        <include name="IDR_MEDIA_ROUTER_MOJOM_JS" file="${mojom_root}\chrome\browser\media\router\media_router.mojom.js" use_base_dir="false" type="BINDATA" />
+        <include name="IDR_MEDIA_ROUTER_BINDINGS_JS" file="media_router_bindings.js" type="BINDATA" />
+      </if>
     </includes>
     <structures>
       <!-- Extension styles. -->
diff --git a/extensions/renderer/resources/guest_view/app_view/app_view.js b/extensions/renderer/resources/guest_view/app_view/app_view.js
index 301c827..a164fab 100644
--- a/extensions/renderer/resources/guest_view/app_view/app_view.js
+++ b/extensions/renderer/resources/guest_view/app_view/app_view.js
@@ -70,7 +70,7 @@
       }
       return;
     }
-    this.attachWindow();
+    this.attachWindow$();
     if (callback) {
       callback(true);
     }
diff --git a/extensions/renderer/resources/guest_view/extension_options/extension_options.js b/extensions/renderer/resources/guest_view/extension_options/extension_options.js
index d96a130..7193607 100644
--- a/extensions/renderer/resources/guest_view/extension_options/extension_options.js
+++ b/extensions/renderer/resources/guest_view/extension_options/extension_options.js
@@ -41,7 +41,7 @@
       var createFailedEvent = new Event('createfailed', { bubbles: true });
       this.dispatchEvent(createFailedEvent);
     } else {
-      this.attachWindow();
+      this.attachWindow$();
     }
   }.bind(this));
 };
diff --git a/extensions/renderer/resources/guest_view/extension_view/extension_view.js b/extensions/renderer/resources/guest_view/extension_view/extension_view.js
index 331f508..0a6804c 100644
--- a/extensions/renderer/resources/guest_view/extension_view/extension_view.js
+++ b/extensions/renderer/resources/guest_view/extension_view/extension_view.js
@@ -29,7 +29,7 @@
 
 ExtensionViewImpl.prototype.createGuest = function() {
   this.guest.create(this.buildParams(), function() {
-    this.attachWindow();
+    this.attachWindow$();
   }.bind(this));
 };
 
diff --git a/extensions/renderer/resources/guest_view/extension_view/extension_view_events.js b/extensions/renderer/resources/guest_view/extension_view/extension_view_events.js
index d099d7b8..901085b 100644
--- a/extensions/renderer/resources/guest_view/extension_view/extension_view_events.js
+++ b/extensions/renderer/resources/guest_view/extension_view/extension_view_events.js
@@ -26,7 +26,7 @@
 };
 
 ExtensionViewEvents.prototype.handleLoadCommitEvent = function(event) {
-  this.extensionViewImpl.onLoadCommit(event.url);
+  this.view.onLoadCommit(event.url);
 };
 
 exports.ExtensionViewEvents = ExtensionViewEvents;
diff --git a/extensions/renderer/resources/guest_view/guest_view.js b/extensions/renderer/resources/guest_view/guest_view.js
index a09f7c60..66d48a2 100644
--- a/extensions/renderer/resources/guest_view/guest_view.js
+++ b/extensions/renderer/resources/guest_view/guest_view.js
@@ -14,11 +14,6 @@
 // Events.
 var ResizeEvent = CreateEvent('guestViewInternal.onResize');
 
-// Possible states.
-var GUEST_STATE_ATTACHED = 2;
-var GUEST_STATE_CREATED = 1;
-var GUEST_STATE_START = 0;
-
 // Error messages.
 var ERROR_MSG_ALREADY_ATTACHED = 'The guest has already been attached.';
 var ERROR_MSG_ALREADY_CREATED = 'The guest has already been created.';
@@ -35,10 +30,10 @@
 function GuestViewImpl(guestView, viewType, guestInstanceId) {
   if (guestInstanceId) {
     this.id = guestInstanceId;
-    this.state = GUEST_STATE_CREATED;
+    this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED;
   } else {
     this.id = 0;
-    this.state = GUEST_STATE_START;
+    this.state = GuestViewImpl.GuestState.GUEST_STATE_START;
   }
   this.actionQueue = [];
   this.contentWindow = null;
@@ -50,6 +45,13 @@
   this.setupOnResize();
 }
 
+// Possible states.
+GuestViewImpl.GuestState = {
+  GUEST_STATE_START: 0,
+  GUEST_STATE_CREATED: 1,
+  GUEST_STATE_ATTACHED: 2
+};
+
 // Sets up the onResize property on the GuestView.
 GuestViewImpl.prototype.setupOnResize = function() {
   $Object.defineProperty(this.guestView, PROPERTY_ON_RESIZE, {
@@ -145,7 +147,7 @@
 };
 
 // Internal implementation of attach().
-GuestViewImpl.prototype.attachImpl = function(
+GuestViewImpl.prototype.attachImpl$ = function(
     internalInstanceId, viewInstanceId, attachParams, callback) {
   // Check the current state.
   if (!this.checkState('attach')) {
@@ -159,7 +161,7 @@
   var callbackWrapper = function(callback, contentWindow) {
     // Check if attaching failed.
     if (!contentWindow) {
-      this.state = GUEST_STATE_CREATED;
+      this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED;
       this.internalInstanceId = 0;
     } else {
       // Only update the contentWindow if attaching is successful.
@@ -176,23 +178,23 @@
                                        callbackWrapper.bind(this, callback));
 
   this.internalInstanceId = internalInstanceId;
-  this.state = GUEST_STATE_ATTACHED;
+  this.state = GuestViewImpl.GuestState.GUEST_STATE_ATTACHED;
 
   // Detach automatically when the container is destroyed.
   GuestViewInternalNatives.RegisterDestructionCallback(
       internalInstanceId, this.weakWrapper(function() {
-    if (this.state != GUEST_STATE_ATTACHED ||
+    if (this.state != GuestViewImpl.GuestState.GUEST_STATE_ATTACHED ||
         this.internalInstanceId != internalInstanceId) {
       return;
     }
 
     this.internalInstanceId = 0;
-    this.state = GUEST_STATE_CREATED;
+    this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED;
   }, viewInstanceId));
 };
 
 // Internal implementation of create().
-GuestViewImpl.prototype.createImpl = function(createParams, callback) {
+GuestViewImpl.prototype.createImpl$ = function(createParams, callback) {
   // Check the current state.
   if (!this.checkState('create')) {
     this.handleCallback(callback);
@@ -209,7 +211,7 @@
 
     // Check if creation failed.
     if (this.id === 0) {
-      this.state = GUEST_STATE_START;
+      this.state = GuestViewImpl.GuestState.GUEST_STATE_START;
       this.contentWindow = null;
     }
 
@@ -217,11 +219,14 @@
     this.handleCallback(callback);
   };
 
-  GuestViewInternal.createGuest(this.viewType,
-                                createParams,
-                                callbackWrapper.bind(this, callback));
+  this.sendCreateRequest(createParams, callbackWrapper.bind(this, callback));
 
-  this.state = GUEST_STATE_CREATED;
+  this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED;
+};
+
+GuestViewImpl.prototype.sendCreateRequest = function(
+    createParams, boundCallback) {
+  GuestViewInternal.createGuest(this.viewType, createParams, boundCallback);
 };
 
 // Internal implementation of destroy().
@@ -232,7 +237,7 @@
     return;
   }
 
-  if (this.state == GUEST_STATE_START) {
+  if (this.state == GuestViewImpl.GuestState.GUEST_STATE_START) {
     // destroy() does nothing in this case.
     this.handleCallback(callback);
     return;
@@ -250,7 +255,7 @@
   this.contentWindow = null;
   this.id = 0;
   this.internalInstanceId = 0;
-  this.state = GUEST_STATE_START;
+  this.state = GuestViewImpl.GuestState.GUEST_STATE_START;
   if (ResizeEvent.hasListener(this.callOnResize)) {
     ResizeEvent.removeListener(this.callOnResize);
   }
@@ -269,7 +274,7 @@
       this.handleCallback.bind(this, callback));
 
   this.internalInstanceId = 0;
-  this.state = GUEST_STATE_CREATED;
+  this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED;
 };
 
 // Internal implementation of setSize().
@@ -295,7 +300,7 @@
 GuestView.prototype.attach = function(
     internalInstanceId, viewInstanceId, attachParams, callback) {
   var internal = privates(this).internal;
-  internal.actionQueue.push(internal.attachImpl.bind(
+  internal.actionQueue.push(internal.attachImpl$.bind(
       internal, internalInstanceId, viewInstanceId, attachParams, callback));
   internal.performNextAction();
 };
@@ -303,7 +308,7 @@
 // Creates the guestview.
 GuestView.prototype.create = function(createParams, callback) {
   var internal = privates(this).internal;
-  internal.actionQueue.push(internal.createImpl.bind(
+  internal.actionQueue.push(internal.createImpl$.bind(
       internal, createParams, callback));
   internal.performNextAction();
 };
@@ -346,3 +351,5 @@
 
 // Exports
 exports.GuestView = GuestView;
+exports.GuestViewImpl = GuestViewImpl;
+exports.ResizeEvent = ResizeEvent;
diff --git a/extensions/renderer/resources/guest_view/guest_view_container.js b/extensions/renderer/resources/guest_view/guest_view_container.js
index ebcc313..f9d1a97a 100644
--- a/extensions/renderer/resources/guest_view/guest_view_container.js
+++ b/extensions/renderer/resources/guest_view/guest_view_container.js
@@ -9,6 +9,7 @@
 var GuestView = require('guestView').GuestView;
 var GuestViewInternalNatives = requireNative('guest_view_internal');
 var IdGenerator = requireNative('id_generator');
+var MessagingNatives = requireNative('messaging_natives');
 
 function GuestViewContainer(element, viewType) {
   privates(element).internal = this;
@@ -22,12 +23,12 @@
   this.guest = new GuestView(viewType);
   this.setupAttributes();
 
-  privates(this).browserPluginElement = this.createBrowserPluginElement();
+  privates(this).internalElement = this.createInternalElement$();
   this.setupFocusPropagation();
   var shadowRoot = this.element.createShadowRoot();
-  shadowRoot.appendChild(privates(this).browserPluginElement);
+  shadowRoot.appendChild(privates(this).internalElement);
 
-  GuestViewInternalNatives.RegisterView(this.viewInstanceId, this);
+  GuestViewInternalNatives.RegisterView(this.viewInstanceId, this, viewType);
 }
 
 // Forward public API methods from |proto| to their internal implementations.
@@ -51,8 +52,7 @@
     if (document.readyState == 'loading')
       return;
 
-    registerBrowserPluginElement(
-        guestViewContainerType.VIEW_TYPE.toLowerCase());
+    registerInternalElement(guestViewContainerType.VIEW_TYPE.toLowerCase());
     registerGuestViewElement(guestViewContainerType);
     window.removeEventListener(event.type, listener, useCapture);
   }, useCapture);
@@ -84,7 +84,7 @@
   });
 };
 
-GuestViewContainer.prototype.createBrowserPluginElement = function() {
+GuestViewContainer.prototype.createInternalElement$ = function() {
   // We create BrowserPlugin as a custom element in order to observe changes
   // to attributes synchronously.
   var browserPluginElement =
@@ -103,15 +103,15 @@
   }
   this.element.addEventListener('focus', this.weakWrapper(function(e) {
     // Focus the BrowserPlugin when the GuestViewContainer takes focus.
-    privates(this).browserPluginElement.focus();
+    privates(this).internalElement.focus();
   }));
   this.element.addEventListener('blur', this.weakWrapper(function(e) {
     // Blur the BrowserPlugin when the GuestViewContainer loses focus.
-    privates(this).browserPluginElement.blur();
+    privates(this).internalElement.blur();
   }));
 };
 
-GuestViewContainer.prototype.attachWindow = function() {
+GuestViewContainer.prototype.attachWindow$ = function() {
   if (!this.internalInstanceId) {
     return true;
   }
@@ -122,22 +122,34 @@
   return true;
 };
 
-GuestViewContainer.prototype.handleBrowserPluginAttributeMutation =
+GuestViewContainer.prototype.makeGCOwnContainer = function(internalInstanceId) {
+  MessagingNatives.BindToGC(this, function() {
+    GuestViewInternalNatives.DestroyContainer(internalInstanceId);
+  }, -1);
+};
+
+GuestViewContainer.prototype.onInternalInstanceId = function(
+    internalInstanceId) {
+  this.internalInstanceId = internalInstanceId;
+  this.makeGCOwnContainer(this.internalInstanceId);
+
+  // Track when the element resizes using the element resize callback.
+  GuestViewInternalNatives.RegisterElementResizeCallback(
+      this.internalInstanceId, this.weakWrapper(this.onElementResize));
+
+  if (!this.guest.getId()) {
+    return;
+  }
+  this.guest.attach(this.internalInstanceId,
+                    this.viewInstanceId,
+                    this.buildParams());
+};
+
+GuestViewContainer.prototype.handleInternalElementAttributeMutation =
     function(name, oldValue, newValue) {
   if (name == 'internalinstanceid' && !oldValue && !!newValue) {
-    privates(this).browserPluginElement.removeAttribute('internalinstanceid');
-    this.internalInstanceId = parseInt(newValue);
-
-    // Track when the element resizes using the element resize callback.
-    GuestViewInternalNatives.RegisterElementResizeCallback(
-        this.internalInstanceId, this.weakWrapper(this.onElementResize));
-
-    if (!this.guest.getId()) {
-      return;
-    }
-    this.guest.attach(this.internalInstanceId,
-                      this.viewInstanceId,
-                      this.buildParams());
+    privates(this).internalElement.removeAttribute('internalinstanceid');
+    this.onInternalInstanceId(parseInt(newValue));
   }
 };
 
@@ -187,7 +199,7 @@
 
 // Registers the browser plugin <object> custom element. |viewType| is the
 // name of the specific guestview container (e.g. 'webview').
-function registerBrowserPluginElement(viewType) {
+function registerInternalElement(viewType) {
   var proto = $Object.create(HTMLElement.prototype);
 
   proto.createdCallback = function() {
@@ -207,7 +219,7 @@
     if (!internal) {
       return;
     }
-    internal.handleBrowserPluginAttributeMutation(name, oldValue, newValue);
+    internal.handleInternalElementAttributeMutation(name, oldValue, newValue);
   };
 
   GuestViewContainer[viewType + 'BrowserPlugin'] =
diff --git a/extensions/renderer/resources/guest_view/guest_view_iframe.js b/extensions/renderer/resources/guest_view/guest_view_iframe.js
new file mode 100644
index 0000000..c27c809
--- /dev/null
+++ b/extensions/renderer/resources/guest_view/guest_view_iframe.js
@@ -0,0 +1,98 @@
+// 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.
+
+// --site-per-process overrides for guest_view.js.
+
+var GuestView = require('guestView').GuestView;
+var GuestViewImpl = require('guestView').GuestViewImpl;
+var GuestViewInternalNatives = requireNative('guest_view_internal');
+var ResizeEvent = require('guestView').ResizeEvent;
+
+var getIframeContentWindow = function(viewInstanceId) {
+  var view = GuestViewInternalNatives.GetViewFromID(viewInstanceId);
+  if (!view)
+    return null;
+
+  var internalIframeElement = privates(view).internalElement;
+  if (internalIframeElement)
+    return internalIframeElement.contentWindow;
+
+  return null;
+};
+
+// Internal implementation of attach().
+GuestViewImpl.prototype.attachImpl$ = function(
+    internalInstanceId, viewInstanceId, attachParams, callback) {
+  // Check the current state.
+  if (!this.checkState('attach')) {
+    this.handleCallback(callback);
+    return;
+  }
+
+  // Callback wrapper function to store the contentWindow from the attachGuest()
+  // callback, handle potential attaching failure, register an automatic detach,
+  // and advance the queue.
+  var callbackWrapper = function(callback, contentWindow) {
+    // Check if attaching failed.
+    contentWindow = getIframeContentWindow(viewInstanceId);
+    if (!contentWindow) {
+      this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED;
+      this.internalInstanceId = 0;
+    } else {
+      // Only update the contentWindow if attaching is successful.
+      this.contentWindow = contentWindow;
+    }
+
+    this.handleCallback(callback);
+  };
+
+  attachParams['instanceId'] = viewInstanceId;
+  var contentWindow = getIframeContentWindow(viewInstanceId);
+  // TODO(lazyboy): Call binding function to attach this guest.
+  // |contentWindow| should be used to retrieve the RenderFrame in cpp.
+
+  this.internalInstanceId = internalInstanceId;
+  this.state = GuestViewImpl.GuestState.GUEST_STATE_ATTACHED;
+
+  // Detach automatically when the container is destroyed.
+  GuestViewInternalNatives.RegisterDestructionCallback(
+      internalInstanceId, this.weakWrapper(function() {
+    if (this.state != GuestViewImpl.GuestState.GUEST_STATE_ATTACHED ||
+        this.internalInstanceId != internalInstanceId) {
+      return;
+    }
+
+    this.internalInstanceId = 0;
+    this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED;
+  }, viewInstanceId));
+};
+
+// Internal implementation of create().
+GuestViewImpl.prototype.createImpl$ = function(createParams, callback) {
+  // Check the current state.
+  if (!this.checkState('create')) {
+    this.handleCallback(callback);
+    return;
+  }
+
+  // Callback wrapper function to store the guestInstanceId from the
+  // createGuest() callback, handle potential creation failure, and advance the
+  // queue.
+  var callbackWrapper = function(callback, guestInfo) {
+    this.id = guestInfo.id;
+
+    // Check if creation failed.
+    if (this.id === 0) {
+      this.state = GuestViewImpl.GuestState.GUEST_STATE_START;
+      this.contentWindow = null;
+    }
+
+    ResizeEvent.addListener(this.callOnResize, {instanceId: this.id});
+    this.handleCallback(callback);
+  };
+
+  this.sendCreateRequest(createParams, callbackWrapper.bind(this, callback));
+
+  this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED;
+};
diff --git a/extensions/renderer/resources/guest_view/guest_view_iframe_container.js b/extensions/renderer/resources/guest_view/guest_view_iframe_container.js
new file mode 100644
index 0000000..3f1c5d9
--- /dev/null
+++ b/extensions/renderer/resources/guest_view/guest_view_iframe_container.js
@@ -0,0 +1,15 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// --site-per-process overrides for guest_view_container.js
+
+var GuestViewContainer = require('guestViewContainer').GuestViewContainer;
+
+GuestViewContainer.prototype.createInternalElement$ = function() {
+  var iframeElement = document.createElement('iframe');
+  iframeElement.style.width = '100%';
+  iframeElement.style.height = '100%';
+  privates(iframeElement).internal = this;
+  return iframeElement;
+};
diff --git a/extensions/renderer/resources/guest_view/surface_view/surface_view.js b/extensions/renderer/resources/guest_view/surface_view/surface_view.js
index 137525c4..be78be12 100644
--- a/extensions/renderer/resources/guest_view/surface_view/surface_view.js
+++ b/extensions/renderer/resources/guest_view/surface_view/surface_view.js
@@ -42,7 +42,7 @@
   this.guest.destroy();
 
   this.guest.create(this.buildParams(), function() {
-    this.attachWindow();
+    this.attachWindow$();
     if (callback) {
       callback(true);
     }
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view.js b/extensions/renderer/resources/guest_view/web_view/web_view.js
index fd0e45c..6fcf028 100644
--- a/extensions/renderer/resources/guest_view/web_view/web_view.js
+++ b/extensions/renderer/resources/guest_view/web_view/web_view.js
@@ -137,7 +137,7 @@
 
 WebViewImpl.prototype.createGuest = function() {
   this.guest.create(this.buildParams(), function() {
-    this.attachWindow();
+    this.attachWindow$();
   }.bind(this));
 };
 
@@ -178,7 +178,7 @@
   return params;
 };
 
-WebViewImpl.prototype.attachWindow = function(opt_guestInstanceId) {
+WebViewImpl.prototype.attachWindow$ = function(opt_guestInstanceId) {
   // If |opt_guestInstanceId| was provided, then a different existing guest is
   // being attached to this webview, and the current one will get destroyed.
   if (opt_guestInstanceId) {
@@ -189,7 +189,7 @@
     this.guest = new GuestView('webview', opt_guestInstanceId);
   }
 
-  return GuestViewContainer.prototype.attachWindow.call(this);
+  return GuestViewContainer.prototype.attachWindow$.call(this);
 };
 
 // Shared implementation of executeScript() and insertCSS().
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
index f5be50a..9cf2c9a 100644
--- a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
+++ b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
@@ -163,7 +163,7 @@
         webViewImpl.onAttach(this.event.partition);
       }
 
-      var attached = webViewImpl.attachWindow(this.event.windowId);
+      var attached = webViewImpl.attachWindow$(this.event.windowId);
       if (!attached) {
         window.console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH);
       }
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_iframe.js b/extensions/renderer/resources/guest_view/web_view/web_view_iframe.js
new file mode 100644
index 0000000..bf099d2
--- /dev/null
+++ b/extensions/renderer/resources/guest_view/web_view/web_view_iframe.js
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This module provides --site-per-process overrides for WebView (<webview>).
+// See web_view.js for details.
+
+var IdGenerator = requireNative('id_generator');
+var WebViewImpl = require('webView').WebViewImpl;
+// NOTE: Do not remove these, we implicitly depend on these in
+// --site-per-process.
+var GuestViewIframe = require('guestViewIframe');
+var GuestViewIframeContainer = require('guestViewIframeContainer');
+
+WebViewImpl.prototype.attachWindow$ = function(opt_guestInstanceId) {
+  // If |opt_guestInstanceId| was provided, then a different existing guest is
+  // being attached to this webview, and the current one will get destroyed.
+  if (opt_guestInstanceId) {
+    if (this.guest.getId() == opt_guestInstanceId) {
+      return true;
+    }
+    this.guest.destroy();
+    this.guest = new GuestView('webview', opt_guestInstanceId);
+  }
+
+  var generatedId = IdGenerator.GetNextId();
+  // Generate an instance id for the container.
+  this.onInternalInstanceId(generatedId);
+  return true;
+};
diff --git a/extensions/renderer/resources/media_router_bindings.js b/extensions/renderer/resources/media_router_bindings.js
new file mode 100644
index 0000000..368b566
--- /dev/null
+++ b/extensions/renderer/resources/media_router_bindings.js
@@ -0,0 +1,487 @@
+// 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.
+
+var mediaRouterObserver;
+
+define('media_router_bindings', [
+    'mojo/public/js/bindings',
+    'mojo/public/js/core',
+    'content/public/renderer/service_provider',
+    'chrome/browser/media/router/media_router.mojom',
+    'extensions/common/mojo/keep_alive.mojom',
+    'mojo/public/js/connection',
+    'mojo/public/js/router',
+], function(bindings,
+            core,
+            serviceProvider,
+            mediaRouterMojom,
+            keepAliveMojom,
+            connector,
+            routerModule) {
+  'use strict';
+
+  /**
+   * Converts a media sink to a MediaSink Mojo object.
+   * @param {!MediaSink} sink A media sink.
+   * @return {!mediaRouterMojom.MediaSink} A Mojo MediaSink object.
+   */
+  function sinkToMojo_(sink) {
+    return new mediaRouterMojom.MediaSink({
+      'name': sink.friendlyName,
+      'sink_id': sink.id,
+    });
+  }
+
+  /**
+   * Returns a Mojo MediaRoute object given a MediaRoute and a
+   * media sink name.
+   * @param {!MediaRoute} route
+   * @param {!string=} opt_sinkName
+   * @return {!mojo.MediaRoute}
+   */
+  function routeToMojo_(route, opt_sinkName) {
+    return new mediaRouterMojom.MediaRoute({
+      'media_route_id': route.id,
+      'media_source': route.mediaSource,
+      'media_sink': new mediaRouterMojom.MediaSink({
+        'sink_id': route.sinkId,
+        'name': opt_sinkName,
+      }),
+      'description': route.description,
+      'icon_url': route.iconUrl,
+      'is_local': route.isLocal
+    });
+  }
+
+  /**
+   * Creates a new MediaRouterObserver.
+   * Converts a route struct to its Mojo form.
+   * @param {!MediaRouterService} service
+   * @constructor
+   */
+  function MediaRouterObserver(service) {
+    /**
+     * The Mojo service proxy. Allows extension code to call methods that reside
+     * in the browser.
+     * @type {!MediaRouterService}
+     */
+    this.service_ = service;
+
+    /**
+     * The provider manager service delegate. Its methods are called by the
+     * browser-resident Mojo service.
+     * @type {!MediaRouter}
+     */
+    this.mrpm_ = new MediaRouter(this);
+
+    /**
+     * The message pipe that connects the Media Router to mrpm_ across
+     * browser/renderer IPC boundaries. Object must remain in scope for the
+     * lifetime of the connection to prevent the connection from closing
+     * automatically.
+     * @type {!mojo.MessagePipe}
+     */
+    this.pipe_ = core.createMessagePipe();
+
+    /**
+     * Handle to a KeepAlive service object, which prevents the extension from
+     * being suspended as long as it remains in scope.
+     * @type {boolean}
+     */
+    this.keepAlive_ = null;
+
+    /**
+     * The stub used to bind the service delegate to the Mojo interface.
+     * Object must remain in scope for the lifetime of the connection to
+     * prevent the connection from closing automatically.
+     * @type {!mojom.MediaRouter}
+     */
+    this.mediaRouterStub_ = connector.bindHandleToStub(
+        this.pipe_.handle0, mediaRouterMojom.MediaRouter);
+
+    // Link mediaRouterStub_ to the provider manager delegate.
+    bindings.StubBindings(this.mediaRouterStub_).delegate = this.mrpm_;
+  }
+
+  /**
+   * Registers the Media Router Provider Manager with the Media Router.
+   * @return {!Promise<string>} Instance ID for the Media Router.
+   */
+  MediaRouterObserver.prototype.start = function() {
+    return this.service_.provideMediaRouter(this.pipe_.handle1).then(
+        function(result) {
+          return result.instance_id;
+        }.bind(this));
+  }
+
+  /**
+   * Sets the service delegate methods.
+   * @param {Object} handlers
+   */
+  MediaRouterObserver.prototype.setHandlers = function(handlers) {
+    this.mrpm_.setHandlers(handlers);
+  }
+
+  /**
+   * The keep alive status.
+   * @return {boolean}
+   */
+  MediaRouterObserver.prototype.getKeepAlive = function() {
+    return this.keepAlive_ != null;
+  };
+
+  /**
+   * Called by the provider manager when a sink list for a given source is
+   * updated.
+   * @param {!string} sourceUrn
+   * @param {!Array<!MediaSink>} sinks
+   */
+  MediaRouterObserver.prototype.onSinksReceived = function(sourceUrn, sinks) {
+    this.service_.onSinksReceived(sourceUrn,
+                                   sinks.map(sinkToMojo_));
+  };
+
+  /**
+   * Called by the provider manager to keep the extension from suspending
+   * if it enters a state where suspension is undesirable (e.g. there is an
+   * active MediaRoute.)
+   * If keepAlive is true, the extension is kept alive.
+   * If keepAlive is false, the extension is allowed to suspend.
+   * @param {boolean} keepAlive
+   */
+  MediaRouterObserver.prototype.setKeepAlive = function(keepAlive) {
+    if (keepAlive === false && this.keepAlive_) {
+      this.keepAlive_.close();
+      this.keepAlive_ = null;
+    } else if (keepAlive === true && !this.keepAlive_) {
+      this.keepAlive_ = new routerModule.Router(
+          serviceProvider.connectToService(
+              keepAliveMojom.KeepAlive.name));
+    }
+  };
+
+  /**
+   * Sends a message to an active media route.
+   * @param {!string} routeId
+   * @param {!Object|string} message A message that can be converted to a JSON
+   * string.
+   */
+  MediaRouterObserver.prototype.onMessage = function(routeId, message) {
+    // TODO(mfoltz): Handle binary messages (ArrayBuffer, Blob).
+    this.service_.onMessage(routeId, JSON.stringify(message));
+  };
+
+  /**
+   * Called by the provider manager to send an issue from a media route
+   * provider to the Media Router, to show the user.
+   * @param {!Object} issue The issue object.
+   */
+  MediaRouterObserver.prototype.onIssue = function(issue) {
+    function issueSeverityToMojo_(severity) {
+      switch (severity) {
+        case 'fatal':
+          return mediaRouterMojom.Issue.Severity.FATAL;
+        case 'warning':
+          return mediaRouterMojom.Issue.Severity.WARNING;
+        case 'notification':
+          return mediaRouterMojom.Issue.Severity.NOTIFICATION;
+        default:
+          console.error('Unknown issue severity: ' + severity);
+          return mediaRouterMojom.Issue.Severity.NOTIFICATION;
+      }
+    }
+
+    function issueActionToMojo_(action) {
+      switch (action) {
+        case 'ok':
+          return mediaRouterMojom.Issue.ActionType.OK;
+        case 'cancel':
+          return mediaRouterMojom.Issue.ActionType.CANCEL;
+        case 'dismiss':
+          return mediaRouterMojom.Issue.ActionType.DISMISS;
+        case 'learn_more':
+          return mediaRouterMojom.Issue.ActionType.LEARN_MORE;
+        default:
+          console.error('Unknown issue action type : ' + action);
+          return mediaRouterMojom.Issue.ActionType.OK;
+      }
+    }
+
+    var secondaryActions = (issue.secondaryActions || []).map(function(e) {
+      return issueActionToMojo_(e);
+    });
+    this.service_.onIssue(new mediaRouterMojom.Issue({
+      'route_id': issue.routeId,
+      'severity': issueSeverityToMojo_(issue.severity),
+      'title': issue.title,
+      'message': issue.message,
+      'default_action': issueActionToMojo_(issue.defaultAction),
+      'secondary_actions': secondaryActions,
+      'help_url': issue.helpUrl,
+      'is_blocking': issue.isBlocking
+    }));
+  };
+
+  /**
+   * Called by the provider manager when the set of active routes
+   * has been updated.
+   * @param {!Array<MediaRoute>} routes The active set of media routes.
+   * @param {!Array<MediaSink>} sinks The active set of media sinks.
+   */
+  MediaRouterObserver.prototype.onRoutesUpdated = function(routes, sinks) {
+    // Create an inverted index relating sink IDs to their names.
+    var sinkNameMap = {};
+    for (var i = 0; i < sinks.length; i++) {
+      sinkNameMap[sinks[i].id] = sinks[i].friendlyName;
+    }
+
+    // Convert MediaRoutes to Mojo objects and add their sink names
+    // via sinkNameMap.
+    var mojoRoutes = routes.map(function(route) {
+      return routeToMojo_(routes[j], sinkNameMap[routes[j].sinkId]);
+    });
+
+    this.service_.onRoutesUpdated(
+        mojoRoutes,
+        sinks.map(MediaRouterObserver.sinkToMojo_));
+  };
+
+  /**
+   * Called by the Provider Manager when an error was encountered in response
+   * to a media route creation request.
+   * @param {!string} requestId The request id.
+   * @param {!string} error The error.
+   */
+  MediaRouterObserver.prototype.onRouteResponseError =
+      function(requestId, error) {
+    this.service_.onRouteResponseError(requestId, error);
+  };
+
+  /**
+   * Called by the provider manager when a route was able to be created by a
+   * media route provider.
+   *
+   * @param {string} requestId The media route request id.
+   * @param {string} routeId The id of the media route that was created.
+   */
+  MediaRouterObserver.prototype.onRouteResponseReceived =
+      function(requestId, routeId) {
+    this.service_.onRouteResponseReceived(requestId, routeId);
+  };
+
+  /**
+   * Object containing callbacks set by the provider manager.
+   * TODO(mfoltz): Better named ProviderManagerDelegate?
+   *
+   * @constructor
+   * @struct
+   */
+  function MediaRouterHandlers() {
+    /**
+     * @type {function(!string, !string, !string=, !string=, !number=}
+     */
+    this.createRoute = null;
+
+    /**
+     * @type {function(!string, !string, !string, !number)}
+     */
+    this.joinRoute = null;
+
+    /**
+     * @type {function(string)}
+     */
+    this.closeRoute = null;
+
+    /**
+     * @type {function(string)}
+     */
+    this.startObservingMediaSinks = null;
+
+    /**
+     * @type {function(string)}
+     */
+    this.stopObservingMediaSinks = null;
+
+    /**
+     * @type {function(string, string)}
+     */
+    this.sendRouteMessage = null;
+
+    /**
+     * @type {function()}
+     */
+    this.startObservingMediaRoutes = null;
+
+    /**
+     * @type {function()}
+     */
+    this.stopObservingMediaRoutes = null;
+  };
+
+  /**
+   * Routes calls from Media Router to the provider manager extension.
+   * Registered with the MediaRouter stub.
+   * @param {!MediaRouterObserver} mediaRouterObserver API to call into the
+   * Media Router mojo interface.
+   * @constructor
+   */
+  function MediaRouter(mediaRouterObserver) {
+    /**
+     * Object containing JS callbacks into Provider Manager code.
+     * @type {!MediaRouterHandlers}
+     */
+    this.handlers_ = new MediaRouterHandlers();
+
+    /**
+     * Proxy class to the browser's Media Router Mojo service.
+     * @type {!MediaRouterObserver}
+     */
+    this.mediaRouter_ = mediaRouterObserver;
+  }
+  MediaRouter.prototype = Object.create(
+      mediaRouterMojom.MediaRouter.stubClass.prototype);
+
+  /*
+   * Sets the callback handler used to invoke methods in the provider manager.
+   *
+   * TODO(mfoltz): Rename to something more explicit?
+   * @param {!MediaRouterHandlers} handlers
+   */
+  MediaRouter.prototype.setHandlers = function(handlers) {
+    this.handlers_ = handlers;
+    var requiredHandlers = [
+      'stopObservingMediaRoutes',
+      'startObservingMediaRoutes',
+      'sendRouteMessage',
+      'closeRoute',
+      'joinRoute',
+      'createRoute',
+      'stopObservingMediaSinks',
+      'startObservingMediaRoutes'
+    ];
+    requiredHandlers.forEach(function(nextHandler) {
+      if (!handlers.hasOwnProperty(nextHandler)) {
+        console.error(nextHandler + ' handler not registered.');
+      }
+    });
+  }
+
+  /**
+   * Starts querying for sinks capable of displaying the media source
+   * designated by |sourceUrn|.  Results are returned by calling
+   * OnSinksReceived.
+   * @param {!string} sourceUrn
+   */
+  MediaRouter.prototype.startObservingMediaSinks =
+      function(sourceUrn) {
+    this.handlers_.startObservingMediaSinks(sourceUrn);
+  };
+
+  /**
+   * Stops querying for sinks capable of displaying |sourceUrn|.
+   * @param {!string} sourceUrn
+   */
+  MediaRouter.prototype.stopObservingMediaSinks =
+      function(sourceUrn) {
+    this.handlers_.stopObservingMediaSinks(sourceUrn);
+  };
+
+  /**
+   * Requests that |sinkId| render the media referenced by |sourceUrn|. If the
+   * request is from the Presentation API, then opt_origin and opt_tabId will
+   * be populated.
+   * @param {!string} sourceUrn The media source to render.
+   * @param {!string} sinkId The media sink ID.
+   * @param {!string=} opt_presentationId Presentation ID from the site
+   *     requesting presentation. TODO(mfoltz): Remove.
+   * @param {!string=} opt_origin The origin of the site requesting
+   *     presentation.
+   * @param {!number=} opt_tabId ID of the tab that requested presentation.
+   * @return {!Promise.<!Object>} A Promise resolving to an object describing
+   *     the newly created media route.
+   */
+  MediaRouter.prototype.createRoute =
+      function(sourceUrn, sinkId, opt_presentationId, opt_origin, opt_tabId) {
+    return this.handlers_.createRoute(
+        sourceUrn, sinkId, opt_presentationId, opt_origin, opt_tabId)
+        .then(function(route) {
+          // Sink name is not used, so it is omitted here.
+          return {route: routeToMojo_(route, "")};
+        }.bind(this))
+        .catch(function(err) {
+          return {error_text: err.message};
+        });
+  };
+
+  /**
+   * Handles a request via the Presentation API to join an existing route given
+   * by |sourceUrn| and |presentationId|. |origin| and |tabId| are used so the
+   * media route provider can limit the scope by origin or tab.
+   * @param {!string} sourceUrn The media source to render.
+   * @param {!string} presentationId The presentation ID to join.
+   * @param {!string} origin The origin of the site requesting join.
+   * @param {!number} tabId The ID of the tab requesting join.
+   * @return {!Promise.<!Object>} Resolved with the route on success,
+   * or with an error message on failure.
+   */
+  MediaRouter.prototype.joinRoute =
+      function(sourceUrn, presentationId, origin, tabId) {
+    return this.handlers_.joinRoute(sourceUrn, presentationId, origin, tabId)
+        .then(function(newRoute) {
+          return {route: routeToMojo_(newRoute)};
+        },
+        function(err) {
+          return {error_text: 'Error joining route: ' + err.message};
+        });
+  };
+
+  /**
+   * Closes the route specified by |routeId|.
+   * @param {!string} routeId
+   */
+  MediaRouter.prototype.closeRoute = function(routeId) {
+    this.handlers_.closeRoute(routeId);
+  };
+
+  /**
+   * Posts a message to the route designated by |routeId|.
+   * @param {!string} routeId
+   * @param {!string} message
+   * @return {!Promise.<boolean>} Resolved with true if the message was sent,
+   *    or false on failure.
+   */
+  MediaRouter.prototype.sendRouteMessage = function(
+      routeId, message) {
+    this.handlers_.sendRouteMessage(routeId, message)
+        .then(function() {
+          return true;
+        }, function() {
+          return false;
+        });
+  };
+
+  /**
+   * Requests that the provider manager start sending information about active
+   * media routes to the Media Router.
+   */
+  MediaRouter.prototype.startObservingMediaRoutes = function() {
+    this.handlers_.startObservingMediaRoutes();
+  };
+
+  /**
+   * Requests that the provider manager stop sending information about active
+   * media routes to the Media Router.
+   */
+  MediaRouter.prototype.stopObservingMediaRoutes = function() {
+    this.handlers_.stopObservingMediaRoutes();
+  };
+
+  mediaRouterObserver = new MediaRouterObserver(connector.bindHandleToProxy(
+      serviceProvider.connectToService(
+          mediaRouterMojom.MediaRouterObserver.name),
+      mediaRouterMojom.MediaRouterObserver));
+
+  return mediaRouterObserver;
+});
+
diff --git a/extensions/renderer/runtime_custom_bindings.cc b/extensions/renderer/runtime_custom_bindings.cc
index 483f08b..c39ce03 100644
--- a/extensions/renderer/runtime_custom_bindings.cc
+++ b/extensions/renderer/runtime_custom_bindings.cc
@@ -129,7 +129,7 @@
   int browser_window_id = args[0]->Int32Value();
 
   std::string view_type_string = *v8::String::Utf8Value(args[1]);
-  StringToUpperASCII(&view_type_string);
+  base::StringToUpperASCII(&view_type_string);
   // |view_type| == VIEW_TYPE_INVALID means getting any type of
   // views.
   ViewType view_type = VIEW_TYPE_INVALID;
diff --git a/extensions/shell/browser/shell_app_delegate.cc b/extensions/shell/browser/shell_app_delegate.cc
index 3871027..6404964 100644
--- a/extensions/shell/browser/shell_app_delegate.cc
+++ b/extensions/shell/browser/shell_app_delegate.cc
@@ -7,6 +7,7 @@
 #include "content/public/browser/web_contents.h"
 #include "extensions/common/constants.h"
 #include "extensions/shell/browser/media_capture_util.h"
+#include "extensions/shell/browser/shell_extension_web_contents_observer.h"
 
 namespace extensions {
 
@@ -17,6 +18,7 @@
 }
 
 void ShellAppDelegate::InitWebContents(content::WebContents* web_contents) {
+  ShellExtensionWebContentsObserver::CreateForWebContents(web_contents);
 }
 
 void ShellAppDelegate::RenderViewCreated(
diff --git a/extensions/shell/browser/shell_desktop_controller_aura.cc b/extensions/shell/browser/shell_desktop_controller_aura.cc
index 5ab8a3c8..f89714a 100644
--- a/extensions/shell/browser/shell_desktop_controller_aura.cc
+++ b/extensions/shell/browser/shell_desktop_controller_aura.cc
@@ -32,7 +32,6 @@
 #include "ui/wm/core/compound_event_filter.h"
 #include "ui/wm/core/cursor_manager.h"
 #include "ui/wm/core/focus_controller.h"
-#include "ui/wm/core/input_method_event_filter.h"
 #include "ui/wm/core/native_cursor_manager.h"
 #include "ui/wm/core/native_cursor_manager_delegate.h"
 
@@ -259,11 +258,6 @@
   aura::client::SetActivationClient(host_->window(), focus_controller);
   focus_client_.reset(focus_controller);
 
-  input_method_filter_.reset(
-      new wm::InputMethodEventFilter(host_->GetAcceleratedWidget()));
-  input_method_filter_->SetInputMethodPropertyInRootWindow(host_->window());
-  root_window_event_filter_->AddHandler(input_method_filter_.get());
-
   capture_client_.reset(
       new aura::client::DefaultCaptureClient(host_->window()));
 
@@ -319,8 +313,6 @@
 
 void ShellDesktopControllerAura::DestroyRootWindow() {
   host_->RemoveObserver(this);
-  if (input_method_filter_)
-    root_window_event_filter_->RemoveHandler(input_method_filter_.get());
   wm::FocusController* focus_controller =
       static_cast<wm::FocusController*>(focus_client_.get());
   if (focus_controller) {
@@ -329,7 +321,6 @@
   }
   root_window_event_filter_.reset();
   capture_client_.reset();
-  input_method_filter_.reset();
   focus_client_.reset();
   cursor_manager_.reset();
 #if defined(OS_CHROMEOS)
diff --git a/extensions/shell/browser/shell_desktop_controller_aura.h b/extensions/shell/browser/shell_desktop_controller_aura.h
index 9a8bc1f..17546c1 100644
--- a/extensions/shell/browser/shell_desktop_controller_aura.h
+++ b/extensions/shell/browser/shell_desktop_controller_aura.h
@@ -46,7 +46,6 @@
 namespace wm {
 class CompoundEventFilter;
 class CursorManager;
-class InputMethodEventFilter;
 }
 
 namespace extensions {
@@ -121,8 +120,6 @@
 
   scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;
 
-  scoped_ptr<wm::InputMethodEventFilter> input_method_filter_;
-
   scoped_ptr<aura::client::FocusClient> focus_client_;
 
   scoped_ptr<wm::CursorManager> cursor_manager_;
diff --git a/extensions/shell/browser/shell_extensions_api_client.cc b/extensions/shell/browser/shell_extensions_api_client.cc
index 43d9fdd3..527b883 100644
--- a/extensions/shell/browser/shell_extensions_api_client.cc
+++ b/extensions/shell/browser/shell_extensions_api_client.cc
@@ -5,12 +5,18 @@
 #include "extensions/shell/browser/shell_extensions_api_client.h"
 
 #include "extensions/shell/browser/shell_app_view_guest_delegate.h"
+#include "extensions/shell/browser/shell_extension_web_contents_observer.h"
 
 namespace extensions {
 
 ShellExtensionsAPIClient::ShellExtensionsAPIClient() {
 }
 
+void ShellExtensionsAPIClient::AttachWebContentsHelpers(
+    content::WebContents* web_contents) const {
+  ShellExtensionWebContentsObserver::CreateForWebContents(web_contents);
+}
+
 AppViewGuestDelegate* ShellExtensionsAPIClient::CreateAppViewGuestDelegate()
     const {
   return new ShellAppViewGuestDelegate();
diff --git a/extensions/shell/browser/shell_extensions_api_client.h b/extensions/shell/browser/shell_extensions_api_client.h
index 6c40889..17a26fc 100644
--- a/extensions/shell/browser/shell_extensions_api_client.h
+++ b/extensions/shell/browser/shell_extensions_api_client.h
@@ -14,6 +14,8 @@
   ShellExtensionsAPIClient();
 
   // ExtensionsAPIClient implementation.
+  void AttachWebContentsHelpers(content::WebContents* web_contents) const
+      override;
   AppViewGuestDelegate* CreateAppViewGuestDelegate() const override;
 };
 
diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc
index 01a7e75..a79d86630 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.cc
+++ b/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -19,6 +19,7 @@
 #include "extensions/shell/browser/api/generated_api_registration.h"
 #include "extensions/shell/browser/shell_extension_host_delegate.h"
 #include "extensions/shell/browser/shell_extension_system_factory.h"
+#include "extensions/shell/browser/shell_extension_web_contents_observer.h"
 #include "extensions/shell/browser/shell_extensions_api_client.h"
 #include "extensions/shell/browser/shell_runtime_api_delegate.h"
 
@@ -240,4 +241,10 @@
   api_client_.reset(api_client);
 }
 
+ExtensionWebContentsObserver*
+ShellExtensionsBrowserClient::GetExtensionWebContentsObserver(
+    content::WebContents* web_contents) {
+  return ShellExtensionWebContentsObserver::FromWebContents(web_contents);
+}
+
 }  // namespace extensions
diff --git a/extensions/shell/browser/shell_extensions_browser_client.h b/extensions/shell/browser/shell_extensions_browser_client.h
index 4d868b7..24ca6d9 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.h
+++ b/extensions/shell/browser/shell_extensions_browser_client.h
@@ -85,6 +85,8 @@
   ExtensionCache* GetExtensionCache() override;
   bool IsBackgroundUpdateAllowed() override;
   bool IsMinBrowserVersionSupported(const std::string& min_version) override;
+  ExtensionWebContentsObserver* GetExtensionWebContentsObserver(
+      content::WebContents* web_contents) override;
 
   // Sets the API client.
   void SetAPIClientForTest(ExtensionsAPIClient* api_client);
diff --git a/extensions/shell/common/shell_content_client_unittest.cc b/extensions/shell/common/shell_content_client_unittest.cc
index 237d2dc..bf5779f7 100644
--- a/extensions/shell/common/shell_content_client_unittest.cc
+++ b/extensions/shell/common/shell_content_client_unittest.cc
@@ -19,7 +19,8 @@
   std::string user_agent = client.GetUserAgent();
 
   // Must start with the usual Mozilla-compatibility string.
-  EXPECT_TRUE(StartsWithASCII(user_agent, "Mozilla/5.0", false)) << user_agent;
+  EXPECT_TRUE(base::StartsWithASCII(user_agent, "Mozilla/5.0", false))
+      << user_agent;
 
   // Must contain a substring like "Chrome/1.2.3.4".
   EXPECT_TRUE(MatchPattern(user_agent, "*Chrome/*.*.*.*")) << user_agent;
diff --git a/extensions/utility/unpacker_unittest.cc b/extensions/utility/unpacker_unittest.cc
index 107a0cc..b323e01 100644
--- a/extensions/utility/unpacker_unittest.cc
+++ b/extensions/utility/unpacker_unittest.cc
@@ -168,8 +168,8 @@
       static_cast<TestExtensionsClient*>(ExtensionsClient::Get()));
 
   EXPECT_FALSE(unpacker_->Run());
-  EXPECT_TRUE(
-      StartsWith(unpacker_->error_message(), ASCIIToUTF16(kExpected), false))
+  EXPECT_TRUE(base::StartsWith(unpacker_->error_message(),
+                               ASCIIToUTF16(kExpected), false))
       << "Expected prefix: \"" << kExpected << "\", actual error: \""
       << unpacker_->error_message() << "\"";
 }
@@ -178,8 +178,8 @@
   const char kExpected[] = "Could not decode image: ";
   SetupUnpacker("bad_image.crx");
   EXPECT_FALSE(unpacker_->Run());
-  EXPECT_TRUE(
-      StartsWith(unpacker_->error_message(), ASCIIToUTF16(kExpected), false))
+  EXPECT_TRUE(base::StartsWith(unpacker_->error_message(),
+                               ASCIIToUTF16(kExpected), false))
       << "Expected prefix: \"" << kExpected << "\", actual error: \""
       << unpacker_->error_message() << "\"";
 }
diff --git a/gin/wrappable.cc b/gin/wrappable.cc
index 27c58df..0fac4e0b 100644
--- a/gin/wrappable.cc
+++ b/gin/wrappable.cc
@@ -36,7 +36,7 @@
 }
 
 v8::Local<v8::Object> WrappableBase::GetWrapperImpl(v8::Isolate* isolate,
-                                                     WrapperInfo* info) {
+                                                    WrapperInfo* info) {
   if (!wrapper_.IsEmpty()) {
     return v8::Local<v8::Object>::New(isolate, wrapper_);
   }
diff --git a/gin/wrappable.h b/gin/wrappable.h
index cd4d30e..f7d82b0d5 100644
--- a/gin/wrappable.h
+++ b/gin/wrappable.h
@@ -12,15 +12,6 @@
 
 namespace gin {
 
-namespace internal {
-
-GIN_EXPORT void* FromV8Impl(v8::Isolate* isolate,
-                            v8::Local<v8::Value> val,
-                            WrapperInfo* info);
-
-}  // namespace internal
-
-
 // Wrappable is a base class for C++ objects that have corresponding v8 wrapper
 // objects. To retain a Wrappable object on the stack, use a gin::Handle.
 //
@@ -51,8 +42,20 @@
 // wrapper for the object. If clients fail to create a wrapper for a wrappable
 // object, the object will leak because we use the weak callback from the
 // wrapper as the signal to delete the wrapped object.
-template<typename T>
-class Wrappable;
+//
+// Wrappable<T> explicitly does not support further subclassing of T.
+// Subclasses of Wrappable<T> should be declared final. Because Wrappable<T>
+// caches the object template using &T::kWrapperInfo as the key, all subclasses
+// would share a single object template. This will lead to hard to debug crashes
+// that look like use-after-free errors.
+
+namespace internal {
+
+GIN_EXPORT void* FromV8Impl(v8::Isolate* isolate,
+                            v8::Local<v8::Value> val,
+                            WrapperInfo* info);
+
+}  // namespace internal
 
 class ObjectTemplateBuilder;
 
@@ -62,6 +65,7 @@
   WrappableBase();
   virtual ~WrappableBase();
 
+  // Overrides of this method should be declared final and not overridden again.
   virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate);
 
   v8::Local<v8::Object> GetWrapperImpl(v8::Isolate* isolate,
@@ -83,8 +87,6 @@
 class Wrappable : public WrappableBase {
  public:
   // Retrieve (or create) the v8 wrapper object cooresponding to this object.
-  // To customize the wrapper created for a subclass, override GetWrapperInfo()
-  // instead of overriding this function.
   v8::Local<v8::Object> GetWrapper(v8::Isolate* isolate) {
     return GetWrapperImpl(isolate, &T::kWrapperInfo);
   }
diff --git a/gin/wrappable_unittest.cc b/gin/wrappable_unittest.cc
index 70cb224..07d4fb3 100644
--- a/gin/wrappable_unittest.cc
+++ b/gin/wrappable_unittest.cc
@@ -40,38 +40,16 @@
 
  protected:
   MyObject() : value_(0) {}
-  ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) override;
+  ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) final {
+    return Wrappable<MyObject>::GetObjectTemplateBuilder(isolate)
+        .SetProperty("value", &MyObject::value, &MyObject::set_value);
+  }
   ~MyObject() override {}
 
  private:
   int value_;
 };
 
-class MyObjectSubclass : public MyObject {
- public:
-  static gin::Handle<MyObjectSubclass> Create(v8::Isolate* isolate) {
-    return CreateHandle(isolate, new MyObjectSubclass());
-  }
-
-  void SayHello(const std::string& name) {
-    result = std::string("Hello, ") + name;
-  }
-
-  std::string result;
-
- private:
-  ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override {
-    return MyObject::GetObjectTemplateBuilder(isolate)
-        .SetMethod("sayHello", &MyObjectSubclass::SayHello);
-  }
-
-  MyObjectSubclass() {
-  }
-
-  ~MyObjectSubclass() override {}
-};
-
 class MyCallableObject : public Wrappable<MyCallableObject> {
  public:
   static WrapperInfo kWrapperInfo;
@@ -83,8 +61,7 @@
   int result() { return result_; }
 
  private:
-  ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override {
+  ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) final {
     return Wrappable<MyCallableObject>::GetObjectTemplateBuilder(isolate)
         .SetCallAsFunctionHandler(&MyCallableObject::Call);
   }
@@ -109,20 +86,9 @@
   static WrapperInfo kWrapperInfo;
 };
 
-class MyObjectBlink : public Wrappable<MyObjectBlink> {
- public:
-  static WrapperInfo kWrapperInfo;
-};
-
 WrapperInfo MyObject::kWrapperInfo = { kEmbedderNativeGin };
-ObjectTemplateBuilder MyObject::GetObjectTemplateBuilder(v8::Isolate* isolate) {
-  return Wrappable<MyObject>::GetObjectTemplateBuilder(isolate)
-      .SetProperty("value", &MyObject::value, &MyObject::set_value);
-}
-
 WrapperInfo MyCallableObject::kWrapperInfo = { kEmbedderNativeGin };
 WrapperInfo MyObject2::kWrapperInfo = { kEmbedderNativeGin };
-WrapperInfo MyObjectBlink::kWrapperInfo = { kEmbedderNativeGin };
 
 typedef V8Test WrappableTest;
 
@@ -155,12 +121,6 @@
   EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped));
   EXPECT_FALSE(unwrapped);
 
-  // An object that's wrapping a C++ object from Blink.
-  thing.Clear();
-  thing = ConvertToV8(isolate, new MyObjectBlink());
-  EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped));
-  EXPECT_FALSE(unwrapped);
-
   // An object that's wrapping a C++ object of the wrong type.
   thing.Clear();
   thing = ConvertToV8(isolate, new MyObject2());
@@ -200,28 +160,6 @@
   EXPECT_EQ(191, obj->value());
 }
 
-TEST_F(WrappableTest, WrappableSubclass) {
-  v8::Isolate* isolate = instance_->isolate();
-  v8::HandleScope handle_scope(isolate);
-
-  gin::Handle<MyObjectSubclass> object(MyObjectSubclass::Create(isolate));
-  v8::Local<v8::String> source = StringToV8(isolate,
-                                             "(function(obj) {"
-                                             "obj.sayHello('Lily');"
-                                             "})");
-  gin::TryCatch try_catch(isolate);
-  v8::Local<v8::Script> script = v8::Script::Compile(source);
-  v8::Local<v8::Value> val = script->Run();
-  v8::Local<v8::Function> func;
-  EXPECT_TRUE(ConvertFromV8(isolate, val, &func));
-  v8::Local<v8::Value> argv[] = {
-    ConvertToV8(isolate, object.get())
-  };
-  func->Call(v8::Undefined(isolate), 1, argv);
-  EXPECT_FALSE(try_catch.HasCaught());
-  EXPECT_EQ("Hello, Lily", object->result);
-}
-
 TEST_F(WrappableTest, CallAsFunction) {
   v8::Isolate* isolate = instance_->isolate();
   v8::HandleScope handle_scope(isolate);
diff --git a/google_apis/drive/drive_api_requests.cc b/google_apis/drive/drive_api_requests.cc
index 57a3ec1..a9a0342 100644
--- a/google_apis/drive/drive_api_requests.cc
+++ b/google_apis/drive/drive_api_requests.cc
@@ -8,6 +8,8 @@
 #include "base/callback.h"
 #include "base/json/json_writer.h"
 #include "base/location.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sparse_histogram.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
@@ -44,6 +46,13 @@
 // Mime type of multipart mixed.
 const char kMultipartMixedMimeTypePrefix[] = "multipart/mixed; boundary=";
 
+// UMA names.
+const char kUMADriveBatchUploadResponseCode[] = "Drive.BatchUploadResponseCode";
+const char kUMADriveTotalFileCountInBatchUpload[] =
+    "Drive.TotalFileCountInBatchUpload";
+const char kUMADriveTotalFileSizeInBatchUpload[] =
+    "Drive.TotalFileSizeInBatchUpload";
+
 // Parses the JSON value to FileResource instance and runs |callback| on the
 // UI thread once parsing is done.
 // This is customized version of ParseJsonAndRun defined above to adapt the
@@ -1314,6 +1323,7 @@
   }
 
   // Build multipart body here.
+  int64 total_size = 0;
   std::vector<ContentTypeAndData> parts;
   for (auto& child : child_requests_) {
     std::string type;
@@ -1341,6 +1351,7 @@
 
     child->data_offset = header.size();
     child->data_size = data.size();
+    total_size += data.size();
 
     parts.push_back(ContentTypeAndData());
     parts.back().type = kHttpContentType;
@@ -1348,6 +1359,10 @@
     parts.back().data.append(data);
   }
 
+  UMA_HISTOGRAM_COUNTS_100(kUMADriveTotalFileCountInBatchUpload, parts.size());
+  UMA_HISTOGRAM_MEMORY_KB(kUMADriveTotalFileSizeInBatchUpload,
+                          total_size / 1024);
+
   std::vector<uint64> part_data_offset;
   GenerateMultipartBody(MULTIPART_MIXED, boundary_, parts, &upload_content_,
                         &part_data_offset);
@@ -1385,6 +1400,8 @@
 }
 
 void BatchUploadRequest::ProcessURLFetchResults(const net::URLFetcher* source) {
+  UMA_HISTOGRAM_SPARSE_SLOWLY(kUMADriveBatchUploadResponseCode, GetErrorCode());
+
   if (!IsSuccessfulDriveApiErrorCode(GetErrorCode())) {
     RunCallbackOnPrematureFailure(GetErrorCode());
     sender_->RequestFinished(this);
diff --git a/google_apis/drive/test_util.cc b/google_apis/drive/test_util.cc
index db14c9d7..c621809 100644
--- a/google_apis/drive/test_util.cc
+++ b/google_apis/drive/test_util.cc
@@ -26,7 +26,7 @@
 bool RemovePrefix(const std::string& input,
                   const std::string& prefix,
                   std::string* output) {
-  if (!StartsWithASCII(input, prefix, true /* case sensitive */))
+  if (!base::StartsWithASCII(input, prefix, true /* case sensitive */))
     return false;
 
   *output = input.substr(prefix.size());
diff --git a/google_apis/gaia/fake_gaia.cc b/google_apis/gaia/fake_gaia.cc
index 456d8db..1b5d408 100644
--- a/google_apis/gaia/fake_gaia.cc
+++ b/google_apis/gaia/fake_gaia.cc
@@ -102,7 +102,8 @@
   std::map<std::string, std::string>::const_iterator auth_header_entry =
       request.headers.find("Authorization");
   if (auth_header_entry != request.headers.end()) {
-    if (StartsWithASCII(auth_header_entry->second, auth_token_prefix, true)) {
+    if (base::StartsWithASCII(auth_header_entry->second, auth_token_prefix,
+                              true)) {
       *access_token = auth_header_entry->second.substr(
           strlen(auth_token_prefix));
       return true;
@@ -266,7 +267,7 @@
   // Handles /SSO GAIA call (not GAIA, made up for SAML tests).
   REGISTER_PATH_RESPONSE_HANDLER("/SSO", HandleSSO);
 
-  // Handles /o/oauth2/token GAIA call.
+  // Handles /oauth2/v4/token GAIA call.
   REGISTER_RESPONSE_HANDLER(
       gaia_urls->oauth2_token_url(), HandleAuthToken);
 
@@ -624,7 +625,7 @@
   std::string grant_type;
   if (!GetQueryParameter(request.content, "grant_type", &grant_type)) {
     http_response->set_code(net::HTTP_BAD_REQUEST);
-    LOG(ERROR) << "No 'grant_type' param in /o/oauth2/token";
+    LOG(ERROR) << "No 'grant_type' param in /oauth2/v4/token";
     return;
   }
 
@@ -633,7 +634,7 @@
     if (!GetQueryParameter(request.content, "code", &auth_code) ||
         auth_code != merge_session_params_.auth_code) {
       http_response->set_code(net::HTTP_BAD_REQUEST);
-      LOG(ERROR) << "No 'code' param in /o/oauth2/token";
+      LOG(ERROR) << "No 'code' param in /oauth2/v4/token";
       return;
     }
 
@@ -683,7 +684,7 @@
     }
   }
 
-  LOG(ERROR) << "Bad request for /o/oauth2/token - "
+  LOG(ERROR) << "Bad request for /oauth2/v4/token - "
               << "refresh_token = " << refresh_token
               << ", scope = " << scope
               << ", client_id = " << client_id;
diff --git a/google_apis/gaia/fake_gaia.h b/google_apis/gaia/fake_gaia.h
index 1f1a3ef..f84e2e7 100644
--- a/google_apis/gaia/fake_gaia.h
+++ b/google_apis/gaia/fake_gaia.h
@@ -64,7 +64,7 @@
     // auth_code cookie value response for /o/oauth2/programmatic_auth call.
     std::string auth_code;
 
-    // OAuth2 refresh and access token generated by /o/oauth2/token call
+    // OAuth2 refresh and access token generated by /oauth2/v4/token call
     // with "...&grant_type=authorization_code".
     std::string refresh_token;
     std::string access_token;
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index eaae715..0ae69127 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -35,7 +35,7 @@
                                 const char* part) {
   for (std::vector<std::string>::const_iterator it = parts.begin();
        it != parts.end(); ++it) {
-    if (LowerCaseEqualsASCII(*it, part))
+    if (base::LowerCaseEqualsASCII(*it, part))
       return true;
   }
   return false;
@@ -539,8 +539,8 @@
   std::vector<std::string>::const_iterator iter;
   for (iter = parts.begin(); iter != parts.end(); ++iter) {
     const std::string& part = *iter;
-    if (StartsWithASCII(
-        part, kClientLoginToOAuth2CookiePartCodePrefix, false)) {
+    if (base::StartsWithASCII(part, kClientLoginToOAuth2CookiePartCodePrefix,
+                              false)) {
       auth_code->assign(part.substr(
           kClientLoginToOAuth2CookiePartCodePrefixLength));
       return true;
diff --git a/google_apis/gaia/gaia_auth_util.cc b/google_apis/gaia/gaia_auth_util.cc
index 33be5a8..e9ec545 100644
--- a/google_apis/gaia/gaia_auth_util.cc
+++ b/google_apis/gaia/gaia_auth_util.cc
@@ -49,10 +49,16 @@
 ListedAccount::~ListedAccount() {}
 
 bool ListedAccount::operator==(const ListedAccount& other) const {
-  return email == other.email &&
-         gaia_id == other.gaia_id &&
-         valid == other.valid &&
-         raw_email == other.raw_email;
+  // Only use ids for comparison if they've been computed by some caller, since
+  // this class does not assign the id.
+  if (!id.empty() && !other.id.empty()) {
+    return id == other.id;
+  } else {
+    return email == other.email &&
+           gaia_id == other.gaia_id &&
+           valid == other.valid &&
+           raw_email == other.raw_email;
+  }
 }
 
 std::string CanonicalizeEmail(const std::string& email_address) {
diff --git a/google_apis/gaia/gaia_urls.cc b/google_apis/gaia/gaia_urls.cc
index d26a73be..0d1619e 100644
--- a/google_apis/gaia/gaia_urls.cc
+++ b/google_apis/gaia/gaia_urls.cc
@@ -41,10 +41,10 @@
 const char kClientLoginToOAuth2UrlSuffix[] = "o/oauth2/programmatic_auth";
 const char kOAuth2AuthUrlSuffix[] = "o/oauth2/auth";
 const char kOAuth2RevokeUrlSuffix[] = "o/oauth2/revoke";
-const char kOAuth2TokenUrlSuffix[] = "o/oauth2/token";
 const char kOAuth2IFrameUrlSuffix[] = "o/oauth2/iframerpc";
 
 // API calls from www.googleapis.com
+const char kOAuth2TokenUrlSuffix[] = "oauth2/v4/token";
 const char kOAuth2IssueTokenUrlSuffix[] = "oauth2/v2/IssueToken";
 const char kOAuth2TokenInfoUrlSuffix[] = "oauth2/v2/tokeninfo";
 const char kOAuthUserInfoUrlSuffix[] = "oauth2/v1/userinfo";
@@ -121,12 +121,12 @@
   client_login_to_oauth2_url_ =
       lso_origin_url_.Resolve(kClientLoginToOAuth2UrlSuffix);
   oauth2_auth_url_ = lso_origin_url_.Resolve(kOAuth2AuthUrlSuffix);
-  oauth2_token_url_ = lso_origin_url_.Resolve(kOAuth2TokenUrlSuffix);
   oauth2_revoke_url_ = lso_origin_url_.Resolve(kOAuth2RevokeUrlSuffix);
   oauth2_iframe_url_ =
       lso_origin_url_.Resolve(kOAuth2IFrameUrlSuffix);
 
   // URLs from www.googleapis.com.
+  oauth2_token_url_ = google_apis_origin_url_.Resolve(kOAuth2TokenUrlSuffix);
   oauth2_issue_token_url_ =
       google_apis_origin_url_.Resolve(kOAuth2IssueTokenUrlSuffix);
   oauth2_token_info_url_ =
diff --git a/google_apis/gaia/oauth2_mint_token_flow.cc b/google_apis/gaia/oauth2_mint_token_flow.cc
index f09174cb..9818f089 100644
--- a/google_apis/gaia/oauth2_mint_token_flow.cc
+++ b/google_apis/gaia/oauth2_mint_token_flow.cc
@@ -41,8 +41,11 @@
     "&scope=%s"
     "&client_id=%s"
     "&origin=%s";
+// TODO(pavely): lib_ver is passed to differentiate IssueToken requests from
+// different code locations. Remove once device_id mismatch is understood.
+// (crbug.com/481596)
 const char kOAuth2IssueTokenBodyFormatDeviceIdAddendum[] =
-    "&device_id=%s&device_type=chrome";
+    "&device_id=%s&device_type=chrome&lib_ver=extension";
 const char kIssueAdviceKey[] = "issueAdvice";
 const char kIssueAdviceValueConsent[] = "consent";
 const char kAccessTokenKey[] = "token";
diff --git a/google_apis/gaia/oauth2_mint_token_flow_unittest.cc b/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
index 89d5bfd..913d555 100644
--- a/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
+++ b/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
@@ -241,7 +241,8 @@
         "&client_id=client1"
         "&origin=ext1"
         "&device_id=device_id1"
-        "&device_type=chrome");
+        "&device_type=chrome"
+        "&lib_ver=extension");
     EXPECT_EQ(expected_body, body);
   }
 }
diff --git a/google_apis/gcm/engine/gcm_store_impl.cc b/google_apis/gcm/engine/gcm_store_impl.cc
index b90630a..1743d13 100644
--- a/google_apis/gcm/engine/gcm_store_impl.cc
+++ b/google_apis/gcm/engine/gcm_store_impl.cc
@@ -342,7 +342,7 @@
   int gcm_registration_count = 0;
   int instance_id_token_count = 0;
   for (const auto& registration : result->registrations) {
-    if (StartsWithASCII(registration.first, "iid-", true))
+    if (base::StartsWithASCII(registration.first, "iid-", true))
       instance_id_token_count++;
     else
       gcm_registration_count++;
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index 9dbe95d..391df10 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -330,6 +330,7 @@
 #define glSwapInterval GLES2_GET_FUN(SwapInterval)
 #define glMatrixLoadfCHROMIUM GLES2_GET_FUN(MatrixLoadfCHROMIUM)
 #define glMatrixLoadIdentityCHROMIUM GLES2_GET_FUN(MatrixLoadIdentityCHROMIUM)
+#define glGetGraphicsResetStatusKHR GLES2_GET_FUN(GetGraphicsResetStatusKHR)
 #define glBlendBarrierKHR GLES2_GET_FUN(BlendBarrierKHR)
 
 #endif  // GPU_GLES2_GL2CHROMIUM_AUTOGEN_H_
diff --git a/gpu/blink/webgraphicscontext3d_impl.cc b/gpu/blink/webgraphicscontext3d_impl.cc
index f2e1434..123ba79 100644
--- a/gpu/blink/webgraphicscontext3d_impl.cc
+++ b/gpu/blink/webgraphicscontext3d_impl.cc
@@ -185,7 +185,6 @@
     : initialized_(false),
       initialize_failed_(false),
       context_lost_callback_(0),
-      context_lost_reason_(GL_NO_ERROR),
       error_message_callback_(0),
       gl_(NULL),
       flush_id_(0) {
@@ -1174,6 +1173,14 @@
   gl_->WaitSync(reinterpret_cast<GLsync>(sync), flags, timeout);
 }
 
+bool WebGraphicsContext3DImpl::isContextLost() {
+  return getGraphicsResetStatusARB() != GL_NO_ERROR;
+}
+
+blink::WGC3Denum WebGraphicsContext3DImpl::getGraphicsResetStatusARB() {
+  return gl_->GetGraphicsResetStatusKHR();
+}
+
 GrGLInterface* WebGraphicsContext3DImpl::createGrGLInterface() {
   return skia_bindings::CreateCommandBufferSkiaGLBinding();
 }
@@ -1230,8 +1237,7 @@
   output_attribs->fail_if_major_perf_caveat =
       attributes.failIfMajorPerformanceCaveat;
   output_attribs->bind_generates_resource = false;
-  output_attribs->es3_context_required =
-      (attributes.webGL && attributes.webGLVersion == 2);
+  output_attribs->webgl_version = attributes.webGLVersion;
 }
 
 }  // namespace gpu_blink
diff --git a/gpu/blink/webgraphicscontext3d_impl.h b/gpu/blink/webgraphicscontext3d_impl.h
index b11c1f48..c053f88 100644
--- a/gpu/blink/webgraphicscontext3d_impl.h
+++ b/gpu/blink/webgraphicscontext3d_impl.h
@@ -921,6 +921,9 @@
                         blink::WGC3Dbitfield flags,
                         blink::WGC3Duint64 timeout);
 
+  virtual bool isContextLost();
+  virtual blink::WGC3Denum getGraphicsResetStatusARB();
+
   virtual GrGLInterface* createGrGLInterface();
 
   ::gpu::gles2::GLES2Interface* GetGLInterface() {
@@ -950,7 +953,6 @@
   bool initialize_failed_;
 
   WebGraphicsContext3D::WebGraphicsContextLostCallback* context_lost_callback_;
-  blink::WGC3Denum context_lost_reason_;
 
   WebGraphicsContext3D::WebGraphicsErrorMessageCallback*
       error_message_callback_;
diff --git a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc
index cc7871c..4f83fa3 100644
--- a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc
+++ b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc
@@ -82,7 +82,6 @@
         bool is_offscreen,
         gfx::AcceleratedWidget window)
     : share_resources_(attributes.shareResources),
-      webgl_context_(attributes.webGL),
       is_offscreen_(is_offscreen),
       window_(window),
       context_(context.Pass()) {
@@ -140,9 +139,6 @@
   real_gl_ = context_->GetImplementation();
   setGLInterface(real_gl_);
 
-  if (real_gl_ && webgl_context_)
-    real_gl_->EnableFeatureCHROMIUM("webgl_enable_glsl_webgl_validation");
-
   initialized_ = true;
   return true;
 }
@@ -158,23 +154,12 @@
   context_->SetLock(lock);
 }
 
-bool WebGraphicsContext3DInProcessCommandBufferImpl::isContextLost() {
-  return context_lost_reason_ != GL_NO_ERROR;
-}
-
-WGC3Denum WebGraphicsContext3DInProcessCommandBufferImpl::
-    getGraphicsResetStatusARB() {
-  return context_lost_reason_;
-}
-
 ::gpu::ContextSupport*
 WebGraphicsContext3DInProcessCommandBufferImpl::GetContextSupport() {
   return real_gl_;
 }
 
 void WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost() {
-  // TODO(kbr): improve the precision here.
-  context_lost_reason_ = GL_UNKNOWN_CONTEXT_RESET_ARB;
   if (context_lost_callback_) {
     context_lost_callback_->onContextLost();
   }
diff --git a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h
index 32bcbbf..d463582 100644
--- a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h
+++ b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h
@@ -59,12 +59,6 @@
   bool InitializeOnCurrentThread();
   void SetLock(base::Lock* lock);
 
-  //----------------------------------------------------------------------
-  // WebGraphicsContext3D methods
-  virtual bool isContextLost();
-
-  virtual blink::WGC3Denum getGraphicsResetStatusARB();
-
   ::gpu::ContextSupport* GetContextSupport();
 
   ::gpu::gles2::GLES2Implementation* GetImplementation() {
@@ -89,7 +83,6 @@
 
   ::gpu::gles2::ContextCreationAttribHelper attribs_;
   bool share_resources_;
-  bool webgl_context_;
 
   bool is_offscreen_;
   // Only used when not offscreen.
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index ab60f0d3..af622ce 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -2699,6 +2699,12 @@
     'gl_test_func': 'glGetFramebufferAttachmentParameterivEXT',
     'result': ['SizedResult<GLint>'],
   },
+  'GetGraphicsResetStatusKHR': {
+    'extension': True,
+    'client_test': False,
+    'gen_cmd': False,
+    'trace_level': 1,
+  },
   'GetInteger64v': {
     'type': 'GETn',
     'result': ['SizedResult<GLint64>'],
diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h
index 10dd75c..07234c7 100644
--- a/gpu/command_buffer/client/client_test_helper.h
+++ b/gpu/command_buffer/client/client_test_helper.h
@@ -111,6 +111,7 @@
   MOCK_METHOD1(SetSurfaceVisible, void(bool visible));
   MOCK_METHOD1(CreateStreamTexture, uint32(uint32));
   MOCK_METHOD1(SetLock, void(base::Lock*));
+  MOCK_METHOD0(IsGpuChannelLost, bool());
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockClientGpuControl);
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 7eb7a0e..591df8a 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1393,6 +1393,9 @@
 void GLES2MatrixLoadIdentityCHROMIUM(GLenum matrixMode) {
   gles2::GetGLContext()->MatrixLoadIdentityCHROMIUM(matrixMode);
 }
+GLenum GLES2GetGraphicsResetStatusKHR() {
+  return gles2::GetGLContext()->GetGraphicsResetStatusKHR();
+}
 void GLES2BlendBarrierKHR() {
   gles2::GetGLContext()->BlendBarrierKHR();
 }
@@ -2620,6 +2623,10 @@
      reinterpret_cast<GLES2FunctionPointer>(glMatrixLoadIdentityCHROMIUM),
     },
     {
+     "glGetGraphicsResetStatusKHR",
+     reinterpret_cast<GLES2FunctionPointer>(glGetGraphicsResetStatusKHR),
+    },
+    {
      "glBlendBarrierKHR",
      reinterpret_cast<GLES2FunctionPointer>(glBlendBarrierKHR),
     },
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index e859299..3a8971e3 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -2187,18 +2187,36 @@
   }
 
   // Check if we can send it all at once.
-  ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
-  if (!buffer.valid()) {
-    return;
+  int32_t shm_id = 0;
+  uint32_t shm_offset = 0;
+  void* buffer_pointer = nullptr;
+
+  ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
+  ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
+
+  if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
+    shm_id = transfer_alloc.shm_id();
+    shm_offset = transfer_alloc.offset();
+    buffer_pointer = transfer_alloc.address();
+  } else {
+    mapped_alloc.Reset(size);
+    if (mapped_alloc.valid()) {
+      transfer_alloc.Discard();
+
+      mapped_alloc.SetFlushAfterRelease(true);
+      shm_id = mapped_alloc.shm_id();
+      shm_offset = mapped_alloc.offset();
+      buffer_pointer = mapped_alloc.address();
+    }
   }
 
-  if (buffer.size() >= size) {
+  if (buffer_pointer) {
     CopyRectToBuffer(
         pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
-        buffer.address(), padded_row_size);
+        buffer_pointer, padded_row_size);
     helper_->TexImage2D(
         target, level, internalformat, width, height, format, type,
-        buffer.shm_id(), buffer.offset());
+        shm_id, shm_offset);
     CheckGLError();
     return;
   }
@@ -2209,7 +2227,7 @@
      0, 0);
   TexSubImage2DImpl(
       target, level, 0, 0, width, height, format, type, unpadded_row_size,
-      pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
+      pixels, src_padded_row_size, GL_TRUE, &transfer_alloc, padded_row_size);
   CheckGLError();
 }
 
@@ -2295,13 +2313,30 @@
   }
 
   // Check if we can send it all at once.
-  ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
-  if (!buffer.valid()) {
-    return;
+  int32_t shm_id = 0;
+  uint32_t shm_offset = 0;
+  void* buffer_pointer = nullptr;
+
+  ScopedTransferBufferPtr transfer_alloc(size, helper_, transfer_buffer_);
+  ScopedMappedMemoryPtr mapped_alloc(0, helper_, mapped_memory_.get());
+
+  if (transfer_alloc.valid() && transfer_alloc.size() >= size) {
+    shm_id = transfer_alloc.shm_id();
+    shm_offset = transfer_alloc.offset();
+    buffer_pointer = transfer_alloc.address();
+  } else {
+    mapped_alloc.Reset(size);
+    if (mapped_alloc.valid()) {
+      transfer_alloc.Discard();
+
+      mapped_alloc.SetFlushAfterRelease(true);
+      shm_id = mapped_alloc.shm_id();
+      shm_offset = mapped_alloc.offset();
+      buffer_pointer = mapped_alloc.address();
+    }
   }
 
-  if (buffer.size() >= size) {
-    void* buffer_pointer = buffer.address();
+  if (buffer_pointer) {
     for (GLsizei z = 0; z < depth; ++z) {
       // Only the last row of the last image is unpadded.
       uint32 src_unpadded_row_size =
@@ -2317,7 +2352,7 @@
     }
     helper_->TexImage3D(
         target, level, internalformat, width, height, depth, format, type,
-        buffer.shm_id(), buffer.offset());
+        shm_id, shm_offset);
     CheckGLError();
     return;
   }
@@ -2328,7 +2363,7 @@
      0, 0);
   TexSubImage3DImpl(
       target, level, 0, 0, 0, width, height, depth, format, type,
-      unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &buffer,
+      unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &transfer_alloc,
       padded_row_size);
   CheckGLError();
 }
@@ -4103,6 +4138,21 @@
   CheckGLError();
 }
 
+GLenum GLES2Implementation::GetGraphicsResetStatusKHR() {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetGraphicsResetStatusKHR()");
+  // If we can't make command buffers then the context is lost.
+  if (gpu_control_->IsGpuChannelLost())
+    return GL_UNKNOWN_CONTEXT_RESET_KHR;
+  // Otherwise, check the command buffer if it is lost.
+  if (helper_->IsContextLost()) {
+    // TODO(danakj): We could GetLastState() off the CommandBuffer and return
+    // the actual reason here if we cared to.
+    return GL_UNKNOWN_CONTEXT_RESET_KHR;
+  }
+  return GL_NO_ERROR;
+}
+
 void GLES2Implementation::Swap() {
   SwapBuffers();
 }
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index b89f8d6..b4b9e98 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -1041,6 +1041,8 @@
 
 void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) override;
 
+GLenum GetGraphicsResetStatusKHR() override;
+
 void BlendBarrierKHR() override;
 
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index db978e1..2dc4bf8 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -133,6 +133,7 @@
   void* AllocUpTo(unsigned int size, unsigned int* size_allocated) override;
   void* Alloc(unsigned int size) override;
   RingBuffer::Offset GetOffset(void* pointer) const override;
+  void DiscardBlock(void* p) override;
   void FreePendingToken(void* p, unsigned int /* token */) override;
 
   size_t MaxTransferBufferSize() {
@@ -296,6 +297,11 @@
   return static_cast<uint8*>(pointer) - actual_buffer();
 }
 
+void MockTransferBuffer::DiscardBlock(void* p) {
+  EXPECT_EQ(last_alloc_, p);
+  last_alloc_ = NULL;
+}
+
 void MockTransferBuffer::FreePendingToken(void* p, unsigned int /* token */) {
   EXPECT_EQ(last_alloc_, p);
   last_alloc_ = NULL;
@@ -585,6 +591,10 @@
     return transfer_buffer_->MaxTransferBufferSize();
   }
 
+  void SetMappedMemoryLimit(size_t limit) {
+    gl_->mapped_memory_->set_max_allocated_bytes(limit);
+  }
+
   ExpectedMemoryInfo GetExpectedMemory(size_t size) {
     return transfer_buffer_->GetExpectedMemory(size);
   }
@@ -593,6 +603,18 @@
     return transfer_buffer_->GetExpectedResultMemory(size);
   }
 
+  ExpectedMemoryInfo GetExpectedMappedMemory(size_t size) {
+    ExpectedMemoryInfo mem;
+
+    // Temporarily allocate memory and expect that memory block to be reused.
+    mem.ptr = static_cast<uint8*>(gl_->mapped_memory_->Alloc(size,
+                                                             &mem.id,
+                                                             &mem.offset));
+    gl_->mapped_memory_->Free(mem.ptr);
+
+    return mem;
+  }
+
   // Sets the ProgramInfoManager. The manager will be owned
   // by the ShareGroup.
   void SetProgramInfoManager(ProgramInfoManager* manager) {
@@ -2301,8 +2323,57 @@
       pixels, mem2.ptr));
 }
 
+TEST_F(GLES2ImplementationTest, TexImage2DViaMappedMem) {
+  struct Cmds {
+    cmds::TexImage2D tex_image_2d;
+    cmd::SetToken set_token;
+  };
+  const GLenum kTarget = GL_TEXTURE_2D;
+  const GLint kLevel = 0;
+  const GLenum kFormat = GL_RGB;
+  const GLsizei kWidth = 3;
+  const GLint kBorder = 0;
+  const GLenum kType = GL_UNSIGNED_BYTE;
+  const GLint kPixelStoreUnpackAlignment = 4;
+
+  uint32 size = 0;
+  uint32 unpadded_row_size = 0;
+  uint32 padded_row_size = 0;
+  ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
+      kWidth, 2, 1, kFormat, kType, kPixelStoreUnpackAlignment,
+      &size, &unpadded_row_size, &padded_row_size));
+  const GLsizei kMaxHeight = (MaxTransferBufferSize() / padded_row_size) * 2;
+  const GLsizei kHeight = kMaxHeight * 2;
+  ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
+      kWidth, kHeight, 1, kFormat, kType, kPixelStoreUnpackAlignment,
+      &size, &unpadded_row_size, &padded_row_size));
+
+  scoped_ptr<uint8[]> pixels(new uint8[size]);
+  for (uint32 ii = 0; ii < size; ++ii) {
+    pixels[ii] = static_cast<uint8>(ii);
+  }
+
+  ExpectedMemoryInfo mem1 = GetExpectedMappedMemory(size);
+
+  Cmds expected;
+  expected.tex_image_2d.Init(
+      kTarget, kLevel, kFormat, kWidth, kHeight, kFormat, kType,
+      mem1.id, mem1.offset);
+  expected.set_token.Init(GetNextToken());
+  gl_->TexImage2D(
+      kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+      pixels.get());
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_TRUE(CheckRect(
+      kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment, false,
+      pixels.get(), mem1.ptr));
+}
+
 // Test TexImage2D with 2 writes
-TEST_F(GLES2ImplementationTest, TexImage2D2Writes) {
+TEST_F(GLES2ImplementationTest, TexImage2DViaTexSubImage2D) {
+  // Set limit to 1 to effectively disable mapped memory.
+  SetMappedMemoryLimit(1);
+
   struct Cmds {
     cmds::TexImage2D tex_image_2d;
     cmds::TexSubImage2D tex_sub_image_2d1;
@@ -2726,7 +2797,58 @@
       false, reinterpret_cast<uint8*>(pixels.get()), mem.ptr));
 }
 
+TEST_F(GLES2ImplementationTest, TexImage3DViaMappedMem) {
+  struct Cmds {
+    cmds::TexImage3D tex_image_3d;
+  };
+  const GLenum kTarget = GL_TEXTURE_3D;
+  const GLint kLevel = 0;
+  const GLint kBorder = 0;
+  const GLenum kFormat = GL_RGB;
+  const GLenum kType = GL_UNSIGNED_BYTE;
+  const GLint kPixelStoreUnpackAlignment = 4;
+  const GLsizei kWidth = 3;
+  const GLsizei kDepth = 2;
+
+  uint32 size = 0;
+  uint32 unpadded_row_size = 0;
+  uint32 padded_row_size = 0;
+  ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
+      kWidth, 2, kDepth, kFormat, kType, kPixelStoreUnpackAlignment,
+      &size, &unpadded_row_size, &padded_row_size));
+  // Makes sure we can just send over the data in one command.
+  const GLsizei kMaxHeight = MaxTransferBufferSize() / padded_row_size / kDepth;
+  const GLsizei kHeight = kMaxHeight * 2;
+  ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
+      kWidth, kHeight, kDepth, kFormat, kType, kPixelStoreUnpackAlignment,
+      &size, NULL, NULL));
+
+  scoped_ptr<uint8[]> pixels(new uint8[size]);
+  for (uint32 ii = 0; ii < size; ++ii) {
+    pixels[ii] = static_cast<uint8>(ii);
+  }
+
+  ExpectedMemoryInfo mem = GetExpectedMappedMemory(size);
+
+  Cmds expected;
+  expected.tex_image_3d.Init(
+      kTarget, kLevel, kFormat, kWidth, kHeight, kDepth,
+      kFormat, kType, mem.id, mem.offset);
+
+  gl_->TexImage3D(
+      kTarget, kLevel, kFormat, kWidth, kHeight, kDepth, kBorder,
+      kFormat, kType, pixels.get());
+
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_TRUE(CheckRect(
+      kWidth, kHeight * kDepth, kFormat, kType, kPixelStoreUnpackAlignment,
+      false, reinterpret_cast<uint8*>(pixels.get()), mem.ptr));
+}
+
 TEST_F(GLES2ImplementationTest, TexImage3DViaTexSubImage3D) {
+  // Set limit to 1 to effectively disable mapped memory.
+  SetMappedMemoryLimit(1);
+
   struct Cmds {
     cmds::TexImage3D tex_image_3d;
     cmds::TexSubImage3D tex_sub_image_3d1;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 6b30a53..ae93c084 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -769,5 +769,6 @@
 virtual void SwapInterval(GLint interval) = 0;
 virtual void MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) = 0;
 virtual void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) = 0;
+virtual GLenum GetGraphicsResetStatusKHR() = 0;
 virtual void BlendBarrierKHR() = 0;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 3471376..290bc28 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -749,5 +749,6 @@
 void SwapInterval(GLint interval) override;
 void MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) override;
 void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) override;
+GLenum GetGraphicsResetStatusKHR() override;
 void BlendBarrierKHR() override;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index 1a462d72..aa07a67 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -1274,6 +1274,9 @@
 }
 void GLES2InterfaceStub::MatrixLoadIdentityCHROMIUM(GLenum /* matrixMode */) {
 }
+GLenum GLES2InterfaceStub::GetGraphicsResetStatusKHR() {
+  return 0;
+}
 void GLES2InterfaceStub::BlendBarrierKHR() {
 }
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index d5f0ed9..b017be2 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -749,5 +749,6 @@
 void SwapInterval(GLint interval) override;
 void MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) override;
 void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) override;
+GLenum GetGraphicsResetStatusKHR() override;
 void BlendBarrierKHR() override;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index be4a030..34b0743f 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -2181,6 +2181,11 @@
   gl_->MatrixLoadIdentityCHROMIUM(matrixMode);
 }
 
+GLenum GLES2TraceImplementation::GetGraphicsResetStatusKHR() {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetGraphicsResetStatusKHR");
+  return gl_->GetGraphicsResetStatusKHR();
+}
+
 void GLES2TraceImplementation::BlendBarrierKHR() {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BlendBarrierKHR");
   gl_->BlendBarrierKHR();
diff --git a/gpu/command_buffer/client/gpu_control.h b/gpu/command_buffer/client/gpu_control.h
index 2b303b3..75bd082 100644
--- a/gpu/command_buffer/client/gpu_control.h
+++ b/gpu/command_buffer/client/gpu_control.h
@@ -85,6 +85,10 @@
   // may not be supported with all implementations.
   virtual void SetLock(base::Lock*) = 0;
 
+  // Returns true if the channel to the Gpu is lost. When true, all contexts
+  // should be considered as lost.
+  virtual bool IsGpuChannelLost() = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(GpuControl);
 };
diff --git a/gpu/command_buffer/client/mapped_memory.cc b/gpu/command_buffer/client/mapped_memory.cc
index 6d57af4..7c5864a 100644
--- a/gpu/command_buffer/client/mapped_memory.cc
+++ b/gpu/command_buffer/client/mapped_memory.cc
@@ -30,7 +30,8 @@
       helper_(helper),
       poll_callback_(poll_callback),
       allocated_memory_(0),
-      max_free_bytes_(unused_memory_reclaim_limit) {
+      max_free_bytes_(unused_memory_reclaim_limit),
+      max_allocated_bytes_(kNoLimit) {
 }
 
 MappedMemoryManager::~MappedMemoryManager() {
@@ -81,6 +82,11 @@
     }
   }
 
+  if (max_allocated_bytes_ != kNoLimit &&
+      (allocated_memory_ + size) > max_allocated_bytes_) {
+    return nullptr;
+  }
+
   // Make a new chunk to satisfy the request.
   CommandBuffer* cmd_buf = helper_->command_buffer();
   unsigned int chunk_size =
@@ -140,4 +146,26 @@
   }
 }
 
+void ScopedMappedMemoryPtr::Release() {
+  if (buffer_) {
+    mapped_memory_manager_->FreePendingToken(buffer_, helper_->InsertToken());
+    buffer_ = nullptr;
+    size_ = 0;
+    shm_id_ = 0;
+    shm_offset_ = 0;
+
+    if (flush_after_release_)
+      helper_->CommandBufferHelper::Flush();
+  }
+}
+
+void ScopedMappedMemoryPtr::Reset(uint32_t new_size) {
+  Release();
+
+  if (new_size) {
+    buffer_ = mapped_memory_manager_->Alloc(new_size, &shm_id_, &shm_offset_);
+    size_ = buffer_ ? new_size : 0;
+  }
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/mapped_memory.h b/gpu/command_buffer/client/mapped_memory.h
index 10ac639..55d94e56 100644
--- a/gpu/command_buffer/client/mapped_memory.h
+++ b/gpu/command_buffer/client/mapped_memory.h
@@ -139,6 +139,14 @@
     chunk_size_multiple_ = multiple;
   }
 
+  size_t max_allocated_bytes() const {
+    return max_allocated_bytes_;
+  }
+
+  void set_max_allocated_bytes(size_t max_allocated_bytes) {
+    max_allocated_bytes_ = max_allocated_bytes;
+  }
+
   // Allocates a block of memory
   // Parameters:
   //   size: size of memory to allocate.
@@ -195,10 +203,71 @@
   MemoryChunkVector chunks_;
   size_t allocated_memory_;
   size_t max_free_bytes_;
+  size_t max_allocated_bytes_;
 
   DISALLOW_COPY_AND_ASSIGN(MappedMemoryManager);
 };
 
+// A class that will manage the lifetime of a mapped memory allocation
+class GPU_EXPORT ScopedMappedMemoryPtr {
+ public:
+  ScopedMappedMemoryPtr(
+      uint32_t size,
+      CommandBufferHelper* helper,
+      MappedMemoryManager* mapped_memory_manager)
+      : buffer_(NULL),
+        size_(0),
+        shm_id_(0),
+        shm_offset_(0),
+        flush_after_release_(false),
+        helper_(helper),
+        mapped_memory_manager_(mapped_memory_manager) {
+    Reset(size);
+  }
+
+  ~ScopedMappedMemoryPtr() {
+    Release();
+  }
+
+  bool valid() const {
+    return buffer_ != NULL;
+  }
+
+  void SetFlushAfterRelease(bool flush_after_release) {
+    flush_after_release_ = flush_after_release;
+  }
+
+  uint32_t size() const {
+    return size_;
+  }
+
+  int32_t shm_id() const {
+    return shm_id_;
+  }
+
+  uint32_t offset() const {
+    return shm_offset_;
+  }
+
+  void* address() const {
+    return buffer_;
+  }
+
+  void Release();
+
+  void Reset(uint32_t new_size);
+
+ private:
+  void* buffer_;
+  uint32_t size_;
+  int32_t shm_id_;
+  uint32_t shm_offset_;
+  bool flush_after_release_;
+  CommandBufferHelper* helper_;
+  MappedMemoryManager* mapped_memory_manager_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedMappedMemoryPtr);
+};
+
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_CLIENT_MAPPED_MEMORY_H_
diff --git a/gpu/command_buffer/client/mapped_memory_unittest.cc b/gpu/command_buffer/client/mapped_memory_unittest.cc
index 6430b667..20b4c53 100644
--- a/gpu/command_buffer/client/mapped_memory_unittest.cc
+++ b/gpu/command_buffer/client/mapped_memory_unittest.cc
@@ -394,6 +394,54 @@
   manager_->Free(mem3);
 }
 
+TEST_F(MappedMemoryManagerTest, MaxAllocationTest) {
+  const unsigned int kSize = 1024;
+  // Reset the manager with a memory limit.
+  manager_.reset(new MappedMemoryManager(
+      helper_.get(), base::Bind(&EmptyPoll), kSize));
+
+  const size_t kLimit = 512;
+  manager_->set_chunk_size_multiple(kLimit);
+
+  // Allocate twice the limit worth of memory (currently unbounded).
+  int32 id1 = -1;
+  unsigned int offset1 = 0xFFFFFFFFU;
+  void* mem1 = manager_->Alloc(kLimit, &id1, &offset1);
+  ASSERT_TRUE(mem1);
+  EXPECT_NE(-1, id1);
+  EXPECT_EQ(0u, offset1);
+
+  int32 id2 = -1;
+  unsigned int offset2 = 0xFFFFFFFFU;
+  void* mem2 = manager_->Alloc(kLimit, &id2, &offset2);
+  ASSERT_TRUE(mem2);
+  EXPECT_NE(-1, id2);
+  EXPECT_EQ(0u, offset2);
+
+  manager_->set_max_allocated_bytes(kLimit);
+
+  // A new allocation should now fail.
+  int32 id3 = -1;
+  unsigned int offset3 = 0xFFFFFFFFU;
+  void* mem3 = manager_->Alloc(kLimit, &id3, &offset3);
+  ASSERT_FALSE(mem3);
+  EXPECT_EQ(-1, id3);
+  EXPECT_EQ(0xFFFFFFFFU, offset3);
+
+  manager_->Free(mem2);
+
+  // New allocation is over the limit but should reuse allocated space
+  int32 id4 = -1;
+  unsigned int offset4 = 0xFFFFFFFFU;
+  void* mem4 = manager_->Alloc(kLimit, &id4, &offset4);
+  ASSERT_TRUE(mem4);
+  EXPECT_EQ(id2, id4);
+  EXPECT_EQ(offset2, offset4);
+
+  manager_->Free(mem1);
+  manager_->Free(mem4);
+}
+
 namespace {
 void Poll(MappedMemoryManagerTest *test, std::list<void*>* list) {
   std::list<void*>::iterator it = list->begin();
diff --git a/gpu/command_buffer/client/ring_buffer.cc b/gpu/command_buffer/client/ring_buffer.cc
index 813bb34..c66fc06 100644
--- a/gpu/command_buffer/client/ring_buffer.cc
+++ b/gpu/command_buffer/client/ring_buffer.cc
@@ -103,6 +103,45 @@
   NOTREACHED() << "attempt to free non-existant block";
 }
 
+void RingBuffer::DiscardBlock(void* pointer) {
+  Offset offset = GetOffset(pointer);
+  offset -= base_offset_;
+  DCHECK(!blocks_.empty()) << "no allocations to discard";
+  for (Container::reverse_iterator it = blocks_.rbegin();
+        it != blocks_.rend();
+        ++it) {
+    Block& block = *it;
+    if (block.offset == offset) {
+      DCHECK(block.state != PADDING)
+          << "block that corresponds to offset already discarded";
+      block.state = PADDING;
+
+      // Remove block if it were in the back along with any extra padding.
+      while (!blocks_.empty() && blocks_.back().state == PADDING) {
+        free_offset_= blocks_.back().offset;
+        blocks_.pop_back();
+      }
+
+      // Remove blocks if it were in the front along with extra padding.
+      while (!blocks_.empty() && blocks_.front().state == PADDING) {
+        blocks_.pop_front();
+        if (blocks_.empty())
+          break;
+
+        in_use_offset_ = blocks_.front().offset;
+      }
+
+      // In the special case when there are no blocks, we should be reset it.
+      if (blocks_.empty()) {
+        in_use_offset_ = 0;
+        free_offset_ = 0;
+      }
+      return;
+    }
+  }
+  NOTREACHED() << "attempt to discard non-existant block";
+}
+
 unsigned int RingBuffer::GetLargestFreeSizeNoWaiting() {
   unsigned int last_token_read = helper_->last_token_read();
   while (!blocks_.empty()) {
diff --git a/gpu/command_buffer/client/ring_buffer.h b/gpu/command_buffer/client/ring_buffer.h
index dfe16f7..00de8a5 100644
--- a/gpu/command_buffer/client/ring_buffer.h
+++ b/gpu/command_buffer/client/ring_buffer.h
@@ -54,6 +54,12 @@
   //   token: the token value to wait for before re-using the memory.
   void FreePendingToken(void* pointer, unsigned int token);
 
+  // Discards a block within the ring buffer.
+  //
+  // Parameters:
+  //   pointer: the pointer to the memory block to free.
+  void DiscardBlock(void* pointer);
+
   // Gets the size of the largest free block that is available without waiting.
   unsigned int GetLargestFreeSizeNoWaiting();
 
diff --git a/gpu/command_buffer/client/ring_buffer_test.cc b/gpu/command_buffer/client/ring_buffer_test.cc
index ac5634a..68d2aaa 100644
--- a/gpu/command_buffer/client/ring_buffer_test.cc
+++ b/gpu/command_buffer/client/ring_buffer_test.cc
@@ -204,4 +204,229 @@
   allocator_->FreePendingToken(pointer, helper_.get()->InsertToken());
 }
 
+// Test that discarding a single allocation clears the block.
+TEST_F(RingBufferTest, DiscardTest) {
+  const unsigned int kAlloc1 = 3*kAlignment;
+  void* ptr = allocator_->Alloc(kAlloc1);
+  EXPECT_EQ(kBufferSize - kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->DiscardBlock(ptr);
+  EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSizeNoWaiting());
+}
+
+// Test that discarding front of the buffer effectively frees the block.
+TEST_F(RingBufferTest, DiscardFrontTest) {
+  const unsigned int kAlloc1 = 3*kAlignment;
+  const unsigned int kAlloc2 = 2*kAlignment;
+  const unsigned int kAlloc3 = kBufferSize - kAlloc1 - kAlloc2;
+  void* ptr1 = allocator_->Alloc(kAlloc1);
+  EXPECT_EQ(kBufferSize - kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr1, helper_.get()->InsertToken());
+
+  void* ptr2 = allocator_->Alloc(kAlloc2);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr1) + kAlloc1,
+            static_cast<uint8_t*>(ptr2));
+  EXPECT_EQ(kBufferSize - kAlloc1 - kAlloc2,
+            allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr2, helper_.get()->InsertToken());
+
+  void* ptr3 = allocator_->Alloc(kAlloc3);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr2) + kAlloc2,
+            static_cast<uint8_t*>(ptr3));
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+
+  // Discard first block should free it up upon GetLargestFreeSizeNoWaiting().
+  allocator_->DiscardBlock(ptr1);
+  EXPECT_EQ(kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr3, helper_.get()->InsertToken());
+}
+
+// Test that discarding middle of the buffer merely marks it as padding.
+TEST_F(RingBufferTest, DiscardMiddleTest) {
+  const unsigned int kAlloc1 = 3*kAlignment;
+  const unsigned int kAlloc2 = 2*kAlignment;
+  const unsigned int kAlloc3 = kBufferSize - kAlloc1 - kAlloc2;
+  void* ptr1 = allocator_->Alloc(kAlloc1);
+  EXPECT_EQ(kBufferSize - kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr1, helper_.get()->InsertToken());
+
+  void* ptr2 = allocator_->Alloc(kAlloc2);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr1) + kAlloc1,
+            static_cast<uint8_t*>(ptr2));
+  EXPECT_EQ(kBufferSize - kAlloc1 - kAlloc2,
+            allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr2, helper_.get()->InsertToken());
+
+  void* ptr3 = allocator_->Alloc(kAlloc3);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr2) + kAlloc2,
+            static_cast<uint8_t*>(ptr3));
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+
+  // Discard middle block should just set it as padding.
+  allocator_->DiscardBlock(ptr2);
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr3, helper_.get()->InsertToken());
+}
+
+// Test that discarding end of the buffer frees it for no waiting.
+TEST_F(RingBufferTest, DiscardEndTest) {
+  const unsigned int kAlloc1 = 3*kAlignment;
+  const unsigned int kAlloc2 = 2*kAlignment;
+  const unsigned int kAlloc3 = kBufferSize - kAlloc1 - kAlloc2;
+  void* ptr1 = allocator_->Alloc(kAlloc1);
+  EXPECT_EQ(kBufferSize - kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr1, helper_.get()->InsertToken());
+
+  void* ptr2 = allocator_->Alloc(kAlloc2);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr1) + kAlloc1,
+            static_cast<uint8_t*>(ptr2));
+  EXPECT_EQ(kBufferSize - kAlloc1 - kAlloc2,
+            allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr2, helper_.get()->InsertToken());
+
+  void* ptr3 = allocator_->Alloc(kAlloc3);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr2) + kAlloc2,
+            static_cast<uint8_t*>(ptr3));
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+
+  // Discard end block should discard it.
+  allocator_->DiscardBlock(ptr3);
+  EXPECT_EQ(kAlloc3, allocator_->GetLargestFreeSizeNoWaiting());
+}
+
+// Test discard end of the buffer that has looped around.
+TEST_F(RingBufferTest, DiscardLoopedEndTest) {
+  const unsigned int kAlloc1 = 3*kAlignment;
+  const unsigned int kAlloc2 = 2*kAlignment;
+  const unsigned int kAlloc3 = kBufferSize - kAlloc1 - kAlloc2;
+  void* ptr1 = allocator_->Alloc(kAlloc1);
+  EXPECT_EQ(kBufferSize - kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr1, helper_.get()->InsertToken());
+
+  void* ptr2 = allocator_->Alloc(kAlloc2);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr1) + kAlloc1,
+            static_cast<uint8_t*>(ptr2));
+  EXPECT_EQ(kBufferSize - kAlloc1 - kAlloc2,
+            allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr2, helper_.get()->InsertToken());
+
+  void* ptr3 = allocator_->Alloc(kAlloc3);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr2) + kAlloc2,
+            static_cast<uint8_t*>(ptr3));
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr3, helper_.get()->InsertToken());
+
+  // This allocation should be at the beginning again, we need to utilize
+  // DiscardBlock here to discard the first item so that we can allocate
+  // at the beginning without the FreeOldestBlock() getting called and freeing
+  // the whole ring buffer.
+  allocator_->DiscardBlock(ptr1);
+  void* ptr4 = allocator_->Alloc(kAlloc1);
+  EXPECT_EQ(ptr1, ptr4);
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+
+  // Discard end block should work properly still.
+  allocator_->DiscardBlock(ptr4);
+  EXPECT_EQ(kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+}
+
+// Test discard end of the buffer that has looped around with padding.
+TEST_F(RingBufferTest, DiscardEndWithPaddingTest) {
+  const unsigned int kAlloc1 = 3*kAlignment;
+  const unsigned int kAlloc2 = 2*kAlignment;
+  const unsigned int kPadding = kAlignment;
+  const unsigned int kAlloc3 = kBufferSize - kAlloc1 - kAlloc2 - kPadding;
+  void* ptr1 = allocator_->Alloc(kAlloc1);
+  EXPECT_EQ(kBufferSize - kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr1, helper_.get()->InsertToken());
+
+  void* ptr2 = allocator_->Alloc(kAlloc2);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr1) + kAlloc1,
+            static_cast<uint8_t*>(ptr2));
+  EXPECT_EQ(kBufferSize - kAlloc1 - kAlloc2,
+            allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr2, helper_.get()->InsertToken());
+
+  void* ptr3 = allocator_->Alloc(kAlloc3);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr2) + kAlloc2,
+            static_cast<uint8_t*>(ptr3));
+  EXPECT_EQ(kPadding, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr3, helper_.get()->InsertToken());
+
+  // Cause it to loop around with padding at the end of ptr3.
+  allocator_->DiscardBlock(ptr1);
+  void* ptr4 = allocator_->Alloc(kAlloc1);
+  EXPECT_EQ(ptr1, ptr4);
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+
+  // Discard end block should also discard the padding.
+  allocator_->DiscardBlock(ptr4);
+  EXPECT_EQ(kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+
+  // We can test that there is padding by attempting to allocate the padding.
+  void* padding = allocator_->Alloc(kPadding);
+  EXPECT_EQ(kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(padding, helper_.get()->InsertToken());
+}
+
+// Test that discard will effectively remove all padding at the end.
+TEST_F(RingBufferTest, DiscardAllPaddingFromEndTest) {
+  const unsigned int kAlloc1 = 3*kAlignment;
+  const unsigned int kAlloc2 = 2*kAlignment;
+  const unsigned int kAlloc3 = kBufferSize - kAlloc1 - kAlloc2;
+  void* ptr1 = allocator_->Alloc(kAlloc1);
+  EXPECT_EQ(kBufferSize - kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr1, helper_.get()->InsertToken());
+
+  void* ptr2 = allocator_->Alloc(kAlloc2);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr1) + kAlloc1,
+            static_cast<uint8_t*>(ptr2));
+  EXPECT_EQ(kBufferSize - kAlloc1 - kAlloc2,
+            allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr2, helper_.get()->InsertToken());
+
+  void* ptr3 = allocator_->Alloc(kAlloc3);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr2) + kAlloc2,
+            static_cast<uint8_t*>(ptr3));
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+
+  // Discarding the middle allocation should turn it into padding.
+  allocator_->DiscardBlock(ptr2);
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+
+  // Discarding the last allocation should discard the middle padding as well.
+  allocator_->DiscardBlock(ptr3);
+  EXPECT_EQ(kAlloc2 + kAlloc3, allocator_->GetLargestFreeSizeNoWaiting());
+}
+
+// Test that discard will effectively remove all padding from the beginning.
+TEST_F(RingBufferTest, DiscardAllPaddingFromBeginningTest) {
+  const unsigned int kAlloc1 = 3*kAlignment;
+  const unsigned int kAlloc2 = 2*kAlignment;
+  const unsigned int kAlloc3 = kBufferSize - kAlloc1 - kAlloc2;
+  void* ptr1 = allocator_->Alloc(kAlloc1);
+  EXPECT_EQ(kBufferSize - kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr1, helper_.get()->InsertToken());
+
+  void* ptr2 = allocator_->Alloc(kAlloc2);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr1) + kAlloc1,
+            static_cast<uint8_t*>(ptr2));
+  EXPECT_EQ(kBufferSize - kAlloc1 - kAlloc2,
+            allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr2, helper_.get()->InsertToken());
+
+  void* ptr3 = allocator_->Alloc(kAlloc3);
+  EXPECT_EQ(static_cast<uint8_t*>(ptr2) + kAlloc2,
+            static_cast<uint8_t*>(ptr3));
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+  allocator_->FreePendingToken(ptr3, helper_.get()->InsertToken());
+
+  // Discarding the middle allocation should turn it into padding.
+  allocator_->DiscardBlock(ptr2);
+  EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+
+  // Discarding the first allocation should discard the middle padding as well.
+  allocator_->DiscardBlock(ptr1);
+  EXPECT_EQ(kAlloc1 + kAlloc2, allocator_->GetLargestFreeSizeNoWaiting());
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/transfer_buffer.cc b/gpu/command_buffer/client/transfer_buffer.cc
index cb02f151..3ff257d 100644
--- a/gpu/command_buffer/client/transfer_buffer.cc
+++ b/gpu/command_buffer/client/transfer_buffer.cc
@@ -73,6 +73,10 @@
   return ring_buffer_->GetOffset(pointer);
 }
 
+void TransferBuffer::DiscardBlock(void* p) {
+  ring_buffer_->DiscardBlock(p);
+}
+
 void TransferBuffer::FreePendingToken(void* p, unsigned int token) {
   ring_buffer_->FreePendingToken(p, token);
   if (bytes_since_last_flush_ >= size_to_flush_ && size_to_flush_ > 0) {
@@ -188,6 +192,14 @@
   }
 }
 
+void ScopedTransferBufferPtr::Discard() {
+  if (buffer_) {
+    transfer_buffer_->DiscardBlock(buffer_);
+    buffer_ = NULL;
+    size_ = 0;
+  }
+}
+
 void ScopedTransferBufferPtr::Reset(unsigned int new_size) {
   Release();
   // NOTE: we allocate buffers of size 0 so that HaveBuffer will be true, so
diff --git a/gpu/command_buffer/client/transfer_buffer.h b/gpu/command_buffer/client/transfer_buffer.h
index 39e62a6..e1f8e91b 100644
--- a/gpu/command_buffer/client/transfer_buffer.h
+++ b/gpu/command_buffer/client/transfer_buffer.h
@@ -47,6 +47,8 @@
 
   virtual RingBuffer::Offset GetOffset(void* pointer) const = 0;
 
+  virtual void DiscardBlock(void* p) = 0;
+
   virtual void FreePendingToken(void* p, unsigned int token) = 0;
 };
 
@@ -71,6 +73,7 @@
   void* AllocUpTo(unsigned int size, unsigned int* size_allocated) override;
   void* Alloc(unsigned int size) override;
   RingBuffer::Offset GetOffset(void* pointer) const override;
+  void DiscardBlock(void* p) override;
   void FreePendingToken(void* p, unsigned int token) override;
 
   // These are for testing.
@@ -163,6 +166,8 @@
 
   void Release();
 
+  void Discard();
+
   void Reset(unsigned int new_size);
 
  private:
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index f154161..3613d8a 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -313,5 +313,8 @@
 GL_APICALL void         GL_APIENTRY glMatrixLoadfCHROMIUM (GLenumMatrixMode matrixMode, const GLfloat* m);
 GL_APICALL void         GL_APIENTRY glMatrixLoadIdentityCHROMIUM (GLenumMatrixMode matrixMode);
 
+// Extension KHR_robustness
+GL_APICALL GLenum	GL_APIENTRY glGetGraphicsResetStatusKHR (void);
+
 // Extension KHR_blend_equation_advanced
 GL_APICALL void GL_APIENTRY glBlendBarrierKHR (void);
diff --git a/gpu/command_buffer/common/capabilities.cc b/gpu/command_buffer/common/capabilities.cc
index 43faad7..8a22871 100644
--- a/gpu/command_buffer/common/capabilities.cc
+++ b/gpu/command_buffer/common/capabilities.cc
@@ -29,6 +29,7 @@
       max_combined_fragment_uniform_components(0),
       max_combined_uniform_blocks(0),
       max_combined_vertex_uniform_components(0),
+      max_copy_texture_chromium_size(0),
       max_draw_buffers(0),
       max_element_index(0),
       max_elements_indices(0),
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h
index 77309308..efae9a70 100644
--- a/gpu/command_buffer/common/capabilities.h
+++ b/gpu/command_buffer/common/capabilities.h
@@ -87,6 +87,7 @@
   int64_t max_combined_fragment_uniform_components;
   int max_combined_uniform_blocks;
   int64_t max_combined_vertex_uniform_components;
+  int max_copy_texture_chromium_size;
   int max_draw_buffers;
   int64_t max_element_index;
   int max_elements_indices;
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index be454295..7a33ab1 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -1082,7 +1082,7 @@
 const int32 kBindGeneratesResource = 0x10000;
 const int32 kFailIfMajorPerfCaveat = 0x10001;
 const int32 kLoseContextWhenOutOfMemory = 0x10002;
-const int32 kES3ContextRequired = 0x10003;
+const int32 kWebGLVersion = 0x10003;
 
 }  // namespace
 
@@ -1099,7 +1099,8 @@
       bind_generates_resource(true),
       fail_if_major_perf_caveat(false),
       lose_context_when_out_of_memory(false),
-      es3_context_required(false) {}
+      webgl_version(0) {
+}
 
 void ContextCreationAttribHelper::Serialize(std::vector<int32>* attribs) const {
   if (alpha_size != -1) {
@@ -1142,8 +1143,8 @@
   attribs->push_back(fail_if_major_perf_caveat ? 1 : 0);
   attribs->push_back(kLoseContextWhenOutOfMemory);
   attribs->push_back(lose_context_when_out_of_memory ? 1 : 0);
-  attribs->push_back(kES3ContextRequired);
-  attribs->push_back(es3_context_required ? 1 : 0);
+  attribs->push_back(kWebGLVersion);
+  attribs->push_back(webgl_version);
   attribs->push_back(kNone);
 }
 
@@ -1198,8 +1199,8 @@
       case kLoseContextWhenOutOfMemory:
         lose_context_when_out_of_memory = value != 0;
         break;
-      case kES3ContextRequired:
-        es3_context_required = value != 0;
+      case kWebGLVersion:
+        webgl_version = value;
         break;
       case kNone:
         // Terminate list, even if more attributes.
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index aac9d603..12b1551 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -216,7 +216,8 @@
   bool bind_generates_resource;
   bool fail_if_major_perf_caveat;
   bool lose_context_when_out_of_memory;
-  bool es3_context_required;
+  // 0 if not a WebGL context.
+  unsigned webgl_version;
 };
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc b/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
index 971dc0d7..1d76dd5d 100644
--- a/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
+++ b/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
@@ -90,10 +90,11 @@
 class TransferThread : public base::Thread {
  public:
   TransferThread() : base::Thread(kAsyncTransferThreadName) {
-    Start();
+    base::Thread::Options options;
 #if defined(OS_ANDROID) || defined(OS_LINUX)
-    SetPriority(base::ThreadPriority::BACKGROUND);
+    options.priority = base::ThreadPriority::BACKGROUND;
 #endif
+    StartWithOptions(options);
   }
   ~TransferThread() override { Stop(); }
 
diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc b/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc
index 3c65f72..86eb718 100644
--- a/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc
+++ b/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc
@@ -47,10 +47,11 @@
   TransferThread()
       : base::Thread(kAsyncTransferThreadName),
         initialized_(false) {
-    Start();
+    base::Thread::Options options;
 #if defined(OS_ANDROID) || defined(OS_LINUX)
-    SetPriority(base::ThreadPriority::BACKGROUND);
+    options.priority = base::ThreadPriority::BACKGROUND;
 #endif
+    StartWithOptions(options);
   }
 
   ~TransferThread() override {
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index 98ebbdbd..f41584ab8 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -35,7 +35,8 @@
     const scoped_refptr<SubscriptionRefSet>& subscription_ref_set,
     const scoped_refptr<ValueStateMap>& pending_valuebuffer_state,
     bool bind_generates_resource)
-    : mailbox_manager_(mailbox_manager),
+    : context_type_(CONTEXT_TYPE_UNDEFINED),
+      mailbox_manager_(mailbox_manager),
       memory_tracker_(memory_tracker),
       shader_translator_cache_(shader_translator_cache),
       subscription_ref_set_(subscription_ref_set),
@@ -76,9 +77,38 @@
   *var = value;
 }
 
+// static
+ContextGroup::ContextType ContextGroup::GetContextType(
+    unsigned webgl_version) {
+  switch (webgl_version) {
+    case 0:
+      return CONTEXT_TYPE_OTHER;
+    case 1:
+      return CONTEXT_TYPE_WEBGL1;
+    case 2:
+      return CONTEXT_TYPE_WEBGL2;
+    default:
+      return CONTEXT_TYPE_UNDEFINED;
+  }
+}
+
 bool ContextGroup::Initialize(
     GLES2Decoder* decoder,
+    ContextGroup::ContextType context_type,
     const DisallowedFeatures& disallowed_features) {
+  if (context_type == CONTEXT_TYPE_UNDEFINED) {
+    LOG(ERROR) << "ContextGroup::Initialize failed because of unknown "
+               << "context type.";
+    return false;
+  }
+  if (context_type_ == CONTEXT_TYPE_UNDEFINED) {
+    context_type_ = context_type;
+  } else if (context_type_ != context_type) {
+    LOG(ERROR) << "ContextGroup::Initialize failed because the type of "
+               << "the context does not fit with the group.";
+    return false;
+  }
+
   // If we've already initialized the group just add the context.
   if (HaveContexts()) {
     decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index 95cd4be2..b2daa4c 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -44,6 +44,15 @@
 // resources.
 class GPU_EXPORT ContextGroup : public base::RefCounted<ContextGroup> {
  public:
+  enum ContextType {
+    CONTEXT_TYPE_WEBGL1,
+    CONTEXT_TYPE_WEBGL2,
+    CONTEXT_TYPE_OTHER,
+    CONTEXT_TYPE_UNDEFINED
+  };
+
+  static ContextType GetContextType(unsigned webgl_version);
+
   ContextGroup(
       const scoped_refptr<MailboxManager>& mailbox_manager,
       const scoped_refptr<MemoryTracker>& memory_tracker,
@@ -57,6 +66,7 @@
   // call to destroy if it succeeds.
   bool Initialize(
       GLES2Decoder* decoder,
+      ContextType context_type,
       const DisallowedFeatures& disallowed_features);
 
   // Destroys all the resources when called for the last context in the group.
@@ -249,6 +259,8 @@
   bool QueryGLFeatureU(GLenum pname, GLint min_required, uint32* v);
   bool HaveContexts();
 
+  ContextType context_type_;
+
   scoped_refptr<MailboxManager> mailbox_manager_;
   scoped_refptr<MemoryTracker> memory_tracker_;
   scoped_refptr<ShaderTranslatorCache> shader_translator_cache_;
diff --git a/gpu/command_buffer/service/context_group_unittest.cc b/gpu/command_buffer/service/context_group_unittest.cc
index afd343d..7c6d5c1 100644
--- a/gpu/command_buffer/service/context_group_unittest.cc
+++ b/gpu/command_buffer/service/context_group_unittest.cc
@@ -68,7 +68,8 @@
 TEST_F(ContextGroupTest, InitializeNoExtensions) {
   TestHelper::SetupContextGroupInitExpectations(
       gl_.get(), DisallowedFeatures(), "", "", kBindGeneratesResource);
-  group_->Initialize(decoder_.get(), DisallowedFeatures());
+  group_->Initialize(
+      decoder_.get(), ContextGroup::CONTEXT_TYPE_OTHER, DisallowedFeatures());
   EXPECT_EQ(static_cast<uint32>(TestHelper::kNumVertexAttribs),
             group_->max_vertex_attribs());
   EXPECT_EQ(static_cast<uint32>(TestHelper::kNumTextureUnits),
@@ -103,8 +104,19 @@
   scoped_ptr<MockGLES2Decoder> decoder2_(new MockGLES2Decoder());
   TestHelper::SetupContextGroupInitExpectations(
       gl_.get(), DisallowedFeatures(), "", "", kBindGeneratesResource);
-  group_->Initialize(decoder_.get(), DisallowedFeatures());
-  group_->Initialize(decoder2_.get(), DisallowedFeatures());
+  EXPECT_TRUE(group_->Initialize(
+      decoder_.get(), ContextGroup::CONTEXT_TYPE_OTHER, DisallowedFeatures()));
+  EXPECT_FALSE(group_->Initialize(
+      decoder2_.get(), ContextGroup::CONTEXT_TYPE_WEBGL1,
+      DisallowedFeatures()));
+  EXPECT_FALSE(group_->Initialize(
+      decoder2_.get(), ContextGroup::CONTEXT_TYPE_WEBGL2,
+      DisallowedFeatures()));
+  EXPECT_FALSE(group_->Initialize(
+      decoder2_.get(), ContextGroup::CONTEXT_TYPE_UNDEFINED,
+      DisallowedFeatures()));
+  EXPECT_TRUE(group_->Initialize(
+      decoder2_.get(), ContextGroup::CONTEXT_TYPE_OTHER, DisallowedFeatures()));
 
   EXPECT_TRUE(group_->buffer_manager() != NULL);
   EXPECT_TRUE(group_->framebuffer_manager() != NULL);
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index c86de231..50114850 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -114,6 +114,9 @@
     workarounds->max_varying_vectors = 16;
   if (workarounds->max_vertex_uniform_vectors_256)
     workarounds->max_vertex_uniform_vectors = 256;
+
+  if (workarounds->max_copy_texture_chromium_size_262144)
+    workarounds->max_copy_texture_chromium_size = 262144;
 }
 
 }  // anonymous namespace.
@@ -175,7 +178,8 @@
     max_cube_map_texture_size(0),
     max_fragment_uniform_vectors(0),
     max_varying_vectors(0),
-    max_vertex_uniform_vectors(0) {
+    max_vertex_uniform_vectors(0),
+    max_copy_texture_chromium_size(0) {
 }
 
 FeatureInfo::FeatureInfo() {
@@ -523,10 +527,11 @@
   }
 
   // Check if we should allow GL_OES_texture_npot
-  if (gl_version_info_->is_es3 ||
-      gl_version_info_->is_desktop_core_profile ||
-      extensions.Contains("GL_ARB_texture_non_power_of_two") ||
-      extensions.Contains("GL_OES_texture_npot")) {
+  if (!disallowed_features_.npot_support &&
+      (gl_version_info_->is_es3 ||
+       gl_version_info_->is_desktop_core_profile ||
+       extensions.Contains("GL_ARB_texture_non_power_of_two") ||
+       extensions.Contains("GL_OES_texture_npot"))) {
     AddExtensionString("GL_OES_texture_npot");
     feature_flags_.npot_ok = true;
   }
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index a26614f..6d2988d8 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -94,6 +94,7 @@
     GLint max_fragment_uniform_vectors;
     GLint max_varying_vectors;
     GLint max_vertex_uniform_vectors;
+    GLint max_copy_texture_chromium_size;
   };
 
   // Constructor with workarounds taken from the current process's CommandLine
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index f2db39f..9c66e440 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -73,10 +73,6 @@
 #include <OpenGL/CGLIOSurface.h>
 #endif
 
-#if defined(OS_WIN)
-#include "base/win/win_util.h"
-#endif
-
 namespace gpu {
 namespace gles2 {
 
@@ -712,7 +708,6 @@
   void SetAsyncPixelTransferManagerForTest(
       AsyncPixelTransferManager* manager) override;
   void SetIgnoreCachedStateForTest(bool ignore) override;
-  void SetAllowExit(bool allow_exit) override;
   void ProcessFinishedAsyncTransfers();
 
   bool GetServiceTextureId(uint32 client_texture_id,
@@ -868,6 +863,10 @@
     return true;
   }
 
+  bool IsWebGLContext() const {
+    return webgl_version_ == 1 || webgl_version_ == 2;
+  }
+
   bool IsOffscreenBufferMultisampled() const {
     return offscreen_target_samples_ > 1;
   }
@@ -1972,12 +1971,17 @@
   bool reset_by_robustness_extension_;
   bool supports_post_sub_buffer_;
 
+  // Indicates whether this is a context for WebGL1, WebGL2, or others.
+  //   0: other types
+  //   1: WebGL 1
+  //   2: WebGL 2
+  unsigned webgl_version_;
+
   // These flags are used to override the state of the shared feature_info_
   // member.  Because the same FeatureInfo instance may be shared among many
   // contexts, the assumptions on the availablity of extensions in WebGL
   // contexts may be broken.  These flags override the shared state to preserve
   // WebGL semantics.
-  bool force_webgl_glsl_validation_;
   bool derivatives_explicitly_enabled_;
   bool frag_depth_explicitly_enabled_;
   bool draw_buffers_explicitly_enabled_;
@@ -2025,8 +2029,6 @@
   GLuint validation_fbo_multisample_;
   GLuint validation_fbo_;
 
-  bool allow_exit_;
-
   typedef gpu::gles2::GLES2Decoder::Error (GLES2DecoderImpl::*CmdHandler)(
       uint32 immediate_data_size,
       const void* data);
@@ -2516,7 +2518,7 @@
       context_was_lost_(false),
       reset_by_robustness_extension_(false),
       supports_post_sub_buffer_(false),
-      force_webgl_glsl_validation_(false),
+      webgl_version_(0),
       derivatives_explicitly_enabled_(false),
       frag_depth_explicitly_enabled_(false),
       draw_buffers_explicitly_enabled_(false),
@@ -2539,8 +2541,7 @@
       gpu_debug_commands_(false),
       validation_texture_(0),
       validation_fbo_multisample_(0),
-      validation_fbo_(0),
-      allow_exit_(false) {
+      validation_fbo_(0) {
   DCHECK(group);
 
   // The shader translator is used for WebGL even when running on EGL
@@ -2573,6 +2574,7 @@
   ContextCreationAttribHelper attrib_parser;
   if (!attrib_parser.Parse(attribs))
     return false;
+  webgl_version_ = attrib_parser.webgl_version;
 
   surfaceless_ = surface->IsSurfaceless() && !offscreen;
 
@@ -2614,23 +2616,30 @@
     return false;
   }
 
-  if (!group_->Initialize(this, disallowed_features)) {
-    LOG(ERROR) << "GpuScheduler::InitializeCommon failed because group "
-               << "failed to initialize.";
+  disallowed_features_ = disallowed_features;
+  if (webgl_version_ == 1) {
+    disallowed_features_.npot_support = true;
+  }
+
+  if (!group_->Initialize(this,
+                          ContextGroup::GetContextType(webgl_version_),
+                          disallowed_features_)) {
     group_ = NULL;  // Must not destroy ContextGroup if it is not initialized.
     Destroy(true);
     return false;
   }
   CHECK_GL_ERROR();
 
-  if (attrib_parser.es3_context_required &&
-      feature_info_->IsES3Capable()) {
+  if (webgl_version_ == 2) {
+    if (!feature_info_->IsES3Capable()) {
+      LOG(ERROR) << "Underlying driver does not support ES3.";
+      Destroy(true);
+      return false;
+    }
     feature_info_->EnableES3Validators();
     set_unsafe_es3_apis_enabled(true);
   }
 
-  disallowed_features_ = disallowed_features;
-
   state_.attrib_values.resize(group_->max_vertex_attribs());
   vertex_array_manager_.reset(new VertexArrayManager());
 
@@ -3118,6 +3127,8 @@
   caps.blend_equation_advanced_coherent =
       feature_info_->feature_flags().blend_equation_advanced_coherent;
   caps.texture_rg = feature_info_->feature_flags().ext_texture_rg;
+  caps.max_copy_texture_chromium_size =
+      feature_info_->workarounds().max_copy_texture_chromium_size;
   return caps;
 }
 
@@ -3157,7 +3168,7 @@
   resources.FragmentPrecisionHigh =
       PrecisionMeetsSpecForHighpFloat(range[0], range[1], precision);
 
-  if (force_webgl_glsl_validation_) {
+  if (IsWebGLContext()) {
     resources.OES_standard_derivatives = derivatives_explicitly_enabled_;
     resources.EXT_frag_depth = frag_depth_explicitly_enabled_;
     resources.EXT_draw_buffers = draw_buffers_explicitly_enabled_;
@@ -3184,8 +3195,8 @@
   }
 
   ShShaderSpec shader_spec;
-  if (force_webgl_glsl_validation_) {
-    shader_spec = unsafe_es3_apis_enabled() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC;
+  if (IsWebGLContext()) {
+    shader_spec = webgl_version_ == 2 ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC;
   } else {
     shader_spec = unsafe_es3_apis_enabled() ? SH_GLES3_SPEC : SH_GLES2_SPEC;
   }
@@ -4520,10 +4531,6 @@
   state_.SetIgnoreCachedStateForTest(ignore);
 }
 
-void GLES2DecoderImpl::SetAllowExit(bool allow_exit) {
-  allow_exit_ = allow_exit;
-}
-
 void GLES2DecoderImpl::OnFboChanged() const {
   if (workarounds().restore_scissor_on_fbo_change)
     state_.fbo_binding_for_scissor_workaround_dirty = true;
@@ -5696,9 +5703,10 @@
       state_.color_clear_alpha);
   glClearStencil(state_.stencil_clear);
   glClearDepth(state_.depth_clear);
-  if (state_.enable_flags.scissor_test) {
-    state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, true);
-  }
+  state_.SetDeviceCapabilityState(GL_SCISSOR_TEST,
+                                  state_.enable_flags.scissor_test);
+  glScissor(state_.scissor_x, state_.scissor_y, state_.scissor_width,
+            state_.scissor_height);
 }
 
 GLenum GLES2DecoderImpl::DoCheckFramebufferStatus(GLenum target) {
@@ -8804,16 +8812,22 @@
   std::string extensions;
   switch (name) {
     case GL_VERSION:
-      str = "OpenGL ES 2.0 Chromium";
+      if (unsafe_es3_apis_enabled())
+        str = "OpenGL ES 3.0 Chromium";
+      else
+        str = "OpenGL ES 2.0 Chromium";
       break;
     case GL_SHADING_LANGUAGE_VERSION:
-      str = "OpenGL ES GLSL ES 1.0 Chromium";
+      if (unsafe_es3_apis_enabled())
+        str = "OpenGL ES GLSL ES 3.0 Chromium";
+      else
+        str = "OpenGL ES GLSL ES 1.0 Chromium";
       break;
     case GL_RENDERER:
     case GL_VENDOR:
       // Return the unmasked VENDOR/RENDERER string for WebGL contexts.
       // They are used by WEBGL_debug_renderer_info.
-      if (!force_webgl_glsl_validation_)
+      if (!IsWebGLContext())
         str = "Chromium";
       else
         str = reinterpret_cast<const char*>(glGetString(name));
@@ -8822,7 +8836,7 @@
       {
         // For WebGL contexts, strip out the OES derivatives and
         // EXT frag depth extensions if they have not been enabled.
-        if (force_webgl_glsl_validation_) {
+        if (IsWebGLContext()) {
           extensions = feature_info_->extensions();
           if (!derivatives_explicitly_enabled_) {
             size_t offset = extensions.find(kOESDerivativeExtension);
@@ -8935,7 +8949,6 @@
     glScissor(xoffset, yoffset, width, height);
     glClear(GL_DEPTH_BUFFER_BIT | (have_stencil ? GL_STENCIL_BUFFER_BIT : 0));
 
-    state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, false);
     RestoreClearState();
 
     glDeleteFramebuffersEXT(1, &fb);
@@ -11131,9 +11144,6 @@
     // needs to be done it seems like refactoring for one to one of those
     // methods is a very low priority.
     const_cast<Validators*>(validators_)->vertex_attrib_type.AddValue(GL_FIXED);
-  } else if (feature_str.compare("webgl_enable_glsl_webgl_validation") == 0) {
-    force_webgl_glsl_validation_ = true;
-    InitializeShaderTranslator();
   } else {
     return error::kNoError;
   }
@@ -11169,13 +11179,11 @@
     return error::kInvalidArguments;
   }
 
-  bool desire_webgl_glsl_validation =
-      feature_str.find("GL_CHROMIUM_webglsl") != std::string::npos;
   bool desire_standard_derivatives = false;
   bool desire_frag_depth = false;
   bool desire_draw_buffers = false;
   bool desire_shader_texture_lod = false;
-  if (force_webgl_glsl_validation_) {
+  if (IsWebGLContext()) {
     desire_standard_derivatives =
         feature_str.find("GL_OES_standard_derivatives") != std::string::npos;
     desire_frag_depth =
@@ -11186,11 +11194,10 @@
         feature_str.find("GL_EXT_shader_texture_lod") != std::string::npos;
   }
 
-  if (desire_webgl_glsl_validation != force_webgl_glsl_validation_ ||
-      desire_standard_derivatives != derivatives_explicitly_enabled_ ||
+  if (desire_standard_derivatives != derivatives_explicitly_enabled_ ||
       desire_frag_depth != frag_depth_explicitly_enabled_ ||
-      desire_draw_buffers != draw_buffers_explicitly_enabled_) {
-    force_webgl_glsl_validation_ |= desire_webgl_glsl_validation;
+      desire_draw_buffers != draw_buffers_explicitly_enabled_ ||
+      desire_shader_texture_lod != shader_texture_lod_explicitly_enabled_) {
     derivatives_explicitly_enabled_ |= desire_standard_derivatives;
     frag_depth_explicitly_enabled_ |= desire_frag_depth;
     draw_buffers_explicitly_enabled_ |= desire_draw_buffers;
@@ -11378,16 +11385,6 @@
   context_lost_reason_ = reason;
   current_decoder_error_ = error::kLostContext;
   context_was_lost_ = true;
-
-  // Work around issues with recovery by allowing a new GPU process to launch.
-  if (workarounds().exit_on_context_lost && allow_exit_) {
-    LOG(ERROR) << "Exiting GPU process because some drivers cannot recover"
-               << " from problems.";
-#if defined(OS_WIN)
-    base::win::SetShouldCrashOnProcessDetach(false);
-#endif
-    exit(0);
-  }
 }
 
 bool GLES2DecoderImpl::CheckResetStatus() {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 26f695c..3ad8a6f 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -45,10 +45,12 @@
 
 struct DisallowedFeatures {
   DisallowedFeatures()
-      : gpu_memory_manager(false) {
+      : gpu_memory_manager(false),
+        npot_support(false) {
   }
 
   bool gpu_memory_manager;
+  bool npot_support;
 };
 
 typedef base::Callback<void(const std::string& key,
@@ -171,10 +173,6 @@
 
   virtual void SetIgnoreCachedStateForTest(bool ignore) = 0;
 
-  // Allow the decoder to exit the current process.
-  // Defaults to |false|.
-  virtual void SetAllowExit(bool allow_exit) = 0;
-
   // Gets the QueryManager for this context.
   virtual QueryManager* GetQueryManager() = 0;
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index dee67f72..0201cf3 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -95,6 +95,7 @@
   InitState init;
   init.gl_version = "OpenGL ES 3.0";
   init.bind_generates_resource = true;
+  init.webgl_version = 2;
   InitDecoderWithCommandLine(init, &command_line);
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index b9fd068..276cb7d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -63,7 +63,7 @@
       return;
     if (!init->extensions.empty())
       init->extensions += " ";
-    if (StartsWithASCII(init->gl_version, "opengl es", false)) {
+    if (base::StartsWithASCII(init->gl_version, "opengl es", false)) {
       init->extensions += kVAOExtensions[0];
     } else {
 #if !defined(OS_MACOSX)
@@ -157,7 +157,8 @@
       request_stencil(false),
       bind_generates_resource(false),
       lose_context_when_out_of_memory(false),
-      use_native_vao(true) {
+      use_native_vao(true),
+      webgl_version(0) {
 }
 
 void GLES2DecoderTestBase::InitDecoder(const InitState& init) {
@@ -227,10 +228,13 @@
   EXPECT_CALL(*mock_decoder_, DoCommands(_, _, _, _)).WillRepeatedly(
       Invoke(mock_decoder_.get(), &MockGLES2Decoder::FakeDoCommands));
 
-  EXPECT_TRUE(
-      group_->Initialize(mock_decoder_.get(), DisallowedFeatures()));
 
-  if (group_->feature_info()->IsES3Capable()) {
+  EXPECT_TRUE(group_->Initialize(
+      mock_decoder_.get(),
+      ContextGroup::GetContextType(init.webgl_version),
+      DisallowedFeatures()));
+
+  if (init.webgl_version == 2) {
     EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_COLOR_ATTACHMENTS, _))
         .WillOnce(SetArgumentPointee<1>(kMaxColorAttachments))
         .RetiresOnSaturation();
@@ -400,9 +404,7 @@
   shared_memory_base_ = buffer->memory();
 
   static const int32 kLoseContextWhenOutOfMemory = 0x10002;
-  static const int32 kES3ContextRequired = 0x10003;
-
-  bool es3_context_required = group_->feature_info()->IsES3Capable();
+  static const int32 kWebGLVersion = 0x10003;
 
   int32 attributes[] = {
       EGL_ALPHA_SIZE,
@@ -413,8 +415,8 @@
       normalized_init.request_stencil ? 8 : 0,
       kLoseContextWhenOutOfMemory,
       normalized_init.lose_context_when_out_of_memory ? 1 : 0,
-      kES3ContextRequired,
-      es3_context_required ? 1 : 0
+      kWebGLVersion,
+      init.webgl_version
   };
   std::vector<int32> attribs(attributes, attributes + arraysize(attributes));
 
@@ -690,19 +692,16 @@
     GLclampf restore_alpha,
     GLuint restore_stencil,
     GLclampf restore_depth,
-    bool restore_scissor_test) {
+    bool restore_scissor_test,
+    GLint restore_scissor_x,
+    GLint restore_scissor_y,
+    GLsizei restore_scissor_width,
+    GLsizei restore_scissor_height) {
   SetupExpectationsForFramebufferClearingMulti(
-      0,
-      0,
-      target,
-      clear_bits,
-      restore_red,
-      restore_green,
-      restore_blue,
-      restore_alpha,
-      restore_stencil,
-      restore_depth,
-      restore_scissor_test);
+      0, 0, target, clear_bits, restore_red, restore_green, restore_blue,
+      restore_alpha, restore_stencil, restore_depth, restore_scissor_test,
+      restore_scissor_x, restore_scissor_y, restore_scissor_width,
+      restore_scissor_height);
 }
 
 void GLES2DecoderTestBase::SetupExpectationsForRestoreClearState(
@@ -712,7 +711,11 @@
     GLclampf restore_alpha,
     GLuint restore_stencil,
     GLclampf restore_depth,
-    bool restore_scissor_test) {
+    bool restore_scissor_test,
+    GLint restore_scissor_x,
+    GLint restore_scissor_y,
+    GLsizei restore_scissor_width,
+    GLsizei restore_scissor_height) {
   EXPECT_CALL(*gl_, ClearColor(
       restore_red, restore_green, restore_blue, restore_alpha))
       .Times(1)
@@ -723,11 +726,11 @@
   EXPECT_CALL(*gl_, ClearDepth(restore_depth))
       .Times(1)
       .RetiresOnSaturation();
-  if (restore_scissor_test) {
-    EXPECT_CALL(*gl_, Enable(GL_SCISSOR_TEST))
-        .Times(1)
-        .RetiresOnSaturation();
-  }
+  SetupExpectationsForEnableDisable(GL_SCISSOR_TEST, restore_scissor_test);
+  EXPECT_CALL(*gl_, Scissor(restore_scissor_x, restore_scissor_y,
+                            restore_scissor_width, restore_scissor_height))
+      .Times(1)
+      .RetiresOnSaturation();
 }
 
 void GLES2DecoderTestBase::SetupExpectationsForFramebufferClearingMulti(
@@ -741,7 +744,11 @@
     GLclampf restore_alpha,
     GLuint restore_stencil,
     GLclampf restore_depth,
-    bool restore_scissor_test) {
+    bool restore_scissor_test,
+    GLint restore_scissor_x,
+    GLint restore_scissor_y,
+    GLsizei restore_scissor_width,
+    GLsizei restore_scissor_height) {
   // TODO(gman): Figure out why InSequence stopped working.
   // InSequence sequence;
   EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(target))
@@ -781,8 +788,9 @@
       .Times(1)
       .RetiresOnSaturation();
   SetupExpectationsForRestoreClearState(
-      restore_red, restore_green, restore_blue, restore_alpha,
-      restore_stencil, restore_depth, restore_scissor_test);
+      restore_red, restore_green, restore_blue, restore_alpha, restore_stencil,
+      restore_depth, restore_scissor_test, restore_scissor_x, restore_scissor_y,
+      restore_scissor_width, restore_scissor_height);
   if (target == GL_READ_FRAMEBUFFER_EXT) {
     EXPECT_CALL(*gl_, BindFramebufferEXT(
         GL_READ_FRAMEBUFFER_EXT, read_framebuffer_service_id))
@@ -1674,6 +1682,18 @@
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
 }
 
+void GLES2DecoderTestBase::DoScissor(GLint x,
+                                     GLint y,
+                                     GLsizei width,
+                                     GLsizei height) {
+  EXPECT_CALL(*gl_, Scissor(x, y, width, height))
+      .Times(1)
+      .RetiresOnSaturation();
+  cmds::Scissor cmd;
+  cmd.Init(x, y, width, height);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
 void GLES2DecoderTestBase::SetupVertexBuffer() {
   DoEnableVertexAttribArray(1);
   DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index 1583462..42a44e2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -199,6 +199,7 @@
     bool bind_generates_resource;
     bool lose_context_when_out_of_memory;
     bool use_native_vao;  // default is true.
+    unsigned webgl_version;  // default to 0, i.e., not WebGL context.
   };
 
   void InitDecoder(const InitState& init);
@@ -326,6 +327,8 @@
   void DoBufferSubData(
       GLenum target, GLint offset, GLsizei size, const void* data);
 
+  void DoScissor(GLint x, GLint y, GLsizei width, GLsizei height);
+
   void SetupVertexBuffer();
   void SetupAllNeededVertexBuffers();
 
@@ -348,25 +351,31 @@
                                      GLsizei width,
                                      GLsizei height);
 
-  void SetupExpectationsForRestoreClearState(
-      GLclampf restore_red,
-      GLclampf restore_green,
-      GLclampf restore_blue,
-      GLclampf restore_alpha,
-      GLuint restore_stencil,
-      GLclampf restore_depth,
-      bool restore_scissor_test);
+  void SetupExpectationsForRestoreClearState(GLclampf restore_red,
+                                             GLclampf restore_green,
+                                             GLclampf restore_blue,
+                                             GLclampf restore_alpha,
+                                             GLuint restore_stencil,
+                                             GLclampf restore_depth,
+                                             bool restore_scissor_test,
+                                             GLint restore_scissor_x,
+                                             GLint restore_scissor_y,
+                                             GLsizei restore_scissor_width,
+                                             GLsizei restore_scissor_height);
 
-  void SetupExpectationsForFramebufferClearing(
-      GLenum target,
-      GLuint clear_bits,
-      GLclampf restore_red,
-      GLclampf restore_green,
-      GLclampf restore_blue,
-      GLclampf restore_alpha,
-      GLuint restore_stencil,
-      GLclampf restore_depth,
-      bool restore_scissor_test);
+  void SetupExpectationsForFramebufferClearing(GLenum target,
+                                               GLuint clear_bits,
+                                               GLclampf restore_red,
+                                               GLclampf restore_green,
+                                               GLclampf restore_blue,
+                                               GLclampf restore_alpha,
+                                               GLuint restore_stencil,
+                                               GLclampf restore_depth,
+                                               bool restore_scissor_test,
+                                               GLint restore_scissor_x,
+                                               GLint restore_scissor_y,
+                                               GLsizei restore_scissor_width,
+                                               GLsizei restore_scissor_height);
 
   void SetupExpectationsForFramebufferClearingMulti(
       GLuint read_framebuffer_service_id,
@@ -379,7 +388,11 @@
       GLclampf restore_alpha,
       GLuint restore_stencil,
       GLclampf restore_depth,
-      bool restore_scissor_test);
+      bool restore_scissor_test,
+      GLint restore_scissor_x,
+      GLint restore_scissor_y,
+      GLsizei restore_scissor_width,
+      GLsizei restore_scissor_height);
 
   void SetupExpectationsForDepthMask(bool mask);
   void SetupExpectationsForEnableDisable(GLenum cap, bool enable);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc
index dfcccf5..579e84b8 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc
@@ -1912,19 +1912,20 @@
                          kFBOServiceTextureId,
                          0,
                          GL_NO_ERROR);
+  DoEnableDisable(GL_SCISSOR_TEST, false);
+  DoScissor(0, 0, 1, 1);
 
   // Setup "render from" texture.
   SetupTexture();
 
   SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER,       // target
                                           GL_COLOR_BUFFER_BIT,  // clear bits
-                                          0,
-                                          0,
-                                          0,
-                                          0,       // color
-                                          0,       // stencil
-                                          1.0f,    // depth
-                                          false);  // scissor test
+                                          0, 0, 0,
+                                          0,      // color
+                                          0,      // stencil
+                                          1.0f,   // depth
+                                          false,  // scissor test
+                                          0, 0, 1, 1);
 
   SetupExpectationsForApplyingDirtyState(false,   // Framebuffer is RGB
                                          false,   // Framebuffer has depth
@@ -2003,16 +2004,17 @@
                             client_renderbuffer_id_,
                             kServiceRenderbufferId,
                             GL_NO_ERROR);
+  DoEnableDisable(GL_SCISSOR_TEST, false);
+  DoScissor(0, 0, 1, 1);
 
   SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER,       // target
                                           GL_COLOR_BUFFER_BIT,  // clear bits
-                                          0,
-                                          0,
-                                          0,
-                                          0,       // color
-                                          0,       // stencil
-                                          1.0f,    // depth
-                                          false);  // scissor test
+                                          0, 0, 0,
+                                          0,      // color
+                                          0,      // stencil
+                                          1.0f,   // depth
+                                          false,  // scissor test
+                                          0, 0, 1, 1);
 
   AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
   SetupExpectationsForApplyingDirtyState(false,   // Framebuffer is RGB
@@ -2138,18 +2140,18 @@
                             client_renderbuffer_id_,
                             kServiceRenderbufferId,
                             GL_NO_ERROR);
-
+  DoEnableDisable(GL_SCISSOR_TEST, false);
+  DoScissor(0, 0, 1, 1);
   SetupTexture();
   SetupExpectationsForFramebufferClearing(
       GL_FRAMEBUFFER,                             // target
       GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,  // clear bits
-      0,
-      0,
-      0,
-      0,       // color
-      0,       // stencil
-      1.0f,    // depth
-      false);  // scissor test
+      0, 0, 0,
+      0,      // color
+      0,      // stencil
+      1.0f,   // depth
+      false,  // scissor test
+      0, 0, 1, 1);
 
   AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
   SetupExpectationsForApplyingDirtyState(false,   // Framebuffer is RGB
@@ -2270,8 +2272,9 @@
                0,
                0);
 
-  // Disable GL_SCISSOR_TEST to make sure we enable it in the clear,
-  // then disable it again.
+  // Set scissor rect and disable GL_SCISSOR_TEST to make sure we enable it in
+  // the clear, then disable it and restore the rect again.
+  DoScissor(0, 0, 32, 32);
   DoEnableDisable(GL_SCISSOR_TEST, false);
 
   EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _)).Times(1).RetiresOnSaturation();
@@ -2296,14 +2299,13 @@
                                   GLES2Decoder::kDefaultStencilMask);
   EXPECT_CALL(*gl_, ClearDepth(1.0f)).Times(1).RetiresOnSaturation();
   SetupExpectationsForDepthMask(true);
-  EXPECT_CALL(*gl_, Scissor(0.0f, 0.0f, 1.0f, 1.0f))
-      .Times(1)
-      .RetiresOnSaturation();
+  SetupExpectationsForEnableDisable(GL_SCISSOR_TEST, true);
+  EXPECT_CALL(*gl_, Scissor(0, 0, 1, 1)).Times(1).RetiresOnSaturation();
 
   EXPECT_CALL(*gl_, Clear(GL_DEPTH_BUFFER_BIT)).Times(1).RetiresOnSaturation();
 
-  EXPECT_CALL(*gl_, Disable(GL_SCISSOR_TEST)).Times(1).RetiresOnSaturation();
-  SetupExpectationsForRestoreClearState(0.0f, 0.0f, 0.0f, 0.0f, 0, 1.0f, true);
+  SetupExpectationsForRestoreClearState(0.0f, 0.0f, 0.0f, 0.0f, 0, 1.0f, false,
+                                        0, 0, 32, 32);
 
   EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, _)).Times(1).RetiresOnSaturation();
   EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0))
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
index 4255ffa..6e47194 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -1675,19 +1675,22 @@
                          kFBOServiceTextureId,
                          0,
                          GL_NO_ERROR);
+  // Set scissor rect and enable GL_SCISSOR_TEST to make sure we re-enable it
+  // and restore the rect again after the clear.
+  DoEnableDisable(GL_SCISSOR_TEST, true);
+  DoScissor(0, 0, 64, 64);
 
   // Setup "render from" texture.
   SetupTexture();
 
   SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER,       // target
                                           GL_COLOR_BUFFER_BIT,  // clear bits
-                                          0,
-                                          0,
-                                          0,
-                                          0,       // color
-                                          0,       // stencil
-                                          1.0f,    // depth
-                                          false);  // scissor test
+                                          0, 0, 0,
+                                          0,      // color
+                                          0,      // stencil
+                                          1.0f,   // depth
+                                          true,  // scissor test
+                                          0, 0, 64, 64);
   SetupExpectationsForApplyingDirtyState(false,    // Framebuffer is RGB
                                          false,    // Framebuffer has depth
                                          false,    // Framebuffer has stencil
@@ -1729,19 +1732,20 @@
                          kFBOServiceTextureId,
                          0,
                          GL_NO_ERROR);
+  DoEnableDisable(GL_SCISSOR_TEST, false);
+  DoScissor(0, 0, 1, 1);
 
   // Setup "render from" texture.
   SetupTexture();
 
   SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER,       // target
                                           GL_COLOR_BUFFER_BIT,  // clear bits
-                                          0,
-                                          0,
-                                          0,
-                                          0,       // color
-                                          0,       // stencil
-                                          1.0f,    // depth
-                                          false);  // scissor test
+                                          0, 0, 0,
+                                          0,      // color
+                                          0,      // stencil
+                                          1.0f,   // depth
+                                          false,  // scissor test
+                                          0, 0, 1, 1);
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -1800,22 +1804,22 @@
                          0,
                          GL_NO_ERROR);
 
-  // Enable GL_SCISSOR_TEST to make sure we disable it in the clear,
-  // then re-enable after.
-  DoEnableDisable(GL_SCISSOR_TEST, true);
+  // Set scissor rect and disable GL_SCISSOR_TEST to make sure we enable it in
+  // the clear, then disable it and restore the rect again.
+  DoScissor(0, 0, 32, 32);
+  DoEnableDisable(GL_SCISSOR_TEST, false);
 
   SetupExpectationsForFramebufferClearingMulti(
       kServiceFramebufferId,  // read framebuffer service id
       0,                      // backbuffer service id
       GL_READ_FRAMEBUFFER,    // target
       GL_COLOR_BUFFER_BIT,    // clear bits
-      0,
-      0,
-      0,
+      0, 0, 0,
       0,      // color
       0,      // stencil
       1.0f,   // depth
-      true);  // scissor test
+      false,  // scissor test
+      0, 0, 32, 32);
 
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -2201,19 +2205,20 @@
                          kFBOServiceTextureId,
                          0,
                          GL_NO_ERROR);
+  DoEnableDisable(GL_SCISSOR_TEST, false);
+  DoScissor(0, 0, 1, 1);
 
   // Setup "render from" texture.
   SetupTexture();
 
   SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER,       // target
                                           GL_COLOR_BUFFER_BIT,  // clear bits
-                                          0,
-                                          0,
-                                          0,
-                                          0,       // color
-                                          0,       // stencil
-                                          1.0f,    // depth
-                                          false);  // scissor test
+                                          0, 0, 0,
+                                          0,      // color
+                                          0,      // stencil
+                                          1.0f,   // depth
+                                          false,  // scissor test
+                                          0, 0, 1, 1);
   SetupExpectationsForApplyingDirtyState(false,    // Framebuffer is RGB
                                          false,    // Framebuffer has depth
                                          false,    // Framebuffer has stencil
diff --git a/gpu/command_buffer/service/gpu_tracer_unittest.cc b/gpu/command_buffer/service/gpu_tracer_unittest.cc
index 8de31fa..9a27a99 100644
--- a/gpu/command_buffer/service/gpu_tracer_unittest.cc
+++ b/gpu/command_buffer/service/gpu_tracer_unittest.cc
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <map>
-#include <set>
-
 #include "base/bind.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "gpu/command_buffer/service/gpu_service_test.h"
@@ -12,17 +9,16 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/gl_mock.h"
 #include "ui/gl/gpu_timing.h"
+#include "ui/gl/gpu_timing_fake.h"
 
 namespace gpu {
 namespace gles2 {
 namespace {
 
 using ::testing::_;
-using ::testing::AtLeast;
 using ::testing::AtMost;
 using ::testing::Exactly;
 using ::testing::Invoke;
-using ::testing::NotNull;
 using ::testing::Return;
 
 int64 g_fakeCPUTime = 0;
@@ -50,107 +46,6 @@
   ~MockOutputter() {}
 };
 
-class GlFakeQueries {
- public:
-  GlFakeQueries() {}
-
-  void Reset() {
-    current_time_ = 0;
-    next_query_id_ = 23;
-    alloced_queries_.clear();
-    query_timestamp_.clear();
-  }
-
-  void SetCurrentGLTime(GLint64 current_time) { current_time_ = current_time; }
-  void SetDisjoint() { disjointed_ = true; }
-
-  void GenQueries(GLsizei n, GLuint* ids) {
-    for (GLsizei i = 0; i < n; i++) {
-      ids[i] = next_query_id_++;
-      alloced_queries_.insert(ids[i]);
-    }
-  }
-
-  void DeleteQueries(GLsizei n, const GLuint* ids) {
-    for (GLsizei i = 0; i < n; i++) {
-      alloced_queries_.erase(ids[i]);
-      query_timestamp_.erase(ids[i]);
-    }
-  }
-
-  void GetQueryObjectiv(GLuint id, GLenum pname, GLint* params) {
-    switch (pname) {
-      case GL_QUERY_RESULT_AVAILABLE: {
-        std::map<GLuint, GLint64>::iterator it = query_timestamp_.find(id);
-        if (it != query_timestamp_.end() && it->second <= current_time_)
-          *params = 1;
-        else
-          *params = 0;
-        break;
-      }
-      default:
-        FAIL() << "Invalid variable passed to GetQueryObjectiv: " << pname;
-    }
-  }
-
-  void QueryCounter(GLuint id, GLenum target) {
-    switch (target) {
-      case GL_TIMESTAMP:
-        ASSERT_TRUE(alloced_queries_.find(id) != alloced_queries_.end());
-        query_timestamp_[id] = current_time_;
-        break;
-      default:
-        FAIL() << "Invalid variable passed to QueryCounter: " << target;
-    }
-  }
-
-  void GetInteger64v(GLenum pname, GLint64 * data) {
-    switch (pname) {
-      case GL_TIMESTAMP:
-        *data = current_time_;
-        break;
-      default:
-        FAIL() << "Invalid variable passed to GetInteger64v: " << pname;
-    }
-  }
-
-  void GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params) {
-    switch (pname) {
-      case GL_QUERY_RESULT:
-        ASSERT_TRUE(query_timestamp_.find(id) != query_timestamp_.end());
-        *params = query_timestamp_.find(id)->second;
-        break;
-      default:
-        FAIL() << "Invalid variable passed to GetQueryObjectui64v: " << pname;
-    }
-  }
-
-  void GetIntegerv(GLenum pname, GLint* params) {
-    switch (pname) {
-      case GL_GPU_DISJOINT_EXT:
-        *params = static_cast<GLint>(disjointed_);
-        disjointed_ = false;
-        break;
-      default:
-        FAIL() << "Invalid variable passed to GetIntegerv: " << pname;
-    }
-  }
-
-  void Finish() {
-  }
-
-  GLenum GetError() {
-    return GL_NO_ERROR;
-  }
-
- protected:
-  bool disjointed_ = false;
-  GLint64 current_time_ = 0;
-  GLuint next_query_id_ = 0;
-  std::set<GLuint> alloced_queries_;
-  std::map<GLuint, GLint64> query_timestamp_;
-};
-
 class GPUTracerTester : public GPUTracer {
  public:
   explicit GPUTracerTester(gles2::GLES2Decoder* decoder)
@@ -215,13 +110,11 @@
     GpuServiceTest::SetUpWithGLVersion(gl_version, extensions);
 
     // Disjoint check should only be called by kTracerTypeDisjointTimer type.
-    if (GetTimerType() == gfx::GPUTiming::kTimerTypeDisjoint) {
-      EXPECT_CALL(*gl_, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(AtLeast(1))
-          .WillRepeatedly(
-              Invoke(&gl_fake_queries_, &GlFakeQueries::GetIntegerv));
-    } else {
-      EXPECT_CALL(*gl_, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(Exactly(0));
-    }
+    if (GetTimerType() == gfx::GPUTiming::kTimerTypeDisjoint)
+      gl_fake_queries_.ExpectDisjointCalls(*gl_);
+    else
+      gl_fake_queries_.ExpectNoDisjointCalls(*gl_);
+
     gpu_timing_client_ = GetGLContext()->CreateGPUTimingClient();
     gpu_timing_client_->SetCpuTimeForTesting(base::Bind(&FakeCpuTime));
     gl_fake_queries_.Reset();
@@ -238,34 +131,10 @@
   }
 
   void ExpectTraceQueryMocks() {
-    if (gpu_timing_client_->IsAvailable() &&
-        gpu_timing_client_->IsTimerOffsetAvailable()) {
+    if (gpu_timing_client_->IsAvailable()) {
       // Delegate query APIs used by GPUTrace to a GlFakeQueries
-      EXPECT_CALL(*gl_, GenQueries(2, NotNull())).Times(AtLeast(1))
-          .WillRepeatedly(
-              Invoke(&gl_fake_queries_, &GlFakeQueries::GenQueries));
-
-      EXPECT_CALL(*gl_, GetQueryObjectiv(_, GL_QUERY_RESULT_AVAILABLE,
-                                            NotNull()))
-          .WillRepeatedly(
-              Invoke(&gl_fake_queries_, &GlFakeQueries::GetQueryObjectiv));
-
-      EXPECT_CALL(*gl_, GetInteger64v(GL_TIMESTAMP, _))
-          .WillRepeatedly(
-              Invoke(&gl_fake_queries_, &GlFakeQueries::GetInteger64v));
-
-      EXPECT_CALL(*gl_, QueryCounter(_, GL_TIMESTAMP)).Times(AtLeast(2))
-          .WillRepeatedly(
-               Invoke(&gl_fake_queries_, &GlFakeQueries::QueryCounter));
-
-      EXPECT_CALL(*gl_, GetQueryObjectui64v(_, GL_QUERY_RESULT, NotNull()))
-          .WillRepeatedly(
-               Invoke(&gl_fake_queries_,
-                      &GlFakeQueries::GetQueryObjectui64v));
-
-      EXPECT_CALL(*gl_, DeleteQueries(2, NotNull())).Times(AtLeast(1))
-          .WillRepeatedly(
-               Invoke(&gl_fake_queries_, &GlFakeQueries::DeleteQueries));
+      const bool elapsed = (GetTimerType() == gfx::GPUTiming::kTimerTypeEXT);
+      gl_fake_queries_.ExpectGPUTimerQuery(*gl_, elapsed);
     }
   }
 
@@ -282,9 +151,12 @@
                                const std::string& category,
                                const std::string& name, int64 expect_start_time,
                                int64 expect_end_time,
+                               bool trace_service,
                                bool trace_device) {
-    EXPECT_CALL(*outputter,
-                TraceServiceEnd(source, category, name));
+    if (trace_service) {
+      EXPECT_CALL(*outputter,
+                  TraceServiceEnd(source, category, name));
+    }
 
     if (trace_device) {
       EXPECT_CALL(*outputter,
@@ -299,35 +171,34 @@
   }
 
   void ExpectOutputterMocks(MockOutputter* outputter,
+                            bool tracing_service,
                             bool tracing_device,
                             GpuTracerSource source,
                             const std::string& category,
                             const std::string& name, int64 expect_start_time,
                             int64 expect_end_time) {
-    ExpectOutputterBeginMocks(outputter, source, category, name);
-    bool valid_timer = tracing_device &&
-                       gpu_timing_client_->IsAvailable() &&
-                       gpu_timing_client_->IsTimerOffsetAvailable();
+    if (tracing_service)
+      ExpectOutputterBeginMocks(outputter, source, category, name);
+    const bool valid_timer = tracing_device &&
+                             gpu_timing_client_->IsAvailable() &&
+                             GetTimerType() != gfx::GPUTiming::kTimerTypeEXT;
     ExpectOutputterEndMocks(outputter, source, category, name,
-                            expect_start_time, expect_end_time, valid_timer);
+                            expect_start_time, expect_end_time,
+                            tracing_service, valid_timer);
   }
 
   void ExpectTracerOffsetQueryMocks() {
     if (GetTimerType() != gfx::GPUTiming::kTimerTypeARB) {
-      EXPECT_CALL(*gl_, GetInteger64v(GL_TIMESTAMP, NotNull()))
-          .Times(Exactly(0));
+      gl_fake_queries_.ExpectNoOffsetCalculationQuery(*gl_);
     } else {
-      EXPECT_CALL(*gl_, GetInteger64v(GL_TIMESTAMP, NotNull()))
-          .Times(AtMost(1))
-          .WillRepeatedly(
-              Invoke(&gl_fake_queries_, &GlFakeQueries::GetInteger64v));
+      gl_fake_queries_.ExpectOffsetCalculationQuery(*gl_);
     }
   }
 
   gfx::GPUTiming::TimerType GetTimerType() { return test_timer_type_; }
 
   gfx::GPUTiming::TimerType test_timer_type_;
-  GlFakeQueries gl_fake_queries_;
+  gfx::GPUTimingFake gl_fake_queries_;
 
   scoped_refptr<gfx::GPUTimingClient> gpu_timing_client_;
   scoped_refptr<MockOutputter> outputter_ref_;
@@ -353,10 +224,9 @@
     const int64 expect_end_time =
         (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time;
 
-    if (tracing_service)
-      ExpectOutputterMocks(outputter_ref_.get(), tracing_device, tracer_source,
-                           category_name, trace_name,
-                           expect_start_time, expect_end_time);
+    ExpectOutputterMocks(outputter_ref_.get(), tracing_service, tracing_device,
+                         tracer_source, category_name, trace_name,
+                         expect_start_time, expect_end_time);
 
     if (tracing_device)
       ExpectTraceQueryMocks();
@@ -380,11 +250,13 @@
     // Shouldn't be available until the queries complete
     gl_fake_queries_.SetCurrentGLTime(end_timestamp -
                                       base::Time::kNanosecondsPerMicrosecond);
+    g_fakeCPUTime = expect_end_time - 1;
     if (tracing_device)
       EXPECT_FALSE(trace->IsAvailable());
 
     // Now it should be available
     gl_fake_queries_.SetCurrentGLTime(end_timestamp);
+    g_fakeCPUTime = expect_end_time;
     EXPECT_TRUE(trace->IsAvailable());
 
     // Proces should output expected Trace results to MockOutputter
@@ -464,10 +336,7 @@
 
   void DoTracerMarkersTest() {
     ExpectTracerOffsetQueryMocks();
-
-    EXPECT_CALL(*gl_, GetError()).Times(AtLeast(0))
-          .WillRepeatedly(
-               Invoke(&gl_fake_queries_, &GlFakeQueries::GetError));
+    gl_fake_queries_.ExpectGetErrorCalls(*gl_);
 
     const std::string category_name("trace_category");
     const std::string trace_name("trace_test");
@@ -512,7 +381,6 @@
                                 source_category, source_trace_name);
       ASSERT_TRUE(tracer.Begin(source_category, source_trace_name, source));
     }
-
     for (int i = 0; i < NUM_TRACER_SOURCES; ++i) {
       // Set times so each source has a different time.
       gl_fake_queries_.SetCurrentGLTime(
@@ -525,33 +393,27 @@
       std::string source_category = category_name + num_char;
       std::string source_trace_name = trace_name + num_char;
 
-      bool valid_timer = gpu_timing_client_->IsAvailable() &&
-                         gpu_timing_client_->IsTimerOffsetAvailable();
+      const bool valid_timer = gpu_timing_client_->IsAvailable() &&
+                               GetTimerType() != gfx::GPUTiming::kTimerTypeEXT;
 
       const GpuTracerSource source = static_cast<GpuTracerSource>(i);
       ExpectOutputterEndMocks(outputter_ref_.get(), source, source_category,
                               source_trace_name, expect_start_time + i,
-                              expect_end_time + i, valid_timer);
-
+                              expect_end_time + i, true, valid_timer);
       // Check if the current category/name are correct for this source.
       ASSERT_EQ(source_category, tracer.CurrentCategory(source));
       ASSERT_EQ(source_trace_name, tracer.CurrentName(source));
 
       ASSERT_TRUE(tracer.End(source));
     }
-
     ASSERT_TRUE(tracer.EndDecoding());
-
     outputter_ref_ = NULL;
   }
 
   void DoDisjointTest() {
     // Cause a disjoint in a middle of a trace and expect no output calls.
     ExpectTracerOffsetQueryMocks();
-
-    EXPECT_CALL(*gl_, GetError()).Times(AtLeast(0))
-          .WillRepeatedly(
-               Invoke(&gl_fake_queries_, &GlFakeQueries::GetError));
+    gl_fake_queries_.ExpectGetErrorCalls(*gl_);
 
     const GpuTracerSource tracer_source = kTraceGroupMarker;
     const std::string category_name("trace_category");
@@ -589,7 +451,7 @@
 
     // Create GPUTimingClient to make sure disjoint value is correct. This
     // should not interfere with the tracer's disjoint value.
-    scoped_refptr<gfx::GPUTimingClient>  disjoint_client =
+    scoped_refptr<gfx::GPUTimingClient> disjoint_client =
         GetGLContext()->CreateGPUTimingClient();
 
     // We assert here based on the disjoint_client because if disjoints are not
@@ -600,7 +462,7 @@
 
     ExpectOutputterEndMocks(outputter_ref_.get(), tracer_source,
                             category_name, trace_name,
-                            expect_start_time, expect_end_time, false);
+                            expect_start_time, expect_end_time, true, false);
 
     ASSERT_TRUE(tracer.End(source));
     ASSERT_TRUE(tracer.EndDecoding());
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index 5b325ab..5140da6 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -912,6 +912,12 @@
 void InProcessCommandBuffer::SetLock(base::Lock*) {
 }
 
+bool InProcessCommandBuffer::IsGpuChannelLost() {
+  // There is no such channel to lose for in-process contexts. This only
+  // makes sense for out-of-process command buffers.
+  return false;
+}
+
 uint32 InProcessCommandBuffer::CreateStreamTextureOnGpuThread(
     uint32 client_texture_id) {
 #if defined(OS_ANDROID)
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index b3f6eb8..c6c4f2c 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -121,6 +121,7 @@
   void SetSurfaceVisible(bool visible) override;
   uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
+  bool IsGpuChannelLost() override;
 
   // The serializer interface to the GPU service (i.e. thread).
   class Service {
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index d527203..76d443d 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -189,7 +189,8 @@
       virtual_manager(NULL),
       bind_generates_resource(false),
       lose_context_when_out_of_memory(false),
-      context_lost_allowed(false) {
+      context_lost_allowed(false),
+      webgl_version(0) {
 }
 
 GLManager::GLManager() : context_lost_allowed_(false) {
@@ -277,6 +278,7 @@
   attrib_helper.alpha_size = 8;
   attrib_helper.depth_size = 16;
   attrib_helper.stencil_size = 8;
+  attrib_helper.webgl_version = options.webgl_version;
   attrib_helper.Serialize(&attribs);
 
   DCHECK(!command_line || !context_group);
@@ -516,4 +518,9 @@
   NOTIMPLEMENTED();
 }
 
+bool GLManager::IsGpuChannelLost() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index c163ac0..10a271a9 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -61,6 +61,10 @@
     bool lose_context_when_out_of_memory;
     // Whether or not it's ok to lose the context.
     bool context_lost_allowed;
+    // 0 indicates not WebGL context - default.
+    // 1 indicates WebGL 1 context.
+    // 2 indicates WebGL 2 context.
+    unsigned webgl_version;
   };
   GLManager();
   ~GLManager() override;
@@ -120,6 +124,7 @@
   void SetSurfaceVisible(bool visible) override;
   uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
+  bool IsGpuChannelLost() override;
 
  private:
   void PumpCommands();
diff --git a/gpu/command_buffer/tests/gl_program_unittest.cc b/gpu/command_buffer/tests/gl_program_unittest.cc
index c0abb12..ef11ae4 100644
--- a/gpu/command_buffer/tests/gl_program_unittest.cc
+++ b/gpu/command_buffer/tests/gl_program_unittest.cc
@@ -25,6 +25,15 @@
   GLManager gl_;
 };
 
+class WebGLProgramTest : public GLProgramTest {
+ protected:
+  void SetUp() override {
+    GLManager::Options options;
+    options.webgl_version = 1;
+    gl_.Initialize(options);
+  }
+};
+
 TEST_F(GLProgramTest, GetSetUniform) {
   static const char* v_shader_str = SHADER(
       attribute vec4 a_vertex;
@@ -189,7 +198,7 @@
   GLTestHelper::CheckGLError("no errors", __LINE__);
 }
 
-TEST_F(GLProgramTest, DeferCompileWithExt) {
+TEST_F(WebGLProgramTest, DeferCompileWithExt) {
   // This test must have extensions enabled.
   gles2::ContextGroup* context_group = gl_.decoder()->GetContextGroup();
   gles2::FeatureInfo* feature_info = context_group->feature_info();
@@ -212,16 +221,7 @@
       }
   )";
 
-  // First compile and link to be shader compiles.
-  GLuint vs_good = GLTestHelper::CompileShader(GL_VERTEX_SHADER, v_shdr_str);
-  GLuint fs_good = GLTestHelper::CompileShader(GL_FRAGMENT_SHADER, f_shdr_str);
-  GLuint program_good = GLTestHelper::LinkProgram(vs_good, fs_good);
-  GLint linked_good = 0;
-  glGetProgramiv(program_good, GL_LINK_STATUS, &linked_good);
-  EXPECT_NE(0, linked_good);
-
-  // Disable extension and be sure shader no longer compiles.
-  ASSERT_TRUE(glEnableFeatureCHROMIUM("webgl_enable_glsl_webgl_validation"));
+  // Extension is disabled by default and be sure shader does not compile.
   GLuint vs_bad = GLTestHelper::CompileShader(GL_VERTEX_SHADER, v_shdr_str);
   GLuint fs_bad = GLTestHelper::CompileShader(GL_FRAGMENT_SHADER, f_shdr_str);
   GLuint program_bad = GLTestHelper::LinkProgram(vs_bad, fs_bad);
@@ -229,26 +229,18 @@
   glGetProgramiv(program_bad, GL_LINK_STATUS, &linked_bad);
   EXPECT_EQ(0, linked_bad);
 
-  // Relinking good compilations without extension disabled should still link.
-  GLuint program_defer_good = GLTestHelper::LinkProgram(vs_good, fs_good);
-  GLint linked_defer_good = 0;
-  glGetProgramiv(program_defer_good, GL_LINK_STATUS, &linked_defer_good);
-  EXPECT_NE(0, linked_defer_good);
-
   // linking bad compilations with extension enabled should still not link.
-  GLuint vs_bad2 = GLTestHelper::CompileShader(GL_VERTEX_SHADER, v_shdr_str);
-  GLuint fs_bad2 = GLTestHelper::CompileShader(GL_FRAGMENT_SHADER, f_shdr_str);
   glRequestExtensionCHROMIUM("GL_EXT_frag_depth");
-  GLuint program_bad2 = GLTestHelper::LinkProgram(vs_bad2, fs_bad2);
-  GLint linked_bad2 = 0;
-  glGetProgramiv(program_bad2, GL_LINK_STATUS, &linked_bad2);
-  EXPECT_EQ(0, linked_bad2);
+  program_bad = GLTestHelper::LinkProgram(vs_bad, fs_bad);
+  linked_bad = 0;
+  glGetProgramiv(program_bad, GL_LINK_STATUS, &linked_bad);
+  EXPECT_EQ(0, linked_bad);
 
   // Be sure extension was actually turned on by recompiling.
-  GLuint vs_good2 = GLTestHelper::LoadShader(GL_VERTEX_SHADER, v_shdr_str);
-  GLuint fs_good2 = GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, f_shdr_str);
-  GLuint program_good2 = GLTestHelper::SetupProgram(vs_good2, fs_good2);
-  EXPECT_NE(0u, program_good2);
+  GLuint vs_good = GLTestHelper::LoadShader(GL_VERTEX_SHADER, v_shdr_str);
+  GLuint fs_good = GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, f_shdr_str);
+  GLuint program_good = GLTestHelper::SetupProgram(vs_good, fs_good);
+  EXPECT_NE(0u, program_good);
 }
 
 TEST_F(GLProgramTest, DeleteAttachedShaderLinks) {
diff --git a/gpu/config/gpu_control_list.cc b/gpu/config/gpu_control_list.cc
index fddcea4..2f4b6aa 100644
--- a/gpu/config/gpu_control_list.cc
+++ b/gpu/config/gpu_control_list.cc
@@ -1029,7 +1029,7 @@
 
     gl_type = kGLTypeGLES;
     if (segments.size() > 3 &&
-        StartsWithASCII(segments[3], "(ANGLE", false)) {
+        base::StartsWithASCII(segments[3], "(ANGLE", false)) {
       gl_type = kGLTypeANGLE;
     }
   } else {
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index 191cca9..6544088b 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
 {
   "name": "gpu driver bug list",
   // Please update the version number whenever you change this file.
-  "version": "8.10",
+  "version": "8.12",
   "entries": [
     {
       "id": 1,
@@ -1414,16 +1414,33 @@
     },
     {
       "id": 119,
-      "description": "Context lost recovery often fails on Mali-400 on Android.",
+      "description": "Context lost recovery often fails on Mali-400/450 on Android.",
       "cr_bugs": [496438],
       "os": {
         "type": "android"
       },
       "gl_vendor": "ARM.*",
-      "gl_renderer": ".*Mali-400.*",
+      "gl_renderer": ".*Mali-4.*",
       "features": [
         "exit_on_context_lost"
       ]
+    },
+    {
+      "id": 120,
+      "description": "CHROMIUM_copy_texture is slow on Mali pre-Lollipop",
+      "cr_bugs": [498443],
+      "os": {
+        "type": "android",
+        "version": {
+          "op": "<",
+          "value": "5.0.0"
+        }
+      },
+      "gl_vendor": "ARM.*",
+      "gl_renderer": "Mali.*",
+      "features": [
+        "max_copy_texture_chromium_size_262144"
+      ]
     }
   ]
 }
diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h
index 015aea3..864b155 100644
--- a/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/gpu/config/gpu_driver_bug_workaround_type.h
@@ -42,6 +42,8 @@
          disable_ext_draw_buffers)                           \
   GPU_OP(DISABLE_EXT_OCCLUSION_QUERY,                        \
          disable_ext_occlusion_query)                        \
+  GPU_OP(DISABLE_GL_RGB_FORMAT,                              \
+         disable_gl_rgb_format)                              \
   GPU_OP(DISABLE_MULTIMONITOR_MULTISAMPLING,                 \
          disable_multimonitor_multisampling)                 \
   GPU_OP(DISABLE_MULTISAMPLED_RENDER_TO_TEXTURE,             \
@@ -74,6 +76,8 @@
          init_varyings_without_static_use)                   \
   GPU_OP(INIT_VERTEX_ATTRIBUTES,                             \
          init_vertex_attributes)                             \
+  GPU_OP(MAX_COPY_TEXTURE_CHROMIUM_SIZE_262144,              \
+         max_copy_texture_chromium_size_262144)              \
   GPU_OP(MAX_CUBE_MAP_TEXTURE_SIZE_LIMIT_1024,               \
          max_cube_map_texture_size_limit_1024)               \
   GPU_OP(MAX_CUBE_MAP_TEXTURE_SIZE_LIMIT_4096,               \
@@ -130,8 +134,6 @@
          validate_multisample_buffer_allocation)             \
   GPU_OP(WAKE_UP_GPU_BEFORE_DRAWING,                         \
          wake_up_gpu_before_drawing)                         \
-  GPU_OP(DISABLE_GL_RGB_FORMAT,                              \
-         disable_gl_rgb_format)                              \
 
 namespace gpu {
 
diff --git a/gpu/config/gpu_info_collector_linux.cc b/gpu/config/gpu_info_collector_linux.cc
index 023c08b..413e949 100644
--- a/gpu/config/gpu_info_collector_linux.cc
+++ b/gpu/config/gpu_info_collector_linux.cc
@@ -56,7 +56,7 @@
   base::StringTokenizer t(contents, "\r\n");
   while (t.GetNext()) {
     std::string line = t.token();
-    if (StartsWithASCII(line, "ReleaseVersion=", true)) {
+    if (base::StartsWithASCII(line, "ReleaseVersion=", true)) {
       size_t begin = line.find_first_of("0123456789");
       if (begin != std::string::npos) {
         size_t end = line.find_first_not_of("0123456789.", begin);
@@ -244,7 +244,7 @@
   DCHECK(gpu_info);
 
   std::string gl_version = gpu_info->gl_version;
-  if (StartsWithASCII(gl_version, "OpenGL ES", true))
+  if (base::StartsWithASCII(gl_version, "OpenGL ES", true))
     gl_version = gl_version.substr(10);
   std::vector<std::string> pieces;
   base::SplitStringAlongWhitespace(gl_version, &pieces);
diff --git a/gpu/config/gpu_test_expectations_parser.cc b/gpu/config/gpu_test_expectations_parser.cc
index 8b3584a..ca4031d 100644
--- a/gpu/config/gpu_test_expectations_parser.cc
+++ b/gpu/config/gpu_test_expectations_parser.cc
@@ -131,13 +131,13 @@
 };
 
 Token ParseToken(const std::string& word) {
-  if (StartsWithASCII(word, "//", false))
+  if (base::StartsWithASCII(word, "//", false))
     return kTokenComment;
-  if (StartsWithASCII(word, "0x", false))
+  if (base::StartsWithASCII(word, "0x", false))
     return kConfigGPUDeviceID;
 
   for (int32 i = 0; i < kNumberOfExactMatchTokens; ++i) {
-    if (LowerCaseEqualsASCII(word, kTokenData[i].name))
+    if (base::LowerCaseEqualsASCII(word, kTokenData[i].name))
       return static_cast<Token>(i);
   }
   return kTokenWord;
diff --git a/gpu/gles2_conform_support/egl/display.cc b/gpu/gles2_conform_support/egl/display.cc
index bd17250..d65e589 100644
--- a/gpu/gles2_conform_support/egl/display.cc
+++ b/gpu/gles2_conform_support/egl/display.cc
@@ -339,4 +339,9 @@
   NOTIMPLEMENTED();
 }
 
+bool Display::IsGpuChannelLost() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
 }  // namespace egl
diff --git a/gpu/gles2_conform_support/egl/display.h b/gpu/gles2_conform_support/egl/display.h
index 9b349bd..0566da6 100644
--- a/gpu/gles2_conform_support/egl/display.h
+++ b/gpu/gles2_conform_support/egl/display.h
@@ -93,6 +93,7 @@
   void SetSurfaceVisible(bool visible) override;
   uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
+  bool IsGpuChannelLost() override;
 
  private:
   EGLNativeDisplayType display_id_;
diff --git a/gpu/ipc/gpu_command_buffer_traits_multi.h b/gpu/ipc/gpu_command_buffer_traits_multi.h
index 98e42336..31326b65 100644
--- a/gpu/ipc/gpu_command_buffer_traits_multi.h
+++ b/gpu/ipc/gpu_command_buffer_traits_multi.h
@@ -49,6 +49,7 @@
   IPC_STRUCT_TRAITS_MEMBER(max_combined_fragment_uniform_components)
   IPC_STRUCT_TRAITS_MEMBER(max_combined_uniform_blocks)
   IPC_STRUCT_TRAITS_MEMBER(max_combined_vertex_uniform_components)
+  IPC_STRUCT_TRAITS_MEMBER(max_copy_texture_chromium_size)
   IPC_STRUCT_TRAITS_MEMBER(max_draw_buffers)
   IPC_STRUCT_TRAITS_MEMBER(max_element_index)
   IPC_STRUCT_TRAITS_MEMBER(max_elements_indices)
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index b9dc50e..75082ce 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -38,22 +38,19 @@
       builders { name: "cast_shell_linux" }
       builders {
         name: "chromeos_x86-generic_chromium_compile_only_ng"
-        experiment_percentage: 0.1
+        experiment_percentage: 1.0
       }
       builders {
         name: "chromeos_amd64-generic_chromium_compile_only_ng"
-        experiment_percentage: 0.1
+        experiment_percentage: 1.0
       }
       builders {
         name: "chromeos_daisy_chromium_compile_only_ng"
-        experiment_percentage: 0.1
+        experiment_percentage: 1.0
       }
       builders { name: "chromium_presubmit" }
       builders { name: "linux_android_rel_ng" }
-      builders {
-        name: "linux_arm_compile"
-        experiment_percentage: 1.0
-      }
+      builders { name: "linux_arm_compile" }
       builders { name: "linux_chromium_asan_rel_ng" }
       builders { name: "linux_chromium_chromeos_compile_dbg_ng" }
       builders { name: "linux_chromium_chromeos_ozone_rel_ng" }
@@ -81,22 +78,18 @@
         experiment_percentage: 0.1
       }
       builders { name: "mac_chromium_rel_ng" }
+      builders {
+        name: "mac_chromium_10.10_rel_ng"
+        experiment_percentage: 0.1
+      }
     }
     buckets {
       name: "tryserver.chromium.win"
       builders {
-        name: "win8_chromium_gn_rel"
-        experiment_percentage: 0.1
-      }
-      builders {
-        name: "win8_chromium_ng"
-        experiment_percentage: 0.1
-      }
-      builders {
         name: "win_chromium_compile_dbg_ng_exp"
         experiment_percentage: 0.1
       }
-      builders { name: "win8_chromium_rel" }
+      builders { name: "win8_chromium_ng" }
       builders { name: "win_chromium_compile_dbg_ng" }
       builders { name: "win_chromium_rel_ng" }
       builders { name: "win_chromium_x64_rel_ng" }
diff --git a/ios/chrome/app/safe_mode_util_unittest.cc b/ios/chrome/app/safe_mode_util_unittest.cc
index 3164d59..1c9de67 100644
--- a/ios/chrome/app/safe_mode_util_unittest.cc
+++ b/ios/chrome/app/safe_mode_util_unittest.cc
@@ -27,7 +27,7 @@
   string lib_system_prefix("libSystem");
   for (size_t i = 0; i < images.size(); ++i) {
     string base_name = base::FilePath(images[i]).BaseName().value();
-    if (StartsWithASCII(base_name, lib_system_prefix, true)) {
+    if (base::StartsWithASCII(base_name, lib_system_prefix, true)) {
       found_lib_system = true;
       break;
     }
diff --git a/ios/chrome/browser/chrome_url_util.mm b/ios/chrome/browser/chrome_url_util.mm
index db685d7..13477a6 100644
--- a/ios/chrome/browser/chrome_url_util.mm
+++ b/ios/chrome/browser/chrome_url_util.mm
@@ -18,7 +18,7 @@
 
 bool UrlIsExternalFileReference(const GURL& url) {
   return url.SchemeIs(ios::GetChromeBrowserProvider()->GetChromeUIScheme()) &&
-         LowerCaseEqualsASCII(url.host(), kChromeUIExternalFileHost);
+         base::LowerCaseEqualsASCII(url.host(), kChromeUIExternalFileHost);
 }
 
 NSURL* UrlToLaunchChrome() {
diff --git a/ios/chrome/browser/dom_distiller/distiller_viewer.cc b/ios/chrome/browser/dom_distiller/distiller_viewer.cc
index 1e1aab9..9ec39528 100644
--- a/ios/chrome/browser/dom_distiller/distiller_viewer.cc
+++ b/ios/chrome/browser/dom_distiller/distiller_viewer.cc
@@ -49,9 +49,8 @@
       distilled_page_prefs_->GetFontFamily());
 
   std::string html_and_script(html);
-  std::string hide_feedback =
-      "document.getElementById('feedbackContainer').style.display = 'none';";
-  html_and_script += "<script>" + js_buffer_ + hide_feedback + "</script>";
+  html_and_script +=
+      "<script> distiller_on_ios = true; " + js_buffer_ + "</script>";
   callback_.Run(url_, html_and_script);
 }
 
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm
index 6659c60..531f1f6 100644
--- a/ios/chrome/browser/experimental_flags.mm
+++ b/ios/chrome/browser/experimental_flags.mm
@@ -71,7 +71,7 @@
   }
 
   // Check if the finch experiment is turned on.
-  return StartsWithASCII(group_name, "Enabled", false);
+  return base::StartsWithASCII(group_name, "Enabled", false);
 }
 
 size_t MemoryWedgeSizeInMB() {
diff --git a/ios/chrome/browser/infobars/confirm_infobar_controller.mm b/ios/chrome/browser/infobars/confirm_infobar_controller.mm
index 172787636..9e93848 100644
--- a/ios/chrome/browser/infobars/confirm_infobar_controller.mm
+++ b/ios/chrome/browser/infobars/confirm_infobar_controller.mm
@@ -5,17 +5,20 @@
 #include "ios/chrome/browser/infobars/confirm_infobar_controller.h"
 
 #include "base/mac/foundation_util.h"
+#include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/ui/infobar_view_delegate.h"
 #import "ios/public/provider/chrome/browser/ui/infobar_view_protocol.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/window_open_disposition.h"
 #include "ui/gfx/image/image.h"
 
 namespace {
 
-// UI Tags for the infobar buttons
-enum ConfirmInfoBarUITags { OK = 1, CANCEL, CLOSE };
+// UI Tags for the infobar elements.
+enum ConfirmInfoBarUITags { OK = 1, CANCEL, CLOSE, TITLE_LINK };
 
 // Converts a UI button tag to the corresponding InfoBarButton.
 ConfirmInfoBarDelegate::InfoBarButton UITagToButton(NSUInteger tag) {
@@ -39,10 +42,13 @@
 
 // Action for any of the user defined buttons.
 - (void)infoBarButtonDidPress:(id)sender;
-
+// Action for any of the user defined links.
+- (void)infobarLinkDidPress:(NSNumber*)tag;
+- (void)updateInfobarLabel:(UIView<InfoBarViewProtocol>*)view;
 @end
 
 @implementation ConfirmInfoBarController {
+  __weak ConfirmInfoBarDelegate* confirmInfobarDelegate_;
 }
 
 #pragma mark -
@@ -52,24 +58,22 @@
     viewForDelegate:(infobars::InfoBarDelegate*)delegate
               frame:(CGRect)frame {
   base::scoped_nsobject<UIView<InfoBarViewProtocol>> infoBarView;
-  ConfirmInfoBarDelegate* infoBarModel = delegate->AsConfirmInfoBarDelegate();
+  confirmInfobarDelegate_ = delegate->AsConfirmInfoBarDelegate();
   infoBarView.reset(
       ios::GetChromeBrowserProvider()->CreateInfoBarView(frame, self.delegate));
   // Model data.
-  NSString* modelMsg = nil;
-  if (infoBarModel->GetMessageText().length())
-    modelMsg = base::SysUTF16ToNSString(infoBarModel->GetMessageText());
-  gfx::Image modelIcon = infoBarModel->GetIcon();
-  int buttons = infoBarModel->GetButtons();
+  gfx::Image modelIcon = confirmInfobarDelegate_->GetIcon();
+  int buttons = confirmInfobarDelegate_->GetButtons();
   NSString* buttonOK = nil;
   if (buttons & ConfirmInfoBarDelegate::BUTTON_OK) {
-    buttonOK = base::SysUTF16ToNSString(
-        infoBarModel->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK));
+    buttonOK = base::SysUTF16ToNSString(confirmInfobarDelegate_->GetButtonLabel(
+        ConfirmInfoBarDelegate::BUTTON_OK));
   }
   NSString* buttonCancel = nil;
   if (buttons & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
-    buttonCancel = base::SysUTF16ToNSString(
-        infoBarModel->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL));
+    buttonCancel =
+        base::SysUTF16ToNSString(confirmInfobarDelegate_->GetButtonLabel(
+            ConfirmInfoBarDelegate::BUTTON_CANCEL));
   }
 
   [infoBarView addCloseButtonWithTag:ConfirmInfoBarUITags::CLOSE
@@ -81,8 +85,7 @@
     [infoBarView addLeftIcon:modelIcon.ToUIImage()];
 
   // Optional message.
-  if (modelMsg)
-    [infoBarView addLabel:modelMsg];
+  [self updateInfobarLabel:infoBarView];
 
   if (buttonOK && buttonCancel) {
     [infoBarView addButton1:buttonOK
@@ -98,11 +101,33 @@
                     action:@selector(infoBarButtonDidPress:)];
   } else {
     // No buttons, only message.
-    DCHECK(modelMsg && !buttonCancel);
+    DCHECK(!confirmInfobarDelegate_->GetMessageText().empty() && !buttonCancel);
   }
   return infoBarView;
 }
 
+- (void)updateInfobarLabel:(UIView<InfoBarViewProtocol>*)view {
+  if (!confirmInfobarDelegate_->GetMessageText().length())
+    return;
+  if (confirmInfobarDelegate_->GetLinkText().length()) {
+    base::string16 msgLink = base::SysNSStringToUTF16(
+        [[view class] stringAsLink:base::SysUTF16ToNSString(
+                                       confirmInfobarDelegate_->GetLinkText())
+                               tag:ConfirmInfoBarUITags::TITLE_LINK]);
+    base::string16 messageText = confirmInfobarDelegate_->GetMessageText();
+    ReplaceFirstSubstringAfterOffset(
+        &messageText, 0, confirmInfobarDelegate_->GetLinkText(), msgLink);
+
+    [view addLabel:base::SysUTF16ToNSString(messageText)
+            target:self
+            action:@selector(infobarLinkDidPress:)];
+  } else {
+    NSString* label =
+        base::SysUTF16ToNSString(confirmInfobarDelegate_->GetMessageText());
+    [view addLabel:label];
+  }
+}
+
 #pragma mark - Handling of User Events
 
 - (void)infoBarButtonDidPress:(id)sender {
@@ -121,4 +146,15 @@
   }
 }
 
+// Title link was clicked.
+- (void)infobarLinkDidPress:(NSNumber*)tag {
+  DCHECK([tag isKindOfClass:[NSNumber class]]);
+  if (!self.delegate) {
+    return;
+  }
+  if ([tag unsignedIntegerValue] == ConfirmInfoBarUITags::TITLE_LINK) {
+    confirmInfobarDelegate_->LinkClicked(NEW_FOREGROUND_TAB);
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/infobars/infobar_controller.h b/ios/chrome/browser/infobars/infobar_controller.h
index d29299c..c77e229 100644
--- a/ios/chrome/browser/infobars/infobar_controller.h
+++ b/ios/chrome/browser/infobars/infobar_controller.h
@@ -18,11 +18,12 @@
 @interface InfoBarController : NSObject
 
 @property(nonatomic, readonly) InfoBarViewDelegate* delegate;
-
 // Designated initializer.
 - (instancetype)initWithDelegate:(InfoBarViewDelegate*)delegate
     NS_DESIGNATED_INITIALIZER;
 
+- (instancetype)init NS_UNAVAILABLE;
+
 // Creates a view and lays out all the infobar elements in it. Will not add
 // it as a subview yet. This method must be overriden in subclasses.
 - (base::scoped_nsobject<UIView<InfoBarViewProtocol>>)
diff --git a/ios/chrome/browser/infobars/infobar_controller.mm b/ios/chrome/browser/infobars/infobar_controller.mm
index 594f0f32..c2c4875 100644
--- a/ios/chrome/browser/infobars/infobar_controller.mm
+++ b/ios/chrome/browser/infobars/infobar_controller.mm
@@ -25,6 +25,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (void)dealloc {
   [_infoBarView removeFromSuperview];
   [super dealloc];
diff --git a/ios/chrome/browser/suggestions/suggestions_service_factory.mm b/ios/chrome/browser/suggestions/suggestions_service_factory.mm
index bc08640..f185973 100644
--- a/ios/chrome/browser/suggestions/suggestions_service_factory.mm
+++ b/ios/chrome/browser/suggestions/suggestions_service_factory.mm
@@ -68,8 +68,9 @@
       new leveldb_proto::ProtoDatabaseImpl<ImageData>(background_task_runner));
   scoped_ptr<ImageFetcher> image_fetcher(new ImageFetcherImpl(
       browser_state->GetRequestContext(), sequenced_worker_pool));
-  scoped_ptr<ImageManager> thumbnail_manager(
-      new ImageManager(image_fetcher.Pass(), db.Pass(), database_dir));
+  scoped_ptr<ImageManager> thumbnail_manager(new ImageManager(
+      image_fetcher.Pass(), db.Pass(), database_dir,
+      web::WebThread::GetTaskRunnerForThread(web::WebThread::DB)));
   return new SuggestionsService(
       browser_state->GetRequestContext(), suggestions_store.Pass(),
       thumbnail_manager.Pass(), blacklist_store.Pass());
diff --git a/ios/chrome/browser/sync/sync_setup_service.cc b/ios/chrome/browser/sync/sync_setup_service.cc
index d617324..ac64153 100644
--- a/ios/chrome/browser/sync/sync_setup_service.cc
+++ b/ios/chrome/browser/sync/sync_setup_service.cc
@@ -190,7 +190,7 @@
     bool sync_enabled) {
   sync_service_->SetSetupInProgress(true);
   if (sync_enabled)
-    sync_service_->UnsuppressAndStart();
+    sync_service_->RequestStart();
   else
-    sync_service_->StopAndSuppress();
+    sync_service_->RequestStop();
 }
diff --git a/ios/chrome/browser/translate/before_translate_infobar_controller.mm b/ios/chrome/browser/translate/before_translate_infobar_controller.mm
index e39f6d7..7a872d9 100644
--- a/ios/chrome/browser/translate/before_translate_infobar_controller.mm
+++ b/ios/chrome/browser/translate/before_translate_infobar_controller.mm
@@ -301,7 +301,7 @@
                            target:self
                            action:@selector(dismissLanguageSelectionView)]);
   base::scoped_nsobject<UINavigationItem> item(
-      [[UINavigationItem alloc] initWithTitle:nil]);
+      [[UINavigationItem alloc] initWithTitle:@""]);
   [item setRightBarButtonItem:doneButton];
   [item setLeftBarButtonItem:cancelButton];
   [item setHidesBackButton:YES];
diff --git a/ios/chrome/browser/ui/commands/generic_chrome_command.h b/ios/chrome/browser/ui/commands/generic_chrome_command.h
index 75d70330..054de4f 100644
--- a/ios/chrome/browser/ui/commands/generic_chrome_command.h
+++ b/ios/chrome/browser/ui/commands/generic_chrome_command.h
@@ -10,12 +10,12 @@
 // Generic command that can be passed to |chromeExecuteCommand|.
 @interface GenericChromeCommand : NSObject
 
-// Mark inherited initializer as unavailable to prevent calling it by mistake.
-- (instancetype)init NS_UNAVAILABLE;
-
 // Initializes the GenericChromeCommand with given |tag|.
 - (instancetype)initWithTag:(NSInteger)tag NS_DESIGNATED_INITIALIZER;
 
+// Mark inherited initializer as unavailable to prevent calling it by mistake.
+- (instancetype)init NS_UNAVAILABLE;
+
 // Convenience method to execute this command on the main window.
 - (void)executeOnMainWindow;
 
diff --git a/ios/chrome/browser/ui/commands/generic_chrome_command.mm b/ios/chrome/browser/ui/commands/generic_chrome_command.mm
index d2512b9..bf00f6b 100644
--- a/ios/chrome/browser/ui/commands/generic_chrome_command.mm
+++ b/ios/chrome/browser/ui/commands/generic_chrome_command.mm
@@ -21,6 +21,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (void)executeOnMainWindow {
   UIWindow* mainWindow = [[UIApplication sharedApplication] keyWindow];
   DCHECK(mainWindow);
diff --git a/ios/chrome/browser/ui/native_content_controller.h b/ios/chrome/browser/ui/native_content_controller.h
index f084d2d..3bca461f 100644
--- a/ios/chrome/browser/ui/native_content_controller.h
+++ b/ios/chrome/browser/ui/native_content_controller.h
@@ -7,7 +7,7 @@
 
 #import <Foundation/Foundation.h>
 
-#import "ios/web/public/web_state/crw_native_content.h"
+#import "ios/web/public/web_state/ui/crw_native_content.h"
 #include "url/gurl.h"
 
 @class UIView;
diff --git a/ios/chrome/browser/updatable_config/updatable_config_base.mm b/ios/chrome/browser/updatable_config/updatable_config_base.mm
index 80c3ddb..58d1058 100644
--- a/ios/chrome/browser/updatable_config/updatable_config_base.mm
+++ b/ios/chrome/browser/updatable_config/updatable_config_base.mm
@@ -113,11 +113,6 @@
 }
 
 // Overrides default designated initializer.
-- (instancetype)init {
-  NOTREACHED();
-  return nil;
-}
-
 - (instancetype)initWithAppId:(NSString*)appId
                       version:(NSString*)appVersion
                         plist:(NSString*)plistName {
@@ -157,6 +152,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (void)dealloc {
   [[NSNotificationCenter defaultCenter] removeObserver:self];
 #if !defined(NDEBUG)
diff --git a/ios/chrome/browser/xcallback_parameters.h b/ios/chrome/browser/xcallback_parameters.h
index 82b89965..ca245b3 100644
--- a/ios/chrome/browser/xcallback_parameters.h
+++ b/ios/chrome/browser/xcallback_parameters.h
@@ -33,6 +33,8 @@
                        createNewTab:(BOOL)createNewTab
     NS_DESIGNATED_INITIALIZER;
 
+- (instancetype)init NS_UNAVAILABLE;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_XCALLBACK_PARAMETERS_H_
diff --git a/ios/chrome/browser/xcallback_parameters.mm b/ios/chrome/browser/xcallback_parameters.mm
index 0d55d38..8554aa76 100644
--- a/ios/chrome/browser/xcallback_parameters.mm
+++ b/ios/chrome/browser/xcallback_parameters.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/xcallback_parameters.h"
 
+#include "base/logging.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 
@@ -41,6 +42,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (NSString*)description {
   return [NSString stringWithFormat:@"SourceApp: %@ (%@)\nSuccessURL: %s\n",
                                     _sourceAppName.get(), _sourceAppId.get(),
diff --git a/ios/chrome/ios_chrome_tests.gyp b/ios/chrome/ios_chrome_tests.gyp
index d6bb2ed..8a55c998 100644
--- a/ios/chrome/ios_chrome_tests.gyp
+++ b/ios/chrome/ios_chrome_tests.gyp
@@ -54,6 +54,8 @@
         '../../base/base.gyp:base',
         '../../testing/gmock.gyp:gmock',
         '../../testing/gtest.gyp:gtest',
+        '../../ui/base/ui_base.gyp:ui_base',
+        '../../url/url.gyp:url_lib',
         '../provider/ios_provider_chrome.gyp:ios_provider_chrome_browser',
         'ios_chrome.gyp:ios_chrome_browser',
       ],
diff --git a/ios/chrome/test/ios_chrome_unit_test_suite.cc b/ios/chrome/test/ios_chrome_unit_test_suite.cc
index bb28a425..7b59a14 100644
--- a/ios/chrome/test/ios_chrome_unit_test_suite.cc
+++ b/ios/chrome/test/ios_chrome_unit_test_suite.cc
@@ -10,6 +10,7 @@
 #include "ios/public/test/test_chrome_provider_initializer.h"
 #include "ios/web/public/web_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
 #include "url/url_util.h"
 
@@ -58,6 +59,9 @@
       testing::UnitTest::GetInstance()->listeners();
   listeners.Append(new IOSChromeUnitTestSuiteInitializer);
 
+  ui::ResourceBundle::InitSharedInstanceWithLocale(
+      "en-US", nullptr, ui::ResourceBundle::LOAD_COMMON_RESOURCES);
+
   // Ensure that all BrowserStateKeyedServiceFactories are built before any
   // test is run so that the dependencies are correctly resolved.
   EnsureBrowserStateKeyedServiceFactoriesBuilt();
diff --git a/ios/crnet/crnet_consumer/crnet_consumer.gyp b/ios/crnet/crnet_consumer/crnet_consumer.gyp
index 5364d76..3882444 100644
--- a/ios/crnet/crnet_consumer/crnet_consumer.gyp
+++ b/ios/crnet/crnet_consumer/crnet_consumer.gyp
@@ -46,10 +46,14 @@
               '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
               '$(SDKROOT)/System/Library/Frameworks/Security.framework',
               '$(SDKROOT)/System/Library/Frameworks/SystemConfiguration.framework',
-              '$(SDKROOT)/usr/lib/libresolv.dylib',
-              '$(SDKROOT)/usr/lib/libsqlite3.dylib',
-              '$(SDKROOT)/usr/lib/libxml2.dylib',
             ],
+            'xcode_settings': {
+              'OTHER_LDFLAGS': [
+                '-lresolv',
+                '-lsqlite3',
+                '-lxml2',
+              ],
+            },
           },
           'xcode_settings': {
             'CLANG_ENABLE_OBJC_ARC': 'YES',
diff --git a/ios/crnet/crnet_environment.mm b/ios/crnet/crnet_environment.mm
index d139b7f..d6623107 100644
--- a/ios/crnet/crnet_environment.mm
+++ b/ios/crnet/crnet_environment.mm
@@ -22,6 +22,7 @@
 #include "crypto/nss_util.h"
 #include "ios/net/cookies/cookie_store_ios.h"
 #include "ios/net/crn_http_protocol_handler.h"
+#include "ios/net/empty_nsurlcache.h"
 #include "ios/net/request_tracker.h"
 #include "ios/web/public/user_agent.h"
 #include "net/base/net_errors.h"
@@ -300,7 +301,7 @@
 void CrNetEnvironment::SetHTTPProtocolHandlerRegistered(bool registered) {
   if (registered) {
     // Disable the default cache.
-    [NSURLCache setSharedURLCache:nil];
+    [NSURLCache setSharedURLCache:[EmptyNSURLCache emptyNSURLCache]];
     // Register the chrome http protocol handler to replace the default one.
     BOOL success = [NSURLProtocol registerClass:[CRNHTTPProtocolHandler class]];
     DCHECK(success);
diff --git a/ios/ios_tests.gyp b/ios/ios_tests.gyp
index e253aa4..7518951e 100644
--- a/ios/ios_tests.gyp
+++ b/ios/ios_tests.gyp
@@ -10,19 +10,28 @@
       'target_name': 'test_support_ios',
       'type': 'static_library',
       'sources': [
+        # TODO(droger): Move most of these files to
+        # //ios/chrome/ios_chrome_tests.gyp, see http://crbug.com/437333
         'public/test/fake_profile_oauth2_token_service_ios_provider.h',
         'public/test/fake_profile_oauth2_token_service_ios_provider.mm',
         'public/test/fake_string_provider.cc',
         'public/test/fake_string_provider.h',
+        'public/test/fake_sync_service_factory.cc',
+        'public/test/fake_sync_service_factory.h',
         'public/test/test_chrome_browser_provider.h',
         'public/test/test_chrome_browser_provider.mm',
         'public/test/test_chrome_provider_initializer.cc',
         'public/test/test_chrome_provider_initializer.h',
+        'public/test/test_keyed_service_provider.cc',
+        'public/test/test_keyed_service_provider.h',
         'public/test/test_updatable_resource_provider.h',
         'public/test/test_updatable_resource_provider.mm',
       ],
       'dependencies': [
         '../base/base.gyp:base',
+        '../components/components.gyp:keyed_service_core',
+        '../components/components.gyp:keyed_service_ios',
+        '../components/components.gyp:sync_driver_test_support',
         '../testing/gtest.gyp:gtest',
         'provider/ios_provider_chrome.gyp:ios_provider_chrome_browser',
       ],
diff --git a/ios/net/clients/crn_forwarding_network_client_factory_unittest.mm b/ios/net/clients/crn_forwarding_network_client_factory_unittest.mm
index 735c7f5..4364cdb 100644
--- a/ios/net/clients/crn_forwarding_network_client_factory_unittest.mm
+++ b/ios/net/clients/crn_forwarding_network_client_factory_unittest.mm
@@ -142,7 +142,7 @@
   for (NSInteger i = 0; i < class_count; i++) {
     std::string class_name = class_getName(classes[i]);
     // Skip the test classes defined above.
-    if (StartsWithASCII(class_name, "TestFactory", false))
+    if (base::StartsWithASCII(class_name, "TestFactory", false))
       continue;
 
     Class subclass_super = classes[i];
diff --git a/ios/net/empty_nsurlcache.h b/ios/net/empty_nsurlcache.h
new file mode 100644
index 0000000..0054e0b
--- /dev/null
+++ b/ios/net/empty_nsurlcache.h
@@ -0,0 +1,15 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_NET_EMPTY_NSURLCACHE_H_
+#define IOS_NET_EMPTY_NSURLCACHE_H_
+
+#import <Foundation/Foundation.h>
+
+// Dummy NSURLCache implementation that does not cache anything.
+@interface EmptyNSURLCache : NSURLCache
++ (instancetype)emptyNSURLCache;
+@end
+
+#endif  // IOS_NET_EMPTY_NSURLCACHE_H_
diff --git a/ios/net/empty_nsurlcache.mm b/ios/net/empty_nsurlcache.mm
new file mode 100644
index 0000000..c08826bb
--- /dev/null
+++ b/ios/net/empty_nsurlcache.mm
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/net/empty_nsurlcache.h"
+
+@implementation EmptyNSURLCache
+
++ (instancetype)emptyNSURLCache {
+  return [[[EmptyNSURLCache alloc] init] autorelease];
+}
+
+- (NSCachedURLResponse*)cachedResponseForRequest:(NSURLRequest*)request {
+  return nil;
+}
+
+@end
diff --git a/ios/net/ios_net.gyp b/ios/net/ios_net.gyp
index bd2e153..b9ad092 100644
--- a/ios/net/ios_net.gyp
+++ b/ios/net/ios_net.gyp
@@ -42,6 +42,8 @@
         'crn_http_protocol_handler_proxy_with_client_thread.mm',
         'crn_http_url_response.h',
         'crn_http_url_response.mm',
+        'empty_nsurlcache.h',
+        'empty_nsurlcache.mm',
         'http_protocol_logging.h',
         'http_protocol_logging.mm',
         'http_response_headers_util.h',
diff --git a/ios/net/request_tracker.mm b/ios/net/request_tracker.mm
index 6eb21c3..a4cfa547 100644
--- a/ios/net/request_tracker.mm
+++ b/ios/net/request_tracker.mm
@@ -34,7 +34,11 @@
   // Adds a factory.
   void AddFactory(CRNForwardingNetworkClientFactory* factory) {
     DCHECK(thread_checker_.CalledOnValidThread());
-    DCHECK_EQ(NSNotFound, [factories_ indexOfObject:factory]);
+    // TODO(justincohen): Cast indexOfObject to work around Xcode beta bugs.
+    // Revisit in future betas where hopefully these types match again.
+    // crbug.com/498825
+    DCHECK_EQ(NSNotFound,
+              static_cast<NSInteger>([factories_ indexOfObject:factory]));
     DCHECK(!IsSelectorOverriden(factory, @selector(clientHandlingRequest:)));
     DCHECK(!IsSelectorOverriden(factory,
                                 @selector(clientHandlingResponse:request:)));
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.cc b/ios/public/provider/chrome/browser/chrome_browser_provider.cc
index 7db527b..52c7b65 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.cc
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.cc
@@ -9,7 +9,7 @@
 namespace ios {
 
 namespace {
-ChromeBrowserProvider* g_chrome_browser_provider;
+ChromeBrowserProvider* g_chrome_browser_provider = nullptr;
 }  // namespace
 
 void SetChromeBrowserProvider(ChromeBrowserProvider* provider) {
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.h b/ios/public/provider/chrome/browser/chrome_browser_provider.h
index 4f1e12a..1924d6db 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.h
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.h
@@ -21,10 +21,6 @@
 class URLRequestContextGetter;
 }
 
-namespace web {
-class WebState;
-}
-
 // TODO(ios): Determine the best way to interface with Obj-C code through
 // the ChromeBrowserProvider. crbug/298181
 #ifdef __OBJC__
@@ -83,9 +79,8 @@
   virtual void SetUIViewAlphaWithAnimation(UIView* view, float alpha);
   // Returns an instance of a CardUnmaskPromptView used to unmask Wallet cards.
   // The view is responsible for its own lifetime.
-  virtual autofill::CardUnmaskPromptView*
-      CreateCardUnmaskPromptView(
-          autofill::CardUnmaskPromptController* controller);
+  virtual autofill::CardUnmaskPromptView* CreateCardUnmaskPromptView(
+      autofill::CardUnmaskPromptController* controller);
   // Returns risk data used in Wallet requests.
   virtual std::string GetRiskData();
   // Returns product version with prefix.
diff --git a/ios/public/test/DEPS b/ios/public/test/DEPS
new file mode 100644
index 0000000..3672da23
--- /dev/null
+++ b/ios/public/test/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  '+components/keyed_service/core',
+  '+components/keyed_service/ios',
+  '+components/sync_driver',
+]
diff --git a/ios/public/test/fake_sync_service_factory.cc b/ios/public/test/fake_sync_service_factory.cc
new file mode 100644
index 0000000..1f85f8e
--- /dev/null
+++ b/ios/public/test/fake_sync_service_factory.cc
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/public/test/fake_sync_service_factory.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/sync_driver/fake_sync_service.h"
+
+namespace {
+
+class KeyedFakeSyncService : public KeyedService {
+ public:
+  KeyedFakeSyncService(sync_driver::FakeSyncService* service)
+      : fake_sync_service_(service) {
+    DCHECK(fake_sync_service_);
+  }
+
+  sync_driver::FakeSyncService* fake_sync_service() {
+    return fake_sync_service_.get();
+  }
+
+ private:
+  scoped_ptr<sync_driver::FakeSyncService> fake_sync_service_;
+};
+
+}  // namespace
+
+namespace ios {
+
+// static
+FakeSyncServiceFactory* FakeSyncServiceFactory::GetInstance() {
+  return Singleton<FakeSyncServiceFactory>::get();
+}
+
+// static
+sync_driver::FakeSyncService* FakeSyncServiceFactory::GetForBrowserState(
+    web::BrowserState* browser_state) {
+  return static_cast<KeyedFakeSyncService*>(
+             FakeSyncServiceFactory::GetInstance()->GetServiceForBrowserState(
+                 browser_state, true))->fake_sync_service();
+}
+
+KeyedService* FakeSyncServiceFactory::BuildServiceInstanceFor(
+    web::BrowserState* context) const {
+  return new KeyedFakeSyncService(new sync_driver::FakeSyncService);
+}
+
+FakeSyncServiceFactory::FakeSyncServiceFactory()
+    : BrowserStateKeyedServiceFactory(
+          "FakeSyncService",
+          BrowserStateDependencyManager::GetInstance()) {
+}
+
+FakeSyncServiceFactory::~FakeSyncServiceFactory() {
+}
+
+}  // namespace ios
diff --git a/ios/public/test/fake_sync_service_factory.h b/ios/public/test/fake_sync_service_factory.h
new file mode 100644
index 0000000..2ab0d8d
--- /dev/null
+++ b/ios/public/test/fake_sync_service_factory.h
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_PUBLIC_TEST_FAKE_SYNC_SERVICE_FACTORY_H_
+#define IOS_PUBLIC_TEST_FAKE_SYNC_SERVICE_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+namespace sync_driver {
+class FakeSyncService;
+}
+
+namespace ios {
+
+class FakeSyncServiceFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  // Returns the singleton FakeSyncServiceFactory instance.
+  static FakeSyncServiceFactory* GetInstance();
+
+  // Returns the FakeSyncService associated to |browser_state|.
+  static sync_driver::FakeSyncService* GetForBrowserState(
+      web::BrowserState* browser_state);
+
+ private:
+  friend struct DefaultSingletonTraits<FakeSyncServiceFactory>;
+
+  // BrowserStateKeyedServiceFactory implementation:
+  KeyedService* BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+
+  FakeSyncServiceFactory();
+  ~FakeSyncServiceFactory() override;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeSyncServiceFactory);
+};
+
+}  // namespace ios
+
+#endif  // IOS_PUBLIC_TEST_FAKE_SYNC_SERVICE_FACTORY_H_
diff --git a/ios/public/test/test_chrome_browser_provider.h b/ios/public/test/test_chrome_browser_provider.h
index 698fa65..8ab210a 100644
--- a/ios/public/test/test_chrome_browser_provider.h
+++ b/ios/public/test/test_chrome_browser_provider.h
@@ -24,9 +24,11 @@
   // ChromeBrowserProvider:
   StringProvider* GetStringProvider() override;
   const char* GetChromeUIScheme() override;
+  KeyedServiceProvider* GetKeyedServiceProvider() override;
 
  private:
   scoped_ptr<FakeStringProvider> string_provider_;
+  scoped_ptr<KeyedServiceProvider> test_keyed_service_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(TestChromeBrowserProvider);
 };
diff --git a/ios/public/test/test_chrome_browser_provider.mm b/ios/public/test/test_chrome_browser_provider.mm
index afcf24ca..df12eaa 100644
--- a/ios/public/test/test_chrome_browser_provider.mm
+++ b/ios/public/test/test_chrome_browser_provider.mm
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "ios/public/test/fake_string_provider.h"
+#import "ios/public/test/test_keyed_service_provider.h"
 
 namespace {
 const char kUIScheme[] = "uischeme";
@@ -14,7 +15,8 @@
 namespace ios {
 
 TestChromeBrowserProvider::TestChromeBrowserProvider()
-    : string_provider_(new FakeStringProvider) {
+    : string_provider_(new FakeStringProvider),
+      test_keyed_service_provider_(new TestKeyedServiceProvider) {
 }
 
 TestChromeBrowserProvider::~TestChromeBrowserProvider() {
@@ -31,6 +33,10 @@
   return string_provider_.get();
 }
 
+KeyedServiceProvider* TestChromeBrowserProvider::GetKeyedServiceProvider() {
+  return test_keyed_service_provider_.get();
+}
+
 const char* TestChromeBrowserProvider::GetChromeUIScheme() {
   return kUIScheme;
 }
diff --git a/ios/public/test/test_keyed_service_provider.cc b/ios/public/test/test_keyed_service_provider.cc
new file mode 100644
index 0000000..053d47e4
--- /dev/null
+++ b/ios/public/test/test_keyed_service_provider.cc
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/public/test/test_keyed_service_provider.h"
+
+#include "components/sync_driver/fake_sync_service.h"
+#include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/public/test/fake_sync_service_factory.h"
+
+namespace ios {
+
+TestKeyedServiceProvider::TestKeyedServiceProvider() {
+}
+
+TestKeyedServiceProvider::~TestKeyedServiceProvider() {
+}
+
+KeyedServiceBaseFactory* TestKeyedServiceProvider::GetSyncServiceFactory() {
+  return FakeSyncServiceFactory::GetInstance();
+}
+
+sync_driver::SyncService*
+TestKeyedServiceProvider::GetSyncServiceForBrowserState(
+    ChromeBrowserState* browser_state) {
+  return FakeSyncServiceFactory::GetForBrowserState(browser_state);
+}
+
+}  // namespace ios
diff --git a/ios/public/test/test_keyed_service_provider.h b/ios/public/test/test_keyed_service_provider.h
new file mode 100644
index 0000000..b2867ec
--- /dev/null
+++ b/ios/public/test/test_keyed_service_provider.h
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_PUBLIC_TEST_TEST_KEYED_SERVICE_PROVIDER_H_
+#define IOS_PUBLIC_TEST_TEST_KEYED_SERVICE_PROVIDER_H_
+
+#include "base/macros.h"
+#include "ios/public/provider/chrome/browser/keyed_service_provider.h"
+
+namespace ios {
+
+class TestKeyedServiceProvider : public KeyedServiceProvider {
+ public:
+  TestKeyedServiceProvider();
+  ~TestKeyedServiceProvider() override;
+
+  // KeyedServiceProvider implementation:
+  KeyedServiceBaseFactory* GetSyncServiceFactory() override;
+  sync_driver::SyncService* GetSyncServiceForBrowserState(
+      ChromeBrowserState* browser_state) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestKeyedServiceProvider);
+};
+
+}  // namespace ios
+
+#endif  // IOS_PUBLIC_TEST_TEST_KEYED_SERVICE_PROVIDER_H_
diff --git a/ios/public/test/test_updatable_resource_provider.mm b/ios/public/test/test_updatable_resource_provider.mm
index de8459f2..177f17b 100644
--- a/ios/public/test/test_updatable_resource_provider.mm
+++ b/ios/public/test/test_updatable_resource_provider.mm
@@ -43,6 +43,7 @@
 - (instancetype)initWithDelegate:(id<UpdatableResourceDelegate>)delegate
                            plist:(NSString*)resource_identifier
     NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
 @end
 
 @implementation TestUpdatableResource {
@@ -62,6 +63,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (id<UpdatableResourceDescriptorBridge>)descriptor {
   return _descriptor.get();
 }
diff --git a/ios/third_party/gcdwebserver/gcdwebserver.gyp b/ios/third_party/gcdwebserver/gcdwebserver.gyp
index a1b4210..117c6a2d 100644
--- a/ios/third_party/gcdwebserver/gcdwebserver.gyp
+++ b/ios/third_party/gcdwebserver/gcdwebserver.gyp
@@ -55,8 +55,12 @@
         'libraries': [
           '$(SDKROOT)/System/Library/Frameworks/CFNetwork.framework',
           '$(SDKROOT)/System/Library/Frameworks/MobileCoreServices.framework',
-          '$(SDKROOT)/usr/lib/libz.dylib',
         ],
+        'xcode_settings': {
+          'OTHER_LDFLAGS': [
+            '-lz',
+          ],
+        },
       },
     },
   ],
diff --git a/ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.h b/ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.h
index 997eaa8..bb87190 100644
--- a/ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.h
+++ b/ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.h
@@ -19,6 +19,8 @@
 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState
     NS_DESIGNATED_INITIALIZER;
 
+- (instancetype)init NS_UNAVAILABLE;
+
 @end
 
 #endif  // IOS_WEB_BROWSING_DATA_MANAGERS_CRW_COOKIE_BROWSING_DATA_MANAGER_H_
diff --git a/ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.mm b/ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.mm
index e9006ba..f2c42e2 100644
--- a/ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.mm
+++ b/ios/web/browsing_data_managers/crw_cookie_browsing_data_manager.mm
@@ -20,6 +20,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 #pragma mark CRWBrowsingDataManager implementation
 // TODO(shreyasv): During implementation of the following methods evaluate if
 // the entire BrowserState is required. Looks like only |state_path| may be
diff --git a/ios/web/crw_browsing_data_store.mm b/ios/web/crw_browsing_data_store.mm
index 1d9fbe0..d78db6a 100644
--- a/ios/web/crw_browsing_data_store.mm
+++ b/ios/web/crw_browsing_data_store.mm
@@ -45,6 +45,7 @@
 // run. All remove operations need to be run on the same queue hence it is
 // shared with all CRWBrowsingDataStores.
 + (NSOperationQueue*)operationQueueForRemoveOperations;
+- (instancetype)init NS_UNAVAILABLE;
 
 // The array of all browsing data managers. Must be accessed from the main
 // thread.
@@ -176,6 +177,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (NSString*)description {
   NSString* format = @"<%@: %p; hasPendingOperations = { %@ }>";
   NSString* hasPendingOperationsString =
diff --git a/ios/web/crw_browsing_data_store_unittest.mm b/ios/web/crw_browsing_data_store_unittest.mm
index a35c7f9..4364073c 100644
--- a/ios/web/crw_browsing_data_store_unittest.mm
+++ b/ios/web/crw_browsing_data_store_unittest.mm
@@ -22,6 +22,7 @@
 // Designated init. |browsingDataStore| cannot be null.
 - (instancetype)initWithBrowsingDataStore:
         (CRWBrowsingDataStore*)browsingDataStore NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
 // The number of times that the mode of the underlying CRWBrowsingDataStore
 // changed.
 @property(nonatomic, assign) NSUInteger modeChangeCount;
@@ -48,6 +49,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (void)observeValueForKeyPath:(NSString*)keyPath
                       ofObject:(id)object
                         change:(NSDictionary*)change
diff --git a/ios/web/ios_web.gyp b/ios/web/ios_web.gyp
index da17880..7bc0242 100644
--- a/ios/web/ios_web.gyp
+++ b/ios/web/ios_web.gyp
@@ -68,11 +68,11 @@
         'alloc_with_zone_interceptor.h',
         'alloc_with_zone_interceptor.mm',
         'browser_state.mm',
+        'browser_url_rewriter_impl.cc',
+        'browser_url_rewriter_impl.h',
         'browsing_data_managers/crw_browsing_data_manager.h',
         'browsing_data_managers/crw_cookie_browsing_data_manager.h',
         'browsing_data_managers/crw_cookie_browsing_data_manager.mm',
-        'browser_url_rewriter_impl.cc',
-        'browser_url_rewriter_impl.h',
         'browsing_data_partition_impl.h',
         'browsing_data_partition_impl.mm',
         'crw_browsing_data_store.mm',
@@ -142,12 +142,11 @@
         'public/browser_state.h',
         'public/browser_url_rewriter.h',
         'public/browsing_data_partition.h',
-        'public/crw_browsing_data_store.h',
-        'public/crw_browsing_data_store_delegate.h',
         'public/cert_policy.h',
         'public/cert_store.h',
         'public/certificate_policy_cache.h',
         'public/crw_browsing_data_store.h',
+        'public/crw_browsing_data_store_delegate.h',
         'public/favicon_status.cc',
         'public/favicon_status.h',
         'public/favicon_url.cc',
@@ -175,8 +174,6 @@
         'public/web_controller_factory.h',
         'public/web_controller_factory.mm',
         'public/web_state/credential.h',
-        'public/web_state/crw_native_content.h',
-        'public/web_state/crw_native_content_provider.h',
         'public/web_state/crw_web_controller_observer.h',
         'public/web_state/crw_web_delegate.h',
         'public/web_state/crw_web_user_interface_delegate.h',
@@ -187,6 +184,8 @@
         'public/web_state/js/crw_js_injection_receiver.h',
         'public/web_state/page_scroll_state.h',
         'public/web_state/page_scroll_state.mm',
+        'public/web_state/ui/crw_native_content.h',
+        'public/web_state/ui/crw_native_content_provider.h',
         'public/web_state/url_verification_constants.h',
         'public/web_state/web_state.h',
         'public/web_state/web_state_observer.h',
@@ -314,8 +313,8 @@
         '../..',
       ],
       'sources': [
-        'web_thread_impl.h',
         'web_thread_impl.cc',
+        'web_thread_impl.h',
       ],
     },
     # Target that builds the files that shim WebThread functions to their
@@ -333,8 +332,8 @@
         '../..',
       ],
       'sources': [
-        'web_thread_adapter.h',
         'web_thread_adapter.cc',
+        'web_thread_adapter.h',
       ],
     },
     # Target shared by ios_web and CrNet.
diff --git a/ios/web/net/clients/crw_redirect_network_client.mm b/ios/web/net/clients/crw_redirect_network_client.mm
index 2442834..ae19229d 100644
--- a/ios/web/net/clients/crw_redirect_network_client.mm
+++ b/ios/web/net/clients/crw_redirect_network_client.mm
@@ -17,11 +17,6 @@
 
 @implementation CRWRedirectNetworkClient
 
-- (instancetype)init {
-  NOTREACHED();
-  return nil;
-}
-
 - (instancetype)initWithDelegate:
     (base::WeakNSProtocol<id<CRWRedirectClientDelegate>>)delegate {
   self = [super init];
@@ -35,6 +30,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (void)wasRedirectedToRequest:(NSURLRequest*)request
                  nativeRequest:(net::URLRequest*)nativeRequest
               redirectResponse:(NSURLResponse*)redirectResponse {
diff --git a/ios/web/net/clients/crw_redirect_network_client_factory.mm b/ios/web/net/clients/crw_redirect_network_client_factory.mm
index d3ac5da..3ad439bb 100644
--- a/ios/web/net/clients/crw_redirect_network_client_factory.mm
+++ b/ios/web/net/clients/crw_redirect_network_client_factory.mm
@@ -21,11 +21,6 @@
 
 @implementation CRWRedirectNetworkClientFactory
 
-- (instancetype)init {
-  NOTREACHED();
-  return nil;
-}
-
 - (instancetype)initWithDelegate:(id<CRWRedirectClientDelegate>)delegate {
   self = [super init];
   if (self) {
@@ -36,6 +31,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 #pragma mark - CRNForwardingNetworkClientFactory
 
 - (Class)clientClass {
diff --git a/ios/web/net/request_tracker_impl.mm b/ios/web/net/request_tracker_impl.mm
index 07325389..4854fda 100644
--- a/ios/web/net/request_tracker_impl.mm
+++ b/ios/web/net/request_tracker_impl.mm
@@ -314,6 +314,9 @@
       case web::SECURITY_STYLE_AUTHENTICATION_BROKEN:
         sslInfo = @"Not secure ";
         break;
+      case web::SECURITY_STYLE_WARNING:
+        sslInfo = @"Security warning";
+        break;
       case web::SECURITY_STYLE_AUTHENTICATED:
         if (status_.content_status ==
             web::SSLStatus::DISPLAYED_INSECURE_CONTENT)
diff --git a/ios/web/public/security_style.h b/ios/web/public/security_style.h
index a2fbf841..a72396c 100644
--- a/ios/web/public/security_style.h
+++ b/ios/web/public/security_style.h
@@ -28,6 +28,11 @@
   // this object in an authenticated manner but were unable to do so.
   SECURITY_STYLE_AUTHENTICATION_BROKEN,
 
+  // SECURITY_STYLE_WARNING means that the object was retrieved in an
+  // authenticated manner, but there were security issues with the retrieval or
+  // the object interacted with less secure objects.
+  SECURITY_STYLE_WARNING,
+
   // SECURITY_STYLE_AUTHENTICATED indicates that we successfully retrieved this
   // object over an authenticated protocol, such as HTTPS.
   SECURITY_STYLE_AUTHENTICATED,
diff --git a/ios/web/public/web_state/crw_web_delegate.h b/ios/web/public/web_state/crw_web_delegate.h
index 357899f..6bf0458 100644
--- a/ios/web/public/web_state/crw_web_delegate.h
+++ b/ios/web/public/web_state/crw_web_delegate.h
@@ -11,7 +11,7 @@
 #include "base/ios/block_types.h"
 #include "ios/web/public/favicon_url.h"
 #include "ios/web/public/ssl_status.h"
-#import "ios/web/public/web_state/crw_native_content.h"
+#import "ios/web/public/web_state/ui/crw_native_content.h"
 #include "ios/web/public/web_state/web_state.h"
 #include "ui/base/page_transition_types.h"
 
@@ -188,8 +188,8 @@
 // Called to ask if external URL should be opened. External URL is one that
 // cannot be presented by CRWWebController.
 - (BOOL)webController:(CRWWebController*)webController
-    shouldOpenExternalURL:(const GURL&)url;
-
+    shouldOpenExternalURL:(const GURL&)URL
+        userIsInteracting:(BOOL)userIsInteracting;
 
 // Called when |url| is deemed suitable to be opened in a matching native app.
 // Needs to return whether |url| was opened in a matching native app.
diff --git a/ios/web/public/web_state/page_scroll_state.h b/ios/web/public/web_state/page_scroll_state.h
index 9984019..7fceb2c 100644
--- a/ios/web/public/web_state/page_scroll_state.h
+++ b/ios/web/public/web_state/page_scroll_state.h
@@ -39,6 +39,11 @@
   // can only be applied to CRWUIWebViewWebControllers.
   bool IsZoomScaleLegacyFormat() const;
 
+  // Returns the allowed zoom scale range for this scroll state.
+  double GetMinMaxZoomDifference() const {
+    return maximum_zoom_scale_ - minimum_zoom_scale_;
+  }
+
   // Accessors for scroll offsets and zoom scale.
   double scroll_offset_x() const { return scroll_offset_x_; }
   void set_scroll_offset_x(double scroll_offset_x) {
@@ -59,8 +64,9 @@
   double zoom_scale() const { return zoom_scale_; }
   void set_zoom_scale(double zoom_scale) { zoom_scale_ = zoom_scale; }
 
-  // Comparator operator.
+  // Comparator operators.
   bool operator==(const PageScrollState& other) const;
+  bool operator!=(const PageScrollState& other) const;
 
  private:
   double scroll_offset_x_;
diff --git a/ios/web/public/web_state/page_scroll_state.mm b/ios/web/public/web_state/page_scroll_state.mm
index b7479fd4..b77abb7 100644
--- a/ios/web/public/web_state/page_scroll_state.mm
+++ b/ios/web/public/web_state/page_scroll_state.mm
@@ -69,4 +69,8 @@
          StateValuesAreEqual(zoom_scale_, other.zoom_scale_);
 }
 
+bool PageScrollState::operator!=(const PageScrollState& other) const {
+  return !(*this == other);
+}
+
 }  // namespace web
diff --git a/ios/web/public/web_state/crw_native_content.h b/ios/web/public/web_state/ui/crw_native_content.h
similarity index 93%
rename from ios/web/public/web_state/crw_native_content.h
rename to ios/web/public/web_state/ui/crw_native_content.h
index 61463d3..0273c7b 100644
--- a/ios/web/public/web_state/crw_native_content.h
+++ b/ios/web/public/web_state/ui/crw_native_content.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_WEB_STATE_CRW_NATIVE_CONTENT_H_
-#define IOS_WEB_PUBLIC_WEB_STATE_CRW_NATIVE_CONTENT_H_
+#ifndef IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_NATIVE_CONTENT_H_
+#define IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_NATIVE_CONTENT_H_
 
 #import <UIKit/UIKit.h>
 
@@ -89,4 +89,4 @@
 
 @end
 
-#endif  // IOS_WEB_PUBLIC_WEB_STATE_CRW_NATIVE_CONTENT_H_
+#endif  // IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_NATIVE_CONTENT_H_
diff --git a/ios/web/public/web_state/crw_native_content_provider.h b/ios/web/public/web_state/ui/crw_native_content_provider.h
similarity index 85%
rename from ios/web/public/web_state/crw_native_content_provider.h
rename to ios/web/public/web_state/ui/crw_native_content_provider.h
index 7d4a4cc6..6d9eacd 100644
--- a/ios/web/public/web_state/crw_native_content_provider.h
+++ b/ios/web/public/web_state/ui/crw_native_content_provider.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_PUBLIC_WEB_STATE_CRW_NATIVE_CONTENT_PROVIDER_H_
-#define IOS_WEB_PUBLIC_WEB_STATE_CRW_NATIVE_CONTENT_PROVIDER_H_
+#ifndef IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_NATIVE_CONTENT_PROVIDER_H_
+#define IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_NATIVE_CONTENT_PROVIDER_H_
 #import <UIKit/UIKit.h>
 
 class GURL;
@@ -31,4 +31,4 @@
 
 @end
 
-#endif  // IOS_WEB_PUBLIC_WEB_STATE_CRW_NATIVE_CONTENT_PROVIDER_H_
+#endif  // IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_NATIVE_CONTENT_PROVIDER_H_
diff --git a/ios/web/shell/Info.plist b/ios/web/shell/Info.plist
index 5740b88..d3e1647 100644
--- a/ios/web/shell/Info.plist
+++ b/ios/web/shell/Info.plist
@@ -24,6 +24,11 @@
 	<string>1.0</string>
 	<key>LSRequiresIPhoneOS</key>
 	<true/>
+	<key>NSAppTransportSecurity</key>
+	<dict>
+		<key>NSAllowsArbitraryLoads</key>
+		<true/>
+	</dict>
 	<key>UIRequiredDeviceCapabilities</key>
 	<array>
 		<string>armv7</string>
diff --git a/ios/web/shell/view_controller.mm b/ios/web/shell/view_controller.mm
index 16e78fe7..fc7d52b94 100644
--- a/ios/web/shell/view_controller.mm
+++ b/ios/web/shell/view_controller.mm
@@ -10,6 +10,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "ios/net/cookies/cookie_store_ios.h"
 #import "ios/net/crn_http_protocol_handler.h"
+#import "ios/net/empty_nsurlcache.h"
 #import "ios/web/navigation/crw_session_controller.h"
 #include "ios/web/navigation/web_load_params.h"
 #import "ios/web/net/crw_url_verifying_protocol_handler.h"
@@ -130,7 +131,7 @@
 
 - (void)setUpNetworkStack {
   // Disable the default cache.
-  [NSURLCache setSharedURLCache:nil];
+  [NSURLCache setSharedURLCache:[EmptyNSURLCache emptyNSURLCache]];
 
   _httpProtocolDelegate.reset(new web::WebHTTPProtocolHandlerDelegate(
       _browserState->GetRequestContext()));
diff --git a/ios/web/test/crw_fake_web_controller_observer.mm b/ios/web/test/crw_fake_web_controller_observer.mm
index 1808168..c15553f 100644
--- a/ios/web/test/crw_fake_web_controller_observer.mm
+++ b/ios/web/test/crw_fake_web_controller_observer.mm
@@ -15,11 +15,6 @@
 
 @synthesize pageLoaded = _pageLoaded;
 
-- (instancetype)init {
-  NOTREACHED();
-  return nil;
-}
-
 - (instancetype)initWithCommandPrefix:(NSString*)commandPrefix {
   DCHECK(commandPrefix);
   self = [super init];
@@ -29,6 +24,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (void)pageLoaded:(CRWWebController*)webController {
   _pageLoaded = YES;
 }
diff --git a/ios/web/weak_nsobject_counter.mm b/ios/web/weak_nsobject_counter.mm
index bd14b7b..edcf01a 100644
--- a/ios/web/weak_nsobject_counter.mm
+++ b/ios/web/weak_nsobject_counter.mm
@@ -29,11 +29,6 @@
   linked_ptr<NSUInteger> _counter;
 }
 
-- (instancetype)init {
-  NOTREACHED();
-  return nil;
-}
-
 - (instancetype)initWithSharedCounter:(const linked_ptr<NSUInteger>&)counter
                    objectToBeObserved:(id)object {
   self = [super init];
@@ -48,6 +43,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (void)dealloc {
   DCHECK(_counter.get());
   (*_counter)--;
diff --git a/ios/web/web_state/js/crw_js_early_script_manager_unittest.mm b/ios/web/web_state/js/crw_js_early_script_manager_unittest.mm
index f0f2bfb2..ff163b2 100644
--- a/ios/web/web_state/js/crw_js_early_script_manager_unittest.mm
+++ b/ios/web/web_state/js/crw_js_early_script_manager_unittest.mm
@@ -43,7 +43,12 @@
   // |earlyScript| is a substring of |injectionContent|. The latter wraps the
   // former with "if (typeof __gCrWeb !== 'object')" check to avoid multiple
   // injections.
-  EXPECT_NE(NSNotFound, [injectionContent rangeOfString:earlyScript].location);
+  // TODO(justincohen): Cast indexOfObject to work around Xcode beta bugs.
+  // Revisit in future betas where hopefully these types match again.
+  // crbug.com/498825
+  EXPECT_NE(NSNotFound,
+            static_cast<NSInteger>(
+                [injectionContent rangeOfString:earlyScript].location));
 }
 
 }  // namespace
diff --git a/ios/web/web_state/ui/crw_ui_simple_web_view_controller.mm b/ios/web/web_state/ui/crw_ui_simple_web_view_controller.mm
index dd15a3d9..7d12883 100644
--- a/ios/web/web_state/ui/crw_ui_simple_web_view_controller.mm
+++ b/ios/web/web_state/ui/crw_ui_simple_web_view_controller.mm
@@ -72,7 +72,7 @@
   [_webView loadData:data
               MIMEType:@"application/pdf"
       textEncodingName:@"utf-8"
-               baseURL:nil];
+               baseURL:[NSURL URLWithString:@""]];
 }
 
 - (void)evaluateJavaScript:(NSString*)script
diff --git a/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm b/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm
index 1aff4fb..424b549 100644
--- a/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm
@@ -815,6 +815,10 @@
   self.webScrollView.zoomScale = zoomScale;
 }
 
+-(BOOL)shouldAbortLoadForCancelledURL:(const GURL&)cancelledURL {
+  return YES;
+}
+
 #pragma mark - JS to ObjC messaging
 
 - (void)respondToJSInvoke {
diff --git a/ios/web/web_state/ui/crw_web_controller+protected.h b/ios/web/web_state/ui/crw_web_controller+protected.h
index 5087983..688e71f 100644
--- a/ios/web/web_state/ui/crw_web_controller+protected.h
+++ b/ios/web/web_state/ui/crw_web_controller+protected.h
@@ -167,6 +167,10 @@
 - (void)applyWebViewScrollZoomScaleFromScrollState:
     (const web::PageScrollState&)scrollState;
 
+// Returns YES if load should be aborted when NSURLCancelledError is
+// encountered for |cancelledURL|.
+- (BOOL)shouldAbortLoadForCancelledURL:(const GURL&)cancelledURL;
+
 #pragma mark - Optional methods for subclasses
 // Subclasses may overwrite methods in this section.
 
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index c566bf0..ba6746d 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -49,12 +49,12 @@
 #include "ios/web/public/user_metrics.h"
 #include "ios/web/public/web_client.h"
 #include "ios/web/public/web_state/credential.h"
-#import "ios/web/public/web_state/crw_native_content.h"
-#import "ios/web/public/web_state/crw_native_content_provider.h"
 #import "ios/web/public/web_state/crw_web_controller_observer.h"
 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h"
 #import "ios/web/public/web_state/js/crw_js_injection_manager.h"
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
+#import "ios/web/public/web_state/ui/crw_native_content.h"
+#import "ios/web/public/web_state/ui/crw_native_content_provider.h"
 #include "ios/web/public/web_state/url_verification_constants.h"
 #include "ios/web/public/web_state/web_state.h"
 #include "ios/web/web_state/blocked_popup_info.h"
@@ -108,6 +108,17 @@
 NewWindowInfo::~NewWindowInfo() {
 }
 
+// Struct to capture data about a user interaction. Records the time of the
+// interaction and the main document URL at that time.
+struct UserInteractionEvent {
+  UserInteractionEvent(GURL url)
+      : main_document_url(url), time(CFAbsoluteTimeGetCurrent()) {}
+  // Main document URL at the time the interaction occurred.
+  GURL main_document_url;
+  // Time that the interaction occured, measured in seconds since Jan 1 2001.
+  CFAbsoluteTime time;
+};
+
 }  // namespace web
 
 namespace {
@@ -204,8 +215,8 @@
   scoped_ptr<base::DictionaryValue> _DOMElementForLastTouch;
   // Whether a click is in progress.
   BOOL _clickInProgress;
-  // The time of the last click, measured in seconds since Jan 1 2001.
-  CFAbsoluteTime _lastClickTimeInSeconds;
+  // Data on the recorded last user interaction.
+  scoped_ptr<web::UserInteractionEvent> _lastUserInteraction;
   // The time of the last page transfer start, measured in seconds since Jan 1
   // 2001.
   CFAbsoluteTime _lastTransferTimeInSeconds;
@@ -298,6 +309,11 @@
 - (NSString*)javascriptToReplaceWebViewURL:(const GURL&)url
                            stateObjectJSON:(NSString*)stateObject;
 - (BOOL)isLoaded;
+// Called by NSNotificationCenter upon orientation changes.
+- (void)orientationDidChange;
+// Queries the web view for the user-scalable meta tag and calls
+// |-applyPageScrollState:userScalable:| with the result.
+- (void)applyPageScrollState:(const web::PageScrollState&)scrollState;
 // Restores state of the web view's scroll view from |scrollState|.
 // |isUserScalable| represents the value of user-scalable meta tag.
 - (void)applyPageScrollState:(const web::PageScrollState&)scrollState
@@ -377,8 +393,9 @@
 // Returns YES if the url was succesfully opened in the native app.
 - (BOOL)urlTriggersNativeAppLaunch:(const GURL&)url
                          sourceURL:(const GURL&)sourceURL;
-// Returns whether external |url| should be opened.
-- (BOOL)shouldOpenExternalURL:(const GURL&)url;
+// Returns whether external URL request should be opened.
+- (BOOL)shouldOpenExternalURLRequest:(NSURLRequest*)request
+                         targetFrame:(const web::FrameInfo*)targetFrame;
 // Called when a page updates its history stack using pushState or replaceState.
 - (void)didUpdateHistoryStateWithPageURL:(const GURL&)url;
 
@@ -580,6 +597,11 @@
     _gestureRecognizers.reset([[NSMutableArray alloc] init]);
     _webViewToolbars.reset([[NSMutableArray alloc] init]);
     _pendingLoadCompleteActions.reset([[NSMutableArray alloc] init]);
+    [[NSNotificationCenter defaultCenter]
+        addObserver:self
+           selector:@selector(orientationDidChange)
+               name:UIApplicationDidChangeStatusBarOrientationNotification
+             object:nil];
   }
   return self;
 }
@@ -678,6 +700,7 @@
   DCHECK(_isBeingDestroyed);  // 'close' must have been called already.
   DCHECK(!self.webView);
   _touchTrackingRecognizer.get().touchTrackingDelegate = nil;
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
   [super dealloc];
 }
 
@@ -2560,9 +2583,8 @@
 }
 
 - (void)resetDocumentSpecificState {
-  _lastClickTimeInSeconds = -DBL_MAX;
+  _lastUserInteraction.reset();
   _clickInProgress = NO;
-
   _lastSeenWindowID.reset([[_windowIDJSManager windowId] copy]);
 }
 
@@ -2725,7 +2747,7 @@
   // TODO(droger):  Check transition type before opening an external
   // application? For example, only allow it for TYPED and LINK transitions.
   if (![CRWWebController webControllerCanShow:requestURL]) {
-    if (![self shouldOpenExternalURL:requestURL]) {
+    if (![self shouldOpenExternalURLRequest:request targetFrame:targetFrame]) {
       return NO;
     }
 
@@ -2791,20 +2813,20 @@
   NSTimeInterval requestCreationDate =
       [[userInfo objectForKey:@"CreationDate"] timeIntervalSinceReferenceDate];
   bool userInteracted = false;
-  if (requestCreationDate != 0.0) {
+  if (requestCreationDate != 0.0 && _lastUserInteraction) {
     NSTimeInterval timeSinceInteraction =
-        requestCreationDate - _lastClickTimeInSeconds;
+        requestCreationDate - _lastUserInteraction->time;
     // The error is considered to be the result of a user interaction if any
     // interaction happened just before the request was made.
     // TODO(droger): If the user interacted with the page after the request was
     // made (i.e. creationTimeSinceLastInteraction < 0), then
-    // |_lastClickTimeInSeconds| has been overridden. The current behavior is to
+    // |_lastUserInteraction| has been overridden. The current behavior is to
     // discard the interstitial in that case. A better decision could be made if
     // we had a history of all the user interactions instead of just the last
     // one.
     userInteracted =
         timeSinceInteraction < kMaximumDelayForUserInteractionInSeconds &&
-        _lastClickTimeInSeconds > _lastTransferTimeInSeconds &&
+        _lastUserInteraction->time > _lastTransferTimeInSeconds &&
         timeSinceInteraction >= 0.0;
   } else {
     // If the error does not have timing information, check if the user
@@ -2862,10 +2884,13 @@
     return;
   }
 
+  // TODO(ios): Audit comments and behavior below regarding error origin. The
+  // error has been translated and may appear to have originated in the Chrome
+  // network stack when that is not true (crbug.com/496972)
   // Ignore cancelled errors.
   if ([error code] == NSURLErrorCancelled) {
     NSError* underlyingError = [userInfo objectForKey:NSUnderlyingErrorKey];
-    if (underlyingError) {
+    if (underlyingError && [self shouldAbortLoadForCancelledURL:errorGURL]) {
       DCHECK([underlyingError isKindOfClass:[NSError class]]);
 
       // The Error contains an NSUnderlyingErrorKey so it's being generated
@@ -2897,6 +2922,12 @@
   [self loadErrorInNativeView:error];
 }
 
+- (BOOL)shouldAbortLoadForCancelledURL:(const GURL &)cancelledURL {
+  // Subclasses must implement this method.
+  NOTREACHED();
+  return YES;
+}
+
 #pragma mark -
 #pragma mark WebUI
 
@@ -3070,7 +3101,15 @@
   _clickInProgress = touched;
   if (touched) {
     _userInteractionRegistered = YES;
-    _lastClickTimeInSeconds = CFAbsoluteTimeGetCurrent();
+    if (_isBeingDestroyed)
+      return;
+    const web::NavigationManagerImpl& navigationManager =
+        self.webStateImpl->GetNavigationManagerImpl();
+    GURL mainDocumentURL =
+        navigationManager.GetEntryCount()
+            ? navigationManager.GetLastCommittedItem()->GetURL()
+            : [self currentURL];
+    _lastUserInteraction.reset(new web::UserInteractionEvent(mainDocumentURL));
   }
 }
 
@@ -3085,14 +3124,18 @@
 - (BOOL)userIsInteracting {
   // If page transfer started after last click, user is deemed to be no longer
   // interacting.
-  if (_lastTransferTimeInSeconds > _lastClickTimeInSeconds)
+  if (!_lastUserInteraction ||
+      _lastTransferTimeInSeconds > _lastUserInteraction->time) {
     return NO;
+  }
   return [self userClickedRecently];
 }
 
 - (BOOL)userClickedRecently {
+  if (!_lastUserInteraction)
+    return NO;
   return _clickInProgress ||
-         ((CFAbsoluteTimeGetCurrent() - _lastClickTimeInSeconds) <
+         ((CFAbsoluteTimeGetCurrent() - _lastUserInteraction->time) <
           kMaximumDelayForUserInteractionInSeconds);
 }
 
@@ -3205,8 +3248,9 @@
 #pragma mark Session Information
 
 - (CRWSessionController*)sessionController {
-  DCHECK(_webStateImpl);
-  return _webStateImpl->GetNavigationManagerImpl().GetSessionController();
+  return _webStateImpl
+      ? _webStateImpl->GetNavigationManagerImpl().GetSessionController()
+      : nil;
 }
 
 - (CRWSessionEntry*)currentSessionEntry {
@@ -3301,18 +3345,60 @@
             _scrollStateOnStartLoading.scroll_offset_y() &&
         [self absoluteZoomScaleForScrollState:currentScrollState] ==
             [self absoluteZoomScaleForScrollState:_scrollStateOnStartLoading]) {
-      base::WeakNSObject<CRWWebController> weakSelf(self);
-      [self queryUserScalableProperty:^(BOOL isUserScalable) {
-        base::scoped_nsobject<CRWWebController> strongSelf([weakSelf retain]);
-        [strongSelf applyPageScrollState:pageScrollState
-                            userScalable:isUserScalable];
-      }];
+      [self applyPageScrollState:pageScrollState];
     }
   }
 }
 
+- (void)orientationDidChange {
+  // When rotating, the available zoom scale range may change, zoomScale's
+  // percentage into this range should remain constant.  However, there are
+  // two known bugs with respect to adjusting the zoomScale on rotation:
+  // - WKWebView sometimes erroneously resets the scroll view's zoom scale to
+  // an incorrect value ( rdar://20100815 ).
+  // - After zooming occurs in a UIWebView that's displaying a page with a hard-
+  // coded viewport width, the zoom will not be updated upon rotation
+  // ( crbug.com/485055 ).
+  if (!self.webView)
+    return;
+  web::NavigationItem* currentItem = self.currentNavItem;
+  if (!currentItem)
+    return;
+  web::PageScrollState scrollState = currentItem->GetPageScrollState();
+  if (!scrollState.IsValid())
+    return;
+  CGFloat zoomPercentage =
+      (scrollState.zoom_scale() - scrollState.minimum_zoom_scale()) /
+      scrollState.GetMinMaxZoomDifference();
+  scrollState.set_minimum_zoom_scale(self.webScrollView.minimumZoomScale);
+  scrollState.set_maximum_zoom_scale(self.webScrollView.maximumZoomScale);
+  scrollState.set_zoom_scale(scrollState.minimum_zoom_scale() +
+                             zoomPercentage *
+                                 scrollState.GetMinMaxZoomDifference());
+  currentItem->SetPageScrollState(scrollState);
+  [self applyPageScrollState:currentItem->GetPageScrollState()];
+}
+
+- (void)applyPageScrollState:(const web::PageScrollState&)scrollState {
+  if (!scrollState.IsValid())
+    return;
+  base::WeakNSObject<CRWWebController> weakSelf(self);
+  web::PageScrollState scrollStateCopy = scrollState;
+  [self queryUserScalableProperty:^(BOOL isUserScalable) {
+    base::scoped_nsobject<CRWWebController> strongSelf([weakSelf retain]);
+    [strongSelf applyPageScrollState:scrollStateCopy
+                        userScalable:isUserScalable];
+  }];
+}
+
 - (void)applyPageScrollState:(const web::PageScrollState&)scrollState
                 userScalable:(BOOL)isUserScalable {
+  // Early return if |scrollState| doesn't match the current NavigationItem.
+  // This can sometimes occur in tests, as navigation occurs programmatically
+  // and |-applyPageScrollState:| is asynchronous.
+  web::NavigationItem* currentItem = [self currentSessionEntry].navigationItem;
+  if (currentItem && currentItem->GetPageScrollState() != scrollState)
+    return;
   DCHECK(scrollState.IsValid());
   if (isUserScalable) {
     [self prepareToApplyWebViewScrollZoomScale];
@@ -3518,10 +3604,27 @@
                       linkClicked:linkClicked];
 }
 
-- (BOOL)shouldOpenExternalURL:(const GURL&)url {
+- (BOOL)shouldOpenExternalURLRequest:(NSURLRequest*)request
+                         targetFrame:(const web::FrameInfo*)targetFrame {
+  // Prevent subrequests from opening an external URL if the main document URL
+  // has changed since the last user interaction.
+  BOOL isMainFrame = targetFrame
+                         ? targetFrame->is_main_frame
+                         : [request.URL isEqual:request.mainDocumentURL];
+  BOOL documentChangedAfterUserInteraction =
+      _lastUserInteraction &&
+      net::GURLWithNSURL(request.mainDocumentURL) !=
+          _lastUserInteraction->main_document_url;
+  if (!isMainFrame && documentChangedAfterUserInteraction)
+    return NO;
+
+  GURL requestURL = net::GURLWithNSURL(request.URL);
   return [_delegate respondsToSelector:@selector(webController:
-                                           shouldOpenExternalURL:)] &&
-         [_delegate webController:self shouldOpenExternalURL:url];
+                                           shouldOpenExternalURL:
+                                               userIsInteracting:)] &&
+         [_delegate webController:self
+             shouldOpenExternalURL:requestURL
+                 userIsInteracting:[self userIsInteracting]];
 }
 
 - (BOOL)urlTriggersNativeAppLaunch:(const GURL&)url
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.mm b/ios/web/web_state/ui/crw_web_controller_container_view.mm
index ffa5571..e54e303 100644
--- a/ios/web/web_state/ui/crw_web_controller_container_view.mm
+++ b/ios/web/web_state/ui/crw_web_controller_container_view.mm
@@ -97,11 +97,6 @@
 
 @implementation CRWWebControllerContainerView
 
-- (instancetype)init {
-  NOTREACHED();
-  return nil;
-}
-
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
@@ -112,6 +107,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 #pragma mark Accessors
 
 - (void)setToolbarContainerView:(CRWToolbarContainerView*)toolbarContainerView {
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 830504a9..5b65bbc 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -45,7 +45,6 @@
 @end
 
 @interface CRWWebController (PrivateAPI)
-- (void)setPageScrollState:(const web::PageScrollState&)scrollState;
 - (void)setJsMessageQueueThrottled:(BOOL)throttle;
 - (void)removeDocumentLoadCommandsFromQueue;
 - (GURL)updateURLForHistoryNavigationFromURL:(const GURL&)startURL
@@ -839,7 +838,8 @@
       [NSError errorWithDomain:NSURLErrorDomain
                           code:NSURLErrorServerCertificateHasUnknownRoot
                       userInfo:nil];
-  [static_cast<id<WKNavigationDelegate>>(webController_.get()) webView:nil
+  WKWebView* webView = static_cast<WKWebView*>([webController_ webView]);
+  [static_cast<id<WKNavigationDelegate>>(webController_.get()) webView:webView
                                           didFailProvisionalNavigation:nil
                                                              withError:error];
 
@@ -935,13 +935,14 @@
   float originMinimumZoomScale = scrollView.minimumZoomScale;
   float originMaximumZoomScale = scrollView.maximumZoomScale;
 
-  web::PageScrollState scrollState =
+  web::WebState* webState = [this->webController_ webState];
+  webState->GetNavigationManager()->GetLastCommittedItem()->SetPageScrollState(
       this->CreateTestScrollState(CGPointMake(1.0, 1.0),  // scroll offset
-                                  3.0,                    // relative zoom scale
-                                  1.0,   // original minimum zoom scale
-                                  5.0,   // original maximum zoom scale
-                                  1.0);  // original zoom scale
-  [this->webController_ setPageScrollState:scrollState];
+                                  3.0,    // relative zoom scale
+                                  1.0,    // original minimum zoom scale
+                                  5.0,    // original maximum zoom scale
+                                  1.0));  // original zoom scale
+  [this->webController_ restoreStateFromHistory];
 
   // setPageState: is async; wait for its completion.
   scrollView = [[[this->webController_ view] subviews][0] scrollView];
@@ -964,13 +965,15 @@
                   " /></head><body>Test</body></html>");
 
   ui::test::uiview_utils::ForceViewRendering([this->webController_ view]);
-  web::PageScrollState scrollState =
+
+  web::WebState* webState = [this->webController_ webState];
+  webState->GetNavigationManager()->GetLastCommittedItem()->SetPageScrollState(
       this->CreateTestScrollState(CGPointMake(1.0, 1.0),  // scroll offset
-                                  3.0,                    // relative zoom scale
-                                  1.0,   // original minimum zoom scale
-                                  10.0,  // original maximum zoom scale
-                                  1.0);  // original zoom scale
-  [this->webController_ setPageScrollState:scrollState];
+                                  3.0,    // relative zoom scale
+                                  1.0,    // original minimum zoom scale
+                                  10.0,   // original maximum zoom scale
+                                  1.0));  // original zoom scale
+  [this->webController_ restoreStateFromHistory];
 
   // setPageState: is async; wait for its completion.
   id webView = [[this->webController_ view] subviews][0];
@@ -998,13 +1001,14 @@
                   " /></head><body>Test</body></html>");
   ASSERT_TRUE(this->webController_.get().atTop);
 
-  web::PageScrollState scrollState =
+  web::WebState* webState = [this->webController_ webState];
+  webState->GetNavigationManager()->GetLastCommittedItem()->SetPageScrollState(
       this->CreateTestScrollState(CGPointMake(0.0, 30.0),  // scroll offset
-                                  5.0,   // relative zoom scale
-                                  1.0,   // original minimum zoom scale
-                                  5.0,   // original maximum zoom scale
-                                  1.0);  // original zoom scale
-  [this->webController_ setPageScrollState:scrollState];
+                                  5.0,    // relative zoom scale
+                                  1.0,    // original minimum zoom scale
+                                  5.0,    // original maximum zoom scale
+                                  1.0));  // original zoom scale
+  [this->webController_ restoreStateFromHistory];
 
   // setPageState: is async; wait for its completion.
   id webView = [[this->webController_ view] subviews][0];
diff --git a/ios/web/web_state/ui/crw_wk_web_view_crash_detector.mm b/ios/web/web_state/ui/crw_wk_web_view_crash_detector.mm
index c6f015e..2dd10ab6 100644
--- a/ios/web/web_state/ui/crw_wk_web_view_crash_detector.mm
+++ b/ios/web/web_state/ui/crw_wk_web_view_crash_detector.mm
@@ -45,11 +45,6 @@
   base::mac::ScopedBlock<ProceduralBlock> _crashHandler;
 }
 
-- (instancetype)init {
-  NOTREACHED();
-  return nil;
-}
-
 - (instancetype)initWithWebView:(WKWebView*)webView
                    crashHandler:(ProceduralBlock)handler {
   DCHECK(webView);
@@ -71,6 +66,11 @@
   return self;
 }
 
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
 - (void)dealloc {
   [_webView removeObserver:self forKeyPath:kCrashIndicatorKeyPath];
   [super dealloc];
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
index 3ee70f3..6f52538 100644
--- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
@@ -17,8 +17,8 @@
 #import "ios/web/navigation/crw_session_controller.h"
 #include "ios/web/navigation/web_load_params.h"
 #include "ios/web/public/web_client.h"
-#import "ios/web/public/web_state/crw_native_content_provider.h"
 #import "ios/web/public/web_state/js/crw_js_injection_manager.h"
+#import "ios/web/public/web_state/ui/crw_native_content_provider.h"
 #import "ios/web/ui_web_view_util.h"
 #include "ios/web/web_state/blocked_popup_info.h"
 #include "ios/web/web_state/frame_info.h"
@@ -421,6 +421,12 @@
   self.webScrollView.zoomScale = zoomScale;
 }
 
+- (BOOL)shouldAbortLoadForCancelledURL:(const GURL&)cancelledURL {
+  // Do not abort the load if it is for an app specific URL, as such errors
+  // are produced during the app specific URL load process.
+  return !web::GetWebClient()->IsAppSpecificURL(cancelledURL);
+}
+
 #pragma mark Private methods
 
 - (NSString*)documentMIMEType {
@@ -975,17 +981,19 @@
 - (void)webView:(WKWebView *)webView
     didStartProvisionalNavigation:(WKNavigation *)navigation {
   GURL webViewURL = net::GURLWithNSURL(webView.URL);
-  // If this navigation has not yet been registered, do so. loadPhase check is
-  // necessary because lastRegisteredRequestURL may be the same as the
-  // webViewURL on a new tab created by window.open (default is about::blank).
-  // TODO(jyquinn): Audit [CRWWebController loadCurrentURL] for other tasks that
+  // Intercept renderer-initiated navigations. If this navigation has not yet
+  // been registered, do so. loadPhase check is necessary because
+  // lastRegisteredRequestURL may be the same as the webViewURL on a new tab
+  // created by window.open (default is about::blank).
+  // TODO(jyquinn): Audit [CRWWebController loadWithParams] for other tasks that
   // should be performed here.
   if (self.lastRegisteredRequestURL != webViewURL ||
       self.loadPhase != web::LOAD_REQUESTED) {
     // Reset current WebUI if one exists.
     [self clearWebUI];
-    // If webViewURL is a chrome URL, abort the current load and initialize the
-    // load from the web controller.
+    // Restart app specific URL loads to properly capture state.
+    // TODO(jyquinn): Extract necessary tasks for app specific URL navigation
+    // rather than restarting the load.
     if (web::GetWebClient()->IsAppSpecificURL(webViewURL)) {
       [self abortWebLoad];
       web::WebLoadParams params(webViewURL);
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm b/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
index db1cd90a..322c88e9 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
@@ -68,6 +68,9 @@
             other_provider.GetWebViewConfiguration().processPool);
 }
 
+#if 0
+// TODO(shreyasv) Disabled for usage of nil on latest Xcode beta.
+// crbug.com/498841
 // Tests that internal configuration object can not be changed by clients.
 TEST_F(WKWebViewConfigurationProviderTest, ConfigurationProtection) {
   CR_TEST_REQUIRES_WK_WEB_VIEW();
@@ -93,6 +96,7 @@
   EXPECT_EQ(userContentController.get(),
             provider.GetWebViewConfiguration().userContentController);
 }
+#endif
 
 // Tests that |HasWebViewConfiguration| returns false by default.
 TEST_F(WKWebViewConfigurationProviderTest, NoConfigurationByDefault) {
diff --git a/ipc/mojo/ipc_message_pipe_reader.cc b/ipc/mojo/ipc_message_pipe_reader.cc
index 35ba7fd6..44bd10a8f 100644
--- a/ipc/mojo/ipc_message_pipe_reader.cc
+++ b/ipc/mojo/ipc_message_pipe_reader.cc
@@ -152,14 +152,9 @@
     if (read_result == MOJO_RESULT_SHOULD_WAIT)
       break;
     if (read_result != MOJO_RESULT_OK) {
-      // FAILED_PRECONDITION means that all the received messages
-      // got consumed and the peer is already closed.
-      if (read_result != MOJO_RESULT_FAILED_PRECONDITION) {
-        DLOG(WARNING)
-            << "Pipe got error from ReadMessage(). Closing: " << read_result;
-        OnPipeError(read_result);
-      }
-
+      DLOG(WARNING)
+          << "Pipe got error from ReadMessage(). Closing: " << read_result;
+      OnPipeError(read_result);
       Close();
       break;
     }
diff --git a/mandoline/app/BUILD.gn b/mandoline/app/BUILD.gn
index e74aeb1f..066842d5 100644
--- a/mandoline/app/BUILD.gn
+++ b/mandoline/app/BUILD.gn
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo.gni")
-
 group("app") {
   deps = [
     "//mandoline/ui",
diff --git a/mandoline/app/android/BUILD.gn b/mandoline/app/android/BUILD.gn
index e9a35b8..07edbdc 100644
--- a/mandoline/app/android/BUILD.gn
+++ b/mandoline/app/android/BUILD.gn
@@ -4,7 +4,6 @@
 
 assert(is_android)
 
-import("//third_party/mojo/src/mojo/public/mojo.gni")
 import("//build/config/android/config.gni")
 import("//build/config/android/rules.gni")
 import("//mojo/generate_mojo_shell_assets_list.gni")
@@ -19,6 +18,8 @@
 
 executable("mandoline_runner") {
   deps = [
+    ":jni_headers",
+    "//mandoline/ui/browser/public/interfaces",
     "//mojo/common",
     "//mojo/environment:chromium",
     "//mojo/runner:mojo_runner_lib",
@@ -26,6 +27,7 @@
 
   sources = [
     "../core_services_initialization.cc",
+    "mandoline_activity.cc",
     "mandoline_context_init.cc",
   ]
 
@@ -50,6 +52,7 @@
   clear_dir = true
   dest = mandoline_assets_dir
   deps = [
+    "//components/devtools_service",
     "//components/html_viewer",
     "//components/view_manager",
     "//components/view_manager/surfaces",
@@ -60,6 +63,7 @@
   ]
   sources = [
     "$root_out_dir/core_services.mojo",
+    "$root_out_dir/devtools_service.mojo",
     "$root_out_dir/lib.stripped/libbootstrap.so",
     "$root_out_dir/network_service.mojo",
     "$root_out_dir/obj/mojo/runner/bootstrap_java.dex.jar",
@@ -69,6 +73,17 @@
   # Directories can't be specified as sources so pass manually to the script.
   args =
       [ "--files=" + rebase_path("$root_out_dir/html_viewer", root_build_dir) ]
+
+  if (use_aura) {
+    deps += [
+      "//mandoline/ui/browser",
+      "//mandoline/ui/omnibox",
+    ]
+
+    args +=
+        [ "--files=" + rebase_path("$root_out_dir/browser", root_build_dir) ] +
+        [ "--files=" + rebase_path("$root_out_dir/omnibox", root_build_dir) ]
+  }
 }
 
 generate_mojo_shell_assets_list("build_mandoline_assets") {
@@ -78,6 +93,27 @@
   dir = mandoline_assets_dir
 }
 
+android_library("java") {
+  java_files = [ "apk/src/org/chromium/mandoline/MandolineActivity.java" ]
+
+  deps = [
+    "//mojo/runner:java",
+    "//base:base_java",
+  ]
+}
+
+generate_jni("jni_headers") {
+  sources = [
+    "apk/src/org/chromium/mandoline/MandolineActivity.java",
+  ]
+  jni_package = "mandoline"
+}
+
+android_resources("mandoline_apk_resources") {
+  custom_package = "org.chromium.mandoline"
+  resource_dirs = [ "apk/res" ]
+}
+
 android_apk("mandoline_apk") {
   apk_name = "Mandoline"
 
@@ -90,6 +126,8 @@
   deps = [
     ":build_mandoline_assets",
     ":copy_mandoline_runner",
+    ":java",
+    ":mandoline_apk_resources",
     "//mojo/runner:java",
     "//mojo/runner:resources",
     "//base:base_java",
diff --git a/mandoline/app/android/DEPS b/mandoline/app/android/DEPS
new file mode 100644
index 0000000..c80012b5
--- /dev/null
+++ b/mandoline/app/android/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+jni",
+]
diff --git a/mandoline/app/android/apk/AndroidManifest.xml b/mandoline/app/android/apk/AndroidManifest.xml
index a4158f1f..fb8ffebb 100644
--- a/mandoline/app/android/apk/AndroidManifest.xml
+++ b/mandoline/app/android/apk/AndroidManifest.xml
@@ -14,17 +14,22 @@
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 
     <application android:name="org.chromium.mojo.shell.MojoShellApplication"
-                 android:label="Mandoline">
+                 android:label="Mandoline"                 
+                 android:icon="@drawable/mandoline">
         <meta-data android:name="com.google.android.gms.version"
                    android:value="@integer/google_play_services_version" />
         <meta-data android:name="mojo_lib"
                    android:value="libmandoline_runner.so" />
-        <activity android:name="org.chromium.mojo.shell.MojoShellActivity"
+        <activity android:name="org.chromium.mandoline.MandolineActivity"
                   android:launchMode="singleTask"
                   android:theme="@android:style/Theme.Holo.Light.NoActionBar"
                   android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
                   android:hardwareAccelerated="true">
             <intent-filter>
+              <action android:name="android.intent.action.MAIN" />
+              <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
                 <action android:name="android.intent.action.VIEW"/>
                 <category android:name="android.intent.category.DEFAULT"/>
                 <category android:name="android.intent.category.BROWSABLE"/>
diff --git a/mandoline/app/android/apk/res/drawable/mandoline.png b/mandoline/app/android/apk/res/drawable/mandoline.png
new file mode 100644
index 0000000..129bc15b
--- /dev/null
+++ b/mandoline/app/android/apk/res/drawable/mandoline.png
Binary files differ
diff --git a/mandoline/app/android/apk/src/org/chromium/mandoline/MandolineActivity.java b/mandoline/app/android/apk/src/org/chromium/mandoline/MandolineActivity.java
new file mode 100644
index 0000000..bfe9000
--- /dev/null
+++ b/mandoline/app/android/apk/src/org/chromium/mandoline/MandolineActivity.java
@@ -0,0 +1,67 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.mandoline;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
+import org.chromium.mojo.shell.ShellMain;
+
+/**
+ * Activity hosting the Mojo View Manager for Mandoline.
+ */
+@JNINamespace("mandoline")
+public class MandolineActivity extends Activity {
+    private static final String TAG = "cr.MandolineActivity";
+    private static final String EXTRAS = "org.chromium.mandoline.extras";
+
+    @Override
+    protected void onCreate(final Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        String[] parameters = getIntent().getStringArrayExtra(EXTRAS);
+        if (parameters != null) {
+            for (String s : parameters) {
+                s = s.replace("\\,", ",");
+            }
+        }
+        if (Intent.ACTION_VIEW.equals(getIntent().getAction())) {
+            Uri uri = getIntent().getData();
+            if (uri != null) {
+                Log.i(TAG, "MandolineActivity opening " + uri);
+                if (parameters == null) {
+                    parameters = new String[] {uri.toString()};
+                } else {
+                    String[] newParameters = new String[parameters.length + 1];
+                    System.arraycopy(parameters, 0, newParameters, 0, parameters.length);
+                    newParameters[parameters.length] = uri.toString();
+                    parameters = newParameters;
+                }
+            }
+        }
+
+        ShellMain.ensureInitialized(this, parameters);
+        ShellMain.start();
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+
+        if (Intent.ACTION_VIEW.equals(intent.getAction())) {
+            Uri uri = intent.getData();
+            if (uri != null) {
+                Log.i(TAG, "MandolineActivity launching new intent for uri: " + uri);
+                nativeLaunchURL(uri.toString());
+            }
+        }
+    }
+
+    private static native void nativeLaunchURL(String url);
+}
diff --git a/mandoline/app/android/mandoline_activity.cc b/mandoline/app/android/mandoline_activity.cc
new file mode 100644
index 0000000..d57a4b2
--- /dev/null
+++ b/mandoline/app/android/mandoline_activity.cc
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+#include "jni/MandolineActivity_jni.h"
+#include "mandoline/ui/browser/public/interfaces/launch_handler.mojom.h"
+#include "mojo/runner/android/main.h"
+#include "mojo/runner/context.h"
+
+namespace mandoline {
+
+static void LaunchURL(JNIEnv* env, jclass clazz, jstring jurl) {
+  LaunchHandlerPtr launch_handler;
+  mojo::runner::GetContext()->application_manager()->ConnectToService(
+      GURL("mojo:browser"), &launch_handler);
+  launch_handler->LaunchURL(
+      base::android::ConvertJavaStringToUTF8(env, jurl));
+}
+
+bool RegisterMandolineActivity(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace mandoline
diff --git a/mandoline/app/core_services_initialization.cc b/mandoline/app/core_services_initialization.cc
index 7e9fde8..5dd1640 100644
--- a/mandoline/app/core_services_initialization.cc
+++ b/mandoline/app/core_services_initialization.cc
@@ -16,14 +16,14 @@
                                            GURL("mojo:core_services"), "Core");
   manager->RegisterApplicationPackageAlias(GURL("mojo:filesystem"),
                                            GURL("mojo:core_services"), "Files");
-#if !defined(OS_ANDROID)
+#if defined(USE_AURA)
   manager->RegisterApplicationPackageAlias(GURL("mojo:view_manager"),
                                            GURL("mojo:core_services"),
                                            "Surfaces");
 #endif
   manager->RegisterApplicationPackageAlias(
       GURL("mojo:network_service"), GURL("mojo:core_services"), "Network");
-#if !defined(OS_ANDROID)
+#if defined(USE_AURA)
   manager->RegisterApplicationPackageAlias(
       GURL("mojo:omnibox"), GURL("mojo:core_services"), "Core");
 #endif
diff --git a/mandoline/app/desktop/BUILD.gn b/mandoline/app/desktop/BUILD.gn
index ce3e6ea..9c3d8e2 100644
--- a/mandoline/app/desktop/BUILD.gn
+++ b/mandoline/app/desktop/BUILD.gn
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo.gni")
-
 group("desktop") {
   deps = [
     ":mandoline",
diff --git a/mandoline/services/core_services/BUILD.gn b/mandoline/services/core_services/BUILD.gn
index 92899364..4c1ebf9 100644
--- a/mandoline/services/core_services/BUILD.gn
+++ b/mandoline/services/core_services/BUILD.gn
@@ -6,8 +6,7 @@
 # we ship with.
 
 import("//build/config/ui.gni")
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
-import("//testing/test.gni")
+import("//mojo/public/mojo_application.gni")
 
 if (is_android) {
   import("//build/config/android/rules.gni")
@@ -75,7 +74,7 @@
     "//mojo/services/tracing:lib",
   ]
 
-  if (!is_android) {
+  if (use_aura) {
     deps += [
       "//components/view_manager/public/cpp",
       "//mandoline/ui/omnibox:lib",
diff --git a/mandoline/services/core_services/core_services_application_delegate.cc b/mandoline/services/core_services/core_services_application_delegate.cc
index 3867c55..b31fff8b 100644
--- a/mandoline/services/core_services/core_services_application_delegate.cc
+++ b/mandoline/services/core_services/core_services_application_delegate.cc
@@ -21,7 +21,7 @@
 #include "mojo/services/tracing/tracing_app.h"
 #include "url/gurl.h"
 
-#if !defined(OS_ANDROID)
+#if defined(USE_AURA)
 #include "mandoline/ui/omnibox/omnibox_impl.h"
 #endif
 
@@ -129,7 +129,7 @@
     delegate.reset(new filesystem::FileSystemApp);
   else if (url == "mojo://network_service/")
     delegate.reset(new NetworkServiceDelegate);
-#if !defined(OS_ANDROID)
+#if defined(USE_AURA)
   else if (url == "mojo://omnibox/")
     delegate.reset(new mandoline::OmniboxImpl);
 #endif
diff --git a/mandoline/services/navigation/public/interfaces/BUILD.gn b/mandoline/services/navigation/public/interfaces/BUILD.gn
index 5b5dca6..f86683d 100644
--- a/mandoline/services/navigation/public/interfaces/BUILD.gn
+++ b/mandoline/services/navigation/public/interfaces/BUILD.gn
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/module_args/mojo.gni")
-import("$mojo_sdk_root/mojo/public/tools/bindings/mojom.gni")
+import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
   sources = [
diff --git a/mandoline/tab/BUILD.gn b/mandoline/tab/BUILD.gn
index c52d60b..50094386 100644
--- a/mandoline/tab/BUILD.gn
+++ b/mandoline/tab/BUILD.gn
@@ -2,16 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//testing/test.gni")
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
-import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
+import("//mojo/public/mojo_application.gni")
 
 source_set("tab") {
   sources = [
     "frame.cc",
     "frame.h",
-    "frame_services.cc",
-    "frame_services.h",
+    "frame_connection.cc",
+    "frame_connection.h",
     "frame_tree.cc",
     "frame_tree.h",
     "frame_tree_delegate.h",
@@ -22,8 +20,9 @@
     "//base",
     "//components/view_manager/public/cpp",
     "//mandoline/tab/public/interfaces",
-    "//mojo/application/public/cpp",
+    "//mojo/application/public/cpp:sources",
     "//mojo/application/public/interfaces",
+    "//mojo/services/network/public/interfaces",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
   ]
 }
diff --git a/mandoline/tab/DEPS b/mandoline/tab/DEPS
index b13593c5..192c8b5 100644
--- a/mandoline/tab/DEPS
+++ b/mandoline/tab/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+components/view_manager/public",
   "+mojo/application/public",
+  "+mojo/services/network/public/interfaces",
   "+third_party/mojo/src/mojo/public",
 ]
diff --git a/mandoline/tab/frame_apptest.cc b/mandoline/tab/frame_apptest.cc
index 4c1ec9d47..d71e20c 100644
--- a/mandoline/tab/frame_apptest.cc
+++ b/mandoline/tab/frame_apptest.cc
@@ -90,9 +90,7 @@
   ApplicationDelegate* GetApplicationDelegate() override { return this; }
 
   // Overridden from ViewManagerDelegate:
-  void OnEmbed(View* root,
-               mojo::InterfaceRequest<mojo::ServiceProvider> services,
-               mojo::ServiceProviderPtr exposed_services) override {
+  void OnEmbed(View* root) override {
     most_recent_view_manager_ = root->view_manager();
     QuitRunLoop();
   }
diff --git a/mandoline/tab/frame_connection.cc b/mandoline/tab/frame_connection.cc
new file mode 100644
index 0000000..36e6234
--- /dev/null
+++ b/mandoline/tab/frame_connection.cc
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mandoline/tab/frame_connection.h"
+
+#include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/application/public/cpp/application_impl.h"
+
+namespace mandoline {
+
+FrameConnection::FrameConnection() : application_connection_(nullptr) {
+}
+
+FrameConnection::~FrameConnection() {
+}
+
+void FrameConnection::Init(mojo::ApplicationImpl* app,
+                           mojo::URLRequestPtr request,
+                           mojo::ViewManagerClientPtr* view_manage_client) {
+  DCHECK(!application_connection_);
+  application_connection_ = app->ConnectToApplication(request.Pass());
+  application_connection_->ConnectToService(view_manage_client);
+  application_connection_->ConnectToService(&frame_tree_client_);
+}
+
+}  // namespace mandoline
diff --git a/mandoline/tab/frame_connection.h b/mandoline/tab/frame_connection.h
new file mode 100644
index 0000000..2ff44f83
--- /dev/null
+++ b/mandoline/tab/frame_connection.h
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MANDOLINE_TAB_FRAME_CONNECTION_H_
+#define MANDOLINE_TAB_FRAME_CONNECTION_H_
+
+#include "base/basictypes.h"
+#include "components/view_manager/public/interfaces/view_manager.mojom.h"
+#include "mandoline/tab/frame_user_data.h"
+#include "mandoline/tab/public/interfaces/frame_tree.mojom.h"
+#include "mojo/services/network/public/interfaces/url_loader.mojom.h"
+
+namespace mojo {
+class ApplicationConnection;
+class ApplicationImpl;
+}
+
+namespace mandoline {
+
+// FrameConnection is a FrameUserData that manages the connection to a
+// particular frame. It is also responsible for obtaining the necessary
+// services from the remote side.
+class FrameConnection : public FrameUserData {
+ public:
+  FrameConnection();
+  ~FrameConnection() override;
+
+  void Init(mojo::ApplicationImpl* app,
+            mojo::URLRequestPtr request,
+            mojo::ViewManagerClientPtr* view_manage_client);
+
+  FrameTreeClient* frame_tree_client() { return frame_tree_client_.get(); }
+
+  mojo::ApplicationConnection* application_connection() {
+    return application_connection_;
+  }
+
+ private:
+  FrameTreeClientPtr frame_tree_client_;
+  // TODO(sky): needs to be destroyed when connection lost.
+  mojo::ApplicationConnection* application_connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameConnection);
+};
+
+}  // namespace mandoline
+
+#endif  // MANDOLINE_TAB_FRAME_CONNECTION_H_
diff --git a/mandoline/tab/frame_services.cc b/mandoline/tab/frame_services.cc
deleted file mode 100644
index ea64a41..0000000
--- a/mandoline/tab/frame_services.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mandoline/tab/frame_services.h"
-
-#include "mojo/application/public/cpp/connect.h"
-
-namespace mandoline {
-
-FrameServices::FrameServices() {
-}
-
-FrameServices::~FrameServices() {
-}
-
-void FrameServices::Init(
-    mojo::InterfaceRequest<mojo::ServiceProvider>* services,
-    mojo::ServiceProviderPtr* exposed_services) {
-  *services = GetProxy(&services_).Pass();
-
-  if (exposed_services) {
-    mojo::ServiceProviderPtr exposed_services_ptr;
-    exposed_services_.Bind(GetProxy(&exposed_services_ptr));
-    *exposed_services = exposed_services_ptr.Pass();
-  }
-
-  mojo::ConnectToService(services_.get(), &frame_tree_client_);
-}
-
-}  // namespace mandoline
diff --git a/mandoline/tab/frame_services.h b/mandoline/tab/frame_services.h
deleted file mode 100644
index fc7ea654..0000000
--- a/mandoline/tab/frame_services.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MANDOLINE_TAB_FRAME_SERVICES_H_
-#define MANDOLINE_TAB_FRAME_SERVICES_H_
-
-#include "base/basictypes.h"
-#include "mandoline/tab/frame_user_data.h"
-#include "mandoline/tab/public/interfaces/frame_tree.mojom.h"
-#include "mojo/application/public/cpp/service_provider_impl.h"
-
-namespace mandoline {
-
-// FrameServices is a FrameUserData that manages the ServiceProviders exposed
-// to each client. It is also responsible for obtaining the FrameTreeClient
-// from the remote side.
-class FrameServices : public FrameUserData {
- public:
-  FrameServices();
-  ~FrameServices() override;
-
-  void Init(mojo::InterfaceRequest<mojo::ServiceProvider>* services,
-            mojo::ServiceProviderPtr* exposed_services);
-
-  FrameTreeClient* frame_tree_client() { return frame_tree_client_.get(); }
-
- private:
-  mojo::ServiceProviderImpl exposed_services_;
-  mojo::ServiceProviderPtr services_;
-  FrameTreeClientPtr frame_tree_client_;
-
-  DISALLOW_COPY_AND_ASSIGN(FrameServices);
-};
-
-}  // namespace mandoline
-
-#endif  // MANDOLINE_TAB_FRAME_SERVICES_H_
diff --git a/mandoline/tools/android_run_mandoline.py b/mandoline/tools/android/install_mandoline.py
similarity index 79%
copy from mandoline/tools/android_run_mandoline.py
copy to mandoline/tools/android/install_mandoline.py
index 71ac9ad3..3cf465b6 100755
--- a/mandoline/tools/android_run_mandoline.py
+++ b/mandoline/tools/android/install_mandoline.py
@@ -9,12 +9,13 @@
 import sys
 
 sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(__file__)),
-                                os.pardir, os.pardir, 'mojo', 'tools'))
+                                os.pardir, os.pardir, os.pardir, 'mojo',
+                                'tools'))
 
 from mopy.android import AndroidShell
 from mopy.config import Config
 
-USAGE = ("android_run_mandoline.py [<shell-and-app-args>] [<mojo-app>]")
+USAGE = ("install_mandoline.py [<shell-and-app-args>]")
 
 def main():
   logging.basicConfig()
@@ -29,8 +30,6 @@
   parser.add_argument('--target-cpu', help='CPU architecture to run for.',
                       choices=['x64', 'x86', 'arm'], default='arm')
   parser.add_argument('--device', help='Serial number of the target device.')
-  parser.add_argument('--gdb', help='Run gdb',
-                      default=False, action='store_true')
   runner_args, args = parser.parse_known_args()
 
   config = Config(target_os=Config.OS_ANDROID,
@@ -39,8 +38,6 @@
                   apk_name="Mandoline.apk")
   shell = AndroidShell(config)
   shell.InitShell(None, runner_args.device)
-  p = shell.ShowLogs()
-  shell.StartShell(args, sys.stdout, p.terminate, runner_args.gdb)
   return 0
 
 
diff --git a/mandoline/tools/android_run_mandoline.py b/mandoline/tools/android/run_mandoline.py
similarity index 80%
rename from mandoline/tools/android_run_mandoline.py
rename to mandoline/tools/android/run_mandoline.py
index 71ac9ad3..78a3d905 100755
--- a/mandoline/tools/android_run_mandoline.py
+++ b/mandoline/tools/android/run_mandoline.py
@@ -9,12 +9,13 @@
 import sys
 
 sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(__file__)),
-                                os.pardir, os.pardir, 'mojo', 'tools'))
+                                os.pardir, os.pardir, os.pardir, 'mojo',
+                                'tools'))
 
 from mopy.android import AndroidShell
 from mopy.config import Config
 
-USAGE = ("android_run_mandoline.py [<shell-and-app-args>] [<mojo-app>]")
+USAGE = ("run_mandoline.py [<shell-and-app-args>] [<start-page-url>]")
 
 def main():
   logging.basicConfig()
@@ -40,7 +41,11 @@
   shell = AndroidShell(config)
   shell.InitShell(None, runner_args.device)
   p = shell.ShowLogs()
-  shell.StartShell(args, sys.stdout, p.terminate, runner_args.gdb)
+  shell.StartActivity('MandolineActivity',
+                      args,
+                      sys.stdout,
+                      p.terminate,
+                      runner_args.gdb)
   return 0
 
 
diff --git a/mandoline/ui/BUILD.gn b/mandoline/ui/BUILD.gn
index 572918fa..96f1734 100644
--- a/mandoline/ui/BUILD.gn
+++ b/mandoline/ui/BUILD.gn
@@ -2,14 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo.gni")
+import("//build/config/ui.gni")
 
 group("ui") {
   deps = [
     "browser",
   ]
-
-  if (!is_android) {
+  if (use_aura) {
     deps += [ "omnibox" ]
   }
 }
diff --git a/mandoline/ui/aura/BUILD.gn b/mandoline/ui/aura/BUILD.gn
index 1bccf3c..a25c02b 100644
--- a/mandoline/ui/aura/BUILD.gn
+++ b/mandoline/ui/aura/BUILD.gn
@@ -49,4 +49,11 @@
     "//ui/resources:ui_test_pak",
     "//ui/views",
   ]
+
+  if (is_android) {
+    deps += [
+      "//components/resource_provider/public/cpp",
+      "//components/resource_provider/public/interfaces",
+    ]
+  }
 }
diff --git a/mandoline/ui/aura/DEPS b/mandoline/ui/aura/DEPS
index d7c4cb6..91015f8 100644
--- a/mandoline/ui/aura/DEPS
+++ b/mandoline/ui/aura/DEPS
@@ -2,6 +2,7 @@
   "+cc",
   "-cc/blink",
   "+components/gpu",
+  "+components/resource_provider",
   "+components/view_manager",
   "+mojo/application/public",
   "+mojo/cc",
diff --git a/mandoline/ui/aura/aura_init.cc b/mandoline/ui/aura/aura_init.cc
index f14a477a..946a118 100644
--- a/mandoline/ui/aura/aura_init.cc
+++ b/mandoline/ui/aura/aura_init.cc
@@ -9,54 +9,75 @@
 #include "base/path_service.h"
 #include "mandoline/ui/aura/screen_mojo.h"
 #include "ui/aura/env.h"
+#include "ui/base/ime/input_method_initializer.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
 
+#if defined(OS_ANDROID)
+#include "components/resource_provider/public/cpp/resource_loader.h"
+#endif
+
 namespace mandoline {
+
+#if defined(OS_ANDROID)
 namespace {
 
-// Used to ensure we only init once.
-class Setup {
- public:
-  Setup() {
-    base::i18n::InitializeICU();
+// Paths resources are loaded from.
+const char kResourceIcudtl[] = "icudtl.dat";
+const char kResourceUIPak[] = "ui_test.pak";
 
-    ui::RegisterPathProvider();
-
-    base::FilePath ui_test_pak_path;
-    CHECK(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
-    ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
-
-    // There is a bunch of static state in gfx::Font, by running this now,
-    // before any other apps load, we ensure all the state is set up.
-    gfx::Font();
-  }
-
-  ~Setup() {
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(Setup);
-};
-
-static base::LazyInstance<Setup>::Leaky setup = LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
-void InitViews() {
-  setup.Get();
+std::set<std::string> GetResourcePaths() {
+  std::set<std::string> paths;
+  paths.insert(kResourceIcudtl);
+  paths.insert(kResourceUIPak);
+  return paths;
 }
 
-AuraInit::AuraInit() {
+}  // namespace
+#endif  // defined(OS_ANDROID)
+
+AuraInit::AuraInit(mojo::Shell* shell) {
   aura::Env::CreateInstance(false);
 
   screen_.reset(ScreenMojo::Create());
   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get());
+  InitializeResources(shell);
 
-  InitViews();
+  ui::InitializeInputMethodForTesting();
 }
 
 AuraInit::~AuraInit() {
 }
 
+void AuraInit::InitializeResources(mojo::Shell* shell) {
+  if (ui::ResourceBundle::HasSharedInstance())
+    return;
+#if defined(OS_ANDROID)
+  resource_provider::ResourceLoader resource_loader(shell, GetResourcePaths());
+  if (!resource_loader.BlockUntilLoaded())
+    return;
+  CHECK(resource_loader.loaded());
+  base::i18n::InitializeICUWithFileDescriptor(
+      resource_loader.ReleaseFile(kResourceIcudtl).TakePlatformFile(),
+      base::MemoryMappedFile::Region::kWholeFile);
+  ui::RegisterPathProvider();
+  ui::ResourceBundle::InitSharedInstanceWithPakPath(base::FilePath());
+  ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
+      resource_loader.ReleaseFile(kResourceUIPak),
+      ui::SCALE_FACTOR_100P);
+#else
+  base::i18n::InitializeICU();
+
+  ui::RegisterPathProvider();
+
+  base::FilePath ui_test_pak_path;
+  CHECK(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
+  ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
+#endif
+
+  // There is a bunch of static state in gfx::Font, by running this now,
+  // before any other apps load, we ensure all the state is set up.
+  gfx::Font();
+}
+
 }  // namespace mandoline
diff --git a/mandoline/ui/aura/aura_init.h b/mandoline/ui/aura/aura_init.h
index abe833f..98f065b88 100644
--- a/mandoline/ui/aura/aura_init.h
+++ b/mandoline/ui/aura/aura_init.h
@@ -7,6 +7,10 @@
 
 #include "base/memory/scoped_ptr.h"
 
+namespace mojo {
+class Shell;
+}
+
 namespace mandoline {
 
 class ScreenMojo;
@@ -14,10 +18,12 @@
 // Sets up necessary state for aura when run with the viewmanager.
 class AuraInit {
  public:
-  AuraInit();
+  explicit AuraInit(mojo::Shell* shell);
   ~AuraInit();
 
  private:
+  void InitializeResources(mojo::Shell* shell);
+
   scoped_ptr<ScreenMojo> screen_;
 
   DISALLOW_COPY_AND_ASSIGN(AuraInit);
diff --git a/mandoline/ui/aura/native_widget_view_manager.cc b/mandoline/ui/aura/native_widget_view_manager.cc
index da6f031..4c74102 100644
--- a/mandoline/ui/aura/native_widget_view_manager.cc
+++ b/mandoline/ui/aura/native_widget_view_manager.cc
@@ -8,7 +8,6 @@
 #include "mandoline/ui/aura/window_tree_host_mojo.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "mojo/converters/input_events/input_events_type_converters.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/default_capture_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
@@ -34,53 +33,6 @@
   DISALLOW_COPY_AND_ASSIGN(FocusRulesImpl);
 };
 
-class MinimalInputEventFilter : public ui::internal::InputMethodDelegate,
-                                public ui::EventHandler {
- public:
-  explicit MinimalInputEventFilter(aura::Window* root)
-      : root_(root) {
-    input_method_.reset(new InputMethodMandoline(this));
-    input_method_->OnFocus();
-    root_->AddPreTargetHandler(this);
-    root_->SetProperty(aura::client::kRootWindowInputMethodKey,
-                       input_method_.get());
-  }
-
-  ~MinimalInputEventFilter() override {
-    root_->RemovePreTargetHandler(this);
-    root_->SetProperty(aura::client::kRootWindowInputMethodKey,
-                       static_cast<ui::InputMethod*>(NULL));
-  }
-
- private:
-  // ui::EventHandler:
-  void OnKeyEvent(ui::KeyEvent* event) override {
-    // See the comment in InputMethodEventFilter::OnKeyEvent() for details.
-    if (event->IsTranslated()) {
-      event->SetTranslated(false);
-    } else {
-      if (input_method_->DispatchKeyEvent(*event))
-        event->StopPropagation();
-    }
-  }
-
-  // ui::internal::InputMethodDelegate:
-  bool DispatchKeyEventPostIME(const ui::KeyEvent& event) override {
-    // See the comment in InputMethodEventFilter::DispatchKeyEventPostIME() for
-    // details.
-    ui::KeyEvent aura_event(event);
-    aura_event.SetTranslated(true);
-    ui::EventDispatchDetails details =
-        root_->GetHost()->dispatcher()->OnEventFromSource(&aura_event);
-    return aura_event.handled() || details.dispatcher_destroyed;
-  }
-
-  aura::Window* root_;
-  scoped_ptr<ui::InputMethod> input_method_;
-
-  DISALLOW_COPY_AND_ASSIGN(MinimalInputEventFilter);
-};
-
 }  // namespace
 
 NativeWidgetViewManager::NativeWidgetViewManager(
@@ -92,9 +44,6 @@
   window_tree_host_.reset(new WindowTreeHostMojo(shell, view_));
   window_tree_host_->InitHost();
 
-  ime_filter_.reset(
-      new MinimalInputEventFilter(window_tree_host_->window()));
-
   focus_client_.reset(new wm::FocusController(new FocusRulesImpl));
 
   aura::client::SetFocusClient(window_tree_host_->window(),
diff --git a/mandoline/ui/aura/native_widget_view_manager.h b/mandoline/ui/aura/native_widget_view_manager.h
index dd96ce11..a92c36e 100644
--- a/mandoline/ui/aura/native_widget_view_manager.h
+++ b/mandoline/ui/aura/native_widget_view_manager.h
@@ -56,8 +56,6 @@
 
   scoped_ptr<wm::FocusController> focus_client_;
 
-  scoped_ptr<ui::internal::InputMethodDelegate> ime_filter_;
-
   mojo::View* view_;
 
   scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;
diff --git a/mandoline/ui/aura/window_tree_host_mojo.cc b/mandoline/ui/aura/window_tree_host_mojo.cc
index 1cd7a53b..aea5cb2 100644
--- a/mandoline/ui/aura/window_tree_host_mojo.cc
+++ b/mandoline/ui/aura/window_tree_host_mojo.cc
@@ -92,13 +92,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// WindowTreeHostMojo, ui::EventSource implementation:
-
-ui::EventProcessor* WindowTreeHostMojo::GetEventProcessor() {
-  return dispatcher();
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // WindowTreeHostMojo, ViewObserver implementation:
 
 void WindowTreeHostMojo::OnViewBoundsChanged(
diff --git a/mandoline/ui/aura/window_tree_host_mojo.h b/mandoline/ui/aura/window_tree_host_mojo.h
index 3fb2769..c00c7748 100644
--- a/mandoline/ui/aura/window_tree_host_mojo.h
+++ b/mandoline/ui/aura/window_tree_host_mojo.h
@@ -26,7 +26,6 @@
 class SurfaceContextFactory;
 
 class WindowTreeHostMojo : public aura::WindowTreeHost,
-                           public ui::EventSource,
                            public mojo::ViewObserver {
  public:
   WindowTreeHostMojo(mojo::Shell* shell, mojo::View* view);
@@ -53,9 +52,6 @@
   void MoveCursorToNative(const gfx::Point& location) override;
   void OnCursorVisibilityChangedNative(bool show) override;
 
-  // ui::EventSource:
-  ui::EventProcessor* GetEventProcessor() override;
-
   // mojo::ViewObserver:
   void OnViewBoundsChanged(mojo::View* view,
                            const mojo::Rect& old_bounds,
diff --git a/mandoline/ui/browser/BUILD.gn b/mandoline/ui/browser/BUILD.gn
index b0370231..8bdb7c2 100644
--- a/mandoline/ui/browser/BUILD.gn
+++ b/mandoline/ui/browser/BUILD.gn
@@ -2,10 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//build/config/ui.gni")
+import("//mojo/mojo_application_package.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
-mojo_native_application("browser") {
+mojo_application_package("browser") {
   sources = [
     "main.cc",
   ]
@@ -14,6 +15,12 @@
     ":lib",
     "//mandoline/services/navigation/public/interfaces",
     "//mojo/application/public/cpp",
+    "//third_party/icu:icudata",
+    "//ui/resources:ui_test_pak",
+  ]
+  resources = [
+    "$root_out_dir/icudtl.dat",
+    "$root_out_dir/ui_test.pak",
   ]
 }
 
@@ -21,26 +28,12 @@
   sources = [
     "browser.cc",
     "browser.h",
-    "merged_service_provider.cc",
-    "merged_service_provider.h",
     "navigator_host_impl.cc",
     "navigator_host_impl.h",
   ]
 
-  if (is_android) {
-    sources += [
-      "android/android_ui.cc",
-      "android/android_ui.h",
-    ]
-  } else {
-    sources += [
-      "desktop/desktop_ui.cc",
-      "desktop/desktop_ui.h",
-    ]
-  }
-
   deps = [
-    ":interfaces",
+    "public/interfaces",
     "//base",
     "//components/view_manager/public/cpp",
     "//mandoline/services/navigation/public/interfaces",
@@ -53,21 +46,17 @@
     "//ui/mojo/events:interfaces",
   ]
 
-  if (!is_android) {
+  if (is_mac || use_aura) {
+    sources += [
+      "desktop/desktop_ui.cc",
+      "desktop/desktop_ui.h",
+    ]
     deps += [ "//mandoline/ui/aura" ]
+  } else {
+    assert(is_android)
+    sources += [
+      "android/android_ui.cc",
+      "android/android_ui.h",
+    ]
   }
 }
-
-mojom("interfaces") {
-  sources = [
-    "omnibox.mojom",
-    "view_embedder.mojom",
-  ]
-
-  import_dirs = [ "//mojo/services" ]
-
-  deps = [
-    "//mojo/application/public/interfaces",
-    "//mojo/services/network/public/interfaces",
-  ]
-}
diff --git a/mandoline/ui/browser/browser.cc b/mandoline/ui/browser/browser.cc
index 50c774c4..1ffb1ce 100644
--- a/mandoline/ui/browser/browser.cc
+++ b/mandoline/ui/browser/browser.cc
@@ -9,10 +9,9 @@
 #include "components/view_manager/public/cpp/view.h"
 #include "components/view_manager/public/cpp/view_manager_init.h"
 #include "mandoline/tab/frame.h"
-#include "mandoline/tab/frame_services.h"
+#include "mandoline/tab/frame_connection.h"
 #include "mandoline/tab/frame_tree.h"
 #include "mandoline/ui/browser/browser_ui.h"
-#include "mandoline/ui/browser/merged_service_provider.h"
 #include "mojo/application/public/cpp/application_runner.h"
 #include "mojo/common/common_type_converters.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
@@ -39,7 +38,6 @@
       omnibox_(nullptr),
       navigator_host_(this),
       app_(nullptr) {
-  exposed_services_impl_.AddService<mojo::NavigatorHost>(this);
 }
 
 Browser::~Browser() {
@@ -50,7 +48,7 @@
 }
 
 void Browser::ReplaceContentWithRequest(mojo::URLRequestPtr request) {
-  Embed(request.Pass(), nullptr, nullptr);
+  Embed(request.Pass());
 }
 
 void Browser::Initialize(mojo::ApplicationImpl* app) {
@@ -74,6 +72,7 @@
 
 bool Browser::ConfigureIncomingConnection(
     mojo::ApplicationConnection* connection) {
+  connection->AddService<LaunchHandler>(this);
   // TODO: register embed interface here.
   return true;
 }
@@ -84,10 +83,7 @@
   return true;
 }
 
-void Browser::OnEmbed(
-    mojo::View* root,
-    mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services) {
+void Browser::OnEmbed(mojo::View* root) {
   // Browser does not support being embedded more than once.
   CHECK(!root_);
 
@@ -113,24 +109,26 @@
 
   // Now that we're ready, either load a pending url or the default url.
   if (pending_request_) {
-    Embed(pending_request_.Pass(), services.Pass(), exposed_services.Pass());
+    Embed(pending_request_.Pass());
   } else if (!default_url_.empty()) {
     mojo::URLRequestPtr request(mojo::URLRequest::New());
     request->url = mojo::String::From(default_url_);
-    Embed(request.Pass(), services.Pass(), exposed_services.Pass());
+    Embed(request.Pass());
   }
 }
 
-bool Browser::OnWillEmbed(
-    mojo::View* view,
-    mojo::InterfaceRequest<mojo::ServiceProvider>* services,
-    mojo::ServiceProviderPtr* exposed_services) {
+void Browser::OnEmbedForDescendant(mojo::View* view,
+                                   mojo::URLRequestPtr request,
+                                   mojo::ViewManagerClientPtr* client) {
   // TODO(sky): move this to Frame/FrameTree.
   Frame* frame = Frame::FindFirstFrameAncestor(view);
   if (!frame) {
     // TODO(sky): add requestor url so that we can return false if it's not
     // an app we expect.
-    return true;
+    mojo::ApplicationConnection* connection =
+        app_->ConnectToApplication(request.Pass());
+    connection->ConnectToService(client);
+    return;
   }
 
   Frame* parent = frame;
@@ -141,12 +139,11 @@
     frame = nullptr;
   }
 
-  scoped_ptr<FrameServices> frame_services(new FrameServices);
-  frame_services->Init(services, exposed_services);
-  FrameTreeClient* frame_tree_client = frame_services->frame_tree_client();
+  scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
+  frame_connection->Init(app_, request.Pass(), client);
+  FrameTreeClient* frame_tree_client = frame_connection->frame_tree_client();
   frame_tree_->CreateAndAddFrame(view, parent, frame_tree_client,
-                                 frame_services.Pass());
-  return true;
+                                 frame_connection.Pass());
 }
 
 void Browser::OnViewManagerDestroyed(mojo::ViewManager* view_manager) {
@@ -168,12 +165,10 @@
   ReplaceContentWithRequest(request.Pass());
 }
 
-void Browser::Embed(mojo::URLRequestPtr request,
-                    mojo::InterfaceRequest<mojo::ServiceProvider> services,
-                    mojo::ServiceProviderPtr exposed_services) {
-  std::string string_url = request->url.To<std::string>();
+void Browser::Embed(mojo::URLRequestPtr request) {
+  const std::string string_url = request->url.To<std::string>();
   if (string_url == "mojo:omnibox") {
-    ShowOmnibox(request.Pass(), services.Pass(), exposed_services.Pass());
+    ShowOmnibox(request.Pass());
     return;
   }
 
@@ -191,21 +186,25 @@
   if (changed)
     ui_->OnURLChanged();
 
-  merged_service_provider_.reset(
-      new MergedServiceProvider(exposed_services.Pass(), this));
-  scoped_ptr<FrameServices> frame_services(new FrameServices);
-  // TODO(sky): FrameServices and MergedServiceProvider need to be combined.
-  // TODO(sky): FrameServices needs to man in the middle services.
-  frame_services->Init(&services, nullptr);
-  FrameTreeClient* frame_tree_client = frame_services->frame_tree_client();
+  scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
+  mojo::ViewManagerClientPtr view_manager_client;
+  frame_connection->Init(app_, request.Pass(), &view_manager_client);
+  frame_connection->application_connection()->AddService<mojo::NavigatorHost>(
+      this);
+  FrameTreeClient* frame_tree_client = frame_connection->frame_tree_client();
   frame_tree_.reset(new FrameTree(content_, nullptr, frame_tree_client,
-                                  frame_services.Pass()));
-  content_->Embed(request.Pass(), services.Pass(),
-                  merged_service_provider_->GetServiceProviderPtr().Pass());
+                                  frame_connection.Pass()));
+  content_->Embed(view_manager_client.Pass());
 
   navigator_host_.RecordNavigation(gurl.spec());
 }
 
+void Browser::LaunchURL(const mojo::String& url) {
+  mojo::URLRequestPtr request(mojo::URLRequest::New());
+  request->url = url;
+  ReplaceContentWithRequest(request.Pass());
+}
+
 void Browser::Create(mojo::ApplicationConnection* connection,
                      mojo::InterfaceRequest<mojo::NavigatorHost> request) {
   navigator_host_.Bind(request.Pass());
@@ -216,17 +215,23 @@
   view_embedder_bindings_.AddBinding(this, request.Pass());
 }
 
-void Browser::ShowOmnibox(
-    mojo::URLRequestPtr request,
-    mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services) {
+void Browser::Create(mojo::ApplicationConnection* connection,
+                     mojo::InterfaceRequest<LaunchHandler> request) {
+  launch_handler_bindings_.AddBinding(this, request.Pass());
+}
+
+void Browser::ShowOmnibox(mojo::URLRequestPtr request) {
   if (!omnibox_) {
     omnibox_ = root_->view_manager()->CreateView();
     root_->AddChild(omnibox_);
     omnibox_->SetVisible(true);
     omnibox_->SetBounds(root_->bounds());
   }
-  omnibox_->Embed(request.Pass(), services.Pass(), exposed_services.Pass());
+  mojo::ViewManagerClientPtr view_manager_client;
+  mojo::ApplicationConnection* connection =
+      app_->ConnectToApplication(request.Pass());
+  connection->ConnectToService(&view_manager_client);
+  omnibox_->Embed(view_manager_client.Pass());
 }
 
 }  // namespace mandoline
diff --git a/mandoline/ui/browser/browser.h b/mandoline/ui/browser/browser.h
index 3728f3ac..92c7d726 100644
--- a/mandoline/ui/browser/browser.h
+++ b/mandoline/ui/browser/browser.h
@@ -10,12 +10,12 @@
 #include "components/view_manager/public/interfaces/view_manager_root.mojom.h"
 #include "mandoline/services/navigation/public/interfaces/navigation.mojom.h"
 #include "mandoline/ui/browser/navigator_host_impl.h"
-#include "mandoline/ui/browser/omnibox.mojom.h"
-#include "mandoline/ui/browser/view_embedder.mojom.h"
+#include "mandoline/ui/browser/public/interfaces/launch_handler.mojom.h"
+#include "mandoline/ui/browser/public/interfaces/omnibox.mojom.h"
+#include "mandoline/ui/browser/public/interfaces/view_embedder.mojom.h"
 #include "mojo/application/public/cpp/application_delegate.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/connect.h"
-#include "mojo/application/public/cpp/service_provider_impl.h"
 #include "mojo/common/weak_binding_set.h"
 #include "ui/mojo/events/input_events.mojom.h"
 #include "url/gurl.h"
@@ -28,15 +28,16 @@
 
 class BrowserUI;
 class FrameTree;
-class MergedServiceProvider;
 
 class Browser : public mojo::ApplicationDelegate,
                 public mojo::ViewManagerDelegate,
                 public mojo::ViewManagerRootClient,
                 public OmniboxClient,
                 public ViewEmbedder,
+                public LaunchHandler,
                 public mojo::InterfaceFactory<mojo::NavigatorHost>,
-                public mojo::InterfaceFactory<ViewEmbedder> {
+                public mojo::InterfaceFactory<ViewEmbedder>,
+                public mojo::InterfaceFactory<LaunchHandler> {
  public:
   Browser();
   ~Browser() override;
@@ -57,12 +58,10 @@
       mojo::ApplicationConnection* connection) override;
 
   // Overridden from mojo::ViewManagerDelegate:
-  void OnEmbed(mojo::View* root,
-               mojo::InterfaceRequest<mojo::ServiceProvider> services,
-               mojo::ServiceProviderPtr exposed_services) override;
-  bool OnWillEmbed(mojo::View* view,
-                   mojo::InterfaceRequest<mojo::ServiceProvider>* services,
-                   mojo::ServiceProviderPtr* exposed_services) override;
+  void OnEmbed(mojo::View* root) override;
+  void OnEmbedForDescendant(mojo::View* view,
+                            mojo::URLRequestPtr request,
+                            mojo::ViewManagerClientPtr* client) override;
   void OnViewManagerDestroyed(mojo::ViewManager* view_manager) override;
 
   // Overridden from ViewManagerRootClient:
@@ -72,9 +71,10 @@
   void OpenURL(const mojo::String& url) override;
 
   // Overridden from ViewEmbedder:
-  void Embed(mojo::URLRequestPtr request,
-             mojo::InterfaceRequest<mojo::ServiceProvider> services,
-             mojo::ServiceProviderPtr exposed_services) override;
+  void Embed(mojo::URLRequestPtr request) override;
+
+  // Overridden from LaunchHandler:
+  void LaunchURL(const mojo::String& url) override;
 
   // Overridden from mojo::InterfaceFactory<mojo::NavigatorHost>:
   void Create(mojo::ApplicationConnection* connection,
@@ -84,9 +84,11 @@
   void Create(mojo::ApplicationConnection* connection,
               mojo::InterfaceRequest<ViewEmbedder> request) override;
 
-  void ShowOmnibox(mojo::URLRequestPtr request,
-                   mojo::InterfaceRequest<mojo::ServiceProvider> services,
-                   mojo::ServiceProviderPtr exposed_services);
+  // Overridden from mojo::InterfaceFactory<LaunchHandler>:
+  void Create(mojo::ApplicationConnection* connection,
+              mojo::InterfaceRequest<LaunchHandler> request) override;
+
+  void ShowOmnibox(mojo::URLRequestPtr request);
 
   scoped_ptr<mojo::ViewManagerInit> view_manager_init_;
 
@@ -98,10 +100,8 @@
   std::string default_url_;
   mojo::URLRequestPtr pending_request_;
 
-  mojo::ServiceProviderImpl exposed_services_impl_;
-  scoped_ptr<MergedServiceProvider> merged_service_provider_;
-
   mojo::WeakBindingSet<ViewEmbedder> view_embedder_bindings_;
+  mojo::WeakBindingSet<LaunchHandler> launch_handler_bindings_;
 
   NavigatorHostImpl navigator_host_;
 
diff --git a/mandoline/ui/browser/desktop/desktop_ui.cc b/mandoline/ui/browser/desktop/desktop_ui.cc
index b454f21..b417243 100644
--- a/mandoline/ui/browser/desktop/desktop_ui.cc
+++ b/mandoline/ui/browser/desktop/desktop_ui.cc
@@ -8,7 +8,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "mandoline/ui/aura/native_widget_view_manager.h"
 #include "mandoline/ui/browser/browser.h"
-#include "mandoline/ui/browser/omnibox.mojom.h"
+#include "mandoline/ui/browser/public/interfaces/omnibox.mojom.h"
 #include "mojo/common/common_type_converters.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "ui/views/background.h"
@@ -21,10 +21,10 @@
 // DesktopUI, public:
 
 DesktopUI::DesktopUI(Browser* browser, mojo::ApplicationImpl* application_impl)
-    : browser_(browser),
+    : aura_init_(application_impl->shell()),
+      browser_(browser),
       application_impl_(application_impl),
-      omnibox_launcher_(
-          new views::LabelButton(this, base::ASCIIToUTF16("Open Omnibox"))),
+      omnibox_launcher_(nullptr),
       root_(nullptr),
       client_binding_(browser) {
 }
@@ -40,6 +40,8 @@
   views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView;
   widget_delegate->GetContentsView()->set_background(
     views::Background::CreateSolidBackground(0xFFDDDDDD));
+  omnibox_launcher_ =
+      new views::LabelButton(this, base::ASCIIToUTF16("Open Omnibox"));
   widget_delegate->GetContentsView()->AddChildView(omnibox_launcher_);
   widget_delegate->GetContentsView()->SetLayoutManager(this);
 
diff --git a/mandoline/ui/browser/desktop/desktop_ui.h b/mandoline/ui/browser/desktop/desktop_ui.h
index 3ff608cc..3be7f10 100644
--- a/mandoline/ui/browser/desktop/desktop_ui.h
+++ b/mandoline/ui/browser/desktop/desktop_ui.h
@@ -7,7 +7,7 @@
 
 #include "mandoline/ui/aura/aura_init.h"
 #include "mandoline/ui/browser/browser_ui.h"
-#include "mandoline/ui/browser/omnibox.mojom.h"
+#include "mandoline/ui/browser/public/interfaces/omnibox.mojom.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/layout/layout_manager.h"
 
diff --git a/mandoline/ui/browser/merged_service_provider.cc b/mandoline/ui/browser/merged_service_provider.cc
deleted file mode 100644
index fe4a83a..0000000
--- a/mandoline/ui/browser/merged_service_provider.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mandoline/ui/browser/merged_service_provider.h"
-
-namespace mandoline {
-
-MergedServiceProvider::MergedServiceProvider(
-    mojo::ServiceProviderPtr exposed_services,
-    mojo::InterfaceFactory<mojo::NavigatorHost>* factory)
-    : exposed_services_(exposed_services.Pass()), factory_(factory) {
-}
-
-MergedServiceProvider::~MergedServiceProvider() {
-}
-
-mojo::ServiceProviderPtr MergedServiceProvider::GetServiceProviderPtr() {
-  mojo::ServiceProviderPtr sp;
-  binding_.reset(new mojo::Binding<mojo::ServiceProvider>(this, GetProxy(&sp)));
-  return sp.Pass();
-}
-
-void MergedServiceProvider::ConnectToService(
-    const mojo::String& interface_name,
-    mojo::ScopedMessagePipeHandle pipe) {
-  if (interface_name == mojo::NavigatorHost::Name_) {
-    factory_->Create(nullptr,
-                     mojo::MakeRequest<mojo::NavigatorHost>(pipe.Pass()));
-  } else if (exposed_services_.get()) {
-    exposed_services_->ConnectToService(interface_name, pipe.Pass());
-  }
-}
-
-}  // namespace mandoline
diff --git a/mandoline/ui/browser/merged_service_provider.h b/mandoline/ui/browser/merged_service_provider.h
deleted file mode 100644
index 20a94d5d..0000000
--- a/mandoline/ui/browser/merged_service_provider.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MANDOLINE_UI_BROWSER_MERGED_SERVICE_PROVIDER_H_
-#define MANDOLINE_UI_BROWSER_MERGED_SERVICE_PROVIDER_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "mandoline/services/navigation/public/interfaces/navigation.mojom.h"
-#include "mojo/application/public/cpp/interface_factory.h"
-#include "mojo/application/public/interfaces/service_provider.mojom.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
-
-namespace mandoline {
-
-// Used to wrap the second incoming WindowManager Embed() "exposed_services"
-// parameter with a new ServiceProvider that adds the Browser's
-// NavigatorHost service.
-class MergedServiceProvider : public mojo::ServiceProvider {
- public:
-  MergedServiceProvider(mojo::ServiceProviderPtr exposed_services,
-                        mojo::InterfaceFactory<mojo::NavigatorHost>* factory);
-  ~MergedServiceProvider() override;
-
-  mojo::ServiceProviderPtr GetServiceProviderPtr();
-
- private:
-  // mojo::ServiceProvider:
-  void ConnectToService(const mojo::String& interface_name,
-                        mojo::ScopedMessagePipeHandle pipe) override;
-
-  mojo::ServiceProviderPtr exposed_services_;
-  mojo::InterfaceFactory<mojo::NavigatorHost>* factory_;
-  scoped_ptr<mojo::Binding<ServiceProvider>> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(MergedServiceProvider);
-};
-
-}  // namespace mandoline
-
-#endif  // MANDOLINE_UI_BROWSER_MERGED_SERVICE_PROVIDER_H_
diff --git a/mandoline/ui/browser/public/interfaces/BUILD.gn b/mandoline/ui/browser/public/interfaces/BUILD.gn
new file mode 100644
index 0000000..ffb04c133
--- /dev/null
+++ b/mandoline/ui/browser/public/interfaces/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+  sources = [
+    "launch_handler.mojom",
+    "omnibox.mojom",
+    "view_embedder.mojom",
+  ]
+
+  import_dirs = [ "//mojo/services" ]
+
+  deps = [
+    "//mojo/application/public/interfaces",
+    "//mojo/services/network/public/interfaces",
+  ]
+}
diff --git a/mandoline/ui/browser/public/interfaces/launch_handler.mojom b/mandoline/ui/browser/public/interfaces/launch_handler.mojom
new file mode 100644
index 0000000..e402d1a
--- /dev/null
+++ b/mandoline/ui/browser/public/interfaces/launch_handler.mojom
@@ -0,0 +1,13 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module mandoline;
+
+// Interface used by the Mojo Shell embedder to forward launch requests from
+// the host OS to load specific URLs. e.g. when a post-launch intent to load
+// a URL comes in from the Android system, the Mandoline Activity will use
+// this interface to forward the requested URL to the browser.
+interface LaunchHandler {
+  LaunchURL(string url);
+};
diff --git a/mandoline/ui/browser/omnibox.mojom b/mandoline/ui/browser/public/interfaces/omnibox.mojom
similarity index 100%
rename from mandoline/ui/browser/omnibox.mojom
rename to mandoline/ui/browser/public/interfaces/omnibox.mojom
diff --git a/mandoline/ui/browser/public/interfaces/view_embedder.mojom b/mandoline/ui/browser/public/interfaces/view_embedder.mojom
new file mode 100644
index 0000000..693dfee
--- /dev/null
+++ b/mandoline/ui/browser/public/interfaces/view_embedder.mojom
@@ -0,0 +1,11 @@
+// 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.
+
+module mandoline;
+
+import "network/public/interfaces/url_loader.mojom";
+
+interface ViewEmbedder {
+  Embed(mojo.URLRequest request);
+};
diff --git a/mandoline/ui/browser/view_embedder.mojom b/mandoline/ui/browser/view_embedder.mojom
deleted file mode 100644
index c71bb5e7..0000000
--- a/mandoline/ui/browser/view_embedder.mojom
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mandoline;
-
-import "mojo/application/public/interfaces/service_provider.mojom";
-import "network/public/interfaces/url_loader.mojom";
-
-interface ViewEmbedder {
-  Embed(mojo.URLRequest request,
-        mojo.ServiceProvider&? services,
-        mojo.ServiceProvider? exposed_services);
-};
diff --git a/mandoline/ui/omnibox/BUILD.gn b/mandoline/ui/omnibox/BUILD.gn
index c7f8c39..af13edb 100644
--- a/mandoline/ui/omnibox/BUILD.gn
+++ b/mandoline/ui/omnibox/BUILD.gn
@@ -2,10 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
-import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
+import("//mojo/mojo_application_package.gni")
 
-mojo_native_application("omnibox") {
+mojo_application_package("omnibox") {
   sources = [
     "main.cc",
   ]
@@ -14,6 +13,13 @@
     ":lib",
     "//mandoline/services/navigation/public/interfaces",
     "//mojo/application/public/cpp",
+    "//third_party/icu:icudata",
+    "//ui/resources:ui_test_pak",
+  ]
+
+  resources = [
+    "$root_out_dir/icudtl.dat",
+    "$root_out_dir/ui_test.pak",
   ]
 }
 
@@ -28,7 +34,7 @@
     "//components/view_manager/public/cpp",
     "//mandoline/services/navigation/public/interfaces",
     "//mandoline/ui/aura",
-    "//mandoline/ui/browser:interfaces",
+    "//mandoline/ui/browser/public/interfaces",
     "//mojo/application/public/interfaces",
     "//mojo/converters/geometry",
     "//skia",
diff --git a/mandoline/ui/omnibox/omnibox_impl.cc b/mandoline/ui/omnibox/omnibox_impl.cc
index 756ab9da..0509693 100644
--- a/mandoline/ui/omnibox/omnibox_impl.cc
+++ b/mandoline/ui/omnibox/omnibox_impl.cc
@@ -51,11 +51,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 // OmniboxImpl, mojo::ViewManagerDelegate implementation:
 
-void OmniboxImpl::OnEmbed(mojo::View* root,
-    mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    mojo::ServiceProviderPtr exposed_services) {
+void OmniboxImpl::OnEmbed(mojo::View* root) {
   if (!aura_init_.get()) {
-    aura_init_.reset(new AuraInit);
+    aura_init_.reset(new AuraInit(app_impl_->shell()));
     edit_ = new views::Textfield;
     edit_->set_controller(this);
   }
@@ -138,7 +136,7 @@
   url_ = url;
   mojo::URLRequestPtr request(mojo::URLRequest::New());
   request->url = mojo::String::From("mojo:omnibox");
-  view_embedder_->Embed(request.Pass(), nullptr, nullptr);
+  view_embedder_->Embed(request.Pass());
 }
 
 }  // namespace mandoline
diff --git a/mandoline/ui/omnibox/omnibox_impl.h b/mandoline/ui/omnibox/omnibox_impl.h
index d6206d4..06bec66 100644
--- a/mandoline/ui/omnibox/omnibox_impl.h
+++ b/mandoline/ui/omnibox/omnibox_impl.h
@@ -6,8 +6,8 @@
 #define MANDOLINE_UI_OMNIBOX_OMNIBOX_IMPL_H_
 
 #include "components/view_manager/public/cpp/view_manager_delegate.h"
-#include "mandoline/ui/browser/omnibox.mojom.h"
-#include "mandoline/ui/browser/view_embedder.mojom.h"
+#include "mandoline/ui/browser/public/interfaces/omnibox.mojom.h"
+#include "mandoline/ui/browser/public/interfaces/view_embedder.mojom.h"
 #include "mojo/application/public/cpp/application_delegate.h"
 #include "mojo/application/public/cpp/interface_factory.h"
 #include "mojo/common/weak_binding_set.h"
@@ -41,9 +41,7 @@
       mojo::ApplicationConnection* connection) override;
 
   // Overridden from mojo::ViewManagerDelegate:
-  void OnEmbed(mojo::View* root,
-               mojo::InterfaceRequest<mojo::ServiceProvider> services,
-               mojo::ServiceProviderPtr exposed_services) override;
+  void OnEmbed(mojo::View* root) override;
   void OnViewManagerDestroyed(mojo::ViewManager* view_manager) override;
 
   // Overridden from views::LayoutManager:
diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc
index 0b41b347..9f46b55 100644
--- a/media/audio/audio_input_device.cc
+++ b/media/audio/audio_input_device.cc
@@ -151,7 +151,7 @@
 }
 
 void AudioInputDevice::OnStateChanged(
-    AudioInputIPCDelegate::State state) {
+    AudioInputIPCDelegateState state) {
   DCHECK(task_runner()->BelongsToCurrentThread());
 
   // Do nothing if the stream has been closed.
@@ -161,14 +161,14 @@
   // TODO(miu): Clean-up inconsistent and incomplete handling here.
   // http://crbug.com/180640
   switch (state) {
-    case AudioInputIPCDelegate::kStopped:
+    case AUDIO_INPUT_IPC_DELEGATE_STATE_STOPPED:
       ShutDownOnIOThread();
       break;
-    case AudioInputIPCDelegate::kRecording:
+    case AUDIO_INPUT_IPC_DELEGATE_STATE_RECORDING:
       NOTIMPLEMENTED();
       break;
-    case AudioInputIPCDelegate::kError:
-      DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)";
+    case AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR:
+      DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)";
       // Don't dereference the callback object if the audio thread
       // is stopped or stopping.  That could mean that the callback
       // object has been deleted.
diff --git a/media/audio/audio_input_device.h b/media/audio/audio_input_device.h
index abfca76..c1bee10 100644
--- a/media/audio/audio_input_device.h
+++ b/media/audio/audio_input_device.h
@@ -104,7 +104,7 @@
                        int length,
                        int total_segments) override;
   void OnVolume(double volume) override;
-  void OnStateChanged(AudioInputIPCDelegate::State state) override;
+  void OnStateChanged(AudioInputIPCDelegateState state) override;
   void OnIPCClosed() override;
 
  private:
diff --git a/media/audio/audio_input_ipc.h b/media/audio/audio_input_ipc.h
index ce7b034d..f9784f58 100644
--- a/media/audio/audio_input_ipc.h
+++ b/media/audio/audio_input_ipc.h
@@ -12,19 +12,18 @@
 
 namespace media {
 
+enum AudioInputIPCDelegateState {
+  AUDIO_INPUT_IPC_DELEGATE_STATE_RECORDING,
+  AUDIO_INPUT_IPC_DELEGATE_STATE_STOPPED,
+  AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR,
+  AUDIO_INPUT_IPC_DELEGATE_STATE_LAST = AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR,
+};
+
 // Contains IPC notifications for the state of the server side
 // (AudioInputController) audio state changes and when an AudioInputController
 // has been created.  Implemented by AudioInputDevice.
 class MEDIA_EXPORT AudioInputIPCDelegate {
  public:
-  // Valid states for the input stream.
-  enum State {
-    kRecording,
-    kStopped,
-    kError,
-    kStateLast = kError
-  };
-
   // Called when an AudioInputController has been created.
   // The shared memory |handle| points to a memory section that's used to
   // transfer data between the AudioInputDevice and AudioInputController
@@ -39,7 +38,7 @@
                                int total_segments) = 0;
 
   // Called when state of an audio stream has changed.
-  virtual void OnStateChanged(State state) = 0;
+  virtual void OnStateChanged(AudioInputIPCDelegateState state) = 0;
 
   // Called when the input stream volume has changed.
   virtual void OnVolume(double volume) = 0;
diff --git a/media/audio/audio_logging.h b/media/audio/audio_logging.h
index 913b8ec4..4d7551f 100644
--- a/media/audio/audio_logging.h
+++ b/media/audio/audio_logging.h
@@ -43,6 +43,11 @@
 
   // Called when an audio component changes volume.  |volume| is the new volume.
   virtual void OnSetVolume(int component_id, double volume) = 0;
+
+  // Called when an audio component switches output device. |device_id| is the
+  // new audio output device.
+  virtual void OnSwitchOutputDevice(int component_id,
+                                    const std::string& device_id) = 0;
 };
 
 // AudioLogFactory dispenses AudioLog instances to owning classes for tracking
diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc
index 2518f950..d55d100 100644
--- a/media/audio/audio_output_device.cc
+++ b/media/audio/audio_output_device.cc
@@ -179,7 +179,7 @@
     ipc_->SetVolume(volume);
 }
 
-void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) {
+void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) {
   DCHECK(task_runner()->BelongsToCurrentThread());
 
   // Do nothing if the stream has been closed.
@@ -189,11 +189,11 @@
   // TODO(miu): Clean-up inconsistent and incomplete handling here.
   // http://crbug.com/180640
   switch (state) {
-    case AudioOutputIPCDelegate::kPlaying:
-    case AudioOutputIPCDelegate::kPaused:
+    case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING:
+    case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED:
       break;
-    case AudioOutputIPCDelegate::kError:
-      DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(kError)";
+    case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR:
+      DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)";
       // Don't dereference the callback object if the audio thread
       // is stopped or stopping.  That could mean that the callback
       // object has been deleted.
diff --git a/media/audio/audio_output_device.h b/media/audio/audio_output_device.h
index ca11b80..6255c71 100644
--- a/media/audio/audio_output_device.h
+++ b/media/audio/audio_output_device.h
@@ -98,7 +98,7 @@
 
   // Methods called on IO thread ----------------------------------------------
   // AudioOutputIPCDelegate methods.
-  void OnStateChanged(AudioOutputIPCDelegate::State state) override;
+  void OnStateChanged(AudioOutputIPCDelegateState state) override;
   void OnStreamCreated(base::SharedMemoryHandle handle,
                        base::SyncSocket::Handle socket_handle,
                        int length) override;
diff --git a/media/audio/audio_output_ipc.h b/media/audio/audio_output_ipc.h
index f85d8e0..9af1df4 100644
--- a/media/audio/audio_output_ipc.h
+++ b/media/audio/audio_output_ipc.h
@@ -5,30 +5,45 @@
 #ifndef MEDIA_AUDIO_AUDIO_OUTPUT_IPC_H_
 #define MEDIA_AUDIO_AUDIO_OUTPUT_IPC_H_
 
+#include <string>
+
 #include "base/memory/shared_memory.h"
 #include "base/sync_socket.h"
 #include "media/audio/audio_parameters.h"
 #include "media/base/media_export.h"
+#include "url/gurl.h"
 
 namespace media {
 
+// Result of an audio output device switch operation
+enum SwitchOutputDeviceResult {
+  SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS = 0,
+  SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_FOUND,
+  SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_AUTHORIZED,
+  SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE,
+  SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_SUPPORTED,
+  SWITCH_OUTPUT_DEVICE_RESULT_LAST =
+      SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_SUPPORTED,
+};
+
+// Current status of the audio output stream in the browser process. Browser
+// sends information about the current playback state and error to the
+// renderer process using this type.
+enum AudioOutputIPCDelegateState {
+  AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING,
+  AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED,
+  AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR,
+  AUDIO_OUTPUT_IPC_DELEGATE_STATE_LAST = AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR
+};
+
 // Contains IPC notifications for the state of the server side
 // (AudioOutputController) audio state changes and when an AudioOutputController
 // has been created.  Implemented by AudioOutputDevice.
 class MEDIA_EXPORT AudioOutputIPCDelegate {
  public:
-  // Current status of the audio output stream in the browser process. Browser
-  // sends information about the current playback state and error to the
-  // renderer process using this type.
-  enum State {
-    kPlaying,
-    kPaused,
-    kError,
-    kStateLast = kError
-  };
 
   // Called when state of an audio stream has changed.
-  virtual void OnStateChanged(State state) = 0;
+  virtual void OnStateChanged(AudioOutputIPCDelegateState state) = 0;
 
   // Called when an audio stream has been created.
   // The shared memory |handle| points to a memory section that's used to
diff --git a/media/audio/fake_audio_log_factory.cc b/media/audio/fake_audio_log_factory.cc
index e8677f2..fd5cf458 100644
--- a/media/audio/fake_audio_log_factory.cc
+++ b/media/audio/fake_audio_log_factory.cc
@@ -4,6 +4,8 @@
 
 #include "media/audio/fake_audio_log_factory.h"
 
+#include <string>
+
 namespace media {
 
 class FakeAudioLogImpl : public AudioLog {
@@ -18,6 +20,8 @@
   void OnClosed(int component_id) override {}
   void OnError(int component_id) override {}
   void OnSetVolume(int component_id, double volume) override {}
+  void OnSwitchOutputDevice(int component_id,
+                            const std::string& device_id) override {}
 };
 
 FakeAudioLogFactory::FakeAudioLogFactory() {}
diff --git a/media/audio_unittests.isolate b/media/audio_unittests.isolate
index fe84e1e..d91c6360 100644
--- a/media/audio_unittests.isolate
+++ b/media/audio_unittests.isolate
@@ -52,31 +52,9 @@
         ],
       },
     }],
-    ['OS=="linux"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
-        ],
-      },
-    }],
-    ['OS=="mac"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
-        ],
-      },
-    }],
-    ['OS=="win"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
-        ],
-      },
-    }],
     ['OS=="mac" and asan==1 and fastbuild==0', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
           '<(PRODUCT_DIR)/audio_unittests.dSYM/',
         ],
       },
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 29547f3d..96254cf2 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -216,11 +216,6 @@
       "media_file_checker.cc",
       "media_file_checker.h",
     ]
-    if (is_win) {
-      sources += [ "media_win.cc" ]
-    } else if (is_posix) {
-      sources += [ "media_posix.cc" ]
-    }
 
     deps += [ "//third_party/ffmpeg" ]
   }
@@ -235,7 +230,6 @@
   }
 
   if (is_android) {
-    sources += [ "media_stub.cc" ]
     public_deps = [
       "//media/base/android",
       "//media/base/android:media_java",
diff --git a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
index c520e34..e71ca86f 100644
--- a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
+++ b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
@@ -24,10 +24,10 @@
 import android.os.HandlerThread;
 import android.os.Process;
 import android.provider.Settings;
-import android.util.Log;
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -35,7 +35,7 @@
 
 @JNINamespace("media")
 class AudioManagerAndroid {
-    private static final String TAG = "AudioManagerAndroid";
+    private static final String TAG = "cr.media";
 
     // Set to true to enable debug logs. Avoid in production builds.
     // NOTE: always check in as false.
@@ -373,8 +373,8 @@
         if (DEBUG) logd("setDevice: " + deviceId);
         if (!mIsInitialized) return false;
         if (!mHasModifyAudioSettingsPermission || !mHasRecordAudioPermission) {
-            Log.w(TAG, "Requires MODIFY_AUDIO_SETTINGS and RECORD_AUDIO");
-            Log.w(TAG, "Selected device will not be available for recording");
+            Log.w(TAG, "Requires MODIFY_AUDIO_SETTINGS and RECORD_AUDIO. "
+                    + "Selected device will not be available for recording");
             return false;
         }
 
@@ -416,8 +416,8 @@
         if (DEBUG) logd("getAudioInputDeviceNames");
         if (!mIsInitialized) return null;
         if (!mHasModifyAudioSettingsPermission || !mHasRecordAudioPermission) {
-            Log.w(TAG, "Requires MODIFY_AUDIO_SETTINGS and RECORD_AUDIO");
-            Log.w(TAG, "No audio device will be available for recording");
+            Log.w(TAG, "Requires MODIFY_AUDIO_SETTINGS and RECORD_AUDIO. "
+                    + "No audio device will be available for recording");
             return null;
         }
 
diff --git a/media/base/android/java/src/org/chromium/media/AudioRecordInput.java b/media/base/android/java/src/org/chromium/media/AudioRecordInput.java
index 65f0689..3a8a71e 100644
--- a/media/base/android/java/src/org/chromium/media/AudioRecordInput.java
+++ b/media/base/android/java/src/org/chromium/media/AudioRecordInput.java
@@ -12,10 +12,10 @@
 import android.media.audiofx.AudioEffect;
 import android.media.audiofx.AudioEffect.Descriptor;
 import android.os.Process;
-import android.util.Log;
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
 
 import java.nio.ByteBuffer;
 
@@ -23,7 +23,7 @@
 // that class for general comments.
 @JNINamespace("media")
 class AudioRecordInput {
-    private static final String TAG = "AudioRecordInput";
+    private static final String TAG = "cr.media";
     // Set to true to enable debug logs. Always check in as false.
     private static final boolean DEBUG = false;
     // We are unable to obtain a precise measurement of the hardware delay on
@@ -65,7 +65,7 @@
                     nativeOnData(mNativeAudioRecordInputStream, bytesRead,
                                  mHardwareDelayBytes);
                 } else {
-                    Log.e(TAG, "read failed: " + bytesRead);
+                    Log.e(TAG, "read failed: %d", bytesRead);
                     if (bytesRead == AudioRecord.ERROR_INVALID_OPERATION) {
                         // This can happen if there is already an active
                         // AudioRecord (e.g. in another tab).
@@ -138,7 +138,7 @@
         } else if (mChannels == 2) {
             channelConfig = AudioFormat.CHANNEL_IN_STEREO;
         } else {
-            Log.e(TAG, "Unsupported number of channels: " + mChannels);
+            Log.e(TAG, "Unsupported number of channels: %d", mChannels);
             return false;
         }
 
@@ -148,7 +148,7 @@
         } else if (mBitsPerSample == 16) {
             audioFormat = AudioFormat.ENCODING_PCM_16BIT;
         } else {
-            Log.e(TAG, "Unsupported bits per sample: " + mBitsPerSample);
+            Log.e(TAG, "Unsupported bits per sample: %d", mBitsPerSample);
             return false;
         }
 
@@ -157,7 +157,7 @@
         // recording under load".
         int minBufferSize = AudioRecord.getMinBufferSize(mSampleRate, channelConfig, audioFormat);
         if (minBufferSize < 0) {
-            Log.e(TAG, "getMinBufferSize error: " + minBufferSize);
+            Log.e(TAG, "getMinBufferSize error: %d", minBufferSize);
             return false;
         }
 
@@ -184,16 +184,14 @@
             }
             int ret = mAEC.setEnabled(mUsePlatformAEC);
             if (ret != AudioEffect.SUCCESS) {
-                Log.e(TAG, "setEnabled error: " + ret);
+                Log.e(TAG, "setEnabled error: %d", ret);
                 return false;
             }
 
             if (DEBUG) {
                 Descriptor descriptor = mAEC.getDescriptor();
-                Log.d(TAG, "AcousticEchoCanceler "
-                        + "name: " + descriptor.name + ", "
-                        + "implementor: " + descriptor.implementor + ", "
-                        + "uuid: " + descriptor.uuid);
+                Log.d(TAG, "AcousticEchoCanceler name: %s, implementor: %s, uuid: %s",
+                            descriptor.name, descriptor.implementor, descriptor.uuid);
             }
         }
         return true;
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
index 04066e0e..eb62b9b9 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -32,7 +32,7 @@
  */
 @JNINamespace("media")
 class MediaCodecBridge {
-    private static final String TAG = "MediaCodecBridge";
+    private static final String TAG = "cr.media";
 
     // Error code for MediaCodecBridge. Keep this value in sync with
     // MediaCodecStatus in media_codec_bridge.h.
@@ -229,8 +229,8 @@
                 codecName = mediaCodec.getName();
                 mediaCodec.release();
             } catch (Exception e) {
-                Log.w(TAG, "getDefaultCodecName: Failed to create MediaCodec: "
-                        + mime + ", direction: " + direction, e);
+                Log.w(TAG, "getDefaultCodecName: Failed to create MediaCodec: %s, direction: %d",
+                        mime, direction, e);
             }
         }
         return codecName;
@@ -342,8 +342,8 @@
                 }
             }
         } catch (Exception e) {
-            Log.e(TAG, "Failed to create MediaCodec: " +  mime + ", isSecure: "
-                    + isSecure + ", direction: " + direction, e);
+            Log.e(TAG, "Failed to create MediaCodec: %s, isSecure: %s, direction: %d",
+                    mime, isSecure, direction, e);
         }
 
         if (mediaCodec == null) {
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
index ad7d581..db00276 100644
--- a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
@@ -56,7 +56,7 @@
     //   calls. Indirect calls should not call release() again to avoid
     //   duplication (even though it doesn't hurt to call release() twice).
 
-    private static final String TAG = "MediaDrmBridge";
+    private static final String TAG = "cr.media";
     private static final String SECURITY_LEVEL = "securityLevel";
     private static final String SERVER_CERTIFICATE = "serviceCertificate";
     private static final String PRIVACY_MODE = "privacyMode";
@@ -211,7 +211,7 @@
             Log.e(TAG, "Cannot create MediaCrypto Session.");
             return false;
         }
-        Log.d(TAG, "MediaCrypto Session created: " + bytesToHexString(mMediaCryptoSession));
+        Log.d(TAG, "MediaCrypto Session created: %s", bytesToHexString(mMediaCryptoSession));
 
         // Create MediaCrypto object.
         try {
@@ -322,7 +322,7 @@
         }
 
         String currentSecurityLevel = mMediaDrm.getPropertyString(SECURITY_LEVEL);
-        Log.e(TAG, "Security level: current " + currentSecurityLevel + ", new " + securityLevel);
+        Log.e(TAG, "Security level: current %s, new %s", currentSecurityLevel, securityLevel);
         if (securityLevel.equals(currentSecurityLevel)) {
             // No need to set the same security level again. This is not just
             // a shortcut! Setting the same security level actually causes an
@@ -334,12 +334,12 @@
             mMediaDrm.setPropertyString(SECURITY_LEVEL, securityLevel);
             return true;
         } catch (java.lang.IllegalArgumentException e) {
-            Log.e(TAG, "Failed to set security level " + securityLevel, e);
+            Log.e(TAG, "Failed to set security level %s", securityLevel, e);
         } catch (java.lang.IllegalStateException e) {
-            Log.e(TAG, "Failed to set security level " + securityLevel, e);
+            Log.e(TAG, "Failed to set security level %s", securityLevel, e);
         }
 
-        Log.e(TAG, "Security level " + securityLevel + " not supported!");
+        Log.e(TAG, "Security level %s not supported!", securityLevel);
         return false;
     }
 
@@ -466,7 +466,7 @@
         }
 
         String result = (request != null) ? "successed" : "failed";
-        Log.d(TAG, "getKeyRequest " + result + "!");
+        Log.d(TAG, "getKeyRequest %s!", result);
 
         return request;
     }
@@ -590,7 +590,7 @@
             }
 
             // Success!
-            Log.d(TAG, "createSession(): Session (" + bytesToHexString(sessionId) + ") created.");
+            Log.d(TAG, "createSession(): Session (%s) created.", bytesToHexString(sessionId));
             onPromiseResolvedWithSession(promiseId, sessionId);
             onSessionMessage(sessionId, request);
             mSessionIds.put(ByteBuffer.wrap(sessionId), mime);
@@ -651,7 +651,7 @@
         mSessionIds.remove(ByteBuffer.wrap(sessionId));
         onPromiseResolved(promiseId);
         onSessionClosed(sessionId);
-        Log.d(TAG, "Session " + bytesToHexString(sessionId) + " closed.");
+        Log.d(TAG, "Session %s closed", bytesToHexString(sessionId));
     }
 
     /**
@@ -685,7 +685,7 @@
                 // TODO(qinmin): remove this exception catch when b/10495563 is fixed.
                 Log.e(TAG, "Exception intentionally caught when calling provideKeyResponse()", e);
             }
-            Log.d(TAG, "Key successfully added for session " + bytesToHexString(sessionId));
+            Log.d(TAG, "Key successfully added for session %s", bytesToHexString(sessionId));
             onPromiseResolved(promiseId);
             onSessionKeysChange(sessionId, true, KEY_STATUS_USABLE);
             return;
@@ -806,7 +806,7 @@
     }
 
     private void onPromiseRejected(final long promiseId, final String errorMessage) {
-        Log.e(TAG, "onPromiseRejected: " + errorMessage);
+        Log.e(TAG, "onPromiseRejected: %s", errorMessage);
         mHandler.post(new Runnable() {
             @Override
             public void run() {
@@ -854,7 +854,7 @@
     }
 
     private void onLegacySessionError(final byte[] sessionId, final String errorMessage) {
-        Log.e(TAG, "onLegacySessionError: " + errorMessage);
+        Log.e(TAG, "onLegacySessionError: %s", errorMessage);
         mHandler.post(new Runnable() {
             @Override
             public void run() {
@@ -885,7 +885,7 @@
                 return;
             }
             if (!sessionExists(sessionId)) {
-                Log.e(TAG, "MediaDrmListener: Invalid session " + bytesToHexString(sessionId));
+                Log.e(TAG, "MediaDrmListener: Invalid session %s", bytesToHexString(sessionId));
                 return;
             }
             switch(event) {
@@ -944,7 +944,7 @@
         protected Void doInBackground(String... urls) {
             mResponseBody = postRequest(urls[0], mDrmRequest);
             if (mResponseBody != null) {
-                Log.d(TAG, "response length=" + mResponseBody.length);
+                Log.d(TAG, "response length=%d", mResponseBody.length);
             }
             return null;
         }
@@ -980,7 +980,7 @@
                     }
                     return bos.toByteArray();
                 } else {
-                    Log.d(TAG, "Server returned HTTP error code " + responseCode);
+                    Log.d(TAG, "Server returned HTTP error code %d", responseCode);
                     return null;
                 }
             } catch (MalformedURLException e) {
diff --git a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
index 8694610..2acb961 100644
--- a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
@@ -13,11 +13,11 @@
 import android.text.TextUtils;
 import android.util.Base64;
 import android.util.Base64InputStream;
-import android.util.Log;
 import android.view.Surface;
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
@@ -35,7 +35,7 @@
 @JNINamespace("media")
 public class MediaPlayerBridge {
 
-    private static final String TAG = "MediaPlayerBridge";
+    private static final String TAG = "cr.media";
 
     // Local player to forward this to. We don't initialize it here since the subclass might not
     // want it.
diff --git a/media/base/android/java/src/org/chromium/media/VideoCaptureAndroid.java b/media/base/android/java/src/org/chromium/media/VideoCaptureAndroid.java
index 21def1f..ba470fd 100644
--- a/media/base/android/java/src/org/chromium/media/VideoCaptureAndroid.java
+++ b/media/base/android/java/src/org/chromium/media/VideoCaptureAndroid.java
@@ -6,7 +6,8 @@
 
 import android.content.Context;
 import android.graphics.ImageFormat;
-import android.util.Log;
+
+import org.chromium.base.Log;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -41,7 +42,7 @@
 
     private int mExpectedFrameSize;
     private static final int NUM_CAPTURE_BUFFERS = 3;
-    private static final String TAG = "VideoCaptureAndroid";
+    private static final String TAG = "cr.media";
 
     static int getNumberOfCameras() {
         return android.hardware.Camera.getNumberOfCameras();
@@ -67,7 +68,7 @@
         try {
             camera = android.hardware.Camera.open(id);
         } catch (RuntimeException ex) {
-            Log.e(TAG, "Camera.open: " + ex);
+            Log.e(TAG, "Camera.open: ", ex);
             return null;
         }
         android.hardware.Camera.Parameters parameters = getCameraParameters(camera);
diff --git a/media/base/android/java/src/org/chromium/media/VideoCaptureCamera.java b/media/base/android/java/src/org/chromium/media/VideoCaptureCamera.java
index 08b977e..310b33f 100644
--- a/media/base/android/java/src/org/chromium/media/VideoCaptureCamera.java
+++ b/media/base/android/java/src/org/chromium/media/VideoCaptureCamera.java
@@ -9,9 +9,9 @@
 import android.graphics.SurfaceTexture;
 import android.opengl.GLES20;
 import android.os.Build;
-import android.util.Log;
 
 import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
 
 import java.io.IOException;
 import java.util.List;
@@ -39,7 +39,7 @@
     protected SurfaceTexture mSurfaceTexture = null;
     protected static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
 
-    private static final String TAG = "VideoCaptureCamera";
+    private static final String TAG = "cr.media";
 
     protected static android.hardware.Camera.CameraInfo getCameraInfo(int id) {
         android.hardware.Camera.CameraInfo cameraInfo =
@@ -74,8 +74,7 @@
 
     @Override
     public boolean allocate(int width, int height, int frameRate) {
-        Log.d(TAG, "allocate: requested (" + width + "x" + height + ")@"
-                + frameRate + "fps");
+        Log.d(TAG, "allocate: requested (%d x %d) @%dfps", width, height, frameRate);
         try {
             mCamera = android.hardware.Camera.open(mId);
         } catch (RuntimeException ex) {
@@ -93,8 +92,8 @@
         // For Camera API, the readings of back-facing camera need to be inverted.
         mInvertDeviceOrientationReadings =
                 (cameraInfo.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
-        Log.d(TAG, "allocate: Rotation dev=" + getDeviceRotation() + ", cam="
-                + mCameraNativeOrientation + ", facing back? " + mInvertDeviceOrientationReadings);
+        Log.d(TAG, "allocate: Rotation dev=%d, cam=%d, facing back? %s", getDeviceRotation(),
+                mCameraNativeOrientation, mInvertDeviceOrientationReadings);
 
         android.hardware.Camera.Parameters parameters = getCameraParameters(mCamera);
         if (parameters == null) {
@@ -126,8 +125,8 @@
                 fpsRangeSize = fpsRange[1] - fpsRange[0];
             }
         }
-        Log.d(TAG, "allocate: fps set to " + chosenFrameRate + ", ["
-                + chosenFpsRange[0] + "-" + chosenFpsRange[1] + "]");
+        Log.d(TAG, "allocate: fps set to %d, [%d-%d]", chosenFrameRate,
+                chosenFpsRange[0], chosenFpsRange[1]);
 
         // Calculate size.
         List<android.hardware.Camera.Size> listCameraSize =
@@ -138,8 +137,7 @@
         for (android.hardware.Camera.Size size : listCameraSize) {
             int diff = Math.abs(size.width - width)
                        + Math.abs(size.height - height);
-            Log.d(TAG, "allocate: supported ("
-                    + size.width + ", " + size.height + "), diff=" + diff);
+            Log.d(TAG, "allocate: supported (%d, %d), diff=%d", size.width, size.height, diff);
             // TODO(wjia): Remove this hack (forcing width to be multiple
             // of 32) by supporting stride in video frame buffer.
             // Right now, VideoCaptureController requires compact YV12
@@ -154,7 +152,7 @@
             Log.e(TAG, "allocate: can not find a multiple-of-32 resolution");
             return false;
         }
-        Log.d(TAG, "allocate: matched (" + matchedWidth + "x" + matchedHeight + ")");
+        Log.d(TAG, "allocate: matched (%d x %d)", matchedWidth, matchedHeight);
 
         if (parameters.isVideoStabilizationSupported()) {
             Log.d(TAG, "Image stabilization supported, currently: "
diff --git a/media/base/android/java/src/org/chromium/media/VideoCaptureCamera2.java b/media/base/android/java/src/org/chromium/media/VideoCaptureCamera2.java
index cdaca75..cc7f7fa 100644
--- a/media/base/android/java/src/org/chromium/media/VideoCaptureCamera2.java
+++ b/media/base/android/java/src/org/chromium/media/VideoCaptureCamera2.java
@@ -20,11 +20,11 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.util.Log;
 import android.util.Size;
 import android.view.Surface;
 
 import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -103,8 +103,8 @@
                 if (image == null) return;
                 if (image.getFormat() != ImageFormat.YUV_420_888
                         || image.getPlanes().length != 3) {
-                    Log.e(TAG, "Unexpected image format: " + image.getFormat()
-                            + " or #planes: " + image.getPlanes().length);
+                    Log.e(TAG, "Unexpected image format: %d or #planes: %d",
+                            image.getFormat(), image.getPlanes().length);
                     return;
                 }
 
@@ -140,7 +140,7 @@
     private ImageReader mImageReader = null;
 
     private static final double kNanoSecondsToFps = 1.0E-9;
-    private static final String TAG = "VideoCaptureCamera2";
+    private static final String TAG = "cr.media";
 
     // Service function to grab CameraCharacteristics and handle exceptions.
     private static CameraCharacteristics getCameraCharacteristics(Context appContext, int id) {
@@ -382,7 +382,7 @@
 
     @Override
     public boolean allocate(int width, int height, int frameRate) {
-        Log.d(TAG, "allocate: requested (" + width + "x" + height + ")@" + frameRate + "fps");
+        Log.d(TAG, "allocate: requested (%d x %d) @%dfps", width, height, frameRate);
         if (mOpeningCamera || mConfiguringCamera) {
             Log.e(TAG, "allocate() invoked while Camera is busy opening/configuring.");
             return false;
diff --git a/media/base/android/java/src/org/chromium/media/VideoCaptureFactory.java b/media/base/android/java/src/org/chromium/media/VideoCaptureFactory.java
index fcc8ebf..d4338cc 100644
--- a/media/base/android/java/src/org/chromium/media/VideoCaptureFactory.java
+++ b/media/base/android/java/src/org/chromium/media/VideoCaptureFactory.java
@@ -7,10 +7,10 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Build;
-import android.util.Log;
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
 // Needed for jni_generator.py to guess correctly the origin of
 // VideoCapture.CaptureFormat.
 import org.chromium.media.VideoCapture;
@@ -37,7 +37,7 @@
             {"Peanut", "peanut"},
         };
         private static int sNumberOfSystemCameras = -1;
-        private static final String TAG = "ChromiumCameraInfo";
+        private static final String TAG = "cr.media";
 
         private static boolean isSpecialDevice() {
             for (String[] device : SPECIAL_DEVICE_LIST) {
@@ -74,7 +74,7 @@
                     } else {
                         sNumberOfSystemCameras = VideoCaptureAndroid.getNumberOfCameras();
                         if (isSpecialDevice()) {
-                            Log.d(TAG, "Special device: " + android.os.Build.MODEL);
+                            Log.d(TAG, "Special device: %s", android.os.Build.MODEL);
                             sNumberOfSystemCameras += VideoCaptureTango.numberOfCameras();
                         }
                     }
diff --git a/media/base/android/java/src/org/chromium/media/VideoCaptureTango.java b/media/base/android/java/src/org/chromium/media/VideoCaptureTango.java
index b3f875fc..9e49afb 100644
--- a/media/base/android/java/src/org/chromium/media/VideoCaptureTango.java
+++ b/media/base/android/java/src/org/chromium/media/VideoCaptureTango.java
@@ -6,7 +6,8 @@
 
 import android.content.Context;
 import android.graphics.ImageFormat;
-import android.util.Log;
+
+import org.chromium.base.Log;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -61,7 +62,7 @@
     private static final int SF_OFFSET_4MP_CHROMA = 112;
 
     private static final byte CHROMA_ZERO_LEVEL = 127;
-    private static final String TAG = "VideoCaptureTango";
+    private static final String TAG = "cr.media";
 
     static int numberOfCameras() {
         return CAM_PARAMS.length;
@@ -180,7 +181,7 @@
                     ByteBuffer.wrap(data, startV, sizeV)
                               .get(mFrameBuffer.array(), sizeY + sizeU, sizeV);
                 } else {
-                    Log.e(TAG, "Unknown camera, #id: " + mTangoCameraId);
+                    Log.e(TAG, "Unknown camera, #id: %d", mTangoCameraId);
                     return;
                 }
                 mFrameBuffer.rewind();  // Important!
diff --git a/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java
index 1d810677..f4a752b 100644
--- a/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java
@@ -10,17 +10,17 @@
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.os.ParcelFileDescriptor;
-import android.util.Log;
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
+import org.chromium.base.Log;
 
 import java.io.File;
 import java.nio.ByteBuffer;
 
 @JNINamespace("media")
 class WebAudioMediaCodecBridge {
-    static final String LOG_TAG = "WebAudioMediaCodec";
+    private static final String TAG = "cr.media";
     // TODO(rtoy): What is the correct timeout value for reading
     // from a file in memory?
     static final long TIMEOUT_MICROSECONDS = 500;
@@ -73,7 +73,7 @@
             try {
                 durationMicroseconds = format.getLong(MediaFormat.KEY_DURATION);
             } catch (Exception e) {
-                Log.d(LOG_TAG, "Cannot get duration");
+                Log.d(TAG, "Cannot get duration");
             }
         }
 
@@ -85,14 +85,14 @@
             durationMicroseconds = 0;
         }
 
-        Log.d(LOG_TAG, "Initial: Tracks: " + extractor.getTrackCount() + " Format: " + format);
+        Log.d(TAG, "Initial: Tracks: %d Format: %s", extractor.getTrackCount(), format);
 
         // Create decoder
         MediaCodec codec;
         try {
             codec = MediaCodec.createDecoderByType(mime);
         } catch (Exception e) {
-            Log.w(LOG_TAG, "Failed to create MediaCodec for mime type: " + mime);
+            Log.w(TAG, "Failed to create MediaCodec for mime type: %s", mime);
             encodedFD.detachFd();
             return false;
         }
@@ -100,13 +100,13 @@
         try {
             codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
         } catch (Exception e) {
-            Log.w(LOG_TAG, "Unable to configure codec for format " + format, e);
+            Log.w(TAG, "Unable to configure codec for format " + format, e);
             return false;
         }
         try {
             codec.start();
         } catch (Exception e) {
-            Log.w(LOG_TAG, "Unable to start()", e);
+            Log.w(TAG, "Unable to start()", e);
             return false;
         }
 
@@ -114,14 +114,14 @@
         try {
             codecInputBuffers = codec.getInputBuffers();
         } catch (Exception e) {
-            Log.w(LOG_TAG, "getInputBuffers() failed", e);
+            Log.w(TAG, "getInputBuffers() failed", e);
             return false;
         }
         ByteBuffer[] codecOutputBuffers;
         try {
             codecOutputBuffers = codec.getOutputBuffers();
         } catch (Exception e) {
-            Log.w(LOG_TAG, "getOutputBuffers() failed", e);
+            Log.w(TAG, "getOutputBuffers() failed", e);
             return false;
         }
 
@@ -141,7 +141,7 @@
                 try {
                     inputBufIndex = codec.dequeueInputBuffer(TIMEOUT_MICROSECONDS);
                 } catch (Exception e) {
-                    Log.w(LOG_TAG, "dequeueInputBuffer(" + TIMEOUT_MICROSECONDS + ") failed.", e);
+                    Log.w(TAG, "dequeueInputBuffer(%d) failed.", TIMEOUT_MICROSECONDS, e);
                     decodedSuccessfully = false;
                     break;
                 }
@@ -165,12 +165,9 @@
                                 presentationTimeMicroSec,
                                 sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
                     } catch (Exception e) {
-                        Log.w(LOG_TAG, "queueInputBuffer("
-                                + inputBufIndex + ", 0, "
-                                + sampleSize + ", "
-                                + presentationTimeMicroSec + ", "
-                                + (sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0)
-                                + ") failed.", e);
+                        Log.w(TAG, "queueInputBuffer(%d, 0, %d, %d, %d) failed.",
+                                inputBufIndex, sampleSize, presentationTimeMicroSec,
+                                (sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0), e);
                         decodedSuccessfully = false;
                         break;
                     }
@@ -188,9 +185,7 @@
             try {
                 outputBufIndex = codec.dequeueOutputBuffer(info, TIMEOUT_MICROSECONDS);
             } catch (Exception e) {
-                Log.w(LOG_TAG, "dequeueOutputBuffer(" + info
-                        + ", " + TIMEOUT_MICROSECONDS
-                        + ") failed");
+                Log.w(TAG, "dequeueOutputBuffer(%s, %d) failed", info, TIMEOUT_MICROSECONDS);
                 e.printStackTrace();
                 decodedSuccessfully = false;
                 break;
@@ -204,10 +199,8 @@
                     // catch any changes in format. But be sure to
                     // initialize it BEFORE we send any decoded audio,
                     // and only initialize once.
-                    Log.d(LOG_TAG, "Final:  Rate: " + sampleRate
-                            + " Channels: " + inputChannelCount
-                            + " Mime: " + mime
-                            + " Duration: " + durationMicroseconds + " microsec");
+                    Log.d(TAG, "Final:  Rate: %d Channels: %d Mime: %s Duration: %d microsec",
+                            sampleRate, inputChannelCount, mime, durationMicroseconds);
 
                     nativeInitializeDestination(nativeMediaCodecBridge,
                                                 inputChannelCount,
@@ -233,7 +226,7 @@
                 MediaFormat newFormat = codec.getOutputFormat();
                 outputChannelCount = newFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
                 sampleRate = newFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
-                Log.d(LOG_TAG, "output format changed to " + newFormat);
+                Log.d(TAG, "output format changed to " + newFormat);
             }
         }
 
diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc
index 14f3300..3d227521 100644
--- a/media/base/android/media_codec_bridge.cc
+++ b/media/base/android/media_codec_bridge.cc
@@ -246,10 +246,10 @@
   // devices while HW decoder video freezes and distortions are
   // investigated - http://crbug.com/446974.
   if (codec_name.length() > 0) {
-    return (StartsWithASCII(codec_name, "OMX.google.", true) ||
-        StartsWithASCII(codec_name, "OMX.SEC.", true) ||
-        StartsWithASCII(codec_name, "OMX.MTK.", true) ||
-        StartsWithASCII(codec_name, "OMX.Exynos.", true));
+    return (base::StartsWithASCII(codec_name, "OMX.google.", true) ||
+            base::StartsWithASCII(codec_name, "OMX.SEC.", true) ||
+            base::StartsWithASCII(codec_name, "OMX.MTK.", true) ||
+            base::StartsWithASCII(codec_name, "OMX.Exynos.", true));
   }
   return true;
 }
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
index 29049cb..de32bc4 100644
--- a/media/base/android/media_player_bridge.cc
+++ b/media/base/android/media_player_bridge.cc
@@ -161,7 +161,7 @@
     DCHECK(j_context);
 
     const std::string data_uri_prefix("data:");
-    if (StartsWithASCII(url, data_uri_prefix, true)) {
+    if (base::StartsWithASCII(url, data_uri_prefix, true)) {
       if (!Java_MediaPlayerBridge_setDataUriDataSource(
           env, j_media_player_bridge_.obj(), j_context, j_url_string.obj())) {
         OnMediaError(MEDIA_ERROR_FORMAT);
diff --git a/media/base/android/media_player_manager.h b/media/base/android/media_player_manager.h
index d2d35f471..bf6ca4e0 100644
--- a/media/base/android/media_player_manager.h
+++ b/media/base/android/media_player_manager.h
@@ -76,9 +76,6 @@
   // Returns the player with the specified id.
   virtual MediaPlayerAndroid* GetPlayer(int player_id) = 0;
 
-  // Called by the player to get a hardware protected surface.
-  virtual void RequestFullScreen(int player_id) = 0;
-
   // Called by the player to request to play. The manager should use this
   // opportunity to check if the current context is appropriate for a media to
   // play.
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc
index ca13a06..be6db141 100644
--- a/media/base/android/media_source_player_unittest.cc
+++ b/media/base/android/media_source_player_unittest.cc
@@ -81,7 +81,6 @@
   void OnWaitingForDecryptionKey(int player_id) override {}
   MediaPlayerAndroid* GetFullscreenPlayer() override { return NULL; }
   MediaPlayerAndroid* GetPlayer(int player_id) override { return NULL; }
-  void RequestFullScreen(int player_id) override {}
 
   bool RequestPlay(int player_id) override {
     return allow_play_;
diff --git a/media/base/audio_video_metadata_extractor.cc b/media/base/audio_video_metadata_extractor.cc
index fd666f6c..0ba36e1 100644
--- a/media/base/audio_video_metadata_extractor.cc
+++ b/media/base/audio_video_metadata_extractor.cc
@@ -23,7 +23,7 @@
 // Returns true if the |tag| matches |expected_key|.
 bool ExtractString(AVDictionaryEntry* tag, const char* expected_key,
                    std::string* destination) {
-  if (!LowerCaseEqualsASCII(std::string(tag->key), expected_key))
+  if (!base::LowerCaseEqualsASCII(std::string(tag->key), expected_key))
     return false;
 
   if (destination->empty())
@@ -35,7 +35,7 @@
 // Returns true if the |tag| matches |expected_key|.
 bool ExtractInt(AVDictionaryEntry* tag, const char* expected_key,
                 int* destination) {
-  if (!LowerCaseEqualsASCII(std::string(tag->key), expected_key))
+  if (!base::LowerCaseEqualsASCII(std::string(tag->key), expected_key))
     return false;
 
   int temporary = -1;
diff --git a/media/base/bit_reader_core.cc b/media/base/bit_reader_core.cc
index bcce34b..042e73c 100644
--- a/media/base/bit_reader_core.cc
+++ b/media/base/bit_reader_core.cc
@@ -6,7 +6,6 @@
 
 #include <stdint.h>
 
-#include "base/port.h"
 #include "base/sys_byteorder.h"
 
 namespace {
diff --git a/media/base/cdm_context.cc b/media/base/cdm_context.cc
index ec2b633..b53fc7d 100644
--- a/media/base/cdm_context.cc
+++ b/media/base/cdm_context.cc
@@ -6,9 +6,17 @@
 
 namespace media {
 
-CdmContext::CdmContext() {}
+CdmContext::CdmContext() {
+}
 
-CdmContext::~CdmContext() {}
+CdmContext::~CdmContext() {
+}
+
+CdmContextProvider::CdmContextProvider() {
+}
+
+CdmContextProvider::~CdmContextProvider() {
+}
 
 void IgnoreCdmAttached(bool success) {
 }
diff --git a/media/base/cdm_context.h b/media/base/cdm_context.h
index a0861c4..7d89760 100644
--- a/media/base/cdm_context.h
+++ b/media/base/cdm_context.h
@@ -15,6 +15,7 @@
 
 // An interface representing the context that a media pipeline needs from a
 // content decryption module (CDM) to decrypt (and decode) encrypted buffers.
+// Only used for implementing SetCdm().
 class MEDIA_EXPORT CdmContext {
  public:
   // Indicates an invalid CDM ID. See GetCdmId() for details.
@@ -22,16 +23,16 @@
 
   virtual ~CdmContext();
 
-  // Gets the Decryptor object associated with the CDM. Returns NULL if the CDM
-  // does not support a Decryptor. The returned object is only guaranteed to be
-  // valid during the CDM's lifetime.
+  // Gets the Decryptor object associated with the CDM. Returns nullptr if the
+  // CDM does not support a Decryptor. Must not return nullptr if GetCdmId()
+  // returns kInvalidCdmId. The returned object is only guaranteed to be valid
+  // during the CDM's lifetime.
   virtual Decryptor* GetDecryptor() = 0;
 
-  // Returns an ID associated with the CDM, which can be used to locate the real
-  // CDM instance. This is useful when the CDM is hosted remotely, e.g. in a
-  // different process.
-  // Returns kInvalidCdmId if the CDM cannot be used remotely. In this case,
-  // GetDecryptor() should return a non-null Decryptor.
+  // Returns an ID that identifies a CDM, or kInvalidCdmId. The interpretation
+  // is implementation-specific; current implementations use the ID to locate a
+  // remote CDM in a different process. The return value will not be
+  // kInvalidCdmId if GetDecryptor() returns nullptr.
   virtual int GetCdmId() const = 0;
 
  protected:
@@ -41,6 +42,25 @@
   DISALLOW_COPY_AND_ASSIGN(CdmContext);
 };
 
+// An interface for looking up CdmContext objects by the CDM ID.
+class MEDIA_EXPORT CdmContextProvider {
+ public:
+  virtual ~CdmContextProvider();
+
+  // Returns the CdmContext corresponding to |cdm_id|. Returns nullptr if no
+  // such CdmContext can be found.
+  // Note: Calling GetCdmId() on the returned CdmContext returns kInvalidCdmId
+  // (in all current cases) because the CDM will be local in the process where
+  // GetCdmContext() is called.
+  virtual CdmContext* GetCdmContext(int cdm_id) = 0;
+
+ protected:
+  CdmContextProvider();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CdmContextProvider);
+};
+
 // Callback to notify that the CdmContext has been completely attached to
 // the media pipeline. Parameter indicates whether the operation succeeded.
 typedef base::Callback<void(bool)> CdmAttachedCB;
diff --git a/media/base/demuxer.h b/media/base/demuxer.h
index 3075b59..91f389d 100644
--- a/media/base/demuxer.h
+++ b/media/base/demuxer.h
@@ -56,6 +56,9 @@
   Demuxer();
   ~Demuxer() override;
 
+  // Returns the name of the demuxer for logging purpose.
+  virtual std::string GetDisplayName() const = 0;
+
   // Completes initialization of the demuxer.
   //
   // The demuxer does not own |host| as it is guaranteed to outlive the
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc
index 1cd202c..6b4d0c3 100644
--- a/media/base/key_systems.cc
+++ b/media/base/key_systems.cc
@@ -674,12 +674,12 @@
   SupportedCodecs media_type_codec_mask = EME_CODEC_NONE;
   switch (media_type) {
     case EmeMediaType::AUDIO:
-      if (!StartsWithASCII(container_mime_type, "audio/", true))
+      if (!base::StartsWithASCII(container_mime_type, "audio/", true))
         return EmeConfigRule::NOT_SUPPORTED;
       media_type_codec_mask = audio_codec_mask_;
       break;
     case EmeMediaType::VIDEO:
-      if (!StartsWithASCII(container_mime_type, "video/", true))
+      if (!base::StartsWithASCII(container_mime_type, "video/", true))
         return EmeConfigRule::NOT_SUPPORTED;
       media_type_codec_mask = video_codec_mask_;
       break;
diff --git a/media/base/media.cc b/media/base/media.cc
index 37fc02a..c85d465 100644
--- a/media/base/media.cc
+++ b/media/base/media.cc
@@ -11,70 +11,44 @@
 #include "build/build_config.h"
 #include "media/base/yuv_convert.h"
 
-namespace media {
+#if !defined(MEDIA_DISABLE_FFMPEG)
+#include "media/ffmpeg/ffmpeg_common.h"
+#endif
 
-namespace internal {
-// Platform specific initialization method.
-extern bool InitializeMediaLibraryInternal(const base::FilePath& module_dir);
-}  // namespace internal
+namespace media {
 
 // Media must only be initialized once, so use a LazyInstance to ensure this.
 class MediaInitializer {
- public:
-  bool Initialize(const base::FilePath& module_dir) {
-    base::AutoLock auto_lock(lock_);
-    if (!tried_initialize_) {
-      tried_initialize_ = true;
-      initialized_ = internal::InitializeMediaLibraryInternal(module_dir);
-    }
-    return initialized_;
-  }
-
-  bool IsInitialized() {
-    base::AutoLock auto_lock(lock_);
-    return initialized_;
-  }
-
  private:
   friend struct base::DefaultLazyInstanceTraits<MediaInitializer>;
 
-  MediaInitializer()
-      : initialized_(false),
-        tried_initialize_(false) {
+  MediaInitializer() {
     // Perform initialization of libraries which require runtime CPU detection.
     InitializeCPUSpecificYUVConversions();
+
+#if !defined(MEDIA_DISABLE_FFMPEG)
+    // Disable logging as it interferes with layout tests.
+    av_log_set_level(AV_LOG_QUIET);
+
+#if defined(ALLOCATOR_SHIM)
+    // Remove allocation limit from ffmpeg, so calls go down to shim layer.
+    av_max_alloc(0);
+#endif  // defined(ALLOCATOR_SHIM)
+
+#endif  // !defined(MEDIA_DISABLE_FFMPEG)
   }
 
   ~MediaInitializer() {
     NOTREACHED() << "MediaInitializer should be leaky!";
   }
 
-  base::Lock lock_;
-  bool initialized_;
-  bool tried_initialize_;
-
   DISALLOW_COPY_AND_ASSIGN(MediaInitializer);
 };
 
 static base::LazyInstance<MediaInitializer>::Leaky g_media_library =
     LAZY_INSTANCE_INITIALIZER;
 
-bool InitializeMediaLibrary(const base::FilePath& module_dir) {
-  return g_media_library.Get().Initialize(module_dir);
-}
-
-void InitializeMediaLibraryForTesting() {
-  base::FilePath module_dir;
-  CHECK(PathService::Get(base::DIR_EXE, &module_dir));
-  CHECK(g_media_library.Get().Initialize(module_dir));
-}
-
-bool IsMediaLibraryInitialized() {
-  return g_media_library.Get().IsInitialized();
-}
-
-void InitializeCPUSpecificMediaFeatures() {
-  // Force initialization of the media initializer, but don't call Initialize().
+void InitializeMediaLibrary() {
   g_media_library.Get();
 }
 
diff --git a/media/base/media.h b/media/base/media.h
index c86e568..01a913b 100644
--- a/media/base/media.h
+++ b/media/base/media.h
@@ -16,32 +16,9 @@
 
 namespace media {
 
-// Attempts to initialize the media library (loading DLLs, DSOs, etc.).
-//
-// If |module_dir| is the empty string, then the system default library paths
-// are searched for the dynamic libraries.  If a |module_dir| is provided, then
-// only the specified |module_dir| will be searched for the dynamic libraries.
-//
-// If multiple initializations are attempted with different |module_dir|s
-// specified then the first one to succeed remains effective for the lifetime
-// of the process.
-//
-// Returns true if everything was successfully initialized, false otherwise.
-MEDIA_EXPORT bool InitializeMediaLibrary(const base::FilePath& module_dir);
-
-// Helper function for unit tests to avoid boiler plate code everywhere. This
-// function will crash if it fails to load the media library. This ensures tests
-// fail if the media library is not available.
-MEDIA_EXPORT void InitializeMediaLibraryForTesting();
-
-// Use this if you need to check whether the media library is initialized
-// for the this process, without actually trying to initialize it.
-MEDIA_EXPORT bool IsMediaLibraryInitialized();
-
-// Use this if you need to initialize CPU specific features WITHOUT loading
-// DLLs, DSOs, etc.  Only necessary if InitializeMediaLibrary() is not called;
-// does nothing if the media library has already been initialized.
-MEDIA_EXPORT void InitializeCPUSpecificMediaFeatures();
+// Initializes media libraries (e.g. ffmpeg) as well as CPU specific media
+// features.
+MEDIA_EXPORT void InitializeMediaLibrary();
 
 }  // namespace media
 
diff --git a/media/base/media_log.cc b/media/base/media_log.cc
index 7795235..f5f58de7 100644
--- a/media/base/media_log.cc
+++ b/media/base/media_log.cc
@@ -4,7 +4,6 @@
 
 #include "media/base/media_log.h"
 
-
 #include "base/atomic_sequence_num.h"
 #include "base/json/json_writer.h"
 #include "base/values.h"
@@ -276,10 +275,16 @@
     : level_(level), log_cb_(log_cb) {
 }
 
+LogHelper::LogHelper(MediaLog::MediaLogLevel level,
+                     const scoped_refptr<MediaLog>& media_log)
+    : level_(level), media_log_(media_log) {
+}
+
 LogHelper::~LogHelper() {
-  if (log_cb_.is_null())
-    return;
-  log_cb_.Run(level_, stream_.str());
+  if (!log_cb_.is_null())
+    log_cb_.Run(level_, stream_.str());
+  else if (media_log_)
+    media_log_->AddLogEvent(level_, stream_.str());
 }
 
 }  //namespace media
diff --git a/media/base/media_log.h b/media/base/media_log.h
index 8b40b5d4..3f81795 100644
--- a/media/base/media_log.h
+++ b/media/base/media_log.h
@@ -18,7 +18,6 @@
 
 namespace media {
 
-
 class MEDIA_EXPORT MediaLog : public base::RefCountedThreadSafe<MediaLog> {
  public:
   enum MediaLogLevel {
@@ -87,10 +86,12 @@
 // Second parameter - The string to add to the log.
 typedef base::Callback<void(MediaLog::MediaLogLevel, const std::string&)> LogCB;
 
-// Helper class to make it easier to use log_cb like DVLOG().
+// Helper class to make it easier to use LogCB or MediaLog like DVLOG().
 class LogHelper {
  public:
   LogHelper(MediaLog::MediaLogLevel level, const LogCB& log_cb);
+  LogHelper(MediaLog::MediaLogLevel level,
+            const scoped_refptr<MediaLog>& media_log);
   ~LogHelper();
 
   std::ostream& stream() { return stream_; }
@@ -98,18 +99,19 @@
  private:
   MediaLog::MediaLogLevel level_;
   LogCB log_cb_;
+  const scoped_refptr<MediaLog> media_log_;
   std::stringstream stream_;
 };
 
 // Provides a stringstream to collect a log entry to pass to the provided
-// LogCB at the requested level.
-#define MEDIA_LOG(level, log_cb) \
-  LogHelper((MediaLog::MEDIALOG_##level), (log_cb)).stream()
+// logger (LogCB or MediaLog) at the requested level.
+#define MEDIA_LOG(level, logger) \
+  LogHelper((MediaLog::MEDIALOG_##level), (logger)).stream()
 
 // Logs only while count < max. Increments count for each log. Use LAZY_STREAM
 // to avoid wasteful evaluation of subsequent stream arguments.
-#define LIMITED_MEDIA_LOG(level, log_cb, count, max) \
-  LAZY_STREAM(MEDIA_LOG(level, log_cb), (count) < (max) && ((count)++ || true))
+#define LIMITED_MEDIA_LOG(level, logger, count, max) \
+  LAZY_STREAM(MEDIA_LOG(level, logger), (count) < (max) && ((count)++ || true))
 
 }  // namespace media
 
diff --git a/media/base/media_log_event.h b/media/base/media_log_event.h
index fe8bb75..66aa5f7 100644
--- a/media/base/media_log_event.h
+++ b/media/base/media_log_event.h
@@ -77,7 +77,7 @@
     //         "buffer_end": <last buffered byte>.
     BUFFERED_EXTENTS_CHANGED,
 
-    // Error log reported by media code such as details of an MSE parse error.
+    // Error log reported by media code such as reasons of playback error.
     MEDIA_ERROR_LOG_ENTRY,
     // params: "error": Error string describing the error detected.
 
diff --git a/media/base/media_posix.cc b/media/base/media_posix.cc
deleted file mode 100644
index f8f0c99..0000000
--- a/media/base/media_posix.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/base/media.h"
-
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/strings/stringize_macros.h"
-#include "media/ffmpeg/ffmpeg_common.h"
-#include "third_party/ffmpeg/ffmpeg_stubs.h"
-
-using third_party_ffmpeg::kNumStubModules;
-using third_party_ffmpeg::kModuleFfmpegsumo;
-using third_party_ffmpeg::InitializeStubs;
-using third_party_ffmpeg::StubPathMap;
-
-namespace media {
-namespace internal {
-
-// Handy to prevent shooting ourselves in the foot with macro wizardry.
-#if !defined(LIBAVCODEC_VERSION_MAJOR) || \
-    !defined(LIBAVFORMAT_VERSION_MAJOR) || \
-    !defined(LIBAVUTIL_VERSION_MAJOR)
-#error FFmpeg headers not included!
-#endif
-
-#define AVCODEC_VERSION STRINGIZE(LIBAVCODEC_VERSION_MAJOR)
-#define AVFORMAT_VERSION STRINGIZE(LIBAVFORMAT_VERSION_MAJOR)
-#define AVUTIL_VERSION STRINGIZE(LIBAVUTIL_VERSION_MAJOR)
-
-#if defined(OS_MACOSX)
-// TODO(evan): should be using .so like ffmepgsumo here.
-#define DSO_NAME(MODULE, VERSION) ("lib" MODULE "." VERSION ".dylib")
-static const base::FilePath::CharType kSumoLib[] =
-    FILE_PATH_LITERAL("ffmpegsumo.so");
-#elif defined(OS_POSIX)
-#define DSO_NAME(MODULE, VERSION) ("lib" MODULE ".so." VERSION)
-static const base::FilePath::CharType kSumoLib[] =
-    FILE_PATH_LITERAL("libffmpegsumo.so");
-#else
-#error "Do not know how to construct DSO name for this OS."
-#endif
-
-bool InitializeMediaLibraryInternal(const base::FilePath& module_dir) {
-  StubPathMap paths;
-
-  // First try to initialize with Chrome's sumo library.
-  DCHECK_EQ(kNumStubModules, 1);
-  paths[kModuleFfmpegsumo].push_back(module_dir.Append(kSumoLib).value());
-
-  // If that fails, see if any system libraries are available.
-  paths[kModuleFfmpegsumo].push_back(module_dir.Append(
-      FILE_PATH_LITERAL(DSO_NAME("avutil", AVUTIL_VERSION))).value());
-  paths[kModuleFfmpegsumo].push_back(module_dir.Append(
-      FILE_PATH_LITERAL(DSO_NAME("avcodec", AVCODEC_VERSION))).value());
-  paths[kModuleFfmpegsumo].push_back(module_dir.Append(
-      FILE_PATH_LITERAL(DSO_NAME("avformat", AVFORMAT_VERSION))).value());
-
-  return InitializeStubs(paths);
-}
-
-}  // namespace internal
-}  // namespace media
diff --git a/media/base/media_stub.cc b/media/base/media_stub.cc
deleted file mode 100644
index e3e02e4..0000000
--- a/media/base/media_stub.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/base/media.h"
-
-#include "base/files/file_path.h"
-
-// This file is intended for platforms that don't need to load any media
-// libraries (e.g., Android).
-namespace media {
-namespace internal {
-
-bool InitializeMediaLibraryInternal(const base::FilePath& module_dir) {
-  return true;
-}
-
-}  // namespace internal
-}  // namespace media
diff --git a/media/base/media_win.cc b/media/base/media_win.cc
deleted file mode 100644
index 03d78b1d..0000000
--- a/media/base/media_win.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/base/media.h"
-
-#include <windows.h>
-#if defined(_WIN32_WINNT_WIN8)
-// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
-#undef FACILITY_VISUALCPP
-#endif
-#include <delayimp.h>
-
-#include "base/files/file_path.h"
-#include "base/metrics/sparse_histogram.h"
-#include "media/ffmpeg/ffmpeg_common.h"
-
-#pragma comment(lib, "delayimp.lib")
-
-namespace media {
-namespace internal {
-
-bool InitializeMediaLibraryInternal(const base::FilePath& module_dir) {
-  // LoadLibraryEx(..., LOAD_WITH_ALTERED_SEARCH_PATH) cannot handle
-  // relative path.
-  if (!module_dir.IsAbsolute())
-    return false;
-
-  // Use alternate DLL search path so we don't load dependencies from the
-  // system path.  Refer to http://crbug.com/35857
-  static const char kFFmpegDLL[] = "ffmpegsumo.dll";
-  HMODULE lib = ::LoadLibraryEx(
-      module_dir.AppendASCII(kFFmpegDLL).value().c_str(), NULL,
-      LOAD_WITH_ALTERED_SEARCH_PATH);
-
-  bool initialized = (lib != NULL);
-
-  // TODO(scherkus): Remove all the bool-ness from these functions as we no
-  // longer support disabling HTML5 media at runtime. http://crbug.com/440892
-  if (!initialized) {
-    UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Initialize.Windows", GetLastError());
-    return false;
-  }
-
-  // VS2013 has a bug where FMA3 instructions will be executed on CPUs that
-  // support them despite them being disabled at the OS level, causing illegal
-  // instruction exceptions. Because Web Audio's FFT code *might* run before
-  // HTML5 media code, call av_log_set_level() to force library initialziation.
-  // See http://crbug.com/440892 for details.
-  av_log_set_level(AV_LOG_QUIET);
-
-  return initialized;
-}
-
-}  // namespace internal
-}  // namespace media
diff --git a/media/base/mime_util.cc b/media/base/mime_util.cc
index bc12773..83eef209 100644
--- a/media/base/mime_util.cc
+++ b/media/base/mime_util.cc
@@ -539,12 +539,12 @@
                              bool* is_ambiguous) {
   // Make sure we have avc1.xxxxxx or avc3.xxxxxx
   if (codec_id.size() != 11 ||
-      (!StartsWithASCII(codec_id, "avc1.", true) &&
-       !StartsWithASCII(codec_id, "avc3.", true))) {
+      (!base::StartsWithASCII(codec_id, "avc1.", true) &&
+       !base::StartsWithASCII(codec_id, "avc3.", true))) {
     return false;
   }
 
-  std::string profile = StringToUpperASCII(codec_id.substr(5, 4));
+  std::string profile = base::StringToUpperASCII(codec_id.substr(5, 4));
   if (IsValidH264BaselineProfile(profile)) {
     *codec = MimeUtil::H264_BASELINE;
   } else if (profile == "4D40") {
@@ -557,7 +557,8 @@
     return true;
   }
 
-  *is_ambiguous = !IsValidH264Level(StringToUpperASCII(codec_id.substr(9)));
+  *is_ambiguous =
+      !IsValidH264Level(base::StringToUpperASCII(codec_id.substr(9)));
   return true;
 }
 
diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc
index 0a66c46..f9fd4b5 100644
--- a/media/base/mock_filters.cc
+++ b/media/base/mock_filters.cc
@@ -18,6 +18,10 @@
 
 MockDemuxer::~MockDemuxer() {}
 
+std::string MockDemuxer::GetDisplayName() const {
+  return "MockDemuxer";
+}
+
 MockDemuxerStream::MockDemuxerStream(DemuxerStream::Type type)
     : type_(type), liveness_(LIVENESS_UNKNOWN) {
 }
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index 0f0b7ce..99e113b 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -32,6 +32,7 @@
   virtual ~MockDemuxer();
 
   // Demuxer implementation.
+  virtual std::string GetDisplayName() const;
   MOCK_METHOD3(Initialize,
                void(DemuxerHost* host, const PipelineStatusCB& cb, bool));
   MOCK_METHOD1(SetPlaybackRate, void(double playback_rate));
diff --git a/media/base/run_all_perftests.cc b/media/base/run_all_perftests.cc
index cf6bc47..dcf58fef 100644
--- a/media/base/run_all_perftests.cc
+++ b/media/base/run_all_perftests.cc
@@ -37,7 +37,7 @@
 
   // Run this here instead of main() to ensure an AtExitManager is already
   // present.
-  media::InitializeMediaLibraryForTesting();
+  media::InitializeMediaLibrary();
 }
 
 int main(int argc, char** argv) {
diff --git a/media/base/run_all_unittests.cc b/media/base/run_all_unittests.cc
index 0f741c33..7c0c14a 100644
--- a/media/base/run_all_unittests.cc
+++ b/media/base/run_all_unittests.cc
@@ -42,7 +42,7 @@
 
   // Run this here instead of main() to ensure an AtExitManager is already
   // present.
-  media::InitializeMediaLibraryForTesting();
+  media::InitializeMediaLibrary();
 }
 
 int main(int argc, char** argv) {
diff --git a/media/base/time_source.h b/media/base/time_source.h
index 08cf0f03..496eced8 100644
--- a/media/base/time_source.h
+++ b/media/base/time_source.h
@@ -49,9 +49,12 @@
   // will never go backwards, the frequency at which they update may be low.
   virtual base::TimeDelta CurrentMediaTime() = 0;
 
-  // Converts a vector of media timestamps into a vector of wall clock times. If
-  // the media time is stopped, returns false and does not modify the output
-  // vector. Returns true and converts all timestamps otherwise.
+  // Converts a vector of media timestamps into a vector of wall clock times; if
+  // the media time is stopped, returns false, otherwise returns true. Even if
+  // time is stopped, timestamps will be converted.
+  //
+  // Passing an empty |media_timestamps| vector will return the last known media
+  // time as a wall clock time.
   //
   // Within a single call to GetWallClockTimes() the returned wall clock times
   // are a strictly increasing function of the given media times. There is no
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index aac26e5..e0219fb 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -252,22 +252,24 @@
 
 // static
 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
+    Format format,
     const gpu::MailboxHolder& mailbox_holder,
     const ReleaseMailboxCB& mailbox_holder_release_cb,
     const gfx::Size& coded_size,
     const gfx::Rect& visible_rect,
     const gfx::Size& natural_size,
-    base::TimeDelta timestamp,
-    bool allow_overlay,
-    bool has_alpha) {
+    base::TimeDelta timestamp) {
+  if (format != ARGB) {
+    DLOG(ERROR) << "Only ARGB pixel format supported, got "
+                << FormatToString(format);
+    return nullptr;
+  }
   gpu::MailboxHolder mailbox_holders[kMaxPlanes];
   mailbox_holders[kARGBPlane] = mailbox_holder;
-  Format texture_format = has_alpha ? ARGB : XRGB;
   scoped_refptr<VideoFrame> frame(
-      new VideoFrame(texture_format, STORAGE_TEXTURE, coded_size, visible_rect,
+      new VideoFrame(format, STORAGE_TEXTURE, coded_size, visible_rect,
                      natural_size, mailbox_holders, timestamp));
   frame->mailbox_holders_release_cb_ = mailbox_holder_release_cb;
-  frame->allow_overlay_ = allow_overlay;
   return frame;
 }
 
@@ -280,8 +282,7 @@
     const gfx::Size& coded_size,
     const gfx::Rect& visible_rect,
     const gfx::Size& natural_size,
-    base::TimeDelta timestamp,
-    bool allow_overlay) {
+    base::TimeDelta timestamp) {
   gpu::MailboxHolder mailbox_holders[kMaxPlanes];
   mailbox_holders[kYPlane] = y_mailbox_holder;
   mailbox_holders[kUPlane] = u_mailbox_holder;
@@ -290,7 +291,6 @@
       new VideoFrame(I420, STORAGE_TEXTURE, coded_size, visible_rect,
                      natural_size, mailbox_holders, timestamp));
   frame->mailbox_holders_release_cb_ = mailbox_holder_release_cb;
-  frame->allow_overlay_ = allow_overlay;
   return frame;
 }
 
@@ -455,7 +455,7 @@
   scoped_refptr<VideoFrame> wrapped_frame(new VideoFrame(
       frame->format(), frame->storage_type(), frame->coded_size(), visible_rect,
       natural_size, frame->timestamp()));
-  if (frame->IsEndOfStream())
+  if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM))
     frame->metadata()->SetBoolean(VideoFrameMetadata::END_OF_STREAM, true);
 
   for (size_t i = 0; i < NumPlanes(frame->format()); ++i) {
@@ -613,8 +613,7 @@
       shared_memory_handle_(base::SharedMemory::NULLHandle()),
       shared_memory_offset_(0),
       timestamp_(timestamp),
-      release_sync_point_(0),
-      allow_overlay_(false) {
+      release_sync_point_(0) {
   DCHECK(IsValidConfig(format_, storage_type, coded_size_, visible_rect_,
                        natural_size_));
   memset(&mailbox_holders_, 0, sizeof(mailbox_holders_));
@@ -850,13 +849,6 @@
   done_callbacks_.push_back(callback);
 }
 
-bool VideoFrame::IsEndOfStream() const {
-  bool end_of_stream;
-  return metadata_.GetBoolean(VideoFrameMetadata::END_OF_STREAM,
-                              &end_of_stream) &&
-         end_of_stream;
-}
-
 void VideoFrame::UpdateReleaseSyncPoint(SyncPointClient* client) {
 #if defined(OS_LINUX)
   DCHECK(storage_type_ == STORAGE_TEXTURE || storage_type_ == STORAGE_DMABUFS);
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index e7dbc6b..9b9c789 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -134,14 +134,13 @@
   // |mailbox_holder|, and |mailbox_holder_release_cb| will be called with
   // a syncpoint as the argument when the VideoFrame is to be destroyed.
   static scoped_refptr<VideoFrame> WrapNativeTexture(
+      Format format,
       const gpu::MailboxHolder& mailbox_holder,
       const ReleaseMailboxCB& mailbox_holder_release_cb,
       const gfx::Size& coded_size,
       const gfx::Rect& visible_rect,
       const gfx::Size& natural_size,
-      base::TimeDelta timestamp,
-      bool allow_overlay,
-      bool has_alpha);
+      base::TimeDelta timestamp);
 
   // Wraps a set of native textures representing YUV data with a VideoFrame.
   // |mailbox_holders_release_cb| will be called with a syncpoint as the
@@ -154,8 +153,7 @@
       const gfx::Size& coded_size,
       const gfx::Rect& visible_rect,
       const gfx::Size& natural_size,
-      base::TimeDelta timestamp,
-      bool allow_overlay);
+      base::TimeDelta timestamp);
 
   // Wraps packed image data residing in a memory buffer with a VideoFrame.
   // The image data resides in |data| and is assumed to be packed tightly in a
@@ -355,8 +353,6 @@
   const VideoFrameMetadata* metadata() const { return &metadata_; }
   VideoFrameMetadata* metadata() { return &metadata_; }
 
-  bool allow_overlay() const { return allow_overlay_; }
-
 #if defined(OS_LINUX)
   // Returns backing dmabuf file descriptor for given |plane|, if present.
   int dmabuf_fd(size_t plane) const;
@@ -367,9 +363,6 @@
   CVPixelBufferRef cv_pixel_buffer() const;
 #endif
 
-  // Returns true if this VideoFrame represents the end of the stream.
-  bool IsEndOfStream() const;
-
   base::TimeDelta timestamp() const { return timestamp_; }
   void set_timestamp(base::TimeDelta timestamp) {
     timestamp_ = timestamp;
@@ -498,8 +491,6 @@
 
   VideoFrameMetadata metadata_;
 
-  bool allow_overlay_;
-
   DISALLOW_IMPLICIT_CONSTRUCTORS(VideoFrame);
 };
 
diff --git a/media/base/video_frame_metadata.cc b/media/base/video_frame_metadata.cc
index d663612..938a0181 100644
--- a/media/base/video_frame_metadata.cc
+++ b/media/base/video_frame_metadata.cc
@@ -126,6 +126,11 @@
   return result;
 }
 
+bool VideoFrameMetadata::IsTrue(Key key) const {
+  bool value = false;
+  return GetBoolean(key, &value) && value;
+}
+
 void VideoFrameMetadata::MergeInternalValuesInto(
     base::DictionaryValue* out) const {
   out->MergeDictionary(&dictionary_);
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h
index 10b17be..cee4917 100644
--- a/media/base/video_frame_metadata.h
+++ b/media/base/video_frame_metadata.h
@@ -15,6 +15,12 @@
 class MEDIA_EXPORT VideoFrameMetadata {
  public:
   enum Key {
+    // Sources of VideoFrames use this marker to indicate that the associated
+    // VideoFrame can be overlayed, case in which its contents do not need to be
+    // further composited but displayed directly. Use Get/SetBoolean() for
+    // this Key.
+    ALLOW_OVERLAY,
+
     // Video capture begin/end timestamps.  Consumers can use these values for
     // dynamic optimizations, logging stats, etc.  Use Get/SetTimeTicks() for
     // these keys.
@@ -25,7 +31,8 @@
     // GetInteger()/SetInteger() and VideoFrame::ColorSpace enumeration.
     COLOR_SPACE,
 
-    // Indicates if the current frame is the End of its current Stream.
+    // Indicates if the current frame is the End of its current Stream. Use
+    // Get/SetBoolean() for this Key.
     END_OF_STREAM,
 
     // The estimated duration of this frame (i.e., the amount of time between
@@ -91,6 +98,9 @@
   // Returns null if |key| was not present.
   const base::Value* GetValue(Key key) const WARN_UNUSED_RESULT;
 
+  // Convenience method that returns true if |key| exists and is set to true.
+  bool IsTrue(Key key) const WARN_UNUSED_RESULT;
+
   // For serialization.
   void MergeInternalValuesInto(base::DictionaryValue* out) const;
   void MergeInternalValuesFrom(const base::DictionaryValue& in);
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc
index d1a09f3..02cefdf 100644
--- a/media/base/video_frame_unittest.cc
+++ b/media/base/video_frame_unittest.cc
@@ -155,7 +155,8 @@
 
   // Test an empty frame.
   frame = VideoFrame::CreateEOSFrame();
-  EXPECT_TRUE(frame->IsEndOfStream());
+  EXPECT_TRUE(
+      frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
 }
 
 TEST(VideoFrame, CreateBlackFrame) {
@@ -170,7 +171,8 @@
 
   // Test basic properties.
   EXPECT_EQ(0, frame->timestamp().InMicroseconds());
-  EXPECT_FALSE(frame->IsEndOfStream());
+  EXPECT_FALSE(
+      frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
 
   // Test |frame| properties.
   EXPECT_EQ(VideoFrame::YV12, frame->format());
@@ -252,14 +254,13 @@
 
   {
     scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTexture(
+        VideoFrame::ARGB,
         gpu::MailboxHolder(gpu::Mailbox(), 5, 0 /* sync_point */),
         base::Bind(&TextureCallback, &called_sync_point),
         gfx::Size(10, 10),  // coded_size
         gfx::Rect(10, 10),  // visible_rect
         gfx::Size(10, 10),  // natural_size
-        base::TimeDelta(),  // timestamp
-        false,              // allow_overlay
-        true);              // has_alpha
+        base::TimeDelta()); // timestamp
     EXPECT_EQ(VideoFrame::STORAGE_TEXTURE, frame->storage_type());
     EXPECT_EQ(VideoFrame::ARGB, frame->format());
   }
@@ -307,8 +308,7 @@
         gfx::Size(10, 10),  // coded_size
         gfx::Rect(10, 10),  // visible_rect
         gfx::Size(10, 10),  // natural_size
-        base::TimeDelta(),  // timestamp
-        false);             // allow_overlay
+        base::TimeDelta()); // timestamp
 
     EXPECT_EQ(VideoFrame::STORAGE_TEXTURE, frame->storage_type());
     EXPECT_EQ(VideoFrame::I420, frame->format());
diff --git a/media/base/wall_clock_time_source.cc b/media/base/wall_clock_time_source.cc
index 1c59be94..33ec372e 100644
--- a/media/base/wall_clock_time_source.cc
+++ b/media/base/wall_clock_time_source.cc
@@ -20,16 +20,16 @@
   base::AutoLock auto_lock(lock_);
   DCHECK(!ticking_);
   ticking_ = true;
-  reference_wall_ticks_ = tick_clock_->NowTicks();
+  reference_time_ = tick_clock_->NowTicks();
 }
 
 void WallClockTimeSource::StopTicking() {
   DVLOG(1) << __FUNCTION__;
   base::AutoLock auto_lock(lock_);
   DCHECK(ticking_);
-  base_time_ = CurrentMediaTime_Locked();
+  base_timestamp_ = CurrentMediaTime_Locked();
   ticking_ = false;
-  reference_wall_ticks_ = tick_clock_->NowTicks();
+  reference_time_ = tick_clock_->NowTicks();
 }
 
 void WallClockTimeSource::SetPlaybackRate(double playback_rate) {
@@ -38,8 +38,8 @@
   // Estimate current media time using old rate to use as a new base time for
   // the new rate.
   if (ticking_) {
-    base_time_ = CurrentMediaTime_Locked();
-    reference_wall_ticks_ = tick_clock_->NowTicks();
+    base_timestamp_ = CurrentMediaTime_Locked();
+    reference_time_ = tick_clock_->NowTicks();
   }
 
   playback_rate_ = playback_rate;
@@ -49,7 +49,7 @@
   DVLOG(1) << __FUNCTION__ << "(" << time.InMicroseconds() << ")";
   base::AutoLock auto_lock(lock_);
   CHECK(!ticking_);
-  base_time_ = time;
+  base_timestamp_ = time;
 }
 
 base::TimeDelta WallClockTimeSource::CurrentMediaTime() {
@@ -61,29 +61,34 @@
     const std::vector<base::TimeDelta>& media_timestamps,
     std::vector<base::TimeTicks>* wall_clock_times) {
   base::AutoLock auto_lock(lock_);
-  if (!ticking_ || !playback_rate_)
-    return false;
-
   DCHECK(wall_clock_times->empty());
-  wall_clock_times->reserve(media_timestamps.size());
-  for (const auto& media_timestamp : media_timestamps) {
-    wall_clock_times->push_back(
-        reference_wall_ticks_ +
-        base::TimeDelta::FromMicroseconds(
-            (media_timestamp - base_time_).InMicroseconds() / playback_rate_));
+
+  if (media_timestamps.empty()) {
+    wall_clock_times->push_back(reference_time_);
+  } else {
+    // When playback is paused (rate is zero), assume a rate of 1.0.
+    const double playback_rate = playback_rate_ ? playback_rate_ : 1.0;
+
+    wall_clock_times->reserve(media_timestamps.size());
+    for (const auto& media_timestamp : media_timestamps) {
+      wall_clock_times->push_back(reference_time_ +
+                                  (media_timestamp - base_timestamp_) /
+                                      playback_rate);
+    }
   }
-  return true;
+
+  return playback_rate_ && ticking_;
 }
 
 base::TimeDelta WallClockTimeSource::CurrentMediaTime_Locked() {
   lock_.AssertAcquired();
   if (!ticking_ || !playback_rate_)
-    return base_time_;
+    return base_timestamp_;
 
   base::TimeTicks now = tick_clock_->NowTicks();
-  return base_time_ +
+  return base_timestamp_ +
          base::TimeDelta::FromMicroseconds(
-             (now - reference_wall_ticks_).InMicroseconds() * playback_rate_);
+             (now - reference_time_).InMicroseconds() * playback_rate_);
 }
 
 }  // namespace media
diff --git a/media/base/wall_clock_time_source.h b/media/base/wall_clock_time_source.h
index 2228319..4046e8e 100644
--- a/media/base/wall_clock_time_source.h
+++ b/media/base/wall_clock_time_source.h
@@ -48,8 +48,8 @@
   // delta between our reference ticks and the current system ticks and scaling
   // that time by the playback rate.
   double playback_rate_;
-  base::TimeDelta base_time_;
-  base::TimeTicks reference_wall_ticks_;
+  base::TimeDelta base_timestamp_;
+  base::TimeTicks reference_time_;
 
   // TODO(scherkus): Remove internal locking from this class after access to
   // Renderer::CurrentMediaTime() is single threaded http://crbug.com/370634
diff --git a/media/base/wall_clock_time_source_unittest.cc b/media/base/wall_clock_time_source_unittest.cc
index d9b632ff..f5f0bb3 100644
--- a/media/base/wall_clock_time_source_unittest.cc
+++ b/media/base/wall_clock_time_source_unittest.cc
@@ -28,22 +28,26 @@
     return time_source_.SetMediaTime(base::TimeDelta::FromSeconds(seconds));
   }
 
-  bool IsWallClockNowForMediaTimeInSeconds(int seconds) {
+  base::TimeTicks ConvertMediaTime(base::TimeDelta timestamp,
+                                   bool* is_time_moving) {
     std::vector<base::TimeTicks> wall_clock_times;
-    EXPECT_TRUE(time_source_.GetWallClockTimes(
-        std::vector<base::TimeDelta>(1, base::TimeDelta::FromSeconds(seconds)),
-        &wall_clock_times));
-    return tick_clock_->NowTicks() == wall_clock_times.front();
+    *is_time_moving = time_source_.GetWallClockTimes(
+        std::vector<base::TimeDelta>(1, timestamp), &wall_clock_times);
+    return wall_clock_times[0];
+  }
+
+  bool IsWallClockNowForMediaTimeInSeconds(int seconds) {
+    bool is_time_moving = false;
+    return tick_clock_->NowTicks() ==
+           ConvertMediaTime(base::TimeDelta::FromSeconds(seconds),
+                            &is_time_moving);
   }
 
   bool IsTimeStopped() {
-    std::vector<base::TimeTicks> wall_clock_times;
+    bool is_time_moving = false;
     // Convert any random value, it shouldn't matter for this call.
-    const bool time_stopped = !time_source_.GetWallClockTimes(
-        std::vector<base::TimeDelta>(1, base::TimeDelta::FromSeconds(1)),
-        &wall_clock_times);
-    EXPECT_EQ(time_stopped, wall_clock_times.empty());
-    return time_stopped;
+    ConvertMediaTime(base::TimeDelta::FromSeconds(1), &is_time_moving);
+    return !is_time_moving;
   }
 
  protected:
@@ -118,4 +122,44 @@
   EXPECT_TRUE(IsTimeStopped());
 }
 
+TEST_F(WallClockTimeSourceTest, ConvertsTimestampsWhenStopped) {
+  const base::TimeDelta kOneSecond = base::TimeDelta::FromSeconds(1);
+  bool is_time_moving = false;
+  EXPECT_EQ(base::TimeTicks(),
+            ConvertMediaTime(base::TimeDelta(), &is_time_moving));
+  EXPECT_FALSE(is_time_moving);
+  EXPECT_NE(base::TimeTicks(), ConvertMediaTime(kOneSecond, &is_time_moving));
+  EXPECT_FALSE(is_time_moving);
+  time_source_.StartTicking();
+  time_source_.StopTicking();
+  EXPECT_EQ(tick_clock_->NowTicks(),
+            ConvertMediaTime(base::TimeDelta(), &is_time_moving));
+  EXPECT_FALSE(is_time_moving);
+  EXPECT_EQ(tick_clock_->NowTicks() + kOneSecond,
+            ConvertMediaTime(kOneSecond, &is_time_moving));
+  EXPECT_FALSE(is_time_moving);
+}
+
+TEST_F(WallClockTimeSourceTest, EmptyMediaTimestampsReturnMediaWallClockTime) {
+  std::vector<base::TimeTicks> wall_clock_times;
+  bool is_time_moving = time_source_.GetWallClockTimes(
+      std::vector<base::TimeDelta>(), &wall_clock_times);
+  EXPECT_FALSE(is_time_moving);
+  EXPECT_EQ(base::TimeTicks(), wall_clock_times[0]);
+
+  wall_clock_times.clear();
+  time_source_.StartTicking();
+  is_time_moving = time_source_.GetWallClockTimes(
+      std::vector<base::TimeDelta>(), &wall_clock_times);
+  EXPECT_TRUE(is_time_moving);
+  EXPECT_EQ(tick_clock_->NowTicks(), wall_clock_times[0]);
+
+  wall_clock_times.clear();
+  time_source_.StopTicking();
+  is_time_moving = time_source_.GetWallClockTimes(
+      std::vector<base::TimeDelta>(), &wall_clock_times);
+  EXPECT_FALSE(is_time_moving);
+  EXPECT_EQ(tick_clock_->NowTicks(), wall_clock_times[0]);
+}
+
 }  // namespace media
diff --git a/media/blink/run_all_unittests.cc b/media/blink/run_all_unittests.cc
index e7b8b725..8af78f7 100644
--- a/media/blink/run_all_unittests.cc
+++ b/media/blink/run_all_unittests.cc
@@ -76,7 +76,7 @@
 
   // Run this here instead of main() to ensure an AtExitManager is already
   // present.
-  media::InitializeMediaLibraryForTesting();
+  media::InitializeMediaLibrary();
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   gin::V8Initializer::LoadV8Snapshot();
diff --git a/media/blink/skcanvas_video_renderer.cc b/media/blink/skcanvas_video_renderer.cc
index 2d3a416..f8d6e87 100644
--- a/media/blink/skcanvas_video_renderer.cc
+++ b/media/blink/skcanvas_video_renderer.cc
@@ -12,9 +12,13 @@
 #include "skia/ext/refptr.h"
 #include "third_party/libyuv/include/libyuv.h"
 #include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkImageGenerator.h"
 #include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/GrPaint.h"
+#include "third_party/skia/include/gpu/GrTexture.h"
 #include "third_party/skia/include/gpu/GrTextureProvider.h"
+#include "third_party/skia/include/gpu/SkGr.h"
 #include "third_party/skia/include/gpu/SkGrPixelRef.h"
 #include "ui/gfx/skbitmap_operations.h"
 
@@ -84,32 +88,6 @@
   return true;
 }
 
-bool CopyVideoFrameTextureToSkBitmapTexture(VideoFrame* video_frame,
-                                            SkBitmap* bitmap,
-                                            const Context3D& context_3d) {
-  // Check if we could reuse existing texture based bitmap.
-  // Otherwise, release existing texture based bitmap and allocate
-  // a new one based on video size.
-  if (!IsSkBitmapProperlySizedTexture(bitmap,
-                                      video_frame->visible_rect().size())) {
-    if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap,
-                                 video_frame->visible_rect().size())) {
-      return false;
-    }
-  }
-
-  unsigned texture_id =
-      static_cast<unsigned>((bitmap->getTexture())->getTextureHandle());
-  // If CopyVideoFrameTextureToGLTexture() changes the state of the
-  // |texture_id|, it's needed to invalidate the state cached in skia,
-  // but currently the state isn't changed.
-  SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(
-      context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true,
-      false);
-  bitmap->notifyPixelsChanged();
-  return true;
-}
-
 class SyncPointClientImpl : public VideoFrame::SyncPointClient {
  public:
   explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
@@ -125,6 +103,84 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl);
 };
 
+scoped_ptr<SkImage> CreateSkImageFromVideoFrameYUVTextures(
+    VideoFrame* video_frame,
+    const Context3D& context_3d) {
+  // Support only TEXTURE_YUV_420.
+  DCHECK(video_frame->storage_type() == VideoFrame::STORAGE_TEXTURE);
+  DCHECK_EQ(media::VideoFrame::I420, video_frame->format());
+  DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame->format()));
+
+  gpu::gles2::GLES2Interface* gl = context_3d.gl;
+  DCHECK(gl);
+  gfx::Size ya_tex_size = video_frame->coded_size();
+  gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2,
+                        (ya_tex_size.height() + 1) / 2);
+
+  unsigned source_textures[3] = {0};
+  for (size_t i = 0; i < media::VideoFrame::NumPlanes(video_frame->format());
+       ++i) {
+    // Get the texture from the mailbox and wrap it in a GrTexture.
+    const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i);
+    DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
+           mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES ||
+           mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB);
+    gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point);
+    source_textures[i] = gl->CreateAndConsumeTextureCHROMIUM(
+        mailbox_holder.texture_target, mailbox_holder.mailbox.name);
+  }
+  GrBackendObject handles[3] = {
+      source_textures[0], source_textures[1], source_textures[2]};
+
+  SkISize yuvSizes[] = {
+      {ya_tex_size.width(), ya_tex_size.height()},
+      {uv_tex_size.width(), uv_tex_size.height()},
+      {uv_tex_size.width(), uv_tex_size.height()},
+  };
+
+  // TODO(dcastagna): Skia currently doesn't support Rec709 YUV conversion.
+  DCHECK(!CheckColorSpace(video_frame, VideoFrame::COLOR_SPACE_HD_REC709));
+  SkYUVColorSpace color_space = kRec601_SkYUVColorSpace;
+  if (CheckColorSpace(video_frame, VideoFrame::COLOR_SPACE_JPEG))
+    color_space = kJPEG_SkYUVColorSpace;
+
+  SkImage* img = SkImage::NewFromYUVTexturesCopy(context_3d.gr_context,
+                                                 color_space, handles, yuvSizes,
+                                                 kTopLeft_GrSurfaceOrigin);
+  DCHECK(img);
+  gl->DeleteTextures(3, source_textures);
+  SyncPointClientImpl client(gl);
+  video_frame->UpdateReleaseSyncPoint(&client);
+  return make_scoped_ptr(img);
+}
+
+bool CopyVideoFrameSingleTextureToSkBitmap(VideoFrame* video_frame,
+                                           SkBitmap* bitmap,
+                                           const Context3D& context_3d) {
+  // Check if we could reuse existing texture based bitmap.
+  // Otherwise, release existing texture based bitmap and allocate
+  // a new one based on video size.
+  if (!IsSkBitmapProperlySizedTexture(bitmap,
+                                      video_frame->visible_rect().size())) {
+    if (!AllocateSkBitmapTexture(context_3d.gr_context, bitmap,
+                                 video_frame->visible_rect().size())) {
+      return false;
+    }
+  }
+
+  unsigned texture_id =
+      static_cast<unsigned>((bitmap->getTexture())->getTextureHandle());
+  // If CopyVideoFrameSingleTextureToGLTexture() changes the state of the
+  // |texture_id|, it's needed to invalidate the state cached in skia,
+  // but currently the state isn't changed.
+
+  SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
+      context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true,
+      false);
+  bitmap->notifyPixelsChanged();
+  return true;
+}
+
 }  // anonymous namespace
 
 // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
@@ -290,16 +346,23 @@
         accelerated_last_frame_.reset();
         accelerated_generator_ = nullptr;
       }
-      if (!CopyVideoFrameTextureToSkBitmapTexture(
-              video_frame.get(), &accelerated_last_frame_, context_3d)) {
-        NOTREACHED();
-        return;
-      }
-      DCHECK(video_frame->visible_rect().width() ==
-                 accelerated_last_frame_.width() &&
-             video_frame->visible_rect().height() ==
-                 accelerated_last_frame_.height());
 
+      if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) {
+        accelerated_last_image_.reset();
+        if (!CopyVideoFrameSingleTextureToSkBitmap(
+                video_frame.get(), &accelerated_last_frame_, context_3d)) {
+          NOTREACHED();
+          return;
+        }
+        DCHECK(video_frame->visible_rect().width() ==
+                   accelerated_last_frame_.width() &&
+               video_frame->visible_rect().height() ==
+                   accelerated_last_frame_.height());
+      } else {
+        accelerated_last_image_ = CreateSkImageFromVideoFrameYUVTextures(
+            video_frame.get(), context_3d);
+        DCHECK(accelerated_last_image_);
+      }
       accelerated_last_frame_timestamp_ = video_frame->timestamp();
     }
     target_frame = &accelerated_last_frame_;
@@ -395,7 +458,11 @@
     canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f),
                       -SkFloatToScalar(target_frame->height() * 0.5f));
   }
-  canvas->drawBitmap(*target_frame, 0, 0, &paint);
+  if (accelerated_last_image_) {
+    canvas->drawImage(accelerated_last_image_.get(), 0, 0, &paint);
+  } else {
+    canvas->drawBitmap(*target_frame, 0, 0, &paint);
+  }
   if (need_transform)
     canvas->restore();
   canvas->flush();
@@ -548,7 +615,7 @@
 }
 
 // static
-void SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(
+void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
     gpu::gles2::GLES2Interface* gl,
     VideoFrame* video_frame,
     unsigned int texture,
@@ -595,6 +662,7 @@
 }
 
 void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() {
+  accelerated_last_image_.reset();
   accelerated_last_frame_.reset();
   accelerated_generator_ = nullptr;
   accelerated_last_frame_timestamp_ = media::kNoTimestamp();
diff --git a/media/blink/skcanvas_video_renderer.h b/media/blink/skcanvas_video_renderer.h
index 9b75cd01..5044953 100644
--- a/media/blink/skcanvas_video_renderer.h
+++ b/media/blink/skcanvas_video_renderer.h
@@ -12,6 +12,7 @@
 #include "media/base/video_rotation.h"
 #include "media/filters/context_3d.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkXfermode.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -61,13 +62,14 @@
   // Copy the contents of texture of |video_frame| to texture |texture|.
   // |level|, |internal_format|, |type| specify target texture |texture|.
   // The format of |video_frame| must be VideoFrame::NATIVE_TEXTURE.
-  static void CopyVideoFrameTextureToGLTexture(gpu::gles2::GLES2Interface* gl,
-                                               VideoFrame* video_frame,
-                                               unsigned int texture,
-                                               unsigned int internal_format,
-                                               unsigned int type,
-                                               bool premultiply_alpha,
-                                               bool flip_y);
+  static void CopyVideoFrameSingleTextureToGLTexture(
+      gpu::gles2::GLES2Interface* gl,
+      VideoFrame* video_frame,
+      unsigned int texture,
+      unsigned int internal_format,
+      unsigned int type,
+      bool premultiply_alpha,
+      bool flip_y);
 
  private:
   void ResetLastFrame();
@@ -84,6 +86,7 @@
   // |accelerated_generator_|.
   // It's used when |canvas| parameter in Paint() is Ganesh canvas.
   // Note: all GrContext in SkCanvas instances are same.
+  scoped_ptr<SkImage> accelerated_last_image_;
   SkBitmap accelerated_last_frame_;
   VideoImageGenerator* accelerated_generator_;
   base::TimeDelta accelerated_last_frame_timestamp_;
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index ce3488f3..d68b4757 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -115,12 +115,11 @@
       pipeline_(media_task_runner_, media_log_.get()),
       load_type_(LoadTypeURL),
       opaque_(false),
+      playback_rate_(0.0),
       paused_(true),
       seeking_(false),
-      playback_rate_(0.0),
       ended_(false),
       pending_seek_(false),
-      pending_seek_seconds_(0.0f),
       should_notify_time_changed_(false),
       client_(client),
       delegate_(delegate),
@@ -291,13 +290,31 @@
   if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata)
     SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
 
-  base::TimeDelta seek_time = ConvertSecondsToTimestamp(seconds);
+  base::TimeDelta new_seek_time = ConvertSecondsToTimestamp(seconds);
 
   if (seeking_) {
+    if (new_seek_time == seek_time_) {
+      if (chunk_demuxer_) {
+        if (!pending_seek_) {
+          // If using media source demuxer, only suppress redundant seeks if
+          // there is no pending seek. This enforces that any pending seek that
+          // results in a demuxer seek is preceded by matching
+          // CancelPendingSeek() and StartWaitingForSeek() calls.
+          return;
+        }
+      } else {
+        // Suppress all redundant seeks if unrestricted by media source demuxer
+        // API.
+        pending_seek_ = false;
+        pending_seek_time_ = base::TimeDelta();
+        return;
+      }
+    }
+
     pending_seek_ = true;
-    pending_seek_seconds_ = seconds;
+    pending_seek_time_ = new_seek_time;
     if (chunk_demuxer_)
-      chunk_demuxer_->CancelPendingSeek(seek_time);
+      chunk_demuxer_->CancelPendingSeek(pending_seek_time_);
     return;
   }
 
@@ -308,8 +325,8 @@
   // is completed and generate OnPipelineBufferingStateChanged event to
   // eventually fire seeking and seeked events
   if (paused_) {
-    if (paused_time_ != seek_time) {
-      paused_time_ = seek_time;
+    if (paused_time_ != new_seek_time) {
+      paused_time_ = new_seek_time;
     } else if (old_state == ReadyStateHaveEnoughData) {
       main_task_runner_->PostTask(
           FROM_HERE,
@@ -320,14 +337,14 @@
   }
 
   seeking_ = true;
+  seek_time_ = new_seek_time;
 
   if (chunk_demuxer_)
-    chunk_demuxer_->StartWaitingForSeek(seek_time);
+    chunk_demuxer_->StartWaitingForSeek(seek_time_);
 
   // Kick off the asynchronous seek!
-  pipeline_.Seek(
-      seek_time,
-      BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnPipelineSeeked, true));
+  pipeline_.Seek(seek_time_, BIND_TO_RENDER_LOOP1(
+                                 &WebMediaPlayerImpl::OnPipelineSeeked, true));
 }
 
 void WebMediaPlayerImpl::setRate(double rate) {
@@ -444,6 +461,14 @@
   if (ended_)
     return duration();
 
+  // We know the current seek time better than pipeline: pipeline may processing
+  // an earlier seek before a pending seek has been started, or it might not yet
+  // have the current seek time returnable via GetMediaTime().
+  if (seeking()) {
+    return pending_seek_ ? pending_seek_time_.InSecondsF()
+                         : seek_time_.InSecondsF();
+  }
+
   return (paused_ ? paused_time_ : pipeline_.GetMediaTime()).InSecondsF();
 }
 
@@ -596,7 +621,8 @@
   scoped_refptr<VideoFrame> video_frame = GetCurrentFrameFromCompositor();
 
   if (!video_frame.get() ||
-      video_frame->storage_type() != VideoFrame::STORAGE_TEXTURE) {
+      video_frame->storage_type() != VideoFrame::STORAGE_TEXTURE ||
+      media::VideoFrame::NumPlanes(video_frame->format()) != 1) {
     return false;
   }
 
@@ -605,7 +631,7 @@
   gpu::gles2::GLES2Interface* gl =
       static_cast<gpu_blink::WebGraphicsContext3DImpl*>(web_graphics_context)
           ->GetGLInterface();
-  SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(
+  SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
       gl, video_frame.get(), texture, internal_format, type, premultiply_alpha,
       flip_y);
   return true;
@@ -717,9 +743,12 @@
   DVLOG(1) << __FUNCTION__ << "(" << time_changed << ", " << status << ")";
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   seeking_ = false;
+  seek_time_ = base::TimeDelta();
   if (pending_seek_) {
+    double pending_seek_seconds = pending_seek_time_.InSecondsF();
     pending_seek_ = false;
-    seek(pending_seek_seconds_);
+    pending_seek_time_ = base::TimeDelta();
+    seek(pending_seek_seconds);
     return;
   }
 
@@ -870,7 +899,6 @@
   UMA_HISTOGRAM_BOOLEAN("Media.MSE.Playback",
                         (load_type_ == LoadTypeMediaSource));
 
-  LogCB mse_log_cb;
   Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnEncryptedMediaInitData);
 
@@ -885,11 +913,10 @@
     DCHECK(!chunk_demuxer_);
     DCHECK(!data_source_);
 
-    mse_log_cb = base::Bind(&MediaLog::AddLogEvent, media_log_);
-
     chunk_demuxer_ = new ChunkDemuxer(
         BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
-        encrypted_media_init_data_cb, mse_log_cb, media_log_, true);
+        encrypted_media_init_data_cb,
+        base::Bind(&MediaLog::AddLogEvent, media_log_), media_log_, true);
     demuxer_.reset(chunk_demuxer_);
   }
 
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 427357b1..486a68e 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -274,10 +274,11 @@
   // time we pause and then return that value in currentTime().  Otherwise our
   // clock can creep forward a little bit while the asynchronous
   // SetPlaybackRate(0) is being executed.
-  bool paused_;
-  bool seeking_;
   double playback_rate_;
+  bool paused_;
   base::TimeDelta paused_time_;
+  bool seeking_;
+  base::TimeDelta seek_time_;  // Meaningless when |seeking_| is false.
 
   // TODO(scherkus): Replace with an explicit ended signal to HTMLMediaElement,
   // see http://crbug.com/409280
@@ -286,7 +287,8 @@
   // Seek gets pending if another seek is in progress. Only last pending seek
   // will have effect.
   bool pending_seek_;
-  double pending_seek_seconds_;
+  // |pending_seek_time_| is meaningless when |pending_seek_| is false.
+  base::TimeDelta pending_seek_time_;
 
   // Tracks whether to issue time changed notifications during buffering state
   // changes.
diff --git a/media/cast/cast_unittests.isolate b/media/cast/cast_unittests.isolate
index 26b9395..bf207cd4 100644
--- a/media/cast/cast_unittests.isolate
+++ b/media/cast/cast_unittests.isolate
@@ -34,13 +34,6 @@
         ],
       },
     }],
-    ['OS=="linux"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
-        ],
-      },
-    }],
     ['OS=="linux" or OS=="mac" or OS=="win"', {
       'variables': {
         'files': [
@@ -49,13 +42,6 @@
         ],
       },
     }],
-    ['OS=="mac"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
-        ],
-      },
-    }],
     ['OS=="mac" and asan==1 and fastbuild==0', {
       'variables': {
         'files': [
@@ -63,13 +49,6 @@
         ],
       },
     }],
-    ['OS=="win"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
-        ],
-      },
-    }],
     ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
       'variables': {
         'files': [
diff --git a/media/cast/sender/audio_encoder_unittest.cc b/media/cast/sender/audio_encoder_unittest.cc
index 70b5041..5fd80f1 100644
--- a/media/cast/sender/audio_encoder_unittest.cc
+++ b/media/cast/sender/audio_encoder_unittest.cc
@@ -98,7 +98,7 @@
 class AudioEncoderTest : public ::testing::TestWithParam<TestScenario> {
  public:
   AudioEncoderTest() {
-    InitializeMediaLibraryForTesting();
+    InitializeMediaLibrary();
     testing_clock_ = new base::SimpleTestTickClock();
     testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
   }
diff --git a/media/cast/sender/audio_sender_unittest.cc b/media/cast/sender/audio_sender_unittest.cc
index b0662804..1f4ae9e 100644
--- a/media/cast/sender/audio_sender_unittest.cc
+++ b/media/cast/sender/audio_sender_unittest.cc
@@ -67,7 +67,7 @@
 class AudioSenderTest : public ::testing::Test {
  protected:
   AudioSenderTest() {
-    InitializeMediaLibraryForTesting();
+    InitializeMediaLibrary();
     testing_clock_ = new base::SimpleTestTickClock();
     testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
     task_runner_ = new test::FakeSingleThreadTaskRunner(testing_clock_);
diff --git a/media/cast/sender/h264_vt_encoder_unittest.cc b/media/cast/sender/h264_vt_encoder_unittest.cc
index 89e7c54..62fcb00 100644
--- a/media/cast/sender/h264_vt_encoder_unittest.cc
+++ b/media/cast/sender/h264_vt_encoder_unittest.cc
@@ -42,7 +42,7 @@
   base::TestSuite::Initialize();
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   command_line->AppendSwitch(switches::kEnableInbandTextTracks);
-  media::InitializeMediaLibraryForTesting();
+  media::InitializeMediaLibrary();
 }
 
 }  // namespace
diff --git a/media/cast/test/sender.cc b/media/cast/test/sender.cc
index 73986987..4e3a8db 100644
--- a/media/cast/test/sender.cc
+++ b/media/cast/test/sender.cc
@@ -204,13 +204,8 @@
   base::CommandLine::Init(argc, argv);
   InitLogging(logging::LoggingSettings());
 
-  // Load the media module for FFmpeg decoding.
-  base::FilePath path;
-  PathService::Get(base::DIR_MODULE, &path);
-  if (!media::InitializeMediaLibrary(path)) {
-    LOG(ERROR) << "Could not initialize media library.";
-    return 1;
-  }
+  // Prepare media module for FFmpeg decoding.
+  media::InitializeMediaLibrary();
 
   base::Thread test_thread("Cast sender test app thread");
   base::Thread audio_thread("Cast audio encoder thread");
diff --git a/media/cast/test/simulator.cc b/media/cast/test/simulator.cc
index a3a560e..540f377 100644
--- a/media/cast/test/simulator.cc
+++ b/media/cast/test/simulator.cc
@@ -739,10 +739,7 @@
     }
   }
 
-  if (!media::InitializeMediaLibrary(media_path)) {
-    LOG(ERROR) << "Failed to initialize FFmpeg.";
-    return 1;
-  }
+  media::InitializeMediaLibrary();
 
   base::FilePath source_path = cmd->GetSwitchValuePath(
       media::cast::kSourcePath);
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
index 6a6ff62a..6087dcc 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -44,25 +44,17 @@
 MSVC_POP_WARNING();
 }  // extern "C"
 
-// TODO(tomfinegan): When COMPONENT_BUILD is not defined an AtExitManager must
-// exist before the call to InitializeFFmpegLibraries(). This should no longer
-// be required after http://crbug.com/91970 because we'll be able to get rid of
-// InitializeFFmpegLibraries().
 #if !defined COMPONENT_BUILD
 static base::AtExitManager g_at_exit_manager;
 #endif
 
-// TODO(tomfinegan): InitializeFFmpegLibraries() and |g_cdm_module_initialized|
-// are required for running in the sandbox, and should no longer be required
-// after http://crbug.com/91970 is fixed.
+// Prepare media library.
 static bool InitializeFFmpegLibraries() {
-  base::FilePath file_path;
-  CHECK(PathService::Get(base::DIR_MODULE, &file_path));
-  CHECK(media::InitializeMediaLibrary(file_path));
+  media::InitializeMediaLibrary();
   return true;
 }
-
 static bool g_ffmpeg_lib_initialized = InitializeFFmpegLibraries();
+
 #endif  // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
 
 const char kClearKeyCdmVersion[] = "0.1.0.1";
@@ -230,7 +222,6 @@
 
 void INITIALIZE_CDM_MODULE() {
 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
-  DVLOG(2) << "FFmpeg libraries initialized: " << g_ffmpeg_lib_initialized;
   av_register_all();
 #endif  // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
 }
diff --git a/media/ffmpeg/ffmpeg_common_unittest.cc b/media/ffmpeg/ffmpeg_common_unittest.cc
index ff07307..47c3db3 100644
--- a/media/ffmpeg/ffmpeg_common_unittest.cc
+++ b/media/ffmpeg/ffmpeg_common_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "media/base/media.h"
 #include "media/ffmpeg/ffmpeg_common.h"
 #include "media/filters/ffmpeg_glue.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -12,7 +13,9 @@
 
 class FFmpegCommonTest : public testing::Test {
  public:
-  FFmpegCommonTest() { FFmpegGlue::InitializeFFmpeg(); }
+  FFmpegCommonTest() {
+    FFmpegGlue::InitializeFFmpeg();
+  }
   ~FFmpegCommonTest() override{};
 };
 
@@ -89,17 +92,6 @@
   EXPECT_EQ(0, exploded.millisecond);
 }
 
-#if defined(ALLOCATOR_SHIM) && defined(GTEST_HAS_DEATH_TEST)
-TEST_F(FFmpegCommonTest, WinAllocatorShimDeathTest) {
-  scoped_ptr<char, base::FreeDeleter> ptr;
-  // INT_MAX - 128 is carefully chosen to be below the default limit for
-  // ffmpeg allocations, but above the maximum allowed limit by the allocator
-  // shim, so we can be certain the code is being hit.
-  EXPECT_DEATH(ptr.reset(static_cast<char*>(av_malloc(INT_MAX - 128))), "");
-  ASSERT_TRUE(!ptr);
-}
-#endif
-
 TEST_F(FFmpegCommonTest, UTCDateToTime_Invalid) {
   const char* invalid_date_strings[] = {
     "",
diff --git a/media/filters/audio_clock.cc b/media/filters/audio_clock.cc
index aebc5e5..d93db1df 100644
--- a/media/filters/audio_clock.cc
+++ b/media/filters/audio_clock.cc
@@ -36,7 +36,7 @@
 
   // First write: initialize buffer with silence.
   if (start_timestamp_ == front_timestamp_ && buffered_.empty())
-    PushBufferedAudioData(delay_frames, 0.0f);
+    PushBufferedAudioData(delay_frames, 0.0);
 
   // Move frames from |buffered_| into the computed timestamp based on
   // |delay_frames|.
@@ -47,7 +47,7 @@
       std::max(INT64_C(0), total_buffered_frames_ - delay_frames);
   front_timestamp_ += ComputeBufferedMediaTime(frames_played);
   PushBufferedAudioData(frames_written, playback_rate);
-  PushBufferedAudioData(frames_requested - frames_written, 0.0f);
+  PushBufferedAudioData(frames_requested - frames_written, 0.0);
   PopBufferedAudioData(frames_played);
 
   back_timestamp_ += base::TimeDelta::FromMicroseconds(
@@ -80,6 +80,23 @@
                                         microseconds_per_frame_);
 }
 
+void AudioClock::CompensateForSuspendedWrites(base::TimeDelta elapsed,
+                                              int delay_frames) {
+  const int64_t frames_elapsed =
+      elapsed.InMicroseconds() / microseconds_per_frame_ + 0.5;
+
+  // No need to do anything if we're within the limits of our played out audio
+  // or there are no delay frames, the next WroteAudio() call will expire
+  // everything correctly.
+  if (frames_elapsed < total_buffered_frames_ || !delay_frames)
+    return;
+
+  // Otherwise, flush everything and prime with the delay frames.
+  WroteAudio(0, 0, 0, 0);
+  DCHECK(buffered_.empty());
+  PushBufferedAudioData(delay_frames, 0.0);
+}
+
 base::TimeDelta AudioClock::TimeUntilPlayback(base::TimeDelta timestamp) const {
   DCHECK_GE(timestamp, front_timestamp_);
   DCHECK_LE(timestamp, back_timestamp_);
diff --git a/media/filters/audio_clock.h b/media/filters/audio_clock.h
index fe462aba..f7711f6 100644
--- a/media/filters/audio_clock.h
+++ b/media/filters/audio_clock.h
@@ -59,6 +59,18 @@
                   int delay_frames,
                   double playback_rate);
 
+  // If WroteAudio() calls are suspended (i.e. due to playback being paused) the
+  // AudioClock will not properly advance time (even though all data up until
+  // back_timestamp() will playout on the physical device).
+  //
+  // To compensate for this, when calls resume, before the next WroteAudio(),
+  // callers should call CompensateForSuspendedWrites() to advance the clock for
+  // audio which continued playing out while WroteAudio() calls were suspended.
+  //
+  // |delay_frames| must be provided to properly prime the clock to compensate
+  // for a new initial delay.
+  void CompensateForSuspendedWrites(base::TimeDelta elapsed, int delay_frames);
+
   // Returns the bounds of media data currently buffered by the audio hardware,
   // taking silence and changes in playback rate into account. Buffered audio
   // structure and timestamps are updated with every call to WroteAudio().
diff --git a/media/filters/audio_clock_unittest.cc b/media/filters/audio_clock_unittest.cc
index 3fe437e..2144bb0 100644
--- a/media/filters/audio_clock_unittest.cc
+++ b/media/filters/audio_clock_unittest.cc
@@ -330,4 +330,30 @@
   EXPECT_EQ((huge * 2).InDays(), ContiguousAudioDataBufferedInDays());
 }
 
+TEST_F(AudioClockTest, CompensateForSuspendedWrites) {
+  // Buffer 6 seconds of delay and 1 second of audio data.
+  WroteAudio(10, 10, 60, 1.0);
+
+  // Media timestamp zero has to wait for silence to pass.
+  const int kBaseTimeMs = 6000;
+  EXPECT_EQ(kBaseTimeMs, TimeUntilPlaybackInMilliseconds(0));
+
+  // Elapsing frames less than we have buffered should do nothing.
+  const int kDelayFrames = 2;
+  for (int i = 1000; i <= kBaseTimeMs; i += 1000) {
+    clock_.CompensateForSuspendedWrites(base::TimeDelta::FromMilliseconds(i),
+                                        kDelayFrames);
+    EXPECT_EQ(kBaseTimeMs - (i - 1000), TimeUntilPlaybackInMilliseconds(0));
+
+    // Write silence to simulate maintaining a 7s output buffer.
+    WroteAudio(0, 10, 60, 1.0);
+  }
+
+  // Exhausting all frames should advance timestamps and prime the buffer with
+  // our delay frames value.
+  clock_.CompensateForSuspendedWrites(base::TimeDelta::FromMilliseconds(7000),
+                                      kDelayFrames);
+  EXPECT_EQ(kDelayFrames * 100, TimeUntilPlaybackInMilliseconds(1000));
+}
+
 }  // namespace media
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc
index 29570c9..7fc7a4d 100644
--- a/media/filters/audio_decoder_selector_unittest.cc
+++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -124,8 +124,9 @@
     all_decoders_.erase(
         all_decoders_.begin() + num_decoders, all_decoders_.end());
 
-    decoder_selector_.reset(new AudioDecoderSelector(
-        message_loop_.message_loop_proxy(), all_decoders_.Pass()));
+    decoder_selector_.reset(
+        new AudioDecoderSelector(message_loop_.message_loop_proxy(),
+                                 all_decoders_.Pass(), new MediaLog()));
   }
 
   void SelectDecoder() {
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index 901fd49..2a63c8d8 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -1123,6 +1123,10 @@
   DCHECK(!encrypted_media_init_data_cb_.is_null());
 }
 
+std::string ChunkDemuxer::GetDisplayName() const {
+  return "ChunkDemuxer";
+}
+
 void ChunkDemuxer::Initialize(
     DemuxerHost* host,
     const PipelineStatusCB& cb,
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h
index 9ee3526..cdf2e524 100644
--- a/media/filters/chunk_demuxer.h
+++ b/media/filters/chunk_demuxer.h
@@ -163,6 +163,7 @@
   ~ChunkDemuxer() override;
 
   // Demuxer implementation.
+  std::string GetDisplayName() const override;
   void Initialize(DemuxerHost* host,
                   const PipelineStatusCB& cb,
                   bool enable_text_tracks) override;
diff --git a/media/filters/decoder_selector.cc b/media/filters/decoder_selector.cc
index 4463001..ca32c260 100644
--- a/media/filters/decoder_selector.cc
+++ b/media/filters/decoder_selector.cc
@@ -11,6 +11,7 @@
 #include "media/base/audio_decoder.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/demuxer_stream.h"
+#include "media/base/media_log.h"
 #include "media/base/pipeline.h"
 #include "media/base/video_decoder.h"
 #include "media/filters/decoder_stream_traits.h"
@@ -51,9 +52,11 @@
 template <DemuxerStream::Type StreamType>
 DecoderSelector<StreamType>::DecoderSelector(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-    ScopedVector<Decoder> decoders)
+    ScopedVector<Decoder> decoders,
+    const scoped_refptr<MediaLog>& media_log)
     : task_runner_(task_runner),
       decoders_(decoders.Pass()),
+      media_log_(media_log),
       input_stream_(NULL),
       weak_ptr_factory_(this) {
 }
@@ -109,7 +112,8 @@
   }
 
   decoder_.reset(new typename StreamTraits::DecryptingDecoderType(
-      task_runner_, set_decryptor_ready_cb_, waiting_for_decryption_key_cb_));
+      task_runner_, media_log_, set_decryptor_ready_cb_,
+      waiting_for_decryption_key_cb_));
 
   DecoderStreamTraits<StreamType>::InitializeDecoder(
       decoder_.get(), input_stream_,
@@ -132,7 +136,8 @@
   decoder_.reset();
 
   decrypted_stream_.reset(new DecryptingDemuxerStream(
-      task_runner_, set_decryptor_ready_cb_, waiting_for_decryption_key_cb_));
+      task_runner_, media_log_, set_decryptor_ready_cb_,
+      waiting_for_decryption_key_cb_));
 
   decrypted_stream_->Initialize(
       input_stream_,
diff --git a/media/filters/decoder_selector.h b/media/filters/decoder_selector.h
index 9fa591e..26973067 100644
--- a/media/filters/decoder_selector.h
+++ b/media/filters/decoder_selector.h
@@ -23,6 +23,7 @@
 class DecoderBuffer;
 class DecryptingDemuxerStream;
 class Decryptor;
+class MediaLog;
 
 // DecoderSelector (creates if necessary and) initializes the proper
 // Decoder for a given DemuxerStream. If the given DemuxerStream is
@@ -52,7 +53,8 @@
   // |decoders| contains the Decoders to use when initializing.
   DecoderSelector(
       const scoped_refptr<base::SingleThreadTaskRunner>& message_loop,
-      ScopedVector<Decoder> decoders);
+      ScopedVector<Decoder> decoders,
+      const scoped_refptr<MediaLog>& media_log);
 
   // Aborts pending Decoder selection and fires |select_decoder_cb| with
   // NULL and NULL immediately if it's pending.
@@ -82,6 +84,7 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   ScopedVector<Decoder> decoders_;
+  scoped_refptr<MediaLog> media_log_;
 
   DemuxerStream* input_stream_;
   SetDecryptorReadyCB set_decryptor_ready_cb_;
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc
index bacba00..aaefc04 100644
--- a/media/filters/decoder_stream.cc
+++ b/media/filters/decoder_stream.cc
@@ -12,6 +12,7 @@
 #include "base/trace_event/trace_event.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_log.h"
 #include "media/base/video_decoder.h"
 #include "media/filters/decrypting_demuxer_stream.h"
 
@@ -23,8 +24,7 @@
 static const char* GetTraceString();
 
 #define FUNCTION_DVLOG(level) \
-  DVLOG(level) << __FUNCTION__ << \
-  "<" << DecoderStreamTraits<StreamType>::ToString() << ">"
+  DVLOG(level) << __FUNCTION__ << "<" << GetStreamTypeString() << ">"
 
 template <>
 const char* GetTraceString<DemuxerStream::VIDEO>() {
@@ -45,8 +45,9 @@
       media_log_(media_log),
       state_(STATE_UNINITIALIZED),
       stream_(NULL),
-      decoder_selector_(
-          new DecoderSelector<StreamType>(task_runner, decoders.Pass())),
+      decoder_selector_(new DecoderSelector<StreamType>(task_runner,
+                                                        decoders.Pass(),
+                                                        media_log)),
       active_splice_(false),
       decoding_eos_(false),
       pending_decode_requests_(0),
@@ -77,6 +78,11 @@
 }
 
 template <DemuxerStream::Type StreamType>
+std::string DecoderStream<StreamType>::GetStreamTypeString() {
+  return DecoderStreamTraits<StreamType>::ToString();
+}
+
+template <DemuxerStream::Type StreamType>
 void DecoderStream<StreamType>::Initialize(
     DemuxerStream* stream,
     const InitCB& init_cb,
@@ -244,6 +250,8 @@
   if (!decoder_) {
     if (state_ == STATE_INITIALIZING) {
       state_ = STATE_UNINITIALIZED;
+      MEDIA_LOG(ERROR, media_log_) << GetStreamTypeString()
+                                   << " decoder initialization failed";
       base::ResetAndReturn(&init_cb_).Run(false);
     } else {
       CompleteDecoderReinitialization(false);
@@ -251,10 +259,9 @@
     return;
   }
 
-  const std::string stream_type = DecoderStreamTraits<StreamType>::ToString();
-  media_log_->SetBooleanProperty(stream_type + "_dds",
+  media_log_->SetBooleanProperty(GetStreamTypeString() + "_dds",
                                  decrypting_demuxer_stream_);
-  media_log_->SetStringProperty(stream_type + "_decoder",
+  media_log_->SetStringProperty(GetStreamTypeString() + "_decoder",
                                 decoder_->GetDisplayName());
 
   if (state_ == STATE_REINITIALIZING_DECODER) {
@@ -341,6 +348,7 @@
   switch (status) {
     case Decoder::kDecodeError:
       state_ = STATE_ERROR;
+      MEDIA_LOG(ERROR, media_log_) << GetStreamTypeString() << " decode error";
       ready_outputs_.clear();
       if (!read_cb_.is_null())
         SatisfyRead(DECODE_ERROR, NULL);
@@ -546,6 +554,8 @@
     return;
 
   if (state_ == STATE_ERROR) {
+    MEDIA_LOG(ERROR, media_log_) << GetStreamTypeString()
+                                 << " decoder reinitialization failed";
     SatisfyRead(DECODE_ERROR, NULL);
     return;
   }
diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h
index ce29ac0..c0828b3 100644
--- a/media/filters/decoder_stream.h
+++ b/media/filters/decoder_stream.h
@@ -57,6 +57,9 @@
       const scoped_refptr<MediaLog>& media_log);
   virtual ~DecoderStream();
 
+  // Returns the string representation of the StreamType for logging purpose.
+  std::string GetStreamTypeString();
+
   // Initializes the DecoderStream and returns the initialization result
   // through |init_cb|. Note that |init_cb| is always called asynchronously.
   void Initialize(DemuxerStream* stream,
diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc
index 7b3d2796..7d5bfc8e 100644
--- a/media/filters/decrypting_audio_decoder.cc
+++ b/media/filters/decrypting_audio_decoder.cc
@@ -17,6 +17,7 @@
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/buffers.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_log.h"
 #include "media/base/pipeline.h"
 
 namespace media {
@@ -32,9 +33,11 @@
 
 DecryptingAudioDecoder::DecryptingAudioDecoder(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    const scoped_refptr<MediaLog>& media_log,
     const SetDecryptorReadyCB& set_decryptor_ready_cb,
     const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
+      media_log_(media_log),
       state_(kUninitialized),
       waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
       set_decryptor_ready_cb_(set_decryptor_ready_cb),
@@ -181,6 +184,7 @@
   set_decryptor_ready_cb_.Reset();
 
   if (!decryptor) {
+    MEDIA_LOG(DEBUG, media_log_) << GetDisplayName() << ": no decryptor set";
     base::ResetAndReturn(&init_cb_).Run(false);
     state_ = kError;
     decryptor_attached_cb.Run(false);
@@ -210,6 +214,8 @@
   DCHECK(decode_cb_.is_null());  // No Decode() before initialization finished.
 
   if (!success) {
+    MEDIA_LOG(DEBUG, media_log_) << GetDisplayName()
+                                 << ": failed to init decoder on decryptor";
     base::ResetAndReturn(&init_cb_).Run(false);
     decryptor_ = NULL;
     state_ = kError;
@@ -271,6 +277,7 @@
 
   if (status == Decryptor::kError) {
     DVLOG(2) << "DeliverFrame() - kError";
+    MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": decode error";
     state_ = kDecodeFinished; // TODO add kError state
     base::ResetAndReturn(&decode_cb_).Run(kDecodeError);
     return;
@@ -278,6 +285,8 @@
 
   if (status == Decryptor::kNoKey) {
     DVLOG(2) << "DeliverFrame() - kNoKey";
+    MEDIA_LOG(DEBUG, media_log_) << GetDisplayName() << ": no key";
+
     // Set |pending_buffer_to_decode_| back as we need to try decoding the
     // pending buffer again when new key is added to the decryptor.
     pending_buffer_to_decode_ = scoped_pending_buffer_to_decode;
diff --git a/media/filters/decrypting_audio_decoder.h b/media/filters/decrypting_audio_decoder.h
index e1cc048..7919172 100644
--- a/media/filters/decrypting_audio_decoder.h
+++ b/media/filters/decrypting_audio_decoder.h
@@ -23,6 +23,7 @@
 class AudioTimestampHelper;
 class DecoderBuffer;
 class Decryptor;
+class MediaLog;
 
 // Decryptor-based AudioDecoder implementation that can decrypt and decode
 // encrypted audio buffers and return decrypted and decompressed audio frames.
@@ -32,6 +33,7 @@
  public:
   DecryptingAudioDecoder(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+      const scoped_refptr<MediaLog>& media_log,
       const SetDecryptorReadyCB& set_decryptor_ready_cb,
       const base::Closure& waiting_for_decryption_key_cb);
   ~DecryptingAudioDecoder() override;
@@ -91,6 +93,8 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
+  scoped_refptr<MediaLog> media_log_;
+
   State state_;
 
   InitCB init_cb_;
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
index bb82a4c..07df4e2 100644
--- a/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -61,6 +61,7 @@
   DecryptingAudioDecoderTest()
       : decoder_(new DecryptingAudioDecoder(
             message_loop_.message_loop_proxy(),
+            new MediaLog(),
             base::Bind(
                 &DecryptingAudioDecoderTest::RequestDecryptorNotification,
                 base::Unretained(this)),
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc
index ce16b7492..435a8fb 100644
--- a/media/filters/decrypting_demuxer_stream.cc
+++ b/media/filters/decrypting_demuxer_stream.cc
@@ -11,6 +11,7 @@
 #include "base/single_thread_task_runner.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_log.h"
 #include "media/base/pipeline.h"
 
 namespace media {
@@ -26,9 +27,11 @@
 
 DecryptingDemuxerStream::DecryptingDemuxerStream(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    const scoped_refptr<MediaLog>& media_log,
     const SetDecryptorReadyCB& set_decryptor_ready_cb,
     const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
+      media_log_(media_log),
       state_(kUninitialized),
       waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
       demuxer_stream_(NULL),
@@ -38,6 +41,10 @@
       weak_factory_(this) {
 }
 
+std::string DecryptingDemuxerStream::GetDisplayName() const {
+  return "DecryptingDemuxerStream";
+}
+
 void DecryptingDemuxerStream::Initialize(DemuxerStream* stream,
                                          const PipelineStatusCB& status_cb) {
   DVLOG(2) << __FUNCTION__;
@@ -139,7 +146,7 @@
 }
 
 VideoRotation DecryptingDemuxerStream::video_rotation() {
-  return VIDEO_ROTATION_0;
+  return demuxer_stream_->video_rotation();
 }
 
 DecryptingDemuxerStream::~DecryptingDemuxerStream() {
@@ -176,6 +183,7 @@
   set_decryptor_ready_cb_.Reset();
 
   if (!decryptor) {
+    MEDIA_LOG(DEBUG, media_log_) << GetDisplayName() << ": decryptor not set";
     state_ = kUninitialized;
     base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
     decryptor_attached_cb.Run(false);
@@ -295,6 +303,7 @@
 
   if (status == Decryptor::kError) {
     DVLOG(2) << "DoDeliverBuffer() - kError";
+    MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": decrypt error";
     pending_buffer_to_decrypt_ = NULL;
     state_ = kIdle;
     base::ResetAndReturn(&read_cb_).Run(kAborted, NULL);
@@ -303,6 +312,7 @@
 
   if (status == Decryptor::kNoKey) {
     DVLOG(2) << "DoDeliverBuffer() - kNoKey";
+    MEDIA_LOG(DEBUG, media_log_) << GetDisplayName() << ": no key";
     if (need_to_try_again_if_nokey) {
       // The |state_| is still kPendingDecrypt.
       DecryptPendingBuffer();
diff --git a/media/filters/decrypting_demuxer_stream.h b/media/filters/decrypting_demuxer_stream.h
index e8d82224..a04709e 100644
--- a/media/filters/decrypting_demuxer_stream.h
+++ b/media/filters/decrypting_demuxer_stream.h
@@ -21,6 +21,7 @@
 namespace media {
 
 class DecoderBuffer;
+class MediaLog;
 
 // Decryptor-based DemuxerStream implementation that converts a potentially
 // encrypted demuxer stream to a clear demuxer stream.
@@ -30,6 +31,7 @@
  public:
   DecryptingDemuxerStream(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+      const scoped_refptr<MediaLog>& media_log,
       const SetDecryptorReadyCB& set_decryptor_ready_cb,
       const base::Closure& waiting_for_decryption_key_cb);
 
@@ -45,6 +47,9 @@
   // kUninitialized if |this| hasn't been initialized, or to kIdle otherwise.
   void Reset(const base::Closure& closure);
 
+  // Returns the name of this class for logging purpose.
+  std::string GetDisplayName() const;
+
   // DemuxerStream implementation.
   void Read(const ReadCB& read_cb) override;
   AudioDecoderConfig audio_decoder_config() override;
@@ -100,6 +105,8 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
+  scoped_refptr<MediaLog> media_log_;
+
   State state_;
 
   PipelineStatusCB init_cb_;
diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc
index e5d2567f..63de9df 100644
--- a/media/filters/decrypting_demuxer_stream_unittest.cc
+++ b/media/filters/decrypting_demuxer_stream_unittest.cc
@@ -75,6 +75,7 @@
   DecryptingDemuxerStreamTest()
       : demuxer_stream_(new DecryptingDemuxerStream(
             message_loop_.message_loop_proxy(),
+            new MediaLog(),
             base::Bind(
                 &DecryptingDemuxerStreamTest::RequestDecryptorNotification,
                 base::Unretained(this)),
@@ -88,8 +89,7 @@
             new StrictMock<MockDemuxerStream>(DemuxerStream::VIDEO)),
         clear_buffer_(CreateFakeEncryptedStreamBuffer(true)),
         encrypted_buffer_(CreateFakeEncryptedStreamBuffer(false)),
-        decrypted_buffer_(new DecoderBuffer(kFakeBufferSize)) {
-  }
+        decrypted_buffer_(new DecoderBuffer(kFakeBufferSize)) {}
 
   virtual ~DecryptingDemuxerStreamTest() {
     if (is_decryptor_set_)
diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_video_decoder.cc
index 3627080..19e62b3 100644
--- a/media/filters/decrypting_video_decoder.cc
+++ b/media/filters/decrypting_video_decoder.cc
@@ -12,6 +12,7 @@
 #include "base/trace_event/trace_event.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_log.h"
 #include "media/base/pipeline.h"
 #include "media/base/video_frame.h"
 
@@ -21,9 +22,11 @@
 
 DecryptingVideoDecoder::DecryptingVideoDecoder(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    const scoped_refptr<MediaLog>& media_log,
     const SetDecryptorReadyCB& set_decryptor_ready_cb,
     const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
+      media_log_(media_log),
       state_(kUninitialized),
       waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
       set_decryptor_ready_cb_(set_decryptor_ready_cb),
@@ -164,6 +167,7 @@
   set_decryptor_ready_cb_.Reset();
 
   if (!decryptor) {
+    MEDIA_LOG(DEBUG, media_log_) << GetDisplayName() << ": no decryptor set";
     base::ResetAndReturn(&init_cb_).Run(false);
     state_ = kError;
     decryptor_attached_cb.Run(false);
@@ -189,6 +193,8 @@
   DCHECK(decode_cb_.is_null());  // No Decode() before initialization finished.
 
   if (!success) {
+    MEDIA_LOG(DEBUG, media_log_) << GetDisplayName()
+                                 << ": failed to init decoder on decryptor";
     base::ResetAndReturn(&init_cb_).Run(false);
     decryptor_ = NULL;
     state_ = kError;
@@ -253,6 +259,7 @@
 
   if (status == Decryptor::kError) {
     DVLOG(2) << "DeliverFrame() - kError";
+    MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": decode error";
     state_ = kError;
     base::ResetAndReturn(&decode_cb_).Run(kDecodeError);
     return;
@@ -260,6 +267,8 @@
 
   if (status == Decryptor::kNoKey) {
     DVLOG(2) << "DeliverFrame() - kNoKey";
+    MEDIA_LOG(DEBUG, media_log_) << GetDisplayName() << ": no key";
+
     // Set |pending_buffer_to_decode_| back as we need to try decoding the
     // pending buffer again when new key is added to the decryptor.
     pending_buffer_to_decode_ = scoped_pending_buffer_to_decode;
@@ -285,7 +294,7 @@
 
   DCHECK_EQ(status, Decryptor::kSuccess);
   // No frame returned with kSuccess should be end-of-stream frame.
-  DCHECK(!frame->IsEndOfStream());
+  DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
   output_cb_.Run(frame);
 
   if (scoped_pending_buffer_to_decode->end_of_stream()) {
diff --git a/media/filters/decrypting_video_decoder.h b/media/filters/decrypting_video_decoder.h
index fda546e8f..80b3b81 100644
--- a/media/filters/decrypting_video_decoder.h
+++ b/media/filters/decrypting_video_decoder.h
@@ -19,6 +19,7 @@
 
 class DecoderBuffer;
 class Decryptor;
+class MediaLog;
 
 // Decryptor-based VideoDecoder implementation that can decrypt and decode
 // encrypted video buffers and return decrypted and decompressed video frames.
@@ -28,6 +29,7 @@
  public:
   DecryptingVideoDecoder(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+      const scoped_refptr<MediaLog>& media_log,
       const SetDecryptorReadyCB& set_decryptor_ready_cb,
       const base::Closure& waiting_for_decryption_key_cb);
   ~DecryptingVideoDecoder() override;
@@ -83,6 +85,8 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
+  scoped_refptr<MediaLog> media_log_;
+
   State state_;
 
   InitCB init_cb_;
diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc
index bc3f93a..c76cf07 100644
--- a/media/filters/decrypting_video_decoder_unittest.cc
+++ b/media/filters/decrypting_video_decoder_unittest.cc
@@ -55,6 +55,7 @@
   DecryptingVideoDecoderTest()
       : decoder_(new DecryptingVideoDecoder(
             message_loop_.message_loop_proxy(),
+            new MediaLog(),
             base::Bind(
                 &DecryptingVideoDecoderTest::RequestDecryptorNotification,
                 base::Unretained(this)),
@@ -64,10 +65,9 @@
         num_decrypt_and_decode_calls_(0),
         num_frames_in_decryptor_(0),
         encrypted_buffer_(CreateFakeEncryptedBuffer()),
-        decoded_video_frame_(VideoFrame::CreateBlackFrame(
-            TestVideoConfig::NormalCodedSize())),
-        null_video_frame_(scoped_refptr<VideoFrame>()) {
-  }
+        decoded_video_frame_(
+            VideoFrame::CreateBlackFrame(TestVideoConfig::NormalCodedSize())),
+        null_video_frame_(scoped_refptr<VideoFrame>()) {}
 
   virtual ~DecryptingVideoDecoderTest() {
     Destroy();
diff --git a/media/filters/fake_video_decoder_unittest.cc b/media/filters/fake_video_decoder_unittest.cc
index f335c02..610987d20 100644
--- a/media/filters/fake_video_decoder_unittest.cc
+++ b/media/filters/fake_video_decoder_unittest.cc
@@ -78,7 +78,7 @@
   }
 
   void FrameReady(const scoped_refptr<VideoFrame>& frame) {
-    DCHECK(!frame->IsEndOfStream());
+    DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
     last_decoded_frame_ = frame;
     num_decoded_frames_++;
   }
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 48eaf44..bc6ae8c 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -666,6 +666,10 @@
           &FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr(), cb));
 }
 
+std::string FFmpegDemuxer::GetDisplayName() const {
+  return "FFmpegDemuxer";
+}
+
 void FFmpegDemuxer::Initialize(DemuxerHost* host,
                                const PipelineStatusCB& status_cb,
                                bool enable_text_tracks) {
@@ -783,11 +787,13 @@
                                       bool result) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   if (!blocking_thread_.IsRunning()) {
+    MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state";
     status_cb.Run(PIPELINE_ERROR_ABORT);
     return;
   }
 
   if (!result) {
+    MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": open context failed";
     status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN);
     return;
   }
@@ -808,11 +814,14 @@
                                          int result) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   if (!blocking_thread_.IsRunning() || !data_source_) {
+    MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state";
     status_cb.Run(PIPELINE_ERROR_ABORT);
     return;
   }
 
   if (result < 0) {
+    MEDIA_LOG(ERROR, media_log_) << GetDisplayName()
+                                 << ": find stream info failed";
     status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE);
     return;
   }
@@ -930,6 +939,8 @@
   }
 
   if (!audio_stream && !video_stream) {
+    MEDIA_LOG(ERROR, media_log_) << GetDisplayName()
+                                 << ": no supported streams";
     status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
     return;
   }
@@ -1083,6 +1094,7 @@
   pending_seek_ = false;
 
   if (!blocking_thread_.IsRunning()) {
+    MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state";
     cb.Run(PIPELINE_ERROR_ABORT);
     return;
   }
@@ -1285,6 +1297,7 @@
 }
 
 void FFmpegDemuxer::OnDataSourceError() {
+  MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": data source error";
   host_->OnDemuxerError(PIPELINE_ERROR_READ);
 }
 
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 329364f..98ee3b2 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -169,6 +169,7 @@
   ~FFmpegDemuxer() override;
 
   // Demuxer implementation.
+  std::string GetDisplayName() const override;
   void Initialize(DemuxerHost* host,
                   const PipelineStatusCB& status_cb,
                   bool enable_text_tracks) override;
diff --git a/media/filters/ffmpeg_glue.cc b/media/filters/ffmpeg_glue.cc
index 20ebeafa..7643f235 100644
--- a/media/filters/ffmpeg_glue.cc
+++ b/media/filters/ffmpeg_glue.cc
@@ -96,9 +96,6 @@
 
   FFmpegInitializer()
       : initialized_(false) {
-    // Before doing anything disable logging as it interferes with layout tests.
-    av_log_set_level(AV_LOG_QUIET);
-
     // Register our protocol glue code with FFmpeg.
     if (av_lockmgr_register(&LockManagerOperation) != 0)
       return;
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 160d18f2..afa3ee3 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -188,7 +188,7 @@
   }
 
   void FrameReady(const scoped_refptr<VideoFrame>& frame) {
-    DCHECK(!frame->IsEndOfStream());
+    DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
     output_frames_.push_back(frame);
   }
 
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 504ed84..20a18c5a 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -401,13 +401,15 @@
   DCHECK(decoder_texture_target_);
 
   scoped_refptr<VideoFrame> frame(VideoFrame::WrapNativeTexture(
+      VideoFrame::ARGB,
       gpu::MailboxHolder(pb.texture_mailbox(), decoder_texture_target_,
                          0 /* sync_point */),
       BindToCurrentLoop(base::Bind(
           &GpuVideoDecoder::ReleaseMailbox, weak_factory_.GetWeakPtr(),
           factories_, picture.picture_buffer_id(), pb.texture_id())),
-      pb.size(), visible_rect, natural_size, timestamp, picture.allow_overlay(),
-      true /* has_alpha */));
+      pb.size(), visible_rect, natural_size, timestamp));
+  if (picture.allow_overlay())
+    frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
   CHECK_GT(available_pictures_, 0);
   --available_pictures_;
   bool inserted =
diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc
index e360ba54..d08b6c17 100644
--- a/media/filters/source_buffer_stream_unittest.cc
+++ b/media/filters/source_buffer_stream_unittest.cc
@@ -501,7 +501,7 @@
       bool is_duration_estimated = false;
 
       // Handle splice frame starts.
-      if (StartsWithASCII(timestamps[i], "S(", true)) {
+      if (base::StartsWithASCII(timestamps[i], "S(", true)) {
         CHECK(!splice_frame);
         splice_frame = true;
         // Remove the "S(" off of the token.
diff --git a/media/filters/video_decoder_selector_unittest.cc b/media/filters/video_decoder_selector_unittest.cc
index 2471e76..aa36cffb 100644
--- a/media/filters/video_decoder_selector_unittest.cc
+++ b/media/filters/video_decoder_selector_unittest.cc
@@ -119,8 +119,9 @@
     all_decoders_.erase(
         all_decoders_.begin() + num_decoders, all_decoders_.end());
 
-    decoder_selector_.reset(new VideoDecoderSelector(
-        message_loop_.message_loop_proxy(), all_decoders_.Pass()));
+    decoder_selector_.reset(
+        new VideoDecoderSelector(message_loop_.message_loop_proxy(),
+                                 all_decoders_.Pass(), new MediaLog()));
   }
 
   void SelectDecoder() {
diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc
index 316a538..de09110 100644
--- a/media/filters/video_frame_stream_unittest.cc
+++ b/media/filters/video_frame_stream_unittest.cc
@@ -189,8 +189,10 @@
     DCHECK(pending_read_);
     frame_read_ = frame;
     last_read_status_ = status;
-    if (frame.get() && !frame->IsEndOfStream())
+    if (frame.get() &&
+        !frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) {
       num_decoded_frames_++;
+    }
     pending_read_ = false;
   }
 
@@ -223,7 +225,9 @@
   void ReadAllFrames() {
     do {
       ReadOneFrame();
-    } while (frame_read_.get() && !frame_read_->IsEndOfStream());
+    } while (frame_read_.get() &&
+             !frame_read_->metadata()->IsTrue(
+                 VideoFrameMetadata::END_OF_STREAM));
 
     const int total_num_frames = kNumConfigs * kNumBuffersInOneConfig;
     DCHECK_EQ(num_decoded_frames_, total_num_frames);
@@ -576,7 +580,8 @@
 
   // The read output should indicate end of stream.
   ASSERT_TRUE(frame_read_.get());
-  EXPECT_TRUE(frame_read_->IsEndOfStream());
+  EXPECT_TRUE(
+      frame_read_->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
 }
 
 // No Reset() before initialization is successfully completed.
diff --git a/media/filters/video_renderer_algorithm.cc b/media/filters/video_renderer_algorithm.cc
index d29cad8..bbb4864 100644
--- a/media/filters/video_renderer_algorithm.cc
+++ b/media/filters/video_renderer_algorithm.cc
@@ -69,28 +69,24 @@
   // to Render().  If so, we assume the last frame provided was rendered during
   // those intervals and adjust its render count appropriately.
   AccountForMissedIntervals(deadline_min, deadline_max);
-  last_deadline_max_ = deadline_max;
 
   // Step 3: Update the wall clock timestamps and frame duration estimates for
   // all frames currently in the |frame_queue_|.
-  if (!UpdateFrameStatistics()) {
-    DVLOG(2) << "Failed to update frame statistics.";
-
+  UpdateFrameStatistics();
+  const bool have_known_duration = average_frame_duration_ > base::TimeDelta();
+  if (!(was_time_moving_ && have_known_duration)) {
     ReadyFrame& ready_frame = frame_queue_[last_frame_index_];
     DCHECK(ready_frame.frame);
 
     // If duration is unknown, we don't have enough frames to make a good guess
     // about which frame to use, so always choose the first.
-    if (average_frame_duration_ == base::TimeDelta() &&
-        !ready_frame.start_time.is_null()) {
+    if (was_time_moving_ && !have_known_duration)
       ++ready_frame.render_count;
-    }
 
     return ready_frame.frame;
   }
 
-  DCHECK_GT(average_frame_duration_, base::TimeDelta());
-
+  last_deadline_max_ = deadline_max;
   base::TimeDelta selected_frame_drift;
 
   // Step 4: Attempt to find the best frame by cadence.
@@ -250,9 +246,10 @@
   if (deadline > last_deadline_max_)
     last_deadline_max_ = deadline;
 
-  if (!UpdateFrameStatistics() || frame_queue_.size() < 2)
+  if (frame_queue_.size() < 2)
     return 0;
 
+  UpdateFrameStatistics();
   DCHECK_GT(average_frame_duration_, base::TimeDelta());
 
   // Finds and removes all frames which are too old to be used; I.e., the end of
@@ -308,6 +305,7 @@
   first_frame_ = true;
   cadence_frame_counter_ = 0;
   last_render_ignored_cadence_frame_ = false;
+  was_time_moving_ = false;
 
   // Default to ATSC IS/191 recommendations for maximum acceptable drift before
   // we have enough frames to base the maximum on frame duration.
@@ -355,7 +353,7 @@
 void VideoRendererAlgorithm::EnqueueFrame(
     const scoped_refptr<VideoFrame>& frame) {
   DCHECK(frame);
-  DCHECK(!frame->IsEndOfStream());
+  DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
 
   ReadyFrame ready_frame(frame);
   auto it = frame_queue_.empty() ? frame_queue_.end()
@@ -414,7 +412,7 @@
     base::TimeTicks deadline_min,
     base::TimeTicks deadline_max) {
   if (last_deadline_max_.is_null() || deadline_min <= last_deadline_max_ ||
-      !have_rendered_frames_) {
+      !have_rendered_frames_ || !was_time_moving_) {
     return;
   }
 
@@ -445,7 +443,7 @@
   ready_frame.render_count += render_cycle_count;
 }
 
-bool VideoRendererAlgorithm::UpdateFrameStatistics() {
+void VideoRendererAlgorithm::UpdateFrameStatistics() {
   DCHECK(!frame_queue_.empty());
 
   // Figure out all current ready frame times at once.
@@ -454,10 +452,9 @@
   for (const auto& ready_frame : frame_queue_)
     media_timestamps.push_back(ready_frame.frame->timestamp());
 
-  // If time has stopped, we can bail out early.
   std::vector<base::TimeTicks> wall_clock_times;
-  if (!wall_clock_time_cb_.Run(media_timestamps, &wall_clock_times))
-    return false;
+  was_time_moving_ =
+      wall_clock_time_cb_.Run(media_timestamps, &wall_clock_times);
 
   // Transfer the converted wall clock times into our frame queue.
   DCHECK_EQ(wall_clock_times.size(), frame_queue_.size());
@@ -473,7 +470,7 @@
   frame_queue_.back().start_time = wall_clock_times.back();
 
   if (!frame_duration_calculator_.count())
-    return false;
+    return;
 
   // Compute |average_frame_duration_|, a moving average of the last few frames;
   // see kMovingAverageSamples for the exact number.
@@ -496,7 +493,7 @@
   // If we were called via RemoveExpiredFrames() and Render() was never called,
   // we may not have a render interval yet.
   if (render_interval_ == base::TimeDelta())
-    return true;
+    return;
 
   const bool cadence_changed = cadence_estimator_.UpdateCadenceEstimate(
       render_interval_, average_frame_duration_, max_acceptable_drift_);
@@ -504,15 +501,10 @@
   // No need to update cadence if there's been no change; cadence will be set
   // as frames are added to the queue.
   if (!cadence_changed)
-    return true;
+    return;
 
   cadence_frame_counter_ = 0;
   UpdateCadenceForFrames();
-
-  // Thus far there appears to be no need for special 3:2 considerations, the
-  // smoothness scores seem to naturally fit that pattern based on maximizing
-  // frame coverage.
-  return true;
 }
 
 void VideoRendererAlgorithm::UpdateCadenceForFrames() {
diff --git a/media/filters/video_renderer_algorithm.h b/media/filters/video_renderer_algorithm.h
index 4a3da250..71d251f4 100644
--- a/media/filters/video_renderer_algorithm.h
+++ b/media/filters/video_renderer_algorithm.h
@@ -117,6 +117,10 @@
   // be counted as effective.
   size_t EffectiveFramesQueued() const;
 
+  // Tells the algorithm that Render() callbacks have been suspended for a known
+  // reason and such stoppage shouldn't be counted against future frames.
+  void set_time_stopped() { was_time_moving_ = false; }
+
   size_t frames_queued() const { return frame_queue_.size(); }
 
   // Returns the average of the duration of all frames in |frame_queue_|
@@ -175,9 +179,8 @@
                                  base::TimeTicks deadline_max);
 
   // Updates the render count and wall clock timestamps for all frames in
-  // |frame_queue_|. Returns false if statistics can't be updated at this time;
-  // which occurs if media time has stopped or there are not enough frames to
-  // calculate an average frame duration.  Updates |cadence_estimator_|.
+  // |frame_queue_|.  Updates |was_time_stopped_|, |cadence_estimator_| and
+  // |frame_duration_calculator_|.
   //
   // Note: Wall clock time is recomputed each Render() call because it's
   // expected that the TimeSource powering TimeSource::WallClockTimeCB will skew
@@ -186,7 +189,7 @@
   // TODO(dalecurtis): Investigate how accurate we need the wall clock times to
   // be, so we can avoid recomputing every time (we would need to recompute when
   // playback rate changes occur though).
-  bool UpdateFrameStatistics();
+  void UpdateFrameStatistics();
 
   // Updates the ideal render count for all frames in |frame_queue_| based on
   // the cadence returned by |cadence_estimator_|.  Cadence is assigned based
@@ -304,6 +307,11 @@
   // by cadence in favor of one by drift or coverage.
   bool last_render_ignored_cadence_frame_;
 
+  // Indicates if time was moving, set to the return value from
+  // UpdateFrameStatistics() during Render() or externally by
+  // set_time_stopped().
+  bool was_time_moving_;
+
   DISALLOW_COPY_AND_ASSIGN(VideoRendererAlgorithm);
 };
 
diff --git a/media/filters/video_renderer_algorithm_unittest.cc b/media/filters/video_renderer_algorithm_unittest.cc
index d8b2eb0..9f2a033 100644
--- a/media/filters/video_renderer_algorithm_unittest.cc
+++ b/media/filters/video_renderer_algorithm_unittest.cc
@@ -385,6 +385,40 @@
   ASSERT_TRUE(frame);
   EXPECT_EQ(tg.interval(3), frame->timestamp());
   EXPECT_EQ(0u, frames_dropped);
+  EXPECT_EQ(1, GetCurrentFrameDisplayCount());
+
+  // Stop the time source and verify AccountForMissedIntervals() doesn't try to
+  // account for intervals from pause behavior.
+  time_source_.StopTicking();
+  frame = RenderAndStep(&tg, &frames_dropped);
+  ASSERT_TRUE(frame);
+  EXPECT_EQ(tg.interval(3), frame->timestamp());
+  EXPECT_EQ(0u, frames_dropped);
+  EXPECT_EQ(1, GetCurrentFrameDisplayCount());
+
+  tg.step(100);
+  frame = RenderAndStep(&tg, &frames_dropped);
+  ASSERT_TRUE(frame);
+  EXPECT_EQ(tg.interval(3), frame->timestamp());
+  EXPECT_EQ(0u, frames_dropped);
+  EXPECT_EQ(1, GetCurrentFrameDisplayCount());
+
+  time_source_.StartTicking();
+
+  // Now run the same test using set_time_stopped();
+  frame = RenderAndStep(&tg, &frames_dropped);
+  ASSERT_TRUE(frame);
+  EXPECT_EQ(tg.interval(3), frame->timestamp());
+  EXPECT_EQ(0u, frames_dropped);
+  EXPECT_EQ(2, GetCurrentFrameDisplayCount());
+
+  algorithm_.set_time_stopped();
+  tg.step(100);
+  frame = RenderAndStep(&tg, &frames_dropped);
+  ASSERT_TRUE(frame);
+  EXPECT_EQ(tg.interval(3), frame->timestamp());
+  EXPECT_EQ(0u, frames_dropped);
+  EXPECT_EQ(3, GetCurrentFrameDisplayCount());
 }
 
 TEST_F(VideoRendererAlgorithmTest, OnLastFrameDropped) {
@@ -1004,6 +1038,9 @@
 TEST_F(VideoRendererAlgorithmTest, RemoveExpiredFrames) {
   TickGenerator tg(tick_clock_->NowTicks(), 50);
 
+  // Removing expired frames before anything is enqueued should do nothing.
+  ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
+
   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
   EXPECT_EQ(1u, algorithm_.EffectiveFramesQueued());
@@ -1201,6 +1238,7 @@
       RenderAndStep(&tg, &frames_dropped);
   EXPECT_EQ(1u, frames_queued());
   EXPECT_EQ(frame_1, rendered_frame);
+  EXPECT_EQ(1, GetCurrentFrameDisplayCount());
 
   // The replaced frame should count as dropped.
   EXPECT_EQ(1u, frames_dropped);
@@ -1213,6 +1251,7 @@
   EXPECT_EQ(1u, frames_queued());
   EXPECT_EQ(frame_1, rendered_frame);
   EXPECT_EQ(1u, frames_dropped);
+  EXPECT_EQ(2, GetCurrentFrameDisplayCount());
 
   // Trying to add a frame < 1 ms after the last frame should drop the frame.
   algorithm_.EnqueueFrame(CreateFrame(base::TimeDelta::FromMicroseconds(999)));
@@ -1220,6 +1259,7 @@
   EXPECT_EQ(1u, frames_queued());
   EXPECT_EQ(frame_1, rendered_frame);
   EXPECT_EQ(1u, frames_dropped);
+  EXPECT_EQ(3, GetCurrentFrameDisplayCount());
 
   scoped_refptr<VideoFrame> frame_3 = CreateFrame(tg.interval(1));
   algorithm_.EnqueueFrame(frame_3);
@@ -1232,6 +1272,7 @@
   EXPECT_EQ(1u, frames_queued());
   EXPECT_EQ(frame_3, rendered_frame);
   EXPECT_EQ(1u, frames_dropped);
+  EXPECT_EQ(1, GetCurrentFrameDisplayCount());
 }
 
 TEST_F(VideoRendererAlgorithmTest, CadenceForFutureFrames) {
diff --git a/media/filters/vp8_bool_decoder_unittest.cc b/media/filters/vp8_bool_decoder_unittest.cc
index 83fdfbc..4c741828 100644
--- a/media/filters/vp8_bool_decoder_unittest.cc
+++ b/media/filters/vp8_bool_decoder_unittest.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "media/filters/vp8_bool_decoder.h"
+
+#include <limits>
+
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace media {
@@ -110,7 +113,8 @@
 
   for (size_t i = 0; i < NUM_BITS_TO_TEST; ++i) {
     bool out = !(i & 1);
-    ASSERT_TRUE(bd_.ReadBool(&out, static_cast<int>(i)));
+    ASSERT_LE(i, std::numeric_limits<uint8_t>::max());
+    ASSERT_TRUE(bd_.ReadBool(&out, static_cast<uint8_t>(i)));
     EXPECT_EQ(out, !!(i & 1));
   }
 }
diff --git a/media/formats/mp2t/timestamp_unroller_unittest.cc b/media/formats/mp2t/timestamp_unroller_unittest.cc
index 1805728..93c214d 100644
--- a/media/formats/mp2t/timestamp_unroller_unittest.cc
+++ b/media/formats/mp2t/timestamp_unroller_unittest.cc
@@ -6,7 +6,6 @@
 #include <vector>
 
 #include "base/logging.h"
-#include "base/port.h"
 #include "base/test/perf_test_suite.h"
 #include "media/formats/mp2t/timestamp_unroller.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index 9c605fa..ecc1b8d 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -34,7 +34,8 @@
       audio_object_types_(audio_object_types),
       has_sbr_(has_sbr),
       is_audio_track_encrypted_(false),
-      is_video_track_encrypted_(false) {
+      is_video_track_encrypted_(false),
+      num_top_level_box_skipped_(0) {
 }
 
 MP4StreamParser::~MP4StreamParser() {}
@@ -159,8 +160,14 @@
     // before the head of the 'moof', so keeping this box around is sufficient.)
     return !(*err);
   } else {
-    MEDIA_LOG(DEBUG, log_cb_) << "Skipping unrecognized top-level box: "
-                              << FourCCToString(reader->type());
+    const int kMaxNumLogsForSkippingTopLevelBox = 5;
+
+    // TODO(wolenetz): Do not log when skipping ftyp, since strict MSE would
+    // require ftyp. See http://crbug.com/499077
+    LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_top_level_box_skipped_,
+                      kMaxNumLogsForSkippingTopLevelBox)
+        << "Skipping unrecognized top-level box: "
+        << FourCCToString(reader->type());
   }
 
   queue_.Pop(reader->size());
diff --git a/media/formats/mp4/mp4_stream_parser.h b/media/formats/mp4/mp4_stream_parser.h
index 3760209..a5e9f62 100644
--- a/media/formats/mp4/mp4_stream_parser.h
+++ b/media/formats/mp4/mp4_stream_parser.h
@@ -131,6 +131,10 @@
   bool is_audio_track_encrypted_;
   bool is_video_track_encrypted_;
 
+  // Tracks the number of MEDIA_LOGs for skipping top level boxes. Useful to
+  // prevent log spam.
+  int num_top_level_box_skipped_;
+
   DISALLOW_COPY_AND_ASSIGN(MP4StreamParser);
 };
 
diff --git a/media/media.gyp b/media/media.gyp
index 4427bf0..0f90a57 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -322,10 +322,8 @@
         'base/media_log_event.h',
         'base/media_permission.cc',
         'base/media_permission.h',
-        'base/media_posix.cc',
         'base/media_switches.cc',
         'base/media_switches.h',
-        'base/media_win.cc',
         'base/mime_util.cc',
         'base/mime_util.h',
         'base/moving_average.cc',
@@ -621,7 +619,6 @@
             'base/container_names.h',
             'base/media_file_checker.cc',
             'base/media_file_checker.h',
-            'base/media_posix.cc',
             'ffmpeg/ffmpeg_common.cc',
             'ffmpeg/ffmpeg_common.h',
             'filters/audio_file_reader.cc',
@@ -690,7 +687,6 @@
           'sources': [
             'base/media.cc',
             'base/media.h',
-            'base/media_stub.cc',
           ],
           'sources!': [
             'filters/opus_audio_decoder.cc',
@@ -1253,7 +1249,7 @@
             'test/pipeline_integration_test_base.cc',
           ],
         }],
-        ['os_posix==1 and OS!="mac"', {
+        ['(os_posix==1 and OS!="mac") or (OS=="win" and component!="shared_library" and win_use_allocator_shim==1)', {
           'conditions': [
             ['use_allocator!="none"', {
               'dependencies': [
diff --git a/media/media_nacl.gyp b/media/media_nacl.gyp
index 9697a8a..f345376 100644
--- a/media/media_nacl.gyp
+++ b/media/media_nacl.gyp
@@ -53,7 +53,6 @@
           'sources': [
             'base/media.cc',
             'base/media.h',
-            'base/media_stub.cc',
             'base/simd/convert_rgb_to_yuv.h',
             'base/simd/convert_rgb_to_yuv_c.cc',
             'base/simd/convert_yuv_to_rgb.h',
@@ -63,6 +62,9 @@
             'base/yuv_convert.cc',
             'base/yuv_convert.h',
           ],
+          'defines': [
+            'MEDIA_DISABLE_FFMPEG',
+          ],
         },  # end of target 'media_yuv_nacl'
       ],
     }],
diff --git a/media/media_unittests.isolate b/media/media_unittests.isolate
index 449fa88..7c0d4e4 100644
--- a/media/media_unittests.isolate
+++ b/media/media_unittests.isolate
@@ -52,31 +52,9 @@
         ],
       },
     }],
-    ['OS=="linux"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
-        ],
-      },
-    }],
-    ['OS=="mac"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
-        ],
-      },
-    }],
-    ['OS=="win"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
-        ],
-      },
-    }],
     ['OS=="mac" and asan==1 and fastbuild==0', {
       'variables': {
         'files': [
-          '<(PRODUCT_DIR)/ffmpegsumo.so.dSYM/',
           '<(PRODUCT_DIR)/media_unittests.dSYM/',
         ],
       },
diff --git a/media/midi/midi_manager_alsa.cc b/media/midi/midi_manager_alsa.cc
index a6e35e9..677287f3 100644
--- a/media/midi/midi_manager_alsa.cc
+++ b/media/midi/midi_manager_alsa.cc
@@ -14,7 +14,7 @@
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/posix/eintr_wrapper.h"
-#include "base/safe_strerror_posix.h"
+#include "base/posix/safe_strerror.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
@@ -261,12 +261,13 @@
       udev_monitor_.get(), kUdevSubsystemSound, nullptr);
   if (err != 0) {
     VLOG(1) << "udev_monitor_add_match_subsystem fails: "
-            << safe_strerror(-err);
+            << base::safe_strerror(-err);
     return CompleteInitialization(MIDI_INITIALIZATION_ERROR);
   }
   err = device::udev_monitor_enable_receiving(udev_monitor_.get());
   if (err != 0) {
-    VLOG(1) << "udev_monitor_enable_receiving fails: " << safe_strerror(-err);
+    VLOG(1) << "udev_monitor_enable_receiving fails: "
+            << base::safe_strerror(-err);
     return CompleteInitialization(MIDI_INITIALIZATION_ERROR);
   }
 
@@ -874,7 +875,7 @@
 
   int err = HANDLE_EINTR(poll(pfd, arraysize(pfd), -1));
   if (err < 0) {
-    VLOG(1) << "poll fails: " << safe_strerror(errno);
+    VLOG(1) << "poll fails: " << base::safe_strerror(errno);
     loop_again = false;
   } else {
     if (pfd[0].revents & POLLIN) {
@@ -1268,13 +1269,14 @@
                                                    kUdevSubsystemSound);
   if (err) {
     VLOG(1) << "udev_enumerate_add_match_subsystem fails: "
-            << safe_strerror(-err);
+            << base::safe_strerror(-err);
     return false;
   }
 
   err = device::udev_enumerate_scan_devices(enumerate.get());
   if (err) {
-    VLOG(1) << "udev_enumerate_scan_devices fails: " << safe_strerror(-err);
+    VLOG(1) << "udev_enumerate_scan_devices fails: "
+            << base::safe_strerror(-err);
     return false;
   }
 
diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn
index 338902b..7796db52 100644
--- a/media/mojo/services/BUILD.gn
+++ b/media/mojo/services/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//media/media_options.gni")
 import("//testing/test.gni")
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application.gni")
 
 # Target naming conventions:
 # - converters: C++/Mojo type converters.
@@ -84,6 +84,8 @@
     "mojo_cdm_promise.h",
     "mojo_cdm_service.cc",
     "mojo_cdm_service.h",
+    "mojo_cdm_service_context.cc",
+    "mojo_cdm_service_context.h",
     "mojo_type_trait.h",
   ]
 
diff --git a/media/mojo/services/mojo_cdm_service.cc b/media/mojo/services/mojo_cdm_service.cc
index 926535b..d22ab65 100644
--- a/media/mojo/services/mojo_cdm_service.cc
+++ b/media/mojo/services/mojo_cdm_service.cc
@@ -10,6 +10,7 @@
 #include "media/cdm/aes_decryptor.h"
 #include "media/mojo/services/media_type_converters.h"
 #include "media/mojo/services/mojo_cdm_promise.h"
+#include "media/mojo/services/mojo_cdm_service_context.h"
 #include "mojo/common/common_type_converters.h"
 #include "mojo/common/url_type_converters.h"
 #include "url/gurl.h"
@@ -19,23 +20,35 @@
 typedef MojoCdmPromise<> SimpleMojoCdmPromise;
 typedef MojoCdmPromise<std::string> NewSessionMojoCdmPromise;
 
+scoped_ptr<MojoCdmService> MojoCdmService::Create(
+    const mojo::String& key_system,
+    MojoCdmServiceContext* context,
+    mojo::InterfaceRequest<mojo::ContentDecryptionModule> request) {
+  // Only AesDecryptor is supported.
+  // TODO(xhwang): Use a CdmFactory to create the CDM here. See
+  // http://crbug.com/495273
+  if (!CanUseAesDecryptor(key_system))
+    return nullptr;
+
+  // TODO(xhwang): Pass security origin through.
+  return make_scoped_ptr(
+      new MojoCdmService(key_system, context, request.Pass()));
+}
+
 MojoCdmService::MojoCdmService(
     const mojo::String& key_system,
+    MojoCdmServiceContext* context,
     mojo::InterfaceRequest<mojo::ContentDecryptionModule> request)
-    : binding_(this, request.Pass()), weak_factory_(this) {
+    : binding_(this, request.Pass()), context_(context), weak_factory_(this) {
+  DVLOG(1) << __FUNCTION__ << ": " << key_system;
+  DCHECK(CanUseAesDecryptor(key_system));
+
   base::WeakPtr<MojoCdmService> weak_this = weak_factory_.GetWeakPtr();
-
-  if (CanUseAesDecryptor(key_system)) {
-    // TODO(jrummell): Determine proper origin.
-    cdm_.reset(new AesDecryptor(
-        GURL::EmptyGURL(),
-        base::Bind(&MojoCdmService::OnSessionMessage, weak_this),
-        base::Bind(&MojoCdmService::OnSessionClosed, weak_this),
-        base::Bind(&MojoCdmService::OnSessionKeysChange, weak_this)));
-  }
-
-  // TODO(xhwang): Check key system support in the app.
-  NOTREACHED();
+  cdm_.reset(new AesDecryptor(
+      GURL::EmptyGURL(),
+      base::Bind(&MojoCdmService::OnSessionMessage, weak_this),
+      base::Bind(&MojoCdmService::OnSessionClosed, weak_this),
+      base::Bind(&MojoCdmService::OnSessionKeysChange, weak_this)));
 }
 
 MojoCdmService::~MojoCdmService() {
@@ -49,9 +62,10 @@
 void MojoCdmService::SetServerCertificate(
     mojo::Array<uint8_t> certificate_data,
     const mojo::Callback<void(mojo::CdmPromiseResultPtr)>& callback) {
+  DVLOG(2) << __FUNCTION__;
   cdm_->SetServerCertificate(
       certificate_data.storage(),
-      scoped_ptr<SimpleCdmPromise>(new SimpleMojoCdmPromise(callback)));
+      make_scoped_ptr(new SimpleMojoCdmPromise(callback)));
 }
 
 void MojoCdmService::CreateSessionAndGenerateRequest(
@@ -60,10 +74,11 @@
     mojo::Array<uint8_t> init_data,
     const mojo::Callback<void(mojo::CdmPromiseResultPtr, mojo::String)>&
         callback) {
+  DVLOG(2) << __FUNCTION__;
   cdm_->CreateSessionAndGenerateRequest(
       static_cast<MediaKeys::SessionType>(session_type),
       static_cast<EmeInitDataType>(init_data_type), init_data.storage(),
-      scoped_ptr<NewSessionCdmPromise>(new NewSessionMojoCdmPromise(callback)));
+      make_scoped_ptr(new NewSessionMojoCdmPromise(callback)));
 }
 
 void MojoCdmService::LoadSession(
@@ -71,16 +86,17 @@
     const mojo::String& session_id,
     const mojo::Callback<void(mojo::CdmPromiseResultPtr, mojo::String)>&
         callback) {
-  cdm_->LoadSession(
-      static_cast<MediaKeys::SessionType>(session_type),
-      session_id.To<std::string>(),
-      scoped_ptr<NewSessionCdmPromise>(new NewSessionMojoCdmPromise(callback)));
+  DVLOG(2) << __FUNCTION__;
+  cdm_->LoadSession(static_cast<MediaKeys::SessionType>(session_type),
+                    session_id.To<std::string>(),
+                    make_scoped_ptr(new NewSessionMojoCdmPromise(callback)));
 }
 
 void MojoCdmService::UpdateSession(
     const mojo::String& session_id,
     mojo::Array<uint8_t> response,
     const mojo::Callback<void(mojo::CdmPromiseResultPtr)>& callback) {
+  DVLOG(2) << __FUNCTION__;
   cdm_->UpdateSession(
       session_id.To<std::string>(), response.storage(),
       scoped_ptr<SimpleCdmPromise>(new SimpleMojoCdmPromise(callback)));
@@ -89,17 +105,17 @@
 void MojoCdmService::CloseSession(
     const mojo::String& session_id,
     const mojo::Callback<void(mojo::CdmPromiseResultPtr)>& callback) {
-  cdm_->CloseSession(
-      session_id.To<std::string>(),
-      scoped_ptr<SimpleCdmPromise>(new SimpleMojoCdmPromise(callback)));
+  DVLOG(2) << __FUNCTION__;
+  cdm_->CloseSession(session_id.To<std::string>(),
+                     make_scoped_ptr(new SimpleMojoCdmPromise(callback)));
 }
 
 void MojoCdmService::RemoveSession(
     const mojo::String& session_id,
     const mojo::Callback<void(mojo::CdmPromiseResultPtr)>& callback) {
-  cdm_->RemoveSession(
-      session_id.To<std::string>(),
-      scoped_ptr<SimpleCdmPromise>(new SimpleMojoCdmPromise(callback)));
+  DVLOG(2) << __FUNCTION__;
+  cdm_->RemoveSession(session_id.To<std::string>(),
+                      make_scoped_ptr(new SimpleMojoCdmPromise(callback)));
 }
 
 void MojoCdmService::GetCdmContext(
@@ -108,10 +124,22 @@
   NOTIMPLEMENTED();
 }
 
+CdmContext* MojoCdmService::GetCdmContext() {
+  return cdm_->GetCdmContext();
+}
+
+void MojoCdmService::OnConnectionError() {
+  DVLOG(1) << __FUNCTION__;
+  context_->ServiceHadConnectionError(this);
+  // The above call deleted this instance, so the only safe thing to do is
+  // return.
+}
+
 void MojoCdmService::OnSessionMessage(const std::string& session_id,
                                       MediaKeys::MessageType message_type,
                                       const std::vector<uint8_t>& message,
                                       const GURL& legacy_destination_url) {
+  DVLOG(2) << __FUNCTION__;
   client_->OnSessionMessage(session_id,
                             static_cast<mojo::CdmMessageType>(message_type),
                             mojo::Array<uint8_t>::From(message),
@@ -121,6 +149,7 @@
 void MojoCdmService::OnSessionKeysChange(const std::string& session_id,
                                          bool has_additional_usable_key,
                                          CdmKeysInfo keys_info) {
+  DVLOG(2) << __FUNCTION__;
   mojo::Array<mojo::CdmKeyInformationPtr> keys_data;
   for (const auto& key : keys_info)
     keys_data.push_back(mojo::CdmKeyInformation::From(*key));
@@ -131,11 +160,13 @@
 void MojoCdmService::OnSessionExpirationUpdate(
     const std::string& session_id,
     const base::Time& new_expiry_time_sec) {
+  DVLOG(2) << __FUNCTION__;
   client_->OnSessionExpirationUpdate(session_id,
                                      new_expiry_time_sec.ToDoubleT());
 }
 
 void MojoCdmService::OnSessionClosed(const std::string& session_id) {
+  DVLOG(2) << __FUNCTION__;
   client_->OnSessionClosed(session_id);
 }
 
@@ -143,6 +174,7 @@
                                           MediaKeys::Exception exception,
                                           uint32_t system_code,
                                           const std::string& error_message) {
+  DVLOG(2) << __FUNCTION__;
   client_->OnLegacySessionError(session_id,
                                 static_cast<mojo::CdmException>(exception),
                                 system_code, error_message);
diff --git a/media/mojo/services/mojo_cdm_service.h b/media/mojo/services/mojo_cdm_service.h
index 8e1198af..73497c9 100644
--- a/media/mojo/services/mojo_cdm_service.h
+++ b/media/mojo/services/mojo_cdm_service.h
@@ -11,15 +11,26 @@
 #include "base/memory/weak_ptr.h"
 #include "media/base/media_keys.h"
 #include "media/mojo/interfaces/content_decryption_module.mojom.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
 
 namespace media {
 
+class MojoCdmServiceContext;
+
 // A mojo::ContentDecryptionModule implementation backed by a media::MediaKeys.
-class MojoCdmService : public mojo::ContentDecryptionModule {
+class MojoCdmService : public mojo::ContentDecryptionModule,
+                       public mojo::ErrorHandler {
  public:
-  MojoCdmService(const mojo::String& key_system,
-                 mojo::InterfaceRequest<mojo::ContentDecryptionModule> request);
+  // Creates a MojoCdmService for |key_system| and weakly binds it to the
+  // |request|. Returns null and drops the |request| if no MojoCdmService can be
+  // created for |key_system|. When connection error happens,
+  // ServiceHadConnectionError() will be called on the |context|.
+  static scoped_ptr<MojoCdmService> Create(
+      const mojo::String& key_system,
+      MojoCdmServiceContext* context,
+      mojo::InterfaceRequest<mojo::ContentDecryptionModule> request);
+
   ~MojoCdmService() final;
 
   // mojo::ContentDecryptionModule implementation.
@@ -47,10 +58,21 @@
   void RemoveSession(
       const mojo::String& session_id,
       const mojo::Callback<void(mojo::CdmPromiseResultPtr)>& callback) final;
+  // TODO(xhwang): Rename this to GetDecryptor in the mojom interface.
   void GetCdmContext(int32_t cdm_id,
                      mojo::InterfaceRequest<mojo::Decryptor> decryptor) final;
 
+  // Get CdmContext to be used by the media pipeline.
+  CdmContext* GetCdmContext();
+
  private:
+  MojoCdmService(const mojo::String& key_system,
+                 MojoCdmServiceContext* context,
+                 mojo::InterfaceRequest<mojo::ContentDecryptionModule> request);
+
+  // mojo::ErrorHandler implementation.
+  void OnConnectionError() override;
+
   // Callbacks for firing session events.
   void OnSessionMessage(const std::string& session_id,
                         MediaKeys::MessageType message_type,
@@ -67,8 +89,9 @@
                             uint32_t system_code,
                             const std::string& error_message);
 
-  mojo::StrongBinding<mojo::ContentDecryptionModule> binding_;
+  mojo::Binding<mojo::ContentDecryptionModule> binding_;
 
+  MojoCdmServiceContext* context_;
   scoped_ptr<MediaKeys> cdm_;
 
   mojo::ContentDecryptionModuleClientPtr client_;
diff --git a/media/mojo/services/mojo_cdm_service_context.cc b/media/mojo/services/mojo_cdm_service_context.cc
new file mode 100644
index 0000000..9140e8262
--- /dev/null
+++ b/media/mojo/services/mojo_cdm_service_context.cc
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/mojo/services/mojo_cdm_service_context.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+
+namespace media {
+
+MojoCdmServiceContext::MojoCdmServiceContext() {
+}
+
+MojoCdmServiceContext::~MojoCdmServiceContext() {
+}
+
+void MojoCdmServiceContext::CreateCdmService(
+    const mojo::String& key_system,
+    const mojo::String& security_origin,
+    int32_t cdm_id,
+    mojo::InterfaceRequest<mojo::ContentDecryptionModule> request) {
+  DVLOG(1) << __FUNCTION__ << ": " << key_system;
+
+  // TODO(xhwang): pass |security_origin| down because CdmFactory needs it.
+  scoped_ptr<MojoCdmService> cdm_service =
+      MojoCdmService::Create(key_system, this, request.Pass());
+  if (cdm_service)
+    services_.add(cdm_id, cdm_service.Pass());
+}
+
+CdmContext* MojoCdmServiceContext::GetCdmContext(int32_t cdm_id) {
+  MojoCdmService* service = services_.get(cdm_id);
+  if (!service) {
+    LOG(ERROR) << "CDM context not found: " << cdm_id;
+    return nullptr;
+  }
+
+  return service->GetCdmContext();
+}
+
+void MojoCdmServiceContext::ServiceHadConnectionError(MojoCdmService* service) {
+  for (auto it = services_.begin(); it != services_.end(); ++it) {
+    if (it->second == service) {
+      services_.erase(it);  // This destroys the |service|.
+      return;
+    }
+  }
+
+  NOTREACHED() << "Service " << service << " not found.";
+}
+
+}  // namespace media
diff --git a/media/mojo/services/mojo_cdm_service_context.h b/media/mojo/services/mojo_cdm_service_context.h
new file mode 100644
index 0000000..28bc266
--- /dev/null
+++ b/media/mojo/services/mojo_cdm_service_context.h
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_MOJO_SERVICES_MOJO_CDM_SERVICE_CONTEXT_H_
+#define MEDIA_MOJO_SERVICES_MOJO_CDM_SERVICE_CONTEXT_H_
+
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/macros.h"
+#include "media/base/cdm_context.h"
+#include "media/base/media_export.h"
+#include "media/mojo/services/mojo_cdm_service.h"
+
+namespace media {
+
+// A class that creates, owns and manages all MojoCdmService instances.
+class MEDIA_EXPORT MojoCdmServiceContext : public CdmContextProvider {
+ public:
+  MojoCdmServiceContext();
+  ~MojoCdmServiceContext() override;
+
+  // Creates a MojoCdmService for |key_system| and weakly binds it to |request|.
+  // The created MojoCdmService is owned by |this|. The request will be dropped
+  // if no MojoCdmService can be created, resulting in a connection error.
+  void CreateCdmService(
+      const mojo::String& key_system,
+      const mojo::String& security_origin,
+      int32_t cdm_id,
+      mojo::InterfaceRequest<mojo::ContentDecryptionModule> request);
+
+  // CdmContextProvider implementation.
+  // The returned CdmContext can be destroyed at any time if the pipe is
+  // disconnected.
+  // TODO(xhwang): When implementing SetCdm(), make sure we never dereference
+  // garbage. For example, use media::PlayerTracker.
+  CdmContext* GetCdmContext(int32_t cdm_id) override;
+
+  // Called when there is a connection error with |service|.
+  void ServiceHadConnectionError(MojoCdmService* service);
+
+ private:
+  // A map between CDM ID and MojoCdmService. Owns all MojoCdmService created.
+  base::ScopedPtrHashMap<int32_t, scoped_ptr<MojoCdmService>> services_;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoCdmServiceContext);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_MOJO_SERVICES_MOJO_CDM_SERVICE_CONTEXT_H_
diff --git a/media/mojo/services/renderer_config_default.cc b/media/mojo/services/renderer_config_default.cc
index 7cee1a7a..3b520ef 100644
--- a/media/mojo/services/renderer_config_default.cc
+++ b/media/mojo/services/renderer_config_default.cc
@@ -41,12 +41,7 @@
 class DefaultRendererConfig : public PlatformRendererConfig {
  public:
   DefaultRendererConfig() {
-    // TODO(dalecurtis): This will not work if the process is sandboxed...
-    if (!media::IsMediaLibraryInitialized()) {
-      base::FilePath module_dir;
-      CHECK(PathService::Get(base::DIR_EXE, &module_dir));
-      CHECK(media::InitializeMediaLibrary(module_dir));
-    }
+    InitializeMediaLibrary();
 
     // TODO(dalecurtis): We should find a single owner per process for the audio
     // manager or make it a lazy instance.  It's not safe to call Get()/Create()
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index 59f05b3..2a3c13f 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -14,12 +14,14 @@
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/single_thread_task_runner.h"
+#include "base/time/default_tick_clock.h"
 #include "media/base/audio_buffer.h"
 #include "media/base/audio_buffer_converter.h"
 #include "media/base/audio_hardware_config.h"
 #include "media/base/audio_splicer.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/demuxer_stream.h"
+#include "media/base/media_log.h"
 #include "media/filters/audio_clock.h"
 #include "media/filters/decrypting_demuxer_stream.h"
 
@@ -52,6 +54,8 @@
       audio_buffer_stream_(
           new AudioBufferStream(task_runner, decoders.Pass(), media_log)),
       hardware_config_(hardware_config),
+      media_log_(media_log),
+      tick_clock_(new base::DefaultTickClock()),
       playback_rate_(0.0),
       state_(kUninitialized),
       buffering_state_(BUFFERING_HAVE_NOTHING),
@@ -171,38 +175,59 @@
     const std::vector<base::TimeDelta>& media_timestamps,
     std::vector<base::TimeTicks>* wall_clock_times) {
   base::AutoLock auto_lock(lock_);
-  if (last_render_time_.is_null() || !stop_rendering_time_.is_null() ||
-      !playback_rate_ || buffering_state_ != BUFFERING_HAVE_ENOUGH ||
-      !sink_playing_) {
-    return false;
+  DCHECK(wall_clock_times->empty());
+
+  // When playback is paused (rate is zero), assume a rate of 1.0.
+  const double playback_rate = playback_rate_ ? playback_rate_ : 1.0;
+  const bool is_time_moving = sink_playing_ && playback_rate_ &&
+                              !last_render_time_.is_null() &&
+                              stop_rendering_time_.is_null();
+
+  // Pre-compute the time until playback of the audio buffer extents, since
+  // these values are frequently used below.
+  const base::TimeDelta time_until_front =
+      audio_clock_->TimeUntilPlayback(audio_clock_->front_timestamp());
+  const base::TimeDelta time_until_back =
+      audio_clock_->TimeUntilPlayback(audio_clock_->back_timestamp());
+
+  if (media_timestamps.empty()) {
+    // Return the current media time as a wall clock time while accounting for
+    // frames which may be in the process of play out.
+    wall_clock_times->push_back(std::min(
+        std::max(tick_clock_->NowTicks(), last_render_time_ + time_until_front),
+        last_render_time_ + time_until_back));
+    return is_time_moving;
   }
 
-  DCHECK(wall_clock_times->empty());
   wall_clock_times->reserve(media_timestamps.size());
   for (const auto& media_timestamp : media_timestamps) {
-    base::TimeDelta base_time;
-    if (media_timestamp < audio_clock_->front_timestamp()) {
-      // See notes about |media_time| values less than |base_time| in TimeSource
-      // header.
-      base_time = audio_clock_->front_timestamp();
-    } else if (media_timestamp > audio_clock_->back_timestamp()) {
-      base_time = audio_clock_->back_timestamp();
-    } else {
-      // No need to estimate time, so return the actual wallclock time.
+    // When time was or is moving and the requested media timestamp is within
+    // range of played out audio, we can provide an exact conversion.
+    if (!last_render_time_.is_null() &&
+        media_timestamp >= audio_clock_->front_timestamp() &&
+        media_timestamp <= audio_clock_->back_timestamp()) {
       wall_clock_times->push_back(
-          last_render_time_ +
-          audio_clock_->TimeUntilPlayback(media_timestamp));
+          last_render_time_ + audio_clock_->TimeUntilPlayback(media_timestamp));
       continue;
     }
 
+    base::TimeDelta base_timestamp, time_until_playback;
+    if (media_timestamp < audio_clock_->front_timestamp()) {
+      base_timestamp = audio_clock_->front_timestamp();
+      time_until_playback = time_until_front;
+    } else {
+      base_timestamp = audio_clock_->back_timestamp();
+      time_until_playback = time_until_back;
+    }
+
     // In practice, most calls will be estimates given the relatively small
     // window in which clients can get the actual time.
-    wall_clock_times->push_back(
-        last_render_time_ + audio_clock_->TimeUntilPlayback(base_time) +
-        base::TimeDelta::FromMicroseconds(
-            (media_timestamp - base_time).InMicroseconds() / playback_rate_));
+    wall_clock_times->push_back(last_render_time_ + time_until_playback +
+                                (media_timestamp - base_timestamp) /
+                                    playback_rate);
   }
-  return true;
+
+  return is_time_moving;
 }
 
 TimeSource* AudioRendererImpl::GetTimeSource() {
@@ -596,10 +621,11 @@
   int frames_written = 0;
   {
     base::AutoLock auto_lock(lock_);
-    last_render_time_ = base::TimeTicks::Now();
+    last_render_time_ = tick_clock_->NowTicks();
 
     if (!stop_rendering_time_.is_null()) {
-      // TODO(dalecurtis): Use |stop_rendering_time_| to advance the AudioClock.
+      audio_clock_->CompensateForSuspendedWrites(
+          last_render_time_ - stop_rendering_time_, delay_frames);
       stop_rendering_time_ = base::TimeTicks();
     }
 
@@ -709,6 +735,9 @@
   // OnRenderError() should be removed and the audio stack handle errors without
   // notifying clients. See http://crbug.com/234708 for details.
   HistogramRendererEvent(RENDER_ERROR);
+
+  MEDIA_LOG(ERROR, media_log_) << "audio render error";
+
   // Post to |task_runner_| as this is called on the audio callback thread.
   task_runner_->PostTask(FROM_HERE,
                          base::Bind(error_cb_, PIPELINE_ERROR_DECODE));
@@ -731,14 +760,17 @@
         return;
       }
 
+      MEDIA_LOG(ERROR, media_log_) << "audio decode error during flushing";
       error_cb_.Run(status);
       base::ResetAndReturn(&flush_cb_).Run();
       return;
 
     case kFlushed:
     case kPlaying:
-      if (status != PIPELINE_OK)
+      if (status != PIPELINE_OK) {
+        MEDIA_LOG(ERROR, media_log_) << "audio decode error during playing";
         error_cb_.Run(status);
+      }
       return;
   }
 }
diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h
index 43d12eab..164cdbc5 100644
--- a/media/renderers/audio_renderer_impl.h
+++ b/media/renderers/audio_renderer_impl.h
@@ -36,6 +36,7 @@
 
 namespace base {
 class SingleThreadTaskRunner;
+class TickClock;
 }
 
 namespace media {
@@ -205,6 +206,8 @@
   // Interface to the hardware audio params.
   const AudioHardwareConfig& hardware_config_;
 
+  scoped_refptr<MediaLog> media_log_;
+
   // Cached copy of hardware params from |hardware_config_|.
   AudioParameters audio_parameters_;
 
@@ -217,6 +220,9 @@
   // Callback provided to Flush().
   base::Closure flush_cb_;
 
+  // Overridable tick clock for testing.
+  scoped_ptr<base::TickClock> tick_clock_;
+
   // After Initialize() has completed, all variables below must be accessed
   // under |lock_|. ------------------------------------------------------------
   base::Lock lock_;
@@ -257,7 +263,8 @@
   base::TimeTicks last_render_time_;
 
   // Set to the value of |last_render_time_| when StopRendering_Locked() is
-  // called for any reason.  Cleared by the next successful Render() call.
+  // called for any reason.  Cleared by the next successful Render() call after
+  // being used to adjust for lost time between the last call.
   base::TimeTicks stop_rendering_time_;
 
   // Set upon receipt of the first decoded buffer after a StartPlayingFrom().
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index e65dd4b..6a76435 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/format_macros.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/simple_test_tick_clock.h"
 #include "media/base/audio_buffer_converter.h"
 #include "media/base/audio_hardware_config.h"
 #include "media/base/audio_splicer.h"
@@ -60,6 +61,7 @@
   // Give the decoder some non-garbage media properties.
   AudioRendererImplTest()
       : hardware_config_(AudioParameters(), AudioParameters()),
+        tick_clock_(new base::SimpleTestTickClock()),
         demuxer_stream_(DemuxerStream::AUDIO),
         decoder_(new MockAudioDecoder()),
         ended_(false) {
@@ -98,6 +100,8 @@
                                           decoders.Pass(),
                                           hardware_config_,
                                           new MediaLog()));
+    renderer_->tick_clock_.reset(tick_clock_);
+    tick_clock_->Advance(base::TimeDelta::FromSeconds(1));
   }
 
   virtual ~AudioRendererImplTest() {
@@ -285,14 +289,34 @@
   // Attempts to consume |requested_frames| frames from |renderer_|'s internal
   // buffer. Returns true if and only if all of |requested_frames| were able
   // to be consumed.
-  bool ConsumeBufferedData(OutputFrames requested_frames) {
+  bool ConsumeBufferedData(OutputFrames requested_frames,
+                           base::TimeDelta delay) {
     scoped_ptr<AudioBus> bus =
         AudioBus::Create(kChannels, requested_frames.value);
     int frames_read = 0;
-    EXPECT_TRUE(sink_->Render(bus.get(), 0, &frames_read));
+    EXPECT_TRUE(sink_->Render(bus.get(), delay.InMilliseconds(), &frames_read));
     return frames_read == requested_frames.value;
   }
 
+  bool ConsumeBufferedData(OutputFrames requested_frames) {
+    return ConsumeBufferedData(requested_frames, base::TimeDelta());
+  }
+
+  base::TimeTicks ConvertMediaTime(base::TimeDelta timestamp,
+                                   bool* is_time_moving) {
+    std::vector<base::TimeTicks> wall_clock_times;
+    *is_time_moving = renderer_->GetWallClockTimes(
+        std::vector<base::TimeDelta>(1, timestamp), &wall_clock_times);
+    return wall_clock_times[0];
+  }
+
+  base::TimeTicks CurrentMediaWallClockTime(bool* is_time_moving) {
+    std::vector<base::TimeTicks> wall_clock_times;
+    *is_time_moving = renderer_->GetWallClockTimes(
+        std::vector<base::TimeDelta>(), &wall_clock_times);
+    return wall_clock_times[0];
+  }
+
   OutputFrames frames_buffered() {
     return OutputFrames(renderer_->algorithm_->frames_buffered());
   }
@@ -334,6 +358,7 @@
   scoped_ptr<AudioRendererImpl> renderer_;
   scoped_refptr<FakeAudioRendererSink> sink_;
   AudioHardwareConfig hardware_config_;
+  base::SimpleTestTickClock* tick_clock_;
 
  private:
   void DecodeDecoder(const scoped_refptr<DecoderBuffer>& buffer,
@@ -516,10 +541,6 @@
   WaitForPendingRead();
   StopTicking();
 
-  // After time stops ticking wall clock times should not be returned.
-  EXPECT_FALSE(
-      renderer_->GetWallClockTimes(std::vector<base::TimeDelta>(1), nullptr));
-
   // We shouldn't expect another buffering state change when flushing.
   FlushDuringPendingRead();
 }
@@ -749,4 +770,115 @@
   EXPECT_EQ(FakeAudioRendererSink::kPlaying, sink_->state());
 }
 
+TEST_F(AudioRendererImplTest, TimeSourceBehavior) {
+  Initialize();
+  Preroll();
+
+  AudioTimestampHelper timestamp_helper(kOutputSamplesPerSecond);
+  timestamp_helper.SetBaseTimestamp(base::TimeDelta());
+
+  // Prior to start, time should be shown as not moving.
+  bool is_time_moving = false;
+  EXPECT_EQ(base::TimeTicks(),
+            ConvertMediaTime(base::TimeDelta(), &is_time_moving));
+  EXPECT_FALSE(is_time_moving);
+
+  EXPECT_EQ(base::TimeTicks(), CurrentMediaWallClockTime(&is_time_moving));
+  EXPECT_FALSE(is_time_moving);
+
+  // Start ticking, but use a zero playback rate, time should still be stopped
+  // until a positive playback rate is set and the first Render() is called.
+  renderer_->SetPlaybackRate(0.0);
+  StartTicking();
+  EXPECT_EQ(base::TimeTicks(), CurrentMediaWallClockTime(&is_time_moving));
+  EXPECT_FALSE(is_time_moving);
+  renderer_->SetPlaybackRate(1.0);
+  EXPECT_EQ(base::TimeTicks(), CurrentMediaWallClockTime(&is_time_moving));
+  EXPECT_FALSE(is_time_moving);
+  renderer_->SetPlaybackRate(1.0);
+
+  // Issue the first render call to start time moving.
+  OutputFrames frames_to_consume(frames_buffered().value / 2);
+  EXPECT_TRUE(ConsumeBufferedData(frames_to_consume));
+  WaitForPendingRead();
+
+  // Time shouldn't change just yet because we've only sent the initial audio
+  // data to the hardware.
+  EXPECT_EQ(tick_clock_->NowTicks(),
+            ConvertMediaTime(base::TimeDelta(), &is_time_moving));
+  EXPECT_TRUE(is_time_moving);
+
+  // Consume some more audio data.
+  frames_to_consume = frames_buffered();
+  tick_clock_->Advance(
+      base::TimeDelta::FromSecondsD(1.0 / kOutputSamplesPerSecond));
+  EXPECT_TRUE(ConsumeBufferedData(frames_to_consume));
+
+  // Time should change now that the audio hardware has called back.
+  const base::TimeTicks wall_clock_time_zero =
+      tick_clock_->NowTicks() -
+      timestamp_helper.GetFrameDuration(frames_to_consume.value);
+  EXPECT_EQ(wall_clock_time_zero,
+            ConvertMediaTime(base::TimeDelta(), &is_time_moving));
+  EXPECT_TRUE(is_time_moving);
+
+  // The current wall clock time should change as our tick clock advances, up
+  // until we've reached the end of played out frames.
+  const int kSteps = 4;
+  const base::TimeDelta kAdvanceDelta =
+      timestamp_helper.GetFrameDuration(frames_to_consume.value) / kSteps;
+
+  for (int i = 0; i < kSteps; ++i) {
+    tick_clock_->Advance(kAdvanceDelta);
+    EXPECT_EQ(tick_clock_->NowTicks(),
+              CurrentMediaWallClockTime(&is_time_moving));
+    EXPECT_TRUE(is_time_moving);
+  }
+
+  // Converting the current media time should be relative to wall clock zero.
+  EXPECT_EQ(wall_clock_time_zero + kSteps * kAdvanceDelta,
+            ConvertMediaTime(renderer_->CurrentMediaTime(), &is_time_moving));
+  EXPECT_TRUE(is_time_moving);
+
+  // Advancing once more will exceed the amount of played out frames finally.
+  base::TimeTicks current_time = tick_clock_->NowTicks();
+  tick_clock_->Advance(
+      base::TimeDelta::FromSecondsD(1.0 / kOutputSamplesPerSecond));
+  EXPECT_EQ(current_time, CurrentMediaWallClockTime(&is_time_moving));
+  EXPECT_TRUE(is_time_moving);
+
+  StopTicking();
+  DeliverRemainingAudio();
+
+  // Elapse a lot of time between StopTicking() and the next Render() call.
+  const base::TimeDelta kOneSecond = base::TimeDelta::FromSeconds(1);
+  tick_clock_->Advance(kOneSecond);
+  StartTicking();
+
+  // Time should be stopped until the next render call.
+  EXPECT_EQ(current_time, CurrentMediaWallClockTime(&is_time_moving));
+  EXPECT_FALSE(is_time_moving);
+
+  // Consume some buffered data with a small delay.
+  base::TimeDelta delay_time = base::TimeDelta::FromMilliseconds(50);
+  frames_to_consume.value = frames_buffered().value / 16;
+  EXPECT_TRUE(ConsumeBufferedData(frames_to_consume, delay_time));
+
+  // Verify time is adjusted for the current delay.
+  current_time = tick_clock_->NowTicks() + delay_time;
+  EXPECT_EQ(current_time, CurrentMediaWallClockTime(&is_time_moving));
+  EXPECT_TRUE(is_time_moving);
+  EXPECT_EQ(current_time,
+            ConvertMediaTime(renderer_->CurrentMediaTime(), &is_time_moving));
+  EXPECT_TRUE(is_time_moving);
+
+  // Advance far enough that we shouldn't be clamped to current time (tested
+  // already above).
+  tick_clock_->Advance(kOneSecond);
+  EXPECT_EQ(
+      current_time + timestamp_helper.GetFrameDuration(frames_to_consume.value),
+      CurrentMediaWallClockTime(&is_time_moving));
+  EXPECT_TRUE(is_time_moving);
+}
+
 }  // namespace media
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc
index 2bb45472..d688ca57 100644
--- a/media/renderers/video_renderer_impl.cc
+++ b/media/renderers/video_renderer_impl.cc
@@ -36,7 +36,8 @@
   const bool disabled_via_cli =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableNewVideoRenderer);
-  return !disabled_via_cli && !StartsWithASCII(group_name, "Disabled", true);
+  return !disabled_via_cli &&
+         !base::StartsWithASCII(group_name, "Disabled", true);
 }
 
 VideoRendererImpl::VideoRendererImpl(
@@ -486,7 +487,7 @@
       return;
     }
 
-    if (frame->IsEndOfStream()) {
+    if (frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)) {
       DCHECK(!received_end_of_stream_);
       received_end_of_stream_ = true;
 
@@ -504,9 +505,45 @@
       AddReadyFrame_Locked(frame);
     }
 
+    // Background rendering updates may not be ticking fast enough by itself to
+    // remove expired frames, so give it a boost here by ensuring we don't exit
+    // the decoding cycle too early.
+    //
+    // Similarly, if we've paused for underflow, remove all frames which are
+    // before the current media time.
+    const bool have_nothing = buffering_state_ != BUFFERING_HAVE_ENOUGH;
+    const bool have_nothing_and_paused = have_nothing && !sink_started_;
+    if (was_background_rendering_ ||
+        (use_new_video_renderering_path_ && have_nothing_and_paused &&
+         drop_frames_)) {
+      base::TimeTicks expiry_time;
+      if (have_nothing_and_paused) {
+        // Use the current media wall clock time plus the frame duration since
+        // RemoveExpiredFrames() is expecting the end point of an interval (it
+        // will subtract from the given value).
+        std::vector<base::TimeTicks> current_time;
+        wall_clock_time_cb_.Run(std::vector<base::TimeDelta>(), &current_time);
+        expiry_time = current_time[0] + algorithm_->average_frame_duration();
+      } else {
+        expiry_time = tick_clock_->NowTicks();
+      }
+
+      // Prior to rendering the first frame, |have_nothing_and_paused| will be
+      // true, correspondingly the |expiry_time| will be null; in this case
+      // there's no reason to try and remove any frames.
+      if (!expiry_time.is_null()) {
+        const size_t removed_frames =
+            algorithm_->RemoveExpiredFrames(expiry_time);
+
+        // Frames removed during underflow should be counted as dropped.
+        if (have_nothing_and_paused && removed_frames)
+          frames_dropped_ += removed_frames;
+      }
+    }
+
     // Signal buffering state if we've met our conditions for having enough
     // data.
-    if (buffering_state_ != BUFFERING_HAVE_ENOUGH && HaveEnoughData_Locked()) {
+    if (have_nothing && HaveEnoughData_Locked()) {
       TransitionToHaveEnough_Locked();
       if (use_new_video_renderering_path_ && !sink_started_ &&
           !rendered_end_of_stream_) {
@@ -516,14 +553,6 @@
       }
     }
 
-    // Background rendering updates may not be ticking fast enough by itself to
-    // remove expired frames, so give it a boost here by ensuring we don't exit
-    // the decoding cycle too early.
-    if (was_background_rendering_) {
-      DCHECK(use_new_video_renderering_path_);
-      algorithm_->RemoveExpiredFrames(tick_clock_->NowTicks());
-    }
-
     // Always request more decoded video if we have capacity. This serves two
     // purposes:
     //   1) Prerolling while paused
@@ -590,7 +619,7 @@
     const scoped_refptr<VideoFrame>& frame) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   lock_.AssertAcquired();
-  DCHECK(!frame->IsEndOfStream());
+  DCHECK(!frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
 
   frames_decoded_++;
 
@@ -711,6 +740,7 @@
 void VideoRendererImpl::StopSink() {
   DCHECK(task_runner_->BelongsToCurrentThread());
   sink_->Stop();
+  algorithm_->set_time_stopped();
   sink_started_ = false;
   was_background_rendering_ = false;
 }
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc
index 75c599e..67cc3121 100644
--- a/media/renderers/video_renderer_impl_unittest.cc
+++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -716,6 +716,38 @@
   Destroy();
 }
 
+TEST_P(VideoRendererImplTest, StartPlayingFromThenFlushThenEOS) {
+  // This test is only for the new rendering path.
+  if (!GetParam())
+    return;
+
+  Initialize();
+  QueueFrames("0 30 60 90");
+
+  WaitableMessageLoopEvent event;
+  EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)));
+  EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
+      .WillOnce(RunClosure(event.GetClosure()));
+  StartPlayingFrom(0);
+  event.RunAndWait();
+
+  // Cycle ticking so that we get a non-null reference time.
+  time_source_.StartTicking();
+  time_source_.StopTicking();
+
+  // Flush and simulate a seek past EOS, where some error prevents the decoder
+  // from returning any frames.
+  EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING));
+  Flush();
+
+  StartPlayingFrom(200);
+  WaitForPendingRead();
+  SatisfyPendingReadWithEndOfStream();
+  EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
+  WaitForEnded();
+  Destroy();
+}
+
 INSTANTIATE_TEST_CASE_P(OldVideoRenderer,
                         VideoRendererImplTest,
                         testing::Values(false));
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index dcbb66d..1e891192 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -631,8 +631,7 @@
 
   void SetUp() override {
     ApplicationTestBase::SetUp();
-    if (!IsMediaLibraryInitialized())
-      InitializeMediaLibraryForTesting();
+    InitializeMediaLibrary();
   }
 
  protected:
diff --git a/media/video/capture/fake_video_capture_device.cc b/media/video/capture/fake_video_capture_device.cc
index 12a8a30..613d8a5 100644
--- a/media/video/capture/fake_video_capture_device.cc
+++ b/media/video/capture/fake_video_capture_device.cc
@@ -4,6 +4,7 @@
 
 #include "media/video/capture/fake_video_capture_device.h"
 
+#include <algorithm>
 
 #include "base/bind.h"
 #include "base/strings/stringprintf.h"
@@ -104,6 +105,7 @@
     fake_frame_.reset(new uint8[VideoFrame::AllocationSize(
         VideoFrame::I420, capture_format_.frame_size)]);
     BeepAndScheduleNextCapture(
+        base::TimeTicks::Now(),
         base::Bind(&FakeVideoCaptureDevice::CaptureUsingOwnBuffers,
                    weak_factory_.GetWeakPtr()));
   } else if (device_type_ == USING_CLIENT_BUFFERS_I420 ||
@@ -111,11 +113,13 @@
     DVLOG(1) << "starting with " << (device_type_ == USING_CLIENT_BUFFERS_I420
                                          ? "Client buffers"
                                          : "GpuMemoryBuffers");
-    BeepAndScheduleNextCapture(base::Bind(
-        &FakeVideoCaptureDevice::CaptureUsingClientBuffers,
-        weak_factory_.GetWeakPtr(), (device_type_ == USING_CLIENT_BUFFERS_I420
-                                         ? PIXEL_FORMAT_I420
-                                         : PIXEL_FORMAT_GPUMEMORYBUFFER)));
+    BeepAndScheduleNextCapture(
+        base::TimeTicks::Now(),
+        base::Bind(&FakeVideoCaptureDevice::CaptureUsingClientBuffers,
+                   weak_factory_.GetWeakPtr(),
+                   (device_type_ == USING_CLIENT_BUFFERS_I420
+                        ? PIXEL_FORMAT_I420
+                        : PIXEL_FORMAT_GPUMEMORYBUFFER)));
   } else {
     client_->OnError("Unknown Fake Video Capture Device type.");
   }
@@ -126,7 +130,8 @@
   client_.reset();
 }
 
-void FakeVideoCaptureDevice::CaptureUsingOwnBuffers() {
+void FakeVideoCaptureDevice::CaptureUsingOwnBuffers(
+    base::TimeTicks expected_execution_time) {
   DCHECK(thread_checker_.CalledOnValidThread());
   const size_t frame_size = capture_format_.ImageAllocationSize();
   memset(fake_frame_.get(), 0, frame_size);
@@ -157,12 +162,14 @@
         base::TimeTicks::Now());
   }
   BeepAndScheduleNextCapture(
+      expected_execution_time,
       base::Bind(&FakeVideoCaptureDevice::CaptureUsingOwnBuffers,
                  weak_factory_.GetWeakPtr()));
 }
 
 void FakeVideoCaptureDevice::CaptureUsingClientBuffers(
-    VideoPixelFormat pixel_format) {
+    VideoPixelFormat pixel_format,
+    base::TimeTicks expected_execution_time) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   scoped_ptr<VideoCaptureDevice::Client::Buffer> capture_buffer(
@@ -191,19 +198,29 @@
   }
 
   BeepAndScheduleNextCapture(
+      expected_execution_time,
       base::Bind(&FakeVideoCaptureDevice::CaptureUsingClientBuffers,
                  weak_factory_.GetWeakPtr(), pixel_format));
 }
 
 void FakeVideoCaptureDevice::BeepAndScheduleNextCapture(
-    const base::Closure& next_capture) {
+    base::TimeTicks expected_execution_time,
+    const base::Callback<void(base::TimeTicks)>& next_capture) {
   // Generate a synchronized beep sound every so many frames.
   if (frame_count_++ % kFakeCaptureBeepCycle == 0)
     FakeAudioInputStream::BeepOnce();
 
   // Reschedule next CaptureTask.
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE, next_capture,
-      base::TimeDelta::FromMilliseconds(kFakeCapturePeriodMs));
+  const base::TimeTicks current_time = base::TimeTicks::Now();
+  const base::TimeDelta frame_interval =
+      base::TimeDelta::FromMilliseconds(kFakeCapturePeriodMs);
+  // Don't accumulate any debt if we are lagging behind - just post the next
+  // frame immediately and continue as normal.
+  const base::TimeTicks next_execution_time =
+      std::max(current_time, expected_execution_time + frame_interval);
+  const base::TimeDelta delay = next_execution_time - current_time;
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE, base::Bind(next_capture, next_execution_time), delay);
 }
 
 }  // namespace media
diff --git a/media/video/capture/fake_video_capture_device.h b/media/video/capture/fake_video_capture_device.h
index f4a19f9..3cf45a8 100644
--- a/media/video/capture/fake_video_capture_device.h
+++ b/media/video/capture/fake_video_capture_device.h
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
+#include "base/time/time.h"
 #include "media/video/capture/video_capture_device.h"
 
 namespace media {
@@ -41,9 +42,12 @@
  private:
   static const int kFakeCapturePeriodMs = 50;
 
-  void CaptureUsingOwnBuffers();
-  void CaptureUsingClientBuffers(VideoPixelFormat pixel_format);
-  void BeepAndScheduleNextCapture(const base::Closure& next_capture);
+  void CaptureUsingOwnBuffers(base::TimeTicks expected_execution_time);
+  void CaptureUsingClientBuffers(VideoPixelFormat pixel_format,
+                                 base::TimeTicks expected_execution_time);
+  void BeepAndScheduleNextCapture(
+      base::TimeTicks expected_execution_time,
+      const base::Callback<void(base::TimeTicks)>& next_capture);
 
   // |thread_checker_| is used to check that all methods are called in the
   // correct thread that owns the object.
diff --git a/media/video/capture/file_video_capture_device.cc b/media/video/capture/file_video_capture_device.cc
index 5a45b4a..295a35b 100644
--- a/media/video/capture/file_video_capture_device.cc
+++ b/media/video/capture/file_video_capture_device.cc
@@ -249,6 +249,10 @@
     next_frame_time_ = current_time + frame_interval;
   } else {
     next_frame_time_ += frame_interval;
+    // Don't accumulate any debt if we are lagging behind - just post next frame
+    // immediately and continue as normal.
+    if (next_frame_time_ < current_time)
+      next_frame_time_ = current_time;
   }
   base::MessageLoop::current()->PostDelayedTask(
       FROM_HERE,
diff --git a/media/video/capture/video_capture_device_unittest.cc b/media/video/capture/video_capture_device_unittest.cc
index 3ae4ef5..a89385b 100644
--- a/media/video/capture/video_capture_device_unittest.cc
+++ b/media/video/capture/video_capture_device_unittest.cc
@@ -322,8 +322,7 @@
   EXPECT_EQ(last_format().frame_size.width(), width);
   EXPECT_EQ(last_format().frame_size.height(), height);
   if (last_format().pixel_format != PIXEL_FORMAT_MJPEG)
-    EXPECT_LE(static_cast<size_t>(width * height * 3 / 2),
-              last_format().ImageAllocationSize());
+    EXPECT_EQ(size.GetArea(), last_format().frame_size.GetArea());
   device->StopAndDeAllocate();
 }
 
@@ -345,6 +344,7 @@
 
   EXPECT_CALL(*client_, OnError(_)).Times(0);
 
+  const gfx::Size input_size(640, 480);
   VideoCaptureParams capture_params;
   capture_params.requested_format.frame_size.SetSize(637, 472);
   capture_params.requested_format.frame_rate = 35;
@@ -352,10 +352,10 @@
   device->AllocateAndStart(capture_params, client_.Pass());
   WaitForCapturedFrame();
   device->StopAndDeAllocate();
-  EXPECT_EQ(last_format().frame_size.width(), 640);
-  EXPECT_EQ(last_format().frame_size.height(), 480);
-  EXPECT_EQ(static_cast<size_t>(640 * 480 * 3 / 2),
-            last_format().ImageAllocationSize());
+  EXPECT_EQ(last_format().frame_size.width(), input_size.width());
+  EXPECT_EQ(last_format().frame_size.height(), input_size.height());
+  if (last_format().pixel_format != PIXEL_FORMAT_MJPEG)
+    EXPECT_EQ(input_size.GetArea(), last_format().frame_size.GetArea());
 }
 
 // Cause hangs on Windows Debug. http://crbug.com/417824
diff --git a/media/video/capture/win/video_capture_device_factory_win.cc b/media/video/capture/win/video_capture_device_factory_win.cc
index 8b018fb..8aba237 100644
--- a/media/video/capture/win/video_capture_device_factory_win.cc
+++ b/media/video/capture/win/video_capture_device_factory_win.cc
@@ -103,7 +103,7 @@
   DCHECK_EQ(BLACKLISTED_CAMERA_MAX + 1,
             static_cast<int>(arraysize(kBlacklistedCameraNames)));
   for (size_t i = 0; i < arraysize(kBlacklistedCameraNames); ++i) {
-    if (StartsWithASCII(name, kBlacklistedCameraNames[i], false)) {
+    if (base::StartsWithASCII(name, kBlacklistedCameraNames[i], false)) {
       DVLOG(1) << "Enumerated blacklisted device: " << name;
       UMA_HISTOGRAM_ENUMERATION("Media.VideoCapture.BlacklistedDevice",
           i, BLACKLISTED_CAMERA_MAX + 1);
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index fb5bec0..23a7a94 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -197,13 +197,16 @@
   }
 
   // Create the VideoFrame backed by native textures.
-  return VideoFrame::WrapYUV420NativeTextures(
+  scoped_refptr<VideoFrame> frame = VideoFrame::WrapYUV420NativeTextures(
       mailbox_holders[VideoFrame::kYPlane],
       mailbox_holders[VideoFrame::kUPlane],
       mailbox_holders[VideoFrame::kVPlane],
       base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources),
       size, video_frame->visible_rect(), video_frame->natural_size(),
-      video_frame->timestamp(), video_frame->allow_overlay());
+      video_frame->timestamp());
+  if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY))
+    frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
+  return frame;
 }
 
 // Destroy all the resources posting one task per FrameResources
diff --git a/mojo/application/public/cpp/BUILD.gn b/mojo/application/public/cpp/BUILD.gn
index 809abd9..4e10109 100644
--- a/mojo/application/public/cpp/BUILD.gn
+++ b/mojo/application/public/cpp/BUILD.gn
@@ -2,11 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_sdk.gni")
-
 # GYP version: mojo/mojo_base.gyp:mojo_application_base
 source_set("cpp") {
-  deps = [
+  public_deps = [
     ":sources",
     ":init_commandline",
   ]
@@ -15,7 +13,7 @@
 # Like the target above, but without special commandline initialization that
 # apps use.
 source_set("cpp_for_chromium") {
-  deps = [
+  public_deps = [
     ":sources",
   ]
 }
diff --git a/mojo/application/public/cpp/lazy_interface_ptr.h b/mojo/application/public/cpp/lazy_interface_ptr.h
index 090beb2..30f406e2 100644
--- a/mojo/application/public/cpp/lazy_interface_ptr.h
+++ b/mojo/application/public/cpp/lazy_interface_ptr.h
@@ -17,7 +17,7 @@
  public:
   LazyInterfacePtr() : service_provider_(nullptr) {}
 
-  LazyInterfacePtr(ServiceProvider* service_provider)
+  explicit LazyInterfacePtr(ServiceProvider* service_provider)
       : service_provider_(service_provider) {}
 
   void set_service_provider(ServiceProvider* service_provider) {
diff --git a/mojo/application/public/interfaces/BUILD.gn b/mojo/application/public/interfaces/BUILD.gn
index 525bcbf..fe107dbe 100644
--- a/mojo/application/public/interfaces/BUILD.gn
+++ b/mojo/application/public/interfaces/BUILD.gn
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
-import("$mojo_sdk_root/mojo/public/tools/bindings/mojom.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 # GYP version: mojo/mojo_base.gyp:mojo_application_bindings
diff --git a/mojo/cc/context_provider_mojo.cc b/mojo/cc/context_provider_mojo.cc
index dff9362..fc3b720 100644
--- a/mojo/cc/context_provider_mojo.cc
+++ b/mojo/cc/context_provider_mojo.cc
@@ -12,8 +12,7 @@
 
 ContextProviderMojo::ContextProviderMojo(
     ScopedMessagePipeHandle command_buffer_handle)
-    : command_buffer_handle_(command_buffer_handle.Pass()),
-      context_lost_(false) {
+    : command_buffer_handle_(command_buffer_handle.Pass()) {
 }
 
 bool ContextProviderMojo::BindToCurrentThread() {
@@ -53,9 +52,6 @@
   return &context_lock_;
 }
 
-bool ContextProviderMojo::IsContextLost() {
-  return context_lost_;
-}
 bool ContextProviderMojo::DestroyedOnMainThread() { return !context_; }
 
 ContextProviderMojo::~ContextProviderMojo() {
@@ -65,7 +61,6 @@
 }
 
 void ContextProviderMojo::ContextLost() {
-  context_lost_ = true;
 }
 
 }  // namespace mojo
diff --git a/mojo/cc/context_provider_mojo.h b/mojo/cc/context_provider_mojo.h
index 2102ef26..cc465d0 100644
--- a/mojo/cc/context_provider_mojo.h
+++ b/mojo/cc/context_provider_mojo.h
@@ -27,7 +27,6 @@
   void SetupLock() override;
   base::Lock* GetLock() override;
   Capabilities ContextCapabilities() override;
-  bool IsContextLost() override;
   void VerifyContexts() override {}
   void DeleteCachedResources() override {}
   bool DestroyedOnMainThread() override;
@@ -51,7 +50,6 @@
   ScopedMessagePipeHandle command_buffer_handle_;
   MojoGLES2Context context_;
   scoped_ptr<gpu::gles2::GLES2Interface> context_gl_;
-  bool context_lost_;
 
   base::Lock context_lock_;
 
diff --git a/mojo/converters/surfaces/surfaces_type_converters.cc b/mojo/converters/surfaces/surfaces_type_converters.cc
index f17cfea..0420b28 100644
--- a/mojo/converters/surfaces/surfaces_type_converters.cc
+++ b/mojo/converters/surfaces/surfaces_type_converters.cc
@@ -129,19 +129,15 @@
       cc::TextureDrawQuad* texture_quad =
           render_pass->CreateAndAppendDrawQuad<cc::TextureDrawQuad>();
       texture_quad->SetAll(
-          sqs,
-          input->rect.To<gfx::Rect>(),
-          input->opaque_rect.To<gfx::Rect>(),
-          input->visible_rect.To<gfx::Rect>(),
-          input->needs_blending,
-          texture_quad_state->resource_id,
+          sqs, input->rect.To<gfx::Rect>(), input->opaque_rect.To<gfx::Rect>(),
+          input->visible_rect.To<gfx::Rect>(), input->needs_blending,
+          texture_quad_state->resource_id, gfx::Size(), false,
           texture_quad_state->premultiplied_alpha,
           texture_quad_state->uv_top_left.To<gfx::PointF>(),
           texture_quad_state->uv_bottom_right.To<gfx::PointF>(),
           texture_quad_state->background_color.To<SkColor>(),
           &texture_quad_state->vertex_opacity.storage()[0],
-          texture_quad_state->y_flipped,
-          texture_quad_state->nearest_neighbor);
+          texture_quad_state->y_flipped, texture_quad_state->nearest_neighbor);
       break;
     }
     case MATERIAL_TILED_CONTENT: {
@@ -225,7 +221,9 @@
     const cc::RenderPassId& input) {
   RenderPassIdPtr pass_id(RenderPassId::New());
   pass_id->layer_id = input.layer_id;
-  pass_id->index = input.index;
+  DCHECK_LE(input.index,
+            static_cast<size_t>(std::numeric_limits<uint32_t>::max()));
+  pass_id->index = static_cast<uint32_t>(input.index);
   return pass_id.Pass();
 }
 
diff --git a/mojo/converters/surfaces/tests/surface_unittest.cc b/mojo/converters/surfaces/tests/surface_unittest.cc
index 845a9e3..355e5ee 100644
--- a/mojo/converters/surfaces/tests/surface_unittest.cc
+++ b/mojo/converters/surfaces/tests/surface_unittest.cc
@@ -111,18 +111,11 @@
   float vertex_opacity[4] = {0.1f, 0.5f, 0.4f, 0.8f};
   bool y_flipped = false;
   bool nearest_neighbor = false;
-  texture_quad->SetAll(sqs,
-                       rect,
-                       opaque_rect,
-                       visible_rect,
-                       needs_blending,
-                       resource_id,
-                       premultiplied_alpha,
-                       uv_top_left,
-                       uv_bottom_right,
-                       background_color,
-                       vertex_opacity,
-                       y_flipped,
+  bool allow_overlay = false;
+  texture_quad->SetAll(sqs, rect, opaque_rect, visible_rect, needs_blending,
+                       resource_id, gfx::Size(), allow_overlay,
+                       premultiplied_alpha, uv_top_left, uv_bottom_right,
+                       background_color, vertex_opacity, y_flipped,
                        nearest_neighbor);
 
   QuadPtr mojo_quad = Quad::From<cc::DrawQuad>(*texture_quad);
@@ -151,7 +144,7 @@
   PassPtr mojo_pass = Pass::New();
   mojo_pass->id = RenderPassId::New();
   mojo_pass->id->layer_id = 1;
-  mojo_pass->id->index = 1;
+  mojo_pass->id->index = 1u;
   mojo_pass->quads.push_back(mojo_texture_quad.Pass());
   SharedQuadStatePtr mojo_sqs = SharedQuadState::New();
   mojo_pass->shared_quad_states.push_back(mojo_sqs.Pass());
@@ -170,7 +163,7 @@
   PassPtr mojo_pass = Pass::New();
   mojo_pass->id = RenderPassId::New();
   mojo_pass->id->layer_id = 1;
-  mojo_pass->id->index = 1;
+  mojo_pass->id->index = 1u;
   mojo_pass->quads.push_back(mojo_texture_quad.Pass());
   SharedQuadStatePtr mojo_sqs = SharedQuadState::New();
   mojo_pass->shared_quad_states.push_back(mojo_sqs.Pass());
@@ -278,23 +271,16 @@
   float vertex_opacity[4] = {0.1f, 0.5f, 0.4f, 0.8f};
   bool y_flipped = false;
   bool nearest_neighbor = false;
-  texture_quad->SetAll(sqs,
-                       rect,
-                       opaque_rect,
-                       visible_rect,
-                       needs_blending,
-                       resource_id,
-                       premultiplied_alpha,
-                       uv_top_left,
-                       uv_bottom_right,
-                       background_color,
-                       vertex_opacity,
-                       y_flipped,
+  bool allow_overlay = false;
+  texture_quad->SetAll(sqs, rect, opaque_rect, visible_rect, needs_blending,
+                       resource_id, gfx::Size(), allow_overlay,
+                       premultiplied_alpha, uv_top_left, uv_bottom_right,
+                       background_color, vertex_opacity, y_flipped,
                        nearest_neighbor);
 
   PassPtr mojo_pass = Pass::From(*pass);
   ASSERT_FALSE(mojo_pass.is_null());
-  EXPECT_EQ(6, mojo_pass->id->index);
+  EXPECT_EQ(6u, mojo_pass->id->index);
   EXPECT_EQ(Rect::From(output_rect), mojo_pass->output_rect);
   EXPECT_EQ(Rect::From(damage_rect), mojo_pass->damage_rect);
   EXPECT_EQ(Transform::From(transform_to_root_target),
diff --git a/mojo/gles2/BUILD.gn b/mojo/gles2/BUILD.gn
index 83013a1..557b3d8e 100644
--- a/mojo/gles2/BUILD.gn
+++ b/mojo/gles2/BUILD.gn
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
-
 config("mojo_use_gles2") {
   defines = [ "MOJO_USE_GLES2_IMPL" ]
 }
diff --git a/mojo/gles2/command_buffer_client_impl.cc b/mojo/gles2/command_buffer_client_impl.cc
index 69336791..97ea89a4 100644
--- a/mojo/gles2/command_buffer_client_impl.cc
+++ b/mojo/gles2/command_buffer_client_impl.cc
@@ -335,4 +335,9 @@
 void CommandBufferClientImpl::SetLock(base::Lock* lock) {
 }
 
+bool CommandBufferClientImpl::IsGpuChannelLost() {
+  // This is only possible for out-of-process command buffers.
+  return false;
+}
+
 }  // namespace gles2
diff --git a/mojo/gles2/command_buffer_client_impl.h b/mojo/gles2/command_buffer_client_impl.h
index 75bcc260..16eb7b8 100644
--- a/mojo/gles2/command_buffer_client_impl.h
+++ b/mojo/gles2/command_buffer_client_impl.h
@@ -72,6 +72,7 @@
   void SetSurfaceVisible(bool visible) override;
   uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
+  bool IsGpuChannelLost() override;
 
  private:
   class SyncClientImpl;
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.cc b/mojo/gpu/mojo_gles2_impl_autogen.cc
index 2ffcbf1..f3d0131 100644
--- a/mojo/gpu/mojo_gles2_impl_autogen.cc
+++ b/mojo/gpu/mojo_gles2_impl_autogen.cc
@@ -1615,6 +1615,10 @@
 void MojoGLES2Impl::MatrixLoadIdentityCHROMIUM(GLenum matrixMode) {
   NOTREACHED() << "Unimplemented MatrixLoadIdentityCHROMIUM.";
 }
+GLenum MojoGLES2Impl::GetGraphicsResetStatusKHR() {
+  NOTREACHED() << "Unimplemented GetGraphicsResetStatusKHR.";
+  return 0;
+}
 void MojoGLES2Impl::BlendBarrierKHR() {
   NOTREACHED() << "Unimplemented BlendBarrierKHR.";
 }
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.h b/mojo/gpu/mojo_gles2_impl_autogen.h
index 8b242d7..a6746d0e 100644
--- a/mojo/gpu/mojo_gles2_impl_autogen.h
+++ b/mojo/gpu/mojo_gles2_impl_autogen.h
@@ -774,6 +774,7 @@
   void SwapInterval(GLint interval) override;
   void MatrixLoadfCHROMIUM(GLenum matrixMode, const GLfloat* m) override;
   void MatrixLoadIdentityCHROMIUM(GLenum matrixMode) override;
+  GLenum GetGraphicsResetStatusKHR() override;
   void BlendBarrierKHR() override;
 
  private:
diff --git a/mojo/mojo_application_package.gni b/mojo/mojo_application_package.gni
index f5ace4f..e520856c 100644
--- a/mojo/mojo_application_package.gni
+++ b/mojo/mojo_application_package.gni
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application.gni")
 
 # Used for mojo applications that have resources. This creates a directory
 # named output_name with the following contents:
diff --git a/mojo/public/mojo.gni b/mojo/public/mojo.gni
index f2631a0b..7b43cb33 100644
--- a/mojo/public/mojo.gni
+++ b/mojo/public/mojo.gni
@@ -27,8 +27,15 @@
   mojo_use_dart_apptest_framework = false
 }
 
+# Embedder uses Mojo application code.
+mojo_use_application_in_sdk = true
+if (defined(mojo_disable_application_in_sdk) &&
+    mojo_disable_application_in_sdk) {
+  mojo_use_application_in_sdk = false
+}
+
 # The absolute path to the directory containing the mojo public SDK (i.e., the
 # directory containing mojo/public). The build files within the Mojo public
 # SDK use this variable to allow themselves to be parameterized by the location
 # of the public SDK within a client repo.
-mojo_root = get_path_info("../..", "abspath")
+mojo_root = get_path_info("../../third_party/mojo/src/", "abspath")
diff --git a/mojo/public/mojo_application.gni b/mojo/public/mojo_application.gni
index 2c7ee4a..42e03c2e 100644
--- a/mojo/public/mojo_application.gni
+++ b/mojo/public/mojo_application.gni
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("mojo.gni")
-import("mojo_sdk.gni")
 
 # Generate a binary mojo application.The parameters of this template are those
 # of a shared library.
@@ -295,6 +293,9 @@
   # Variables:
   #   input_so: the .so file to bundle
   #   input_dex_jar: the .dex.jar file to bundle
+  #   deps / public_deps / data_deps (optional):
+  #       Dependencies. The targets that generate the .so/jar inputs should be
+  #       listed in either deps or public_deps.
   #   output_name (optional): override for the output file name
   template("mojo_android_application") {
     assert(defined(invoker.input_so))
@@ -302,7 +303,9 @@
 
     zip_action_name = "${target_name}_zip"
     zip_action_output = "$target_gen_dir/${target_name}.zip"
+    prepend_action_name = target_name
     action(zip_action_name) {
+      visibility = [ ":$prepend_action_name" ]
       script = "//build/android/gn/zip.py"
 
       inputs = [
@@ -321,6 +324,16 @@
         "--inputs=$rebase_inputs",
         "--output=$rebase_output",
       ]
+
+      if (defined(invoker.deps)) {
+        deps = invoker.deps
+      }
+      if (defined(invoker.public_deps)) {
+        public_deps = invoker.public_deps
+      }
+      if (defined(invoker.data_deps)) {
+        data_deps = invoker.data_deps
+      }
     }
 
     if (defined(invoker.output_name)) {
@@ -349,6 +362,10 @@
         "--output=$rebase_output",
         "--line=#!mojo mojo:android_handler",
       ]
+
+      public_deps = [
+        ":$zip_action_name",
+      ]
     }
   }
 }
diff --git a/mojo/public/mojo_sdk.gni b/mojo/public/mojo_sdk.gni
deleted file mode 100644
index dbed84c3..0000000
--- a/mojo/public/mojo_sdk.gni
+++ /dev/null
@@ -1,139 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# The absolute path to the directory containing the mojo public SDK (i.e., the
-# directory containing mojo/public). The build files within the Mojo public
-# SDK use this variable to allow themselves to be parameterized by the location
-# of the public SDK within a client repo.
-mojo_root = get_path_info("../..", "abspath")
-
-# Takes as input a "source_set" that includes dependencies that are relative to
-# the parent directory of the Mojo public SDK (given in |mojo_sdk_deps|).
-# Generates a source_set that has the mojo_sdk_deps added as ordinary deps
-# rebased to the current directory.
-# By default, restricts the entries that are given in invoker.deps and
-# invoker.public_deps to be only within the same file and on a small set of
-# whitelisted external dependencies. This check can be elided by setting
-# restrict_external_deps to false in the invoker. DO NOT DO THIS in
-# //mojo/public.
-#
-# Example of a mojo_sdk_source_set:
-#
-# mojo_sdk_source_set("foo") {
-#   sources = [
-#     "foo.h",
-#     "foo.cc",
-#   ]
-#
-#   # Same-file deps are specified in the ordinary way. Any external
-#   dependencies are specified the same way (although in general there should
-#   be very few of these).
-#   deps = [
-#     ":bar",
-#   ]
-#
-#   # Mojo SDK deps are specified relative to the containing directory of the
-#   SDK via mojo_sdk_deps.
-#   mojo_sdk_deps = [
-#     "mojo/public/cpp/bindings",
-#     "mojo/public/cpp/environment",
-#     "mojo/public/cpp/system",
-#   ]
-# }
-#
-template("mojo_sdk_source_set") {
-  source_set(target_name) {
-    if (defined(invoker.visibility)) {
-      visibility = invoker.visibility
-    } else {
-      visibility = [ "*" ]
-    }
-    if (defined(invoker.mojo_sdk_visibility)) {
-      foreach(sdk_target, invoker.mojo_sdk_visibility) {
-        # Check that the SDK target was not mistakenly given as an absolute
-        # path.
-        assert(get_path_info(sdk_target, "abspath") != sdk_target)
-        visibility += [ rebase_path(sdk_target, ".", mojo_root) ]
-      }
-    }
-
-    if (defined(invoker.testonly)) {
-      testonly = invoker.testonly
-    }
-
-    if (defined(invoker.sources)) {
-      sources = invoker.sources
-    }
-
-    if (defined(invoker.defines)) {
-      defines = invoker.defines
-    }
-
-    if (defined(invoker.libs)) {
-      libs = invoker.libs
-    }
-
-    public_configs =
-        [ rebase_path("mojo/public/build/config:mojo_sdk", ".", mojo_root) ]
-    if (defined(invoker.public_configs)) {
-      public_configs += invoker.public_configs
-    }
-
-    if (defined(invoker.configs)) {
-      configs += invoker.configs
-    }
-
-    if (defined(invoker.allow_circular_includes_from)) {
-      allow_circular_includes_from = invoker.allow_circular_includes_from
-    }
-
-    if (defined(invoker.public_deps) || defined(invoker.deps)) {
-      restrict_external_deps = true
-      if (defined(invoker.restrict_external_deps)) {
-        restrict_external_deps = invoker.restrict_external_deps
-      }
-    }
-
-    public_deps = []
-    if (defined(invoker.public_deps)) {
-      foreach(dep, invoker.public_deps) {
-        if (restrict_external_deps) {
-          # The only deps that are not specified relative to the location of
-          # the Mojo SDK should be on targets within the same file or on a
-          # whitelisted set of external dependencies.
-          assert(get_path_info(dep, "dir") == ".")
-        }
-        public_deps += [ dep ]
-      }
-    }
-    if (defined(invoker.mojo_sdk_public_deps)) {
-      foreach(sdk_dep, invoker.mojo_sdk_public_deps) {
-        # Check that the SDK dep was not mistakenly given as an absolute path.
-        assert(get_path_info(sdk_dep, "abspath") != sdk_dep)
-        public_deps += [ rebase_path(sdk_dep, ".", mojo_root) ]
-      }
-    }
-
-    deps = []
-    if (defined(invoker.deps)) {
-      foreach(dep, invoker.deps) {
-        if (restrict_external_deps) {
-          # The only deps that are not specified relative to the location of
-          # the Mojo SDK should be on targets within the same file or on a
-          # whitelisted set of external dependencies.
-          dep_dir = get_path_info(dep, "dir")
-          assert(dep_dir == "." || dep == "//testing/gtest")
-        }
-        deps += [ dep ]
-      }
-    }
-    if (defined(invoker.mojo_sdk_deps)) {
-      foreach(sdk_dep, invoker.mojo_sdk_deps) {
-        # Check that the SDK dep was not mistakenly given as an absolute path.
-        assert(get_path_info(sdk_dep, "abspath") != sdk_dep)
-        deps += [ rebase_path(sdk_dep, ".", mojo_root) ]
-      }
-    }
-  }
-}
diff --git a/mojo/runner/BUILD.gn b/mojo/runner/BUILD.gn
index 6ed8bb19..98325f2 100644
--- a/mojo/runner/BUILD.gn
+++ b/mojo/runner/BUILD.gn
@@ -2,12 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/ui.gni")
 import("//mojo/generate_mojo_shell_assets_list.gni")
-import("//third_party/mojo/src/mojo/public/mojo.gni")
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
-import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
+import("//mojo/public/mojo_application.gni")
 import("//testing/test.gni")
+import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 # We don't support building in the component build since mojo apps are
 # inherently components.
@@ -123,6 +121,7 @@
     "//base",
     "//base/third_party/dynamic_annotations",
     "//base:base_static",
+    "//components/devtools_service/public/cpp",
     "//components/devtools_service/public/interfaces",
     "//mojo/application/public/cpp",
     "//mojo/common:tracing_impl",
diff --git a/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java b/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java
index bf74956..2939aa5 100644
--- a/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java
+++ b/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java
@@ -23,8 +23,10 @@
         super.onCreate(savedInstanceState);
 
         String[] parameters = getIntent().getStringArrayExtra(EXTRAS);
-        for (String s : parameters) {
-            s = s.replace("\\,", ",");
+        if (parameters != null) {
+            for (String s : parameters) {
+                s = s.replace("\\,", ",");
+            }
         }
         if (Intent.ACTION_VIEW.equals(getIntent().getAction())) {
             Uri uri = getIntent().getData();
@@ -49,8 +51,6 @@
         // InitApplicationContext on the native side. Currently we can't, as PlatformViewportAndroid
         // relies on this being the activity context.
         ShellMain.ensureInitialized(this, parameters);
-
-        // TODO(eseidel): ShellMain can fail, but we're ignoring the return.
         ShellMain.start();
     }
 }
diff --git a/mojo/runner/android/apk/src/org/chromium/mojo/shell/ShellMain.java b/mojo/runner/android/apk/src/org/chromium/mojo/shell/ShellMain.java
index 4af0974..5e98130 100644
--- a/mojo/runner/android/apk/src/org/chromium/mojo/shell/ShellMain.java
+++ b/mojo/runner/android/apk/src/org/chromium/mojo/shell/ShellMain.java
@@ -6,6 +6,9 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
 import android.util.Log;
 
 import org.chromium.base.CalledByNative;
@@ -30,9 +33,8 @@
     // Directory where applications cached with the shell will be extracted.
     // TODO(sky): rename this to CACHED_APP_DIRECTORY.
     private static final String LOCAL_APP_DIRECTORY = "local_apps";
-    // The mojo_shell library is also an executable run in forked processes when running
-    // multi-process.
-    private static final String MOJO_SHELL_EXECUTABLE = "libmojo_runner.so";
+    // The key to the library to run in forked processes when running multi-process.
+    private static final String MOJO_LIB_KEY = "mojo_lib";
 
     // Name of the file containing the assets to extract. File format is a file per line.
     private static final String ASSETS_LIST_NAME = "assets_list";
@@ -69,7 +71,7 @@
     /**
      * Initializes the native system.
      **/
-    static void ensureInitialized(Context applicationContext, String[] parameters) {
+    public static void ensureInitialized(Context applicationContext, String[] parameters) {
         if (sInitialized) return;
         File localAppsDir = getLocalAppsDir(applicationContext);
         try {
@@ -79,9 +81,14 @@
                 FileHelper.extractFromAssets(
                         applicationContext, assetPath, localAppsDir, FileHelper.FileType.PERMANENT);
             }
+            ApplicationInfo ai = applicationContext.getPackageManager().getApplicationInfo(
+                    applicationContext.getPackageName(), PackageManager.GET_META_DATA);
+            Bundle bundle = ai.metaData;
+            String mojo_lib = bundle.getString(MOJO_LIB_KEY);
+
             FileHelper.createTimestampIfNecessary(timestamp);
-            File mojoShell = new File(applicationContext.getApplicationInfo().nativeLibraryDir,
-                    MOJO_SHELL_EXECUTABLE);
+            File mojoShell =
+                    new File(applicationContext.getApplicationInfo().nativeLibraryDir, mojo_lib);
 
             List<String> parametersList = new ArrayList<String>();
             // Program name.
@@ -102,11 +109,9 @@
 
     /**
      * Starts the specified application in the specified context.
-     *
-     * @return <code>true</code> if an application has been launched.
      **/
-    static boolean start() {
-        return nativeStart();
+    public static void start() {
+        nativeStart();
     }
 
     /**
@@ -135,7 +140,7 @@
     private static native void nativeInit(Context context, String mojoShellPath,
             String[] parameters, String cachedAppsDirectory, String tmpDir);
 
-    private static native boolean nativeStart();
+    private static native void nativeStart();
 
     private static native void nativeAddApplicationURL(String url);
 }
diff --git a/mojo/runner/android/main.cc b/mojo/runner/android/main.cc
index 27051872..7435fd9 100644
--- a/mojo/runner/android/main.cc
+++ b/mojo/runner/android/main.cc
@@ -182,10 +182,7 @@
   gfx::GLSurface::InitializeOneOff();
 }
 
-static jboolean Start(JNIEnv* env, jclass clazz) {
-  if (!base::CommandLine::ForCurrentProcess()->GetArgs().size())
-    return false;
-
+static void Start(JNIEnv* env, jclass clazz) {
 #if defined(MOJO_SHELL_DEBUG_URL)
   base::CommandLine::ForCurrentProcess()->AppendArg(MOJO_SHELL_DEBUG_URL);
   // Sleep for 5 seconds to give the debugger a chance to attach.
@@ -195,7 +192,6 @@
   g_shell_thread.Get().reset(new base::DelegateSimpleThread(
       g_shell_runner.Get().get(), "ShellThread"));
   g_shell_thread.Get()->Start();
-  return true;
 }
 
 static void AddApplicationURL(JNIEnv* env, jclass clazz, jstring jurl) {
@@ -207,6 +203,10 @@
   return RegisterNativesImpl(env);
 }
 
+Context* GetContext() {
+  return g_context.Get().get();
+}
+
 }  // namespace runner
 }  // namespace mojo
 
diff --git a/mojo/runner/android/main.h b/mojo/runner/android/main.h
index d09791f..ce33246 100644
--- a/mojo/runner/android/main.h
+++ b/mojo/runner/android/main.h
@@ -10,8 +10,12 @@
 namespace mojo {
 namespace runner {
 
+class Context;
+
 bool RegisterShellMain(JNIEnv* env);
 
+Context* GetContext();
+
 }  // namespace runner
 }  // namespace mojo
 
diff --git a/mojo/runner/context.cc b/mojo/runner/context.cc
index b9e85ecb..57ee11d 100644
--- a/mojo/runner/context.cc
+++ b/mojo/runner/context.cc
@@ -20,6 +20,7 @@
 #include "base/strings/string_util.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "components/devtools_service/public/cpp/switches.h"
 #include "components/devtools_service/public/interfaces/devtools_service.mojom.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_delegate.h"
@@ -174,15 +175,16 @@
 
 void InitDevToolsServiceIfNeeded(shell::ApplicationManager* manager,
                                  const base::CommandLine& command_line) {
-  if (!command_line.HasSwitch(switches::kRemoteDebuggingPort))
+  if (!command_line.HasSwitch(devtools_service::kRemoteDebuggingPort))
     return;
 
   std::string port_str =
-      command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
+      command_line.GetSwitchValueASCII(devtools_service::kRemoteDebuggingPort);
   unsigned port;
   if (!base::StringToUint(port_str, &port) || port > 65535) {
-    LOG(ERROR) << "Invalid value for switch " << switches::kRemoteDebuggingPort
-               << ": '" << port_str << "' is not a valid port number.";
+    LOG(ERROR) << "Invalid value for switch "
+               << devtools_service::kRemoteDebuggingPort << ": '" << port_str
+               << "' is not a valid port number.";
     return;
   }
 
diff --git a/mojo/runner/shell_apptest.cc b/mojo/runner/shell_apptest.cc
index a2bf37db..a675805 100644
--- a/mojo/runner/shell_apptest.cc
+++ b/mojo/runner/shell_apptest.cc
@@ -42,7 +42,7 @@
       http_server::HttpRequestPtr request,
       const Callback<void(http_server::HttpResponsePtr)>& callback) override {
     http_server::HttpResponsePtr response;
-    if (StartsWithASCII(request->relative_url, "/app", true)) {
+    if (base::StartsWithASCII(request->relative_url, "/app", true)) {
       response = http_server::CreateHttpResponse(
           200, std::string(kPingable.data, kPingable.size));
       response->content_type = "application/octet-stream";
diff --git a/mojo/runner/switches.cc b/mojo/runner/switches.cc
index 5d40080..1ed957ec 100644
--- a/mojo/runner/switches.cc
+++ b/mojo/runner/switches.cc
@@ -40,9 +40,6 @@
 // url_resolver.cc for details.
 const char kOrigin[] = "origin";
 
-// Enables remote debug over HTTP on the specified port.
-const char kRemoteDebuggingPort[] = "remote-debugging-port";
-
 // Starts tracing when the shell starts up, saving a trace file on disk after 5
 // seconds or when the shell exits.
 const char kTraceStartup[] = "trace-startup";
diff --git a/mojo/runner/switches.h b/mojo/runner/switches.h
index 3c3da600..a95a4b22 100644
--- a/mojo/runner/switches.h
+++ b/mojo/runner/switches.h
@@ -20,7 +20,6 @@
 extern const char kHelp[];
 extern const char kMapOrigin[];
 extern const char kOrigin[];
-extern const char kRemoteDebuggingPort[];
 extern const char kTraceStartup[];
 extern const char kURLMappings[];
 
diff --git a/mojo/runner/test/BUILD.gn b/mojo/runner/test/BUILD.gn
index e97f462..310dfa9 100644
--- a/mojo/runner/test/BUILD.gn
+++ b/mojo/runner/test/BUILD.gn
@@ -1,7 +1,9 @@
-import("//third_party/mojo/src/mojo/public/mojo.gni")
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/mojo_application.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
-import("//testing/test.gni")
 
 mojom("bindings") {
   sources = [
diff --git a/mojo/services/network/BUILD.gn b/mojo/services/network/BUILD.gn
index 6642b7ef..02ef3f0 100644
--- a/mojo/services/network/BUILD.gn
+++ b/mojo/services/network/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application.gni")
 
 if (is_android) {
   import("//build/config/android/rules.gni")
diff --git a/mojo/services/network/public/cpp/BUILD.gn b/mojo/services/network/public/cpp/BUILD.gn
index 75be8c5..52af16b 100644
--- a/mojo/services/network/public/cpp/BUILD.gn
+++ b/mojo/services/network/public/cpp/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/mojo_sdk.gni")
 
 mojo_sdk_source_set("cpp") {
diff --git a/mojo/services/network/public/interfaces/BUILD.gn b/mojo/services/network/public/interfaces/BUILD.gn
index e72ff78..b39bb2d 100644
--- a/mojo/services/network/public/interfaces/BUILD.gn
+++ b/mojo/services/network/public/interfaces/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
diff --git a/mojo/services/test_service/BUILD.gn b/mojo/services/test_service/BUILD.gn
index 150796c..90bf19a 100644
--- a/mojo/services/test_service/BUILD.gn
+++ b/mojo/services/test_service/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 group("test_service") {
diff --git a/mojo/services/tracing/BUILD.gn b/mojo/services/tracing/BUILD.gn
index b6406f3..c618f37 100644
--- a/mojo/services/tracing/BUILD.gn
+++ b/mojo/services/tracing/BUILD.gn
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojo_native_application("tracing") {
diff --git a/mojo/tools/android_mojo_shell.py b/mojo/tools/android_mojo_shell.py
index 61dcd4e..032557f 100755
--- a/mojo/tools/android_mojo_shell.py
+++ b/mojo/tools/android_mojo_shell.py
@@ -42,7 +42,7 @@
   shell = AndroidShell(config)
   shell.InitShell(runner_args.origin, runner_args.device)
   p = shell.ShowLogs()
-  shell.StartShell(args, sys.stdout, p.terminate)
+  shell.StartActivity('MojoShellActivity', args, sys.stdout, p.terminate)
   return 0
 
 
diff --git a/mojo/tools/apptest_runner.py b/mojo/tools/apptest_runner.py
index d33fbea..269ff703 100755
--- a/mojo/tools/apptest_runner.py
+++ b/mojo/tools/apptest_runner.py
@@ -22,6 +22,8 @@
                       help="a file listing apptests to run")
   parser.add_argument("build_dir", type=str, help="the build output directory")
   parser.add_argument("--verbose", default=False, action='store_true')
+  parser.add_argument('--repeat_count', default=1, metavar='INT',
+                      action='store', type=int)
   parser.add_argument('--write-full-results-to', metavar='FILENAME',
                       help='Path to write the JSON list of full results.')
   args = parser.parse_args()
@@ -50,23 +52,27 @@
   tests = []
   passed = []
   failed = []
-  for test_dict in test_list:
-    test = test_dict["test"]
-    test_name = test_dict.get("name", test)
-    test_type = test_dict.get("type", "gtest")
-    test_args = test_dict.get("args", [])
+  for _ in range(args.repeat_count):
+    for test_dict in test_list:
+      test = test_dict["test"]
+      test_name = test_dict.get("name", test)
+      test_type = test_dict.get("type", "gtest")
+      test_args = test_dict.get("args", [])
 
-    print "Running %s...%s" % (test_name, ("\n" if args.verbose else "")),
-    sys.stdout.flush()
+      print "Running %s...%s" % (test_name, ("\n" if args.verbose else "")),
+      sys.stdout.flush()
 
-    tests.append(test_name)
-    assert test_type in ("gtest", "gtest_isolated")
-    isolate = test_type == "gtest_isolated"
-    result = gtest.run_apptest(config, shell, test_args, test, isolate)
-    passed.extend([test_name] if result else [])
-    failed.extend([] if result else [test_name])
-    print "[  PASSED  ]" if result else "[  FAILED  ]",
-    print test_name if args.verbose or not result else ""
+      tests.append(test_name)
+      assert test_type in ("gtest", "gtest_isolated")
+      isolate = test_type == "gtest_isolated"
+      result = gtest.run_apptest(config, shell, test_args, test, isolate)
+      passed.extend([test_name] if result else [])
+      failed.extend([] if result else [test_name])
+      print "[  PASSED  ]" if result else "[  FAILED  ]",
+      print test_name if args.verbose or not result else ""
+
+    if failed:
+      break;
 
   print "[  PASSED  ] %d apptests" % len(passed),
   print ": %s" % ", ".join(passed) if passed else ""
diff --git a/mojo/tools/data/apptests b/mojo/tools/data/apptests
index 382e8599..faf47575 100644
--- a/mojo/tools/data/apptests
+++ b/mojo/tools/data/apptests
@@ -30,24 +30,29 @@
     "test": "mojo:network_service_apptests",
     "type": "gtest_isolated",
   },
-  # TODO(msw|jam): Fix and enable the shell_apptests: http://crbug.com/479316
+  # TODO(msw|jam): Fix and enable the runner_apptests: http://crbug.com/479316
   #{
-  #  "test": "mojo:shell_apptests",
+  #  "test": "mojo:runner_apptests",
   #  "type": "gtest_isolated",
   #},
+  {
+    "test": "mojo:view_manager_apptests",
+    "type": "gtest_isolated",
+    "args": ["--use-headless-config"]
+  },
 ]
 
 # TODO(msw): Get these tests passing on Android too. http://crbug.com/486220
 if config.target_os != config.OS_ANDROID:
   tests += [
     {
-      "test": "mojo:html_viewer_apptests",
+      "test": "mojo:filesystem_apptests",
       "type": "gtest_isolated",
     },
     {
-      "test": "mojo:view_manager_apptests",
+      "test": "mojo:html_viewer_apptests",
       "type": "gtest_isolated",
-      "args": ["--use-headless-config"]
+      "args": ["--is-headless"]
     },
     {
       "test": "mojo:resource_provider_apptests",
diff --git a/mojo/tools/mopy/android.py b/mojo/tools/mopy/android.py
index e1c747df..fc2f84f 100644
--- a/mojo/tools/mopy/android.py
+++ b/mojo/tools/mopy/android.py
@@ -81,7 +81,7 @@
             return
           time.sleep(1)
         on_fifo_closed()
-        raise Exception("Unable to find fifo.")
+        raise Exception("Unable to find fifo: %s" % path)
       _WaitForFifo()
       stdout_cat = subprocess.Popen(self._CreateADBCommand([
                                       'shell',
@@ -228,7 +228,12 @@
     local_gdb_process.wait()
     signal.signal(signal.SIGINT, signal.SIG_DFL)
 
-  def StartShell(self, arguments, stdout, on_fifo_closed, gdb=False):
+  def StartActivity(self,
+                    activity_name,
+                    arguments,
+                    stdout,
+                    on_fifo_closed,
+                    gdb=False):
     """
     Starts the shell with the given |arguments|, directing output to |stdout|.
     |on_fifo_closed| will be run if the FIFO can't be found or when it's closed.
@@ -243,8 +248,9 @@
            'start',
            '-S',
            '-a', 'android.intent.action.VIEW',
-           '-n', '%s/%s.MojoShellActivity' % (self.target_package,
-                                              'org.chromium.mojo.shell')])
+           '-n', '%s/%s.%s' % (self.target_package,
+                               self.target_package,
+                               activity_name)])
 
     logcat_process = None
     if gdb:
@@ -265,7 +271,7 @@
     map_parameters = [a for a in arguments if a.startswith(MAPPING_PREFIX)]
     parameters += self._StartHttpServerForOriginMappings(map_parameters)
     parameters = [p.replace(',', '\,') for p in parameters]
-    cmd += ['--esa', 'org.chromium.mojo.shell.extras', ','.join(parameters)]
+    cmd += ['--esa', '%s.extras' % self.target_package, ','.join(parameters)]
 
     atexit.register(self.StopShell)
     with open(os.devnull, 'w') as devnull:
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py
index d5859528..fbf5586 100755
--- a/native_client_sdk/src/build_tools/build_sdk.py
+++ b/native_client_sdk/src/build_tools/build_sdk.py
@@ -57,7 +57,7 @@
 PKGVER = os.path.join(BUILD_DIR, 'package_version', 'package_version.py')
 
 NACLPORTS_URL = 'https://chromium.googlesource.com/external/naclports.git'
-NACLPORTS_REV = 'e53078c33d99b0b3cbadbbbbb92cccf7a48d5dc1'
+NACLPORTS_REV = '65c71c1524a74ff8415573e5e5ef7c59ce4ac437'
 
 GYPBUILD_DIR = 'gypbuild'
 
@@ -892,23 +892,21 @@
   """Pull the pinned revision of naclports from SVN."""
   buildbot_common.BuildStep('Sync naclports')
 
-  # In case a previous svn checkout exists, remove it.
+  # In case a previous non-gclient checkout exists, remove it.
   # TODO(sbc): remove this once all the build machines
   # have removed the old checkout
   if (os.path.exists(NACLPORTS_DIR) and
-      not os.path.exists(os.path.join(NACLPORTS_DIR, '.git'))):
+      not os.path.exists(os.path.join(NACLPORTS_DIR, 'src'))):
     buildbot_common.RemoveDir(NACLPORTS_DIR)
 
   if not os.path.exists(NACLPORTS_DIR):
+    buildbot_common.MakeDir(NACLPORTS_DIR)
     # checkout new copy of naclports
-    cmd = ['git', 'clone', NACLPORTS_URL, 'naclports']
-    buildbot_common.Run(cmd, cwd=os.path.dirname(NACLPORTS_DIR))
-  else:
-    # checkout new copy of naclports
-    buildbot_common.Run(['git', 'fetch'], cwd=NACLPORTS_DIR)
+    cmd = ['gclient', 'config', '--name=src', NACLPORTS_URL]
+    buildbot_common.Run(cmd, cwd=NACLPORTS_DIR)
 
   # sync to required revision
-  cmd = ['git', 'checkout', str(NACLPORTS_REV)]
+  cmd = ['gclient', 'sync', '-R', '-r', 'src@' + str(NACLPORTS_REV)]
   buildbot_common.Run(cmd, cwd=NACLPORTS_DIR)
 
 
@@ -927,20 +925,21 @@
   build_script = 'build_tools/buildbot_sdk_bundle.sh'
   buildbot_common.BuildStep('Build naclports')
 
-  bundle_dir = os.path.join(NACLPORTS_DIR, 'out', 'sdk_bundle')
+  naclports_src = os.path.join(NACLPORTS_DIR, 'src')
+  bundle_dir = os.path.join(naclports_src, 'out', 'sdk_bundle')
   out_dir = os.path.join(bundle_dir, 'pepper_%s' % pepper_ver)
 
   # Remove the sdk_bundle directory to remove stale files from previous builds.
   buildbot_common.RemoveDir(bundle_dir)
 
-  buildbot_common.Run([build_script], env=env, cwd=NACLPORTS_DIR)
+  buildbot_common.Run([build_script], env=env, cwd=naclports_src)
 
   # Some naclports do not include a standalone LICENSE/COPYING file
   # so we explicitly list those here for inclusion.
   extra_licenses = ('tinyxml/readme.txt',
                     'jpeg-8d/README',
                     'zlib-1.2.3/README')
-  src_root = os.path.join(NACLPORTS_DIR, 'out', 'build')
+  src_root = os.path.join(naclports_src, 'out', 'build')
   output_license = os.path.join(out_dir, 'ports', 'LICENSE')
   GenerateNotice(src_root, output_license, extra_licenses)
   readme = os.path.join(out_dir, 'ports', 'README')
@@ -954,7 +953,7 @@
   pepper_dir = 'pepper_%s' % pepper_ver
   archive_dirs = [os.path.join(pepper_dir, 'ports')]
 
-  ports_out = os.path.join(NACLPORTS_DIR, 'out', 'sdk_bundle')
+  ports_out = os.path.join(NACLPORTS_DIR, 'src', 'out', 'sdk_bundle')
   cmd = [sys.executable, CYGTAR, '-C', ports_out, '-cjf', tarfile]
   cmd += archive_dirs
   buildbot_common.Run(cmd, cwd=NACL_DIR)
diff --git a/native_client_sdk/src/libraries/third_party/newlib-extras/netdb.h b/native_client_sdk/src/libraries/third_party/newlib-extras/netdb.h
index 52b9f96..ad14f19f 100644
--- a/native_client_sdk/src/libraries/third_party/newlib-extras/netdb.h
+++ b/native_client_sdk/src/libraries/third_party/newlib-extras/netdb.h
@@ -60,6 +60,7 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 #include <machine/ansi.h>
+#include <stdint.h>
 #include <stdio.h>
 
 #ifndef __socklen_t_defined
diff --git a/net/android/java/src/org/chromium/net/AndroidKeyStore.java b/net/android/java/src/org/chromium/net/AndroidKeyStore.java
index 3c7e6fc..89ace17a 100644
--- a/net/android/java/src/org/chromium/net/AndroidKeyStore.java
+++ b/net/android/java/src/org/chromium/net/AndroidKeyStore.java
@@ -28,19 +28,6 @@
     byte[] getRSAKeyModulus(AndroidPrivateKey key);
 
     /**
-     * Returns the 'Q' parameter of a given DSA private key as a byte
-     * buffer.
-     * This can be used by native code to convert it into an OpenSSL BIGNUM
-     * object where DSA_size() works as expected.
-     *
-     * @param key A PrivateKey instance. Must implement DSAKey.
-     * @return A byte buffer corresponding to the Q parameter. This is
-     * a big-endian representation of a BigInteger.
-     */
-    @CalledByNative
-    byte[] getDSAKeyParamQ(AndroidPrivateKey key);
-
-    /**
      * Returns the 'order' parameter of a given ECDSA private key as a
      * a byte buffer.
      * @param key A PrivateKey instance. Must implement ECKey.
@@ -51,17 +38,6 @@
     byte[] getECKeyOrder(AndroidPrivateKey key);
 
     /**
-     * Returns the encoded data corresponding to a given PrivateKey.
-     * Note that this will fail for platform keys on Android 4.0.4
-     * and higher. It can be used on 4.0.3 and older platforms to
-     * route around the platform bug described below.
-     * @param key A PrivateKey instance
-     * @return encoded key as PKCS#8 byte array, can be null.
-     */
-    @CalledByNative
-    byte[] getPrivateKeyEncodedBytes(AndroidPrivateKey key);
-
-    /**
      * Sign a given message with a given PrivateKey object. This method
      * shall only be used to implement signing in the context of SSL
      * client certificate support.
@@ -77,10 +53,9 @@
      *    combined, 36-byte MD5+SHA1 message digest or a DigestInfo
      *    value wrapping a message digest.
      *
-     *  - For a DSA and ECDSA private keys, this should be equivalent to
-     *    calling DSA_sign(0,...) and ECDSA_sign(0,...) respectively. The
-     *    message must be a hash and the function shall compute a direct
-     *    DSA/ECDSA signature for it.
+     *  - For a ECDSA private keys, this should be equivalent to calling
+     *    ECDSA_sign(0,...). The message must be a hash and the function shall
+     *    compute a direct ECDSA signature for it.
      *
      * @param key The PrivateKey handle.
      * @param message The message to sign.
diff --git a/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java b/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java
index 3fbf60c..5e66427 100644
--- a/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java
+++ b/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java
@@ -10,9 +10,6 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.Signature;
-import java.security.interfaces.DSAKey;
-import java.security.interfaces.DSAParams;
-import java.security.interfaces.DSAPrivateKey;
 import java.security.interfaces.ECKey;
 import java.security.interfaces.ECPrivateKey;
 import java.security.interfaces.RSAKey;
@@ -62,17 +59,6 @@
     }
 
     @Override
-    public byte[] getDSAKeyParamQ(AndroidPrivateKey key) {
-        PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
-        if (javaKey instanceof DSAKey) {
-            DSAParams params = ((DSAKey) javaKey).getParams();
-            return params.getQ().toByteArray();
-        }
-        Log.w(TAG, "Not a DSAKey instance!");
-        return null;
-    }
-
-    @Override
     public byte[] getECKeyOrder(AndroidPrivateKey key) {
         PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
         if (javaKey instanceof ECKey) {
@@ -84,12 +70,6 @@
     }
 
     @Override
-    public byte[] getPrivateKeyEncodedBytes(AndroidPrivateKey key) {
-        PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
-        return javaKey.getEncoded();
-    }
-
-    @Override
     public byte[] rawSignDigestWithPrivateKey(AndroidPrivateKey key,
                                                      byte[] message) {
         PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
@@ -103,8 +83,6 @@
                 // on Android 4.0.x and 4.1.x. Fixed in 4.2 and higher.
                 // See https://android-review.googlesource.com/#/c/40352/
                 signature = Signature.getInstance("NONEwithRSA");
-            } else if (javaKey instanceof DSAPrivateKey) {
-                signature = Signature.getInstance("NONEwithDSA");
             } else if (javaKey instanceof ECPrivateKey) {
                 signature = Signature.getInstance("NONEwithECDSA");
             }
@@ -133,7 +111,6 @@
     public int getPrivateKeyType(AndroidPrivateKey key) {
         PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey();
         if (javaKey instanceof RSAPrivateKey) return PrivateKeyType.RSA;
-        if (javaKey instanceof DSAPrivateKey) return PrivateKeyType.DSA;
         if (javaKey instanceof ECPrivateKey) {
             return PrivateKeyType.ECDSA;
         } else {
diff --git a/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStore.aidl b/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStore.aidl
index ee4c65d7..97b21b7c 100644
--- a/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStore.aidl
+++ b/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStore.aidl
@@ -23,8 +23,11 @@
     // Remote calls for AndroidKeyStore - these functions are performing operations
     // with a PrivateKey in the remote process using the handle provided by
     // |getPrivateKeyHandle|.
+
     byte[] getRSAKeyModulus(in int handle);
+    // Deprecated: This RPC is never used.
     byte[] getPrivateKeyEncodedBytes(in int handle);
+    // Deprecated: This RPC is never used.
     byte[] getDSAKeyParamQ(in int handle);
     byte[] getECKeyOrder(in int handle);
     byte[] rawSignDigestWithPrivateKey(in int handle, in byte[] message);
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
index aea674a..b63583d 100644
--- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
+++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
@@ -19,6 +19,7 @@
 
 import org.chromium.base.ApplicationState;
 import org.chromium.base.ApplicationStatus;
+import org.chromium.base.VisibleForTesting;
 
 /**
  * Used by the NetworkChangeNotifier to listens to platform changes in connectivity.
@@ -181,6 +182,7 @@
             registerReceiver();
         } else {
             ApplicationStatus.registerApplicationStateListener(this);
+            onApplicationStateChange(getApplicationState());
         }
     }
 
@@ -198,6 +200,23 @@
         mWifiManagerDelegate = delegate;
     }
 
+    /**
+     * Returns the activity's status.
+     * @return an {@code int} that is one of {@code ApplicationState.HAS_*_ACTIVITIES}.
+     */
+    @VisibleForTesting
+    int getApplicationState() {
+        return ApplicationStatus.getStateForApplication();
+    }
+
+    /**
+     * Returns whether the object has registered to receive network connectivity intents.
+     */
+    @VisibleForTesting
+    boolean isReceiverRegisteredForTesting() {
+        return mRegistered;
+    }
+
     public void destroy() {
         unregisterReceiver();
     }
diff --git a/net/android/java/src/org/chromium/net/RemoteAndroidKeyStore.java b/net/android/java/src/org/chromium/net/RemoteAndroidKeyStore.java
index 3d22d710..f732c45 100644
--- a/net/android/java/src/org/chromium/net/RemoteAndroidKeyStore.java
+++ b/net/android/java/src/org/chromium/net/RemoteAndroidKeyStore.java
@@ -55,18 +55,6 @@
     }
 
     @Override
-    public byte[] getDSAKeyParamQ(AndroidPrivateKey key) {
-        RemotePrivateKey remoteKey = (RemotePrivateKey) key;
-        try {
-            Log.d(TAG, "getDSAKeyParamQ");
-            return mRemoteManager.getDSAKeyParamQ(remoteKey.getHandle());
-        } catch (RemoteException e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    @Override
     public byte[] getECKeyOrder(AndroidPrivateKey key) {
         RemotePrivateKey remoteKey = (RemotePrivateKey) key;
         try {
@@ -103,13 +91,6 @@
     }
 
     @Override
-    public byte[] getPrivateKeyEncodedBytes(AndroidPrivateKey key) {
-        // This should not be called as it's only for older versions of Android.
-        assert false;
-        return null;
-    }
-
-    @Override
     public long getOpenSSLHandleForPrivateKey(AndroidPrivateKey privateKey) {
         // This should not be called as it's only for older versions of Android.
         assert false;
diff --git a/net/android/javatests/src/org/chromium/net/AndroidKeyStoreTestUtil.java b/net/android/javatests/src/org/chromium/net/AndroidKeyStoreTestUtil.java
index 865b1ef..a4cb947 100644
--- a/net/android/javatests/src/org/chromium/net/AndroidKeyStoreTestUtil.java
+++ b/net/android/javatests/src/org/chromium/net/AndroidKeyStoreTestUtil.java
@@ -16,6 +16,9 @@
 import java.security.spec.KeySpec;
 import java.security.spec.PKCS8EncodedKeySpec;
 
+/**
+ * Utility functions to create Android platform keys in tests.
+ */
 @JNINamespace("net::android")
 public class AndroidKeyStoreTestUtil {
 
@@ -35,9 +38,6 @@
             case PrivateKeyType.RSA:
                 algorithm = "RSA";
                 break;
-            case PrivateKeyType.DSA:
-                algorithm = "DSA";
-                break;
             case PrivateKeyType.ECDSA:
                 algorithm = "EC";
                 break;
diff --git a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
index 064bfc817..fa01354 100644
--- a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
+++ b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
@@ -153,6 +153,52 @@
     }
 
     /**
+     * Tests that the receiver registers for connectivity intents during construction.
+     */
+    @UiThreadTest
+    @MediumTest
+    @Feature({"Android-AppBase"})
+    public void testNetworkChangeNotifierRegistersInConstructor() throws InterruptedException {
+        Context context = getInstrumentation().getTargetContext();
+
+        NetworkChangeNotifierAutoDetect.Observer observer =
+                new NetworkChangeNotifierAutoDetect.Observer() {
+            @Override
+            public void onConnectionTypeChanged(int newConnectionType) {}
+            @Override
+            public void onMaxBandwidthChanged(double maxBandwidthMbps) {}
+        };
+
+        NetworkChangeNotifierAutoDetect receiver = new NetworkChangeNotifierAutoDetect(
+                observer, context, false /* always watch for changes */) {
+            @Override
+            int getApplicationState() {
+                return ApplicationState.HAS_RUNNING_ACTIVITIES;
+            }
+        };
+
+        assertTrue(receiver.isReceiverRegisteredForTesting());
+    }
+
+    /**
+     * Tests that the receiver toggles registration for connectivity intents based on activity
+     * state.
+     */
+    @UiThreadTest
+    @MediumTest
+    @Feature({"Android-AppBase"})
+    public void testNetworkChangeNotifierRegistersForIntents() throws InterruptedException {
+        mReceiver.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES);
+        assertTrue(mReceiver.isReceiverRegisteredForTesting());
+
+        mReceiver.onApplicationStateChange(ApplicationState.HAS_PAUSED_ACTIVITIES);
+        assertFalse(mReceiver.isReceiverRegisteredForTesting());
+
+        mReceiver.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES);
+        assertTrue(mReceiver.isReceiverRegisteredForTesting());
+    }
+
+    /**
      * Tests that changing the RSSI_CHANGED_ACTION intent updates MaxBandwidth.
      */
     @UiThreadTest
@@ -304,6 +350,8 @@
     @Feature({"Android-AppBase"})
     public void testCreateNetworkChangeNotifierAlwaysWatchForChanges() throws InterruptedException {
         createTestNotifier(WatchForChanges.ALWAYS);
+        assertTrue(mReceiver.isReceiverRegisteredForTesting());
+
         // Make sure notifications can be received.
         NetworkChangeNotifierTestObserver observer = new NetworkChangeNotifierTestObserver();
         NetworkChangeNotifier.addConnectionTypeObserver(observer);
diff --git a/net/android/keystore.cc b/net/android/keystore.cc
index dd37939..4fa8dbf 100644
--- a/net/android/keystore.cc
+++ b/net/android/keystore.cc
@@ -36,21 +36,6 @@
   return true;
 }
 
-bool GetDSAKeyParamQ(jobject private_key_ref, std::vector<uint8_t>* result) {
-  JNIEnv* env = AttachCurrentThread();
-
-  ScopedJavaLocalRef<jbyteArray> q_ref =
-      Java_AndroidKeyStore_getDSAKeyParamQ(
-          env,
-          GetKeyStore(private_key_ref).obj(),
-          private_key_ref);
-  if (q_ref.is_null())
-    return false;
-
-  JavaByteArrayToByteVector(env, q_ref.obj(), result);
-  return true;
-}
-
 bool GetECKeyOrder(jobject private_key_ref, std::vector<uint8_t>* result) {
   JNIEnv* env = AttachCurrentThread();
 
@@ -67,22 +52,6 @@
   return true;
 }
 
-bool GetPrivateKeyEncodedBytes(jobject private_key_ref,
-                               std::vector<uint8_t>* result) {
-  JNIEnv* env = AttachCurrentThread();
-
-  ScopedJavaLocalRef<jbyteArray> encoded_ref =
-      Java_AndroidKeyStore_getPrivateKeyEncodedBytes(
-          env,
-          GetKeyStore(private_key_ref).obj(),
-          private_key_ref);
-  if (encoded_ref.is_null())
-    return false;
-
-  JavaByteArrayToByteVector(env, encoded_ref.obj(), result);
-  return true;
-}
-
 bool RawSignDigestWithPrivateKey(jobject private_key_ref,
                                  const base::StringPiece& digest,
                                  std::vector<uint8_t>* signature) {
diff --git a/net/android/keystore.h b/net/android/keystore.h
index 1186ef6d..b794799 100644
--- a/net/android/keystore.h
+++ b/net/android/keystore.h
@@ -27,11 +27,14 @@
 // values are shared with Java through org.chromium.net.PrivateKeyType.
 // Example: PRIVATE_KEY_TYPE_RSA.
 //
+// This enum is used as part of an RPC interface, so new values must be
+// appended and not reused.
+//
 // A Java counterpart will be generated for this enum.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net
 enum PrivateKeyType {
   PRIVATE_KEY_TYPE_RSA = 0,
-  PRIVATE_KEY_TYPE_DSA = 1,
+  // Obsolete: PRIVATE_KEY_TYPE_DSA = 1,
   PRIVATE_KEY_TYPE_ECDSA = 2,
   PRIVATE_KEY_TYPE_INVALID = 255,
 };
@@ -47,15 +50,6 @@
 NET_EXPORT bool GetRSAKeyModulus(jobject private_key,
                                  std::vector<uint8_t>* modulus);
 
-// Returns the Q parameter of a given DSAPrivateKey platform object,
-// as a series of bytes, in big-endian representation. This can be used
-// with BN_bin2bn() to convert to an OpenSSL BIGNUM.
-// |private_key| is a JNI reference for the private key.
-// |q| will receive the result bytes on success.
-// Returns true on success, or false on failure (e.g. if the key is
-// not DSA).
-NET_EXPORT bool GetDSAKeyParamQ(jobject private_key, std::vector<uint8_t>* q);
-
 // Returns the order parameter of a given ECPrivateKey platform object,
 // as a series of bytes, in big-endian representation. This can be used
 // with BN_bin2bn() to convert to an OpenSSL BIGNUM.
@@ -65,15 +59,6 @@
 // not EC).
 bool GetECKeyOrder(jobject private_key, std::vector<uint8_t>* order);
 
-// Returns the encoded PKCS#8 representation of a private key.
-// This only works on Android 4.0.3 and older releases for platform keys
-// (i.e. all keys except those explicitely generated by the application).
-// |private_key| is a JNI reference for the private key.
-// |encoded| will receive the encoded data on success.
-// Returns true on success, or false on failure (e.g. on 4.0.4 or higher).
-bool GetPrivateKeyEncodedBytes(jobject private_key,
-                               std::vector<uint8_t>* encoded);
-
 // Compute the signature of a given message, which is actually a hash,
 // using a private key. For more details, please read the comments for the
 // rawSignDigestWithPrivateKey method in AndroidKeyStore.java.
diff --git a/net/android/keystore_openssl.cc b/net/android/keystore_openssl.cc
index dfd3b1f4..3907e59 100644
--- a/net/android/keystore_openssl.cc
+++ b/net/android/keystore_openssl.cc
@@ -6,13 +6,11 @@
 
 #include <jni.h>
 #include <openssl/bn.h>
-#include <openssl/dsa.h>
 #include <openssl/ec.h>
 #include <openssl/engine.h>
 #include <openssl/err.h>
 #include <openssl/evp.h>
 #include <openssl/rsa.h>
-#include <openssl/x509.h>
 #include <stdint.h>
 
 #include "base/android/build_info.h"
@@ -35,9 +33,8 @@
 // are required to sign the digest during the OpenSSL handshake for TLS.
 //
 // The OpenSSL EVP_PKEY type is a generic wrapper around key pairs.
-// Internally, it can hold a pointer to a RSA, DSA or ECDSA structure,
-// which model keypair implementations of each respective crypto
-// algorithm.
+// Internally, it can hold a pointer to a RSA or ECDSA structure, which model
+// keypair implementations of each respective crypto algorithm.
 //
 // The RSA type has a 'method' field pointer to a vtable-like structure
 // called a RSA_METHOD. This contains several function pointers that
@@ -71,8 +68,8 @@
 extern const RSA_METHOD android_rsa_method;
 extern const ECDSA_METHOD android_ecdsa_method;
 
-// KeyExData contains the data that is contained in the EX_DATA of the RSA, DSA
-// and ECDSA objects that are created to wrap Android system keys.
+// KeyExData contains the data that is contained in the EX_DATA of the RSA and
+// EC_KEY objects that are created to wrap Android system keys.
 struct KeyExData {
   // private_key contains a reference to a Java, private-key object.
   jobject private_key;
@@ -80,13 +77,13 @@
   // might not be ABI compatible with Chromium).
   AndroidRSA* legacy_rsa;
   // cached_size contains the "size" of the key. This is the size of the
-  // modulus (in bytes) for RSA, or the group order size for (EC)DSA. This
+  // modulus (in bytes) for RSA, or the group order size for ECDSA. This
   // avoids calling into Java to calculate the size.
   size_t cached_size;
 };
 
-// ExDataDup is called when one of the RSA, DSA or EC_KEY objects is
-// duplicated. We don't support this and it should never happen.
+// ExDataDup is called when one of the RSA or EC_KEY objects is duplicated. We
+// don't support this and it should never happen.
 int ExDataDup(CRYPTO_EX_DATA* to,
               const CRYPTO_EX_DATA* from,
               void** from_d,
@@ -97,7 +94,7 @@
   return 0;
 }
 
-// ExDataFree is called when one of the RSA, DSA or EC_KEY objects is freed.
+// ExDataFree is called when one of the RSA or EC_KEY objects is freed.
 void ExDataFree(void* parent,
                 void* ptr,
                 CRYPTO_EX_DATA* ad,
@@ -113,7 +110,7 @@
   }
 }
 
-// BoringSSLEngine is a BoringSSL ENGINE that implements RSA, DSA and ECDSA by
+// BoringSSLEngine is a BoringSSL ENGINE that implements RSA and ECDSA by
 // forwarding the requested operations to the Java libraries.
 class BoringSSLEngine {
  public:
@@ -402,53 +399,31 @@
     return CreateRsaPkeyWrapper(private_key, nullptr, tracer);
   }
 
-  // Route around platform bug: if Android < 4.2, then
-  // base::android::RawSignDigestWithPrivateKey() cannot work, so instead, try
-  // to get the system OpenSSL's EVP_PKEY begin this PrivateKey object.
+  // Route around platform limitation: if Android < 4.2, then
+  // base::android::RawSignDigestWithPrivateKey() cannot work, so try to get the
+  // system OpenSSL's EVP_PKEY backing this PrivateKey object.
   AndroidEVP_PKEY* sys_pkey =
       GetOpenSSLSystemHandleForPrivateKey(private_key);
-  if (sys_pkey != NULL) {
-    if (sys_pkey->type != ANDROID_EVP_PKEY_RSA) {
-      LOG(ERROR) << "Private key has wrong type!";
-      return nullptr;
+  if (sys_pkey == nullptr)
+    return nullptr;
+
+  if (sys_pkey->type != ANDROID_EVP_PKEY_RSA) {
+    LOG(ERROR) << "Private key has wrong type!";
+    return nullptr;
+  }
+
+  AndroidRSA* sys_rsa = sys_pkey->pkey.rsa;
+  if (sys_rsa->engine) {
+    // |private_key| may not have an engine if the PrivateKey did not come
+    // from the key store, such as in unit tests.
+    if (strcmp(sys_rsa->engine->id, "keystore") == 0) {
+      LeakEngine(private_key);
+    } else {
+      NOTREACHED();
     }
-
-    AndroidRSA* sys_rsa = sys_pkey->pkey.rsa;
-    if (sys_rsa->engine) {
-      // |private_key| may not have an engine if the PrivateKey did not come
-      // from the key store, such as in unit tests.
-      if (strcmp(sys_rsa->engine->id, "keystore") == 0) {
-        LeakEngine(private_key);
-      } else {
-        NOTREACHED();
-      }
-    }
-
-    return CreateRsaPkeyWrapper(private_key, sys_rsa, tracer);
   }
 
-  // GetOpenSSLSystemHandleForPrivateKey() will fail on Android 4.0.3 and
-  // earlier. However, it is possible to get the key content with
-  // PrivateKey.getEncoded() on these platforms.  Note that this method may
-  // return false on 4.0.4 and later.
-  std::vector<uint8_t> encoded;
-  if (!GetPrivateKeyEncodedBytes(private_key, &encoded) || encoded.empty()) {
-    LOG(ERROR) << "Can't get private key data!";
-    return nullptr;
-  }
-  const uint8_t* p = &encoded[0];
-  ScopedPKCS8_PRIV_KEY_INFO pkcs8(
-      d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, encoded.size()));
-  if (!pkcs8.get() || p != &encoded[0] + encoded.size()) {
-    LOG(ERROR) << "Can't decode PrivateKeyInfo";
-    return nullptr;
-  }
-  crypto::ScopedEVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
-  if (!pkey || EVP_PKEY_id(pkey.get()) != EVP_PKEY_RSA) {
-    LOG(ERROR) << "Can't decode RSA key";
-    return nullptr;
-  }
-  return pkey.Pass();
+  return CreateRsaPkeyWrapper(private_key, sys_rsa, tracer);
 }
 
 // Custom ECDSA_METHOD that uses the platform APIs.
diff --git a/net/base/directory_lister.cc b/net/base/directory_lister.cc
index 2327756..efdc53c 100644
--- a/net/base/directory_lister.cc
+++ b/net/base/directory_lister.cc
@@ -12,7 +12,8 @@
 #include "base/i18n/file_util_icu.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/worker_pool.h"
 #include "net/base/net_errors.h"
@@ -97,7 +98,7 @@
                             DirectoryLister* lister)
     : dir_(dir),
       type_(type),
-      origin_loop_(base::MessageLoopProxy::current()),
+      origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       lister_(lister),
       cancelled_(0) {
   DCHECK(lister_);
@@ -106,7 +107,7 @@
 DirectoryLister::Core::~Core() {}
 
 void DirectoryLister::Core::CancelOnOriginThread() {
-  DCHECK(origin_loop_->BelongsToCurrentThread());
+  DCHECK(origin_task_runner_->BelongsToCurrentThread());
 
   base::subtle::NoBarrier_Store(&cancelled_, 1);
   // Core must not call into |lister_| after cancellation, as the |lister_| may
@@ -119,7 +120,7 @@
   scoped_ptr<DirectoryList> directory_list(new DirectoryList());
 
   if (!base::DirectoryExists(dir_)) {
-    origin_loop_->PostTask(
+    origin_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&Core::DoneOnOriginThread, this,
                    base::Passed(directory_list.Pass()), ERR_FILE_NOT_FOUND));
@@ -166,10 +167,9 @@
 
   SortData(directory_list.get(), type_);
 
-  origin_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&Core::DoneOnOriginThread, this,
-                 base::Passed(directory_list.Pass()), OK));
+  origin_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&Core::DoneOnOriginThread, this,
+                            base::Passed(directory_list.Pass()), OK));
 }
 
 bool DirectoryLister::Core::IsCancelled() const {
@@ -178,7 +178,7 @@
 
 void DirectoryLister::Core::DoneOnOriginThread(
     scoped_ptr<DirectoryList> directory_list, int error) const {
-  DCHECK(origin_loop_->BelongsToCurrentThread());
+  DCHECK(origin_task_runner_->BelongsToCurrentThread());
 
   // Need to check if the operation was before first callback.
   if (IsCancelled())
diff --git a/net/base/directory_lister.h b/net/base/directory_lister.h
index 2b43c1d5..a29ff53 100644
--- a/net/base/directory_lister.h
+++ b/net/base/directory_lister.h
@@ -16,7 +16,7 @@
 #include "net/base/net_export.h"
 
 namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 }
 
 namespace net {
@@ -110,7 +110,7 @@
 
     const base::FilePath dir_;
     const ListingType type_;
-    const scoped_refptr<base::MessageLoopProxy> origin_loop_;
+    const scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
 
     // Only used on the origin thread.
     DirectoryLister* lister_;
diff --git a/net/base/elements_upload_data_stream_unittest.cc b/net/base/elements_upload_data_stream_unittest.cc
index 1061bbf..8c72054 100644
--- a/net/base/elements_upload_data_stream_unittest.cc
+++ b/net/base/elements_upload_data_stream_unittest.cc
@@ -12,9 +12,12 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -92,8 +95,8 @@
 
  private:
   void OnInit(const CompletionCallback& callback) {
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::Bind(callback, init_result_));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(callback, init_result_));
   }
 
   int OnRead(IOBuffer* buf,
@@ -104,7 +107,7 @@
     if (IsInMemory()) {
       return read_result_;
     } else {
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(callback, read_result_));
       return ERR_IO_PENDING;
     }
@@ -180,11 +183,8 @@
             base::WriteFile(temp_file_path, kTestData, kTestDataSize));
 
   element_readers_.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file_path,
-                                  0,
-                                  kuint64max,
-                                  base::Time()));
+      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                  temp_file_path, 0, kuint64max, base::Time()));
 
   TestCompletionCallback init_callback;
   scoped_ptr<UploadDataStream> stream(
@@ -219,11 +219,8 @@
       overriding_content_length(kFakeSize);
 
   element_readers_.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file_path,
-                                  0,
-                                  kuint64max,
-                                  base::Time()));
+      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                  temp_file_path, 0, kuint64max, base::Time()));
 
   TestCompletionCallback init_callback;
   scoped_ptr<UploadDataStream> stream(
@@ -337,12 +334,9 @@
 
   const uint64_t kFileRangeOffset = 1;
   const uint64_t kFileRangeLength = 4;
-  element_readers_.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file_path,
-                                  kFileRangeOffset,
-                                  kFileRangeLength,
-                                  base::Time()));
+  element_readers_.push_back(new UploadFileElementReader(
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path,
+      kFileRangeOffset, kFileRangeLength, base::Time()));
 
   element_readers_.push_back(new UploadBytesElementReader(
       kTestData, kTestDataSize));
@@ -528,7 +522,7 @@
   // reusing element_readers_ is wrong.
   ScopedVector<UploadElementReader> element_readers;
   element_readers.push_back(new UploadFileElementReader(
-      base::MessageLoopProxy::current().get(), file_path, 1, 2, time));
+      base::ThreadTaskRunnerHandle::Get().get(), file_path, 1, 2, time));
 
   TestCompletionCallback init_callback;
   scoped_ptr<UploadDataStream> stream(
@@ -571,11 +565,8 @@
   element_readers_.push_back(new UploadBytesElementReader(
       kTestData, kTestDataSize));
   element_readers_.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file_path,
-                                  0,
-                                  kuint64max,
-                                  base::Time()));
+      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                  temp_file_path, 0, kuint64max, base::Time()));
   scoped_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(element_readers_.Pass(), 0));
 
@@ -617,11 +608,8 @@
   element_readers_.push_back(new UploadBytesElementReader(
       kTestData, kTestDataSize));
   element_readers_.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file_path,
-                                  0,
-                                  kuint64max,
-                                  base::Time()));
+      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                  temp_file_path, 0, kuint64max, base::Time()));
   scoped_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(element_readers_.Pass(), 0));
 
@@ -660,11 +648,8 @@
   element_readers_.push_back(new UploadBytesElementReader(
       kTestData, kTestDataSize));
   element_readers_.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file_path,
-                                  0,
-                                  kuint64max,
-                                  base::Time()));
+      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                  temp_file_path, 0, kuint64max, base::Time()));
   scoped_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(element_readers_.Pass(), 0));
 
@@ -719,11 +704,8 @@
   element_readers_.push_back(new UploadBytesElementReader(
       kTestData, kTestDataSize));
   element_readers_.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file_path,
-                                  0,
-                                  kuint64max,
-                                  base::Time()));
+      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                  temp_file_path, 0, kuint64max, base::Time()));
   scoped_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(element_readers_.Pass(), 0));
 
@@ -768,11 +750,8 @@
   element_readers_.push_back(new UploadBytesElementReader(
       kTestData, kTestDataSize));
   element_readers_.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file_path,
-                                  0,
-                                  kuint64max,
-                                  base::Time()));
+      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                  temp_file_path, 0, kuint64max, base::Time()));
   scoped_ptr<UploadDataStream> stream(
       new ElementsUploadDataStream(element_readers_.Pass(), 0));
 
diff --git a/net/base/file_stream_context.cc b/net/base/file_stream_context.cc
index b152a990..888aec82 100644
--- a/net/base/file_stream_context.cc
+++ b/net/base/file_stream_context.cc
@@ -6,7 +6,6 @@
 
 #include "base/files/file_path.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/task_runner.h"
 #include "base/task_runner_util.h"
diff --git a/net/base/file_stream_context.h b/net/base/file_stream_context.h
index f49e5bcb..00b90e63 100644
--- a/net/base/file_stream_context.h
+++ b/net/base/file_stream_context.h
@@ -31,6 +31,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/move.h"
+#include "base/single_thread_task_runner.h"
 #include "base/task_runner.h"
 #include "net/base/completion_callback.h"
 #include "net/base/file_stream.h"
@@ -180,15 +181,15 @@
   // The |buf_len| parameter contains the number of bytes to be read.
   // The |overlapped| parameter is a pointer to the OVERLAPPED structure being
   // used.
-  // The |origin_thread_loop| is a MessageLoopProxy instance used to post tasks
-  // back to the originating thread.
+  // The |origin_thread_task_runner| is a task runner instance used to post
+  // tasks back to the originating thread.
   static void ReadAsync(
       FileStream::Context* context,
       HANDLE file,
       scoped_refptr<IOBuffer> buf,
       int buf_len,
       OVERLAPPED* overlapped,
-      scoped_refptr<base::MessageLoopProxy> origin_thread_loop);
+      scoped_refptr<base::SingleThreadTaskRunner> origin_thread_task_runner);
 
   // This callback executes on the main calling thread. It informs the caller
   // about the result of the ReadFile call.
diff --git a/net/base/file_stream_context_win.cc b/net/base/file_stream_context_win.cc
index 5344e681..d78bf91 100644
--- a/net/base/file_stream_context_win.cc
+++ b/net/base/file_stream_context_win.cc
@@ -7,11 +7,12 @@
 #include <windows.h>
 
 #include "base/files/file_path.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/worker_pool.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -87,8 +88,7 @@
       FROM_HERE,
       base::Bind(&FileStream::Context::ReadAsync, base::Unretained(this),
                  file_.GetPlatformFile(), make_scoped_refptr(buf), buf_len,
-                 &io_context_.overlapped,
-                 base::MessageLoop::current()->message_loop_proxy()));
+                 &io_context_.overlapped, base::ThreadTaskRunnerHandle::Get()));
   return ERR_IO_PENDING;
 }
 
@@ -213,10 +213,10 @@
     scoped_refptr<IOBuffer> buf,
     int buf_len,
     OVERLAPPED* overlapped,
-    scoped_refptr<base::MessageLoopProxy> origin_thread_loop) {
+    scoped_refptr<base::SingleThreadTaskRunner> origin_thread_task_runner) {
   DWORD bytes_read = 0;
   BOOL ret = ::ReadFile(file, buf->data(), buf_len, &bytes_read, overlapped);
-  origin_thread_loop->PostTask(
+  origin_thread_task_runner->PostTask(
       FROM_HERE,
       base::Bind(&FileStream::Context::ReadAsyncResult,
                  base::Unretained(context), ret, bytes_read, ::GetLastError()));
diff --git a/net/base/file_stream_unittest.cc b/net/base/file_stream_unittest.cc
index 1c67b4b..a1e1815 100644
--- a/net/base/file_stream_unittest.cc
+++ b/net/base/file_stream_unittest.cc
@@ -9,12 +9,12 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
 #include "net/base/io_buffer.h"
@@ -71,7 +71,7 @@
 
 TEST_F(FileStreamTest, OpenExplicitClose) {
   TestCompletionCallback callback;
-  FileStream stream(base::MessageLoopProxy::current());
+  FileStream stream(base::ThreadTaskRunnerHandle::Get());
   int flags = base::File::FLAG_OPEN |
               base::File::FLAG_READ |
               base::File::FLAG_ASYNC;
@@ -88,8 +88,8 @@
 
 TEST_F(FileStreamTest, OpenExplicitCloseOrphaned) {
   TestCompletionCallback callback;
-  scoped_ptr<FileStream> stream(new FileStream(
-      base::MessageLoopProxy::current()));
+  scoped_ptr<FileStream> stream(
+      new FileStream(base::ThreadTaskRunnerHandle::Get()));
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
               base::File::FLAG_ASYNC;
   int rv = stream->Open(temp_file_path(), flags, callback.callback());
@@ -119,7 +119,7 @@
 
   // Seek to the beginning of the file and read.
   scoped_ptr<FileStream> read_stream(
-      new FileStream(file.Pass(), base::MessageLoopProxy::current()));
+      new FileStream(file.Pass(), base::ThreadTaskRunnerHandle::Get()));
   ASSERT_EQ(ERR_IO_PENDING,
             read_stream->Seek(base::File::FROM_BEGIN, 0,
                               callback64.callback()));
@@ -139,7 +139,7 @@
   file.Initialize(temp_file_path(), flags);
 
   scoped_ptr<FileStream> write_stream(
-      new FileStream(file.Pass(), base::MessageLoopProxy::current()));
+      new FileStream(file.Pass(), base::ThreadTaskRunnerHandle::Get()));
   ASSERT_EQ(ERR_IO_PENDING,
             write_stream->Seek(base::File::FROM_BEGIN, 0,
                                callback64.callback()));
@@ -162,7 +162,7 @@
   TestCompletionCallback callback;
   TestInt64CompletionCallback callback64;
 
-  FileStream stream(base::MessageLoopProxy::current());
+  FileStream stream(base::ThreadTaskRunnerHandle::Get());
 
   EXPECT_FALSE(stream.IsOpen());
 
@@ -180,7 +180,7 @@
   int64_t file_size;
   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
 
-  FileStream stream(base::MessageLoopProxy::current());
+  FileStream stream(base::ThreadTaskRunnerHandle::Get());
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
               base::File::FLAG_ASYNC;
   TestCompletionCallback callback;
@@ -209,7 +209,7 @@
   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
 
   scoped_ptr<FileStream> stream(
-      new FileStream(base::MessageLoopProxy::current()));
+      new FileStream(base::ThreadTaskRunnerHandle::Get()));
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
               base::File::FLAG_ASYNC;
   TestCompletionCallback callback;
@@ -234,7 +234,7 @@
   int64_t file_size;
   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
 
-  FileStream stream(base::MessageLoopProxy::current());
+  FileStream stream(base::ThreadTaskRunnerHandle::Get());
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
               base::File::FLAG_ASYNC;
   TestCompletionCallback callback;
@@ -268,7 +268,7 @@
 }
 
 TEST_F(FileStreamTest, SeekAround) {
-  FileStream stream(base::MessageLoopProxy::current());
+  FileStream stream(base::ThreadTaskRunnerHandle::Get());
   int flags = base::File::FLAG_OPEN | base::File::FLAG_ASYNC |
               base::File::FLAG_READ;
   TestCompletionCallback callback;
@@ -303,7 +303,7 @@
 }
 
 TEST_F(FileStreamTest, Write) {
-  FileStream stream(base::MessageLoopProxy::current());
+  FileStream stream(base::ThreadTaskRunnerHandle::Get());
   int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
               base::File::FLAG_ASYNC;
   TestCompletionCallback callback;
@@ -329,7 +329,7 @@
 
 TEST_F(FileStreamTest, Write_EarlyDelete) {
   scoped_ptr<FileStream> stream(
-      new FileStream(base::MessageLoopProxy::current()));
+      new FileStream(base::ThreadTaskRunnerHandle::Get()));
   int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
               base::File::FLAG_ASYNC;
   TestCompletionCallback callback;
@@ -359,7 +359,7 @@
   int64_t file_size;
   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
 
-  FileStream stream(base::MessageLoopProxy::current());
+  FileStream stream(base::ThreadTaskRunnerHandle::Get());
   int flags = base::File::FLAG_OPEN | base::File::FLAG_WRITE |
               base::File::FLAG_ASYNC;
   TestCompletionCallback callback;
@@ -399,7 +399,7 @@
   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
 
   scoped_ptr<FileStream> stream(
-      new FileStream(base::MessageLoopProxy::current()));
+      new FileStream(base::ThreadTaskRunnerHandle::Get()));
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
               base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
   TestCompletionCallback callback;
@@ -452,7 +452,7 @@
   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
 
   scoped_ptr<FileStream> stream(
-      new FileStream(base::MessageLoopProxy::current()));
+      new FileStream(base::ThreadTaskRunnerHandle::Get()));
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
               base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
   TestCompletionCallback callback;
@@ -623,7 +623,7 @@
   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
 
   scoped_ptr<FileStream> stream(
-      new FileStream(base::MessageLoopProxy::current()));
+      new FileStream(base::ThreadTaskRunnerHandle::Get()));
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
               base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
   TestCompletionCallback open_callback;
@@ -730,7 +730,7 @@
   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
 
   scoped_ptr<FileStream> stream(
-      new FileStream(base::MessageLoopProxy::current()));
+      new FileStream(base::ThreadTaskRunnerHandle::Get()));
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
               base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
   TestCompletionCallback open_callback;
@@ -800,7 +800,7 @@
   ASSERT_TRUE(file.IsValid());
 
   scoped_ptr<FileStream> stream(
-  new FileStream(file.Pass(), base::MessageLoopProxy::current()));
+      new FileStream(file.Pass(), base::ThreadTaskRunnerHandle::Get()));
 
   scoped_refptr<IOBuffer> buf = new IOBuffer(1);
   buf->data()[0] = 0;
@@ -825,7 +825,7 @@
   ASSERT_TRUE(file.IsValid());
 
   scoped_ptr<FileStream> stream(
-  new FileStream(file.Pass(), base::MessageLoopProxy::current()));
+      new FileStream(file.Pass(), base::ThreadTaskRunnerHandle::Get()));
 
   scoped_refptr<IOBuffer> buf = new IOBuffer(1);
   TestCompletionCallback callback;
@@ -857,7 +857,7 @@
   EXPECT_TRUE(base::GetFileSize(path, &file_size));
   EXPECT_LT(0, file_size);
 
-  FileStream stream(base::MessageLoopProxy::current());
+  FileStream stream(base::ThreadTaskRunnerHandle::Get());
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
               base::File::FLAG_ASYNC;
   TestCompletionCallback callback;
diff --git a/net/base/host_mapping_rules.cc b/net/base/host_mapping_rules.cc
index a2789c0..179a0dc8 100644
--- a/net/base/host_mapping_rules.cc
+++ b/net/base/host_mapping_rules.cc
@@ -72,7 +72,7 @@
   base::SplitString(trimmed, ' ', &parts);
 
   // Test for EXCLUSION rule.
-  if (parts.size() == 2 && LowerCaseEqualsASCII(parts[0], "exclude")) {
+  if (parts.size() == 2 && base::LowerCaseEqualsASCII(parts[0], "exclude")) {
     ExclusionRule rule;
     rule.hostname_pattern = base::StringToLowerASCII(parts[1]);
     exclusion_rules_.push_back(rule);
@@ -80,7 +80,7 @@
   }
 
   // Test for MAP rule.
-  if (parts.size() == 3 && LowerCaseEqualsASCII(parts[0], "map")) {
+  if (parts.size() == 3 && base::LowerCaseEqualsASCII(parts[0], "map")) {
     MapRule rule;
     rule.hostname_pattern = base::StringToLowerASCII(parts[1]);
 
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc
index 4c0d1e0c..4468fc4 100644
--- a/net/base/mime_util.cc
+++ b/net/base/mime_util.cc
@@ -283,7 +283,7 @@
   const std::string left(base_pattern.substr(0, star));
   const std::string right(base_pattern.substr(star + 1));
 
-  if (!StartsWithASCII(base_type, left, false))
+  if (!base::StartsWithASCII(base_type, left, false))
     return false;
 
   if (!right.empty() && !EndsWith(base_type, right, false))
@@ -330,7 +330,8 @@
       return true;
   }
 
-  return type_string.size() > 2 && StartsWithASCII(type_string, "x-", false);
+  return type_string.size() > 2 &&
+         base::StartsWithASCII(type_string, "x-", false);
 }
 
 //----------------------------------------------------------------------------
@@ -457,7 +458,8 @@
     const std::string& leading_mime_type,
     base::hash_set<base::FilePath::StringType>* extensions) {
   for (size_t i = 0; i < mappings_len; ++i) {
-    if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) {
+    if (base::StartsWithASCII(mappings[i].mime_type, leading_mime_type,
+                              false)) {
       std::vector<string> this_extensions;
       base::SplitString(mappings[i].extensions, ',', &this_extensions);
       for (size_t j = 0; j < this_extensions.size(); ++j) {
diff --git a/net/base/mock_file_stream.cc b/net/base/mock_file_stream.cc
index 33844a4f..19ff24e 100644
--- a/net/base/mock_file_stream.cc
+++ b/net/base/mock_file_stream.cc
@@ -5,7 +5,9 @@
 #include "net/base/mock_file_stream.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace net {
 
@@ -87,7 +89,7 @@
   if (!throttled_task_.is_null()) {
     base::Closure throttled_task = throttled_task_;
     throttled_task_.Reset();
-    base::MessageLoop::current()->PostTask(FROM_HERE, throttled_task);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, throttled_task);
   }
 }
 
@@ -114,7 +116,7 @@
 int MockFileStream::ErrorCallback(const CompletionCallback& callback) {
   CHECK_NE(OK, forced_error_);
   if (async_error_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, forced_error_));
     clear_forced_error();
     return ERR_IO_PENDING;
@@ -128,7 +130,7 @@
     const Int64CompletionCallback& callback) {
   CHECK_NE(OK, forced_error_);
   if (async_error_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, forced_error_));
     clear_forced_error();
     return ERR_IO_PENDING;
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index 028b56b..04733a8 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -151,10 +151,6 @@
 static base::LazyInstance<std::multiset<int> >::Leaky
     g_explicitly_allowed_ports = LAZY_INSTANCE_INITIALIZER;
 
-size_t GetCountOfExplicitlyAllowedPorts() {
-  return g_explicitly_allowed_ports.Get().size();
-}
-
 std::string GetSpecificHeader(const std::string& headers,
                               const std::string& name) {
   // We want to grab the Value from the "Key: Value" pairs in the headers,
@@ -260,7 +256,7 @@
 
 base::string16 StripWWW(const base::string16& text) {
   const base::string16 www(base::ASCIIToUTF16("www."));
-  return StartsWith(text, www, true) ? text.substr(www.length()) : text;
+  return base::StartsWith(text, www, true) ? text.substr(www.length()) : text;
 }
 
 base::string16 StripWWWFromHost(const GURL& url) {
@@ -276,21 +272,17 @@
   return port >= 0 && port < 1024;
 }
 
-NET_EXPORT bool IsPortAllowedForScheme(int port,
-                                       const std::string& url_scheme,
-                                       PortOverrideMode port_override_mode) {
+bool IsPortAllowedForScheme(int port, const std::string& url_scheme) {
   // Reject invalid ports.
   if (!IsPortValid(port))
     return false;
 
   // Allow explitly allowed ports for any scheme.
-  if (port_override_mode == PORT_OVERRIDES_ALLOWED &&
-      g_explicitly_allowed_ports.Get().count(port) > 0) {
+  if (g_explicitly_allowed_ports.Get().count(port) > 0)
     return true;
-  }
 
   // FTP requests have an extra set of whitelisted schemes.
-  if (LowerCaseEqualsASCII(url_scheme, url::kFtpScheme)) {
+  if (base::LowerCaseEqualsASCII(url_scheme, url::kFtpScheme)) {
     for (int allowed_ftp_port : kAllowedFtpPorts) {
       if (allowed_ftp_port == port)
         return true;
@@ -307,6 +299,55 @@
   return true;
 }
 
+size_t GetCountOfExplicitlyAllowedPorts() {
+  return g_explicitly_allowed_ports.Get().size();
+}
+
+// Specifies a comma separated list of port numbers that should be accepted
+// despite bans. If the string is invalid no allowed ports are stored.
+void SetExplicitlyAllowedPorts(const std::string& allowed_ports) {
+  if (allowed_ports.empty())
+    return;
+
+  std::multiset<int> ports;
+  size_t last = 0;
+  size_t size = allowed_ports.size();
+  // The comma delimiter.
+  const std::string::value_type kComma = ',';
+
+  // Overflow is still possible for evil user inputs.
+  for (size_t i = 0; i <= size; ++i) {
+    // The string should be composed of only digits and commas.
+    if (i != size && !IsAsciiDigit(allowed_ports[i]) &&
+        (allowed_ports[i] != kComma))
+      return;
+    if (i == size || allowed_ports[i] == kComma) {
+      if (i > last) {
+        int port;
+        base::StringToInt(base::StringPiece(allowed_ports.begin() + last,
+                                            allowed_ports.begin() + i),
+                          &port);
+        ports.insert(port);
+      }
+      last = i + 1;
+    }
+  }
+  g_explicitly_allowed_ports.Get() = ports;
+}
+
+ScopedPortException::ScopedPortException(int port) : port_(port) {
+  g_explicitly_allowed_ports.Get().insert(port);
+}
+
+ScopedPortException::~ScopedPortException() {
+  std::multiset<int>::iterator it =
+      g_explicitly_allowed_ports.Get().find(port_);
+  if (it != g_explicitly_allowed_ports.Get().end())
+    g_explicitly_allowed_ports.Get().erase(it);
+  else
+    NOTREACHED();
+}
+
 int SetNonBlocking(int fd) {
 #if defined(OS_WIN)
   unsigned long no_block = 1;
@@ -585,51 +626,6 @@
   return url.ReplaceComponents(replacements);
 }
 
-// Specifies a comma separated list of port numbers that should be accepted
-// despite bans. If the string is invalid no allowed ports are stored.
-void SetExplicitlyAllowedPorts(const std::string& allowed_ports) {
-  if (allowed_ports.empty())
-    return;
-
-  std::multiset<int> ports;
-  size_t last = 0;
-  size_t size = allowed_ports.size();
-  // The comma delimiter.
-  const std::string::value_type kComma = ',';
-
-  // Overflow is still possible for evil user inputs.
-  for (size_t i = 0; i <= size; ++i) {
-    // The string should be composed of only digits and commas.
-    if (i != size && !IsAsciiDigit(allowed_ports[i]) &&
-        (allowed_ports[i] != kComma))
-      return;
-    if (i == size || allowed_ports[i] == kComma) {
-      if (i > last) {
-        int port;
-        base::StringToInt(base::StringPiece(allowed_ports.begin() + last,
-                                            allowed_ports.begin() + i),
-                          &port);
-        ports.insert(port);
-      }
-      last = i + 1;
-    }
-  }
-  g_explicitly_allowed_ports.Get() = ports;
-}
-
-ScopedPortException::ScopedPortException(int port) : port_(port) {
-  g_explicitly_allowed_ports.Get().insert(port);
-}
-
-ScopedPortException::~ScopedPortException() {
-  std::multiset<int>::iterator it =
-      g_explicitly_allowed_ports.Get().find(port_);
-  if (it != g_explicitly_allowed_ports.Get().end())
-    g_explicitly_allowed_ports.Get().erase(it);
-  else
-    NOTREACHED();
-}
-
 bool HaveOnlyLoopbackAddresses() {
 #if defined(OS_ANDROID)
   return android::HaveOnlyLoopbackAddresses();
diff --git a/net/base/net_util.h b/net/base/net_util.h
index f2ba404..d08008a0 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -71,9 +71,6 @@
 // Convenience for omitting all unecessary types.
 NET_EXPORT extern const FormatUrlType kFormatUrlOmitAll;
 
-// Returns the number of explicitly allowed ports; for testing.
-NET_EXPORT_PRIVATE extern size_t GetCountOfExplicitlyAllowedPorts();
-
 // Splits an input of the form <host>[":"<port>] into its consitituent parts.
 // Saves the result into |*host| and |*port|. If the input did not have
 // the optional port, sets |*port| to -1.
@@ -226,15 +223,26 @@
 // registered by IANA and typically need root access to listen on.
 bool IsWellKnownPort(int port);
 
-enum PortOverrideMode { PORT_OVERRIDES_IGNORED, PORT_OVERRIDES_ALLOWED };
-
-// Checks if the port is allowed for the specified scheme.  If PortOverrideMode
-// is PORT_OVERIDES_ALLOWED, then ports set as allowed with
-// SetExplicitlyAllowedPorts() or by using ScopedPortException() will be
+// Checks if the port is allowed for the specified scheme.  Ports set as allowed
+// with SetExplicitlyAllowedPorts() or by using ScopedPortException() will be
 // considered allowed for any scheme.
-NET_EXPORT bool IsPortAllowedForScheme(int port,
-                                       const std::string& url_scheme,
-                                       PortOverrideMode port_override_mode);
+NET_EXPORT bool IsPortAllowedForScheme(int port, const std::string& url_scheme);
+
+// Returns the number of explicitly allowed ports; for testing.
+NET_EXPORT_PRIVATE size_t GetCountOfExplicitlyAllowedPorts();
+
+NET_EXPORT void SetExplicitlyAllowedPorts(const std::string& allowed_ports);
+
+class NET_EXPORT ScopedPortException {
+ public:
+  explicit ScopedPortException(int port);
+  ~ScopedPortException();
+
+ private:
+  int port_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPortException);
+};
 
 // Set socket to non-blocking mode
 NET_EXPORT int SetNonBlocking(int fd);
@@ -322,19 +330,6 @@
 //   - reference section
 NET_EXPORT_PRIVATE GURL SimplifyUrlForRequest(const GURL& url);
 
-NET_EXPORT void SetExplicitlyAllowedPorts(const std::string& allowed_ports);
-
-class NET_EXPORT ScopedPortException {
- public:
-  explicit ScopedPortException(int port);
-  ~ScopedPortException();
-
- private:
-  int port_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedPortException);
-};
-
 // Returns true if it can determine that only loopback addresses are configured.
 // i.e. if only 127.0.0.1 and ::1 are routable.
 // Also returns false if it cannot determine this.
diff --git a/net/base/net_util_icu.cc b/net/base/net_util_icu.cc
index 541e313..01204a3 100644
--- a/net/base/net_util_icu.cc
+++ b/net/base/net_util_icu.cc
@@ -194,15 +194,17 @@
 
   UErrorCode status = U_ZERO_ERROR;
 #ifdef U_WCHAR_IS_UTF16
-  icu::UnicodeSet dangerous_characters(icu::UnicodeString(
-      L"[[\\ \u00ad\u00bc\u00bd\u01c3\u0337\u0338"
-      L"\u05c3\u05f4\u06d4\u0702\u115f\u1160][\u2000-\u200b]"
-      L"[\u2024\u2027\u2028\u2029\u2039\u203a\u2044\u205f]"
-      L"[\u2154-\u2156][\u2159-\u215b][\u215f\u2215\u23ae"
-      L"\u29f6\u29f8\u2afb\u2afd][\u2ff0-\u2ffb][\u3014"
-      L"\u3015\u3033\u3164\u321d\u321e\u33ae\u33af\u33c6\u33df\ufe14"
-      L"\ufe15\ufe3f\ufe5d\ufe5e\ufeff\uff0e\uff06\uff61\uffa0\ufff9]"
-      L"[\ufffa-\ufffd]]"), status);
+  icu::UnicodeSet dangerous_characters(
+      icu::UnicodeString(
+          L"[[\\ \u00ad\u00bc\u00bd\u01c3\u0337\u0338"
+          L"\u05c3\u05f4\u06d4\u0702\u115f\u1160][\u2000-\u200b]"
+          L"[\u2024\u2027\u2028\u2029\u2039\u203a\u2044\u205f]"
+          L"[\u2154-\u2156][\u2159-\u215b][\u215f\u2215\u23ae"
+          L"\u29f6\u29f8\u2afb\u2afd][\u2ff0-\u2ffb][\u3014"
+          L"\u3015\u3033\u3164\u321d\u321e\u33ae\u33af\u33c6\u33df\ufe14"
+          L"\ufe15\ufe3f\ufe5d\ufe5e\ufeff\uff0e\uff06\uff61\uffa0\ufff9]"
+          L"[\ufffa-\ufffd]\U0001f50f\U0001f510\U0001f512\U0001f513]"),
+      status);
   DCHECK(U_SUCCESS(status));
   icu::RegexMatcher dangerous_patterns(icu::UnicodeString(
       // Lone katakana no, so, or n
@@ -219,7 +221,8 @@
       "\\u29f6\\u29f8\\u2afb\\u2afd][\\u2ff0-\\u2ffb][\\u3014"
       "\\u3015\\u3033\\u3164\\u321d\\u321e\\u33ae\\u33af\\u33c6\\u33df\\ufe14"
       "\\ufe15\\ufe3f\\ufe5d\\ufe5e\\ufeff\\uff0e\\uff06\\uff61\\uffa0\\ufff9]"
-      "[\\ufffa-\\ufffd]]", -1, US_INV), status);
+      "[\\ufffa-\\ufffd]\\U0001f50f\\U0001f510\\U0001f512\\U0001f513]", -1,
+      US_INV), status);
   DCHECK(U_SUCCESS(status));
   icu::RegexMatcher dangerous_patterns(icu::UnicodeString(
       // Lone katakana no, so, or n
@@ -676,7 +679,8 @@
   // Reject "view-source:view-source:..." to avoid deep recursion.
   const char kViewSourceTwice[] = "view-source:view-source:";
   if (url.SchemeIs(kViewSource) &&
-      !StartsWithASCII(url.possibly_invalid_spec(), kViewSourceTwice, false)) {
+      !base::StartsWithASCII(url.possibly_invalid_spec(), kViewSourceTwice,
+                             false)) {
     return FormatViewSourceUrl(url, languages, format_types,
                                unescape_rules, new_parsed, prefix_end,
                                adjustments);
@@ -701,8 +705,8 @@
   // formatted URL is directly pre-filled into an input field.)  For this reason
   // we avoid stripping "http://" in this case.
   bool omit_http = (format_types & kFormatUrlOmitHTTP) &&
-      EqualsASCII(url_string, kHTTP) &&
-      !StartsWithASCII(url.host(), kFTP, true);
+                   base::EqualsASCII(url_string, kHTTP) &&
+                   !base::StartsWithASCII(url.host(), kFTP, true);
   new_parsed->scheme = parsed.scheme;
 
   // Username & password.
@@ -789,7 +793,8 @@
                            &url_string, &new_parsed->ref, adjustments);
 
   // If we need to strip out http do it after the fact.
-  if (omit_http && StartsWith(url_string, base::ASCIIToUTF16(kHTTP), true)) {
+  if (omit_http &&
+      base::StartsWith(url_string, base::ASCIIToUTF16(kHTTP), true)) {
     const size_t kHTTPSize = arraysize(kHTTP) - 1;
     url_string = url_string.substr(kHTTPSize);
     // Because offsets in the |adjustments| are already calculated with respect
diff --git a/net/base/net_util_icu_unittest.cc b/net/base/net_util_icu_unittest.cc
index bfe63c1..f643426 100644
--- a/net/base/net_util_icu_unittest.cc
+++ b/net/base/net_util_icu_unittest.cc
@@ -331,6 +331,21 @@
      false, false, false, false, false,
      false, false, false, false, false,
   }},
+  // Padlock icon spoof.
+  {"xn--google-hj64e", L"\U0001f512google.com",
+    {false, false, false, false, false,
+     false, false, false, false, false,
+     false, false, false, false, false,
+     false, false, false, false, false,
+  }},
+  // Ensure that blacklisting "\xd83d\xdd12" did not inadvertently blacklist
+  // all strings with the surrogate '\xdd12'.
+  {"xn--fk9c.com", L"\U00010912.com",
+    {true,  false, false, false, false,
+     false, false, false, false, false,
+     false, false, false, false, false,
+     false, false, false, false, false,
+  }},
 #if 0
   // These two cases are special. We need a separate test.
   // U+3000 and U+3002 are normalized to ASCII space and dot.
@@ -422,7 +437,9 @@
           WideToUTF16(idn_cases[i].unicode_output) :
           ASCIIToUTF16(idn_cases[i].input));
       AppendLanguagesToOutputs(kLanguages[j], &expected, &output);
-      EXPECT_EQ(expected, output);
+      EXPECT_EQ(expected, output) << "input: \"" << idn_cases[i].input
+                                  << "\", languages: \"" << kLanguages[j]
+                                  << "\"";
     }
   }
 }
@@ -438,7 +455,9 @@
           WideToUTF16(idn_cases[i].unicode_output) :
           ASCIIToUTF16(idn_cases[i].input));
       AppendLanguagesToOutputs(kLanguages[j], &expected, &output);
-      EXPECT_EQ(expected, output);
+      EXPECT_EQ(expected, output) << "input: \"" << idn_cases[i].input
+                                  << "\", languages: \"" << kLanguages[j]
+                                  << "\"";
     }
   }
 }
diff --git a/net/base/network_quality_estimator.h b/net/base/network_quality_estimator.h
index ecfa08a..8be76c3 100644
--- a/net/base/network_quality_estimator.h
+++ b/net/base/network_quality_estimator.h
@@ -34,7 +34,8 @@
   ~NetworkQualityEstimator() override;
 
   // Returns an estimate of the current network quality.
-  NetworkQuality GetEstimate() const;
+  // Virtualized for testing.
+  virtual NetworkQuality GetEstimate() const;
 
   // Notifies NetworkQualityEstimator that a response has been received.
   // |prefilter_bytes_read| is the count of the bytes received prior to
diff --git a/net/base/nss_memio.c b/net/base/nss_memio.c
index 5705403..895b7b2 100644
--- a/net/base/nss_memio.c
+++ b/net/base/nss_memio.c
@@ -440,6 +440,9 @@
     } else /* if (bytes_read < 0) */ {
         mb->last_err = bytes_read;
     }
+
+    /* Clear read_requested now that the read has been satisfied. */
+    ((PRFilePrivate *)secret)->read_requested = 0;
 }
 
 int memio_GetWriteParams(memio_Private *secret,
diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc
index ba96659a..8245f9d 100644
--- a/net/base/sdch_manager.cc
+++ b/net/base/sdch_manager.cc
@@ -41,9 +41,6 @@
 // static
 bool SdchManager::g_sdch_enabled_ = true;
 
-// static
-bool SdchManager::g_secure_scheme_supported_ = true;
-
 SdchManager::DictionarySet::DictionarySet() {}
 
 SdchManager::DictionarySet::~DictionarySet() {}
@@ -111,11 +108,6 @@
   g_sdch_enabled_ = enabled;
 }
 
-// static
-void SdchManager::EnableSecureSchemeSupport(bool enabled) {
-  g_secure_scheme_supported_ = enabled;
-}
-
 void SdchManager::BlacklistDomain(const GURL& url,
                                   SdchProblemCode blacklist_reason) {
   SetAllowLatencyExperiment(url, false);
@@ -180,9 +172,6 @@
   if (!g_sdch_enabled_ )
     return SDCH_DISABLED;
 
-  if (!secure_scheme_supported() && url.SchemeIsCryptographic())
-    return SDCH_SECURE_SCHEME_NOT_SUPPORTED;
-
   if (blacklisted_domains_.empty())
     return SDCH_OK;
 
@@ -243,9 +232,6 @@
       referring_url.scheme() != dictionary_url.scheme())
     return SDCH_DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST;
 
-  if (!secure_scheme_supported() && referring_url.SchemeIsCryptographic())
-    return SDCH_DICTIONARY_SELECTED_FOR_SSL;
-
   // TODO(jar): Remove this failsafe conservative hack which is more restrictive
   // than current SDCH spec when needed, and justified by security audit.
   if (!referring_url.SchemeIsHTTPOrHTTPS())
@@ -262,8 +248,6 @@
   int count = 0;
   scoped_ptr<SdchManager::DictionarySet> result(new DictionarySet);
   for (const auto& entry: dictionaries_) {
-    if (!secure_scheme_supported() && target_url.SchemeIsCryptographic())
-      continue;
     if (entry.second->data.CanUse(target_url) != SDCH_OK)
       continue;
     if (entry.second->data.Expired())
@@ -294,12 +278,6 @@
   if (it == dictionaries_.end())
     return result.Pass();
 
-  if (!SdchManager::secure_scheme_supported() &&
-      target_url.SchemeIsCryptographic()) {
-    *problem_code = SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
-    return result.Pass();
-  }
-
   *problem_code = it->second->data.CanUse(target_url);
   if (*problem_code != SDCH_OK)
     return result.Pass();
@@ -482,7 +460,6 @@
   scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
 
   value->SetBoolean("sdch_enabled", sdch_enabled());
-  value->SetBoolean("secure_scheme_support", secure_scheme_supported());
 
   scoped_ptr<base::ListValue> entry_list(new base::ListValue());
   for (const auto& entry: dictionaries_) {
diff --git a/net/base/sdch_manager.h b/net/base/sdch_manager.h
index 366b81f..c8d0a84 100644
--- a/net/base/sdch_manager.h
+++ b/net/base/sdch_manager.h
@@ -103,11 +103,6 @@
 
   static bool sdch_enabled() { return g_sdch_enabled_; }
 
-  // Enables or disables SDCH compression over secure connection.
-  static void EnableSecureSchemeSupport(bool enabled);
-
-  static bool secure_scheme_supported() { return g_secure_scheme_supported_; }
-
   // Briefly prevent further advertising of SDCH on this domain (if SDCH is
   // enabled). After enough calls to IsInSupportedDomain() the blacklisting
   // will be removed. Additional blacklists take exponentially more calls
@@ -227,10 +222,6 @@
   // Support SDCH compression, by advertising in headers.
   static bool g_sdch_enabled_;
 
-  // Support SDCH compression for HTTPS requests and responses. When supported,
-  // HTTPS applicable dictionaries MUST have been acquired securely via HTTPS.
-  static bool g_secure_scheme_supported_;
-
   // A simple implementation of a RFC 3548 "URL safe" base64 encoder.
   static void UrlSafeBase64Encode(const std::string& input,
                                   std::string* output);
diff --git a/net/base/sdch_manager_unittest.cc b/net/base/sdch_manager_unittest.cc
index 9bb0e7ef..71362f7 100644
--- a/net/base/sdch_manager_unittest.cc
+++ b/net/base/sdch_manager_unittest.cc
@@ -101,11 +101,7 @@
  protected:
   SdchManagerTest()
       : sdch_manager_(new SdchManager),
-        default_support_(false),
-        default_https_support_(false) {
-    default_support_ = sdch_manager_->sdch_enabled();
-    default_https_support_ = sdch_manager_->secure_scheme_supported();
-  }
+        default_support_(sdch_manager_->sdch_enabled()) { }
 
   ~SdchManagerTest() override {}
 
@@ -114,7 +110,6 @@
   // Reset globals back to default state.
   void TearDown() override {
     SdchManager::EnableSdchSupport(default_support_);
-    SdchManager::EnableSecureSchemeSupport(default_https_support_);
   }
 
   // Attempt to add a dictionary to the manager and probe for success or
@@ -128,7 +123,6 @@
  private:
   scoped_ptr<SdchManager> sdch_manager_;
   bool default_support_;
-  bool default_https_support_;
 };
 
 static std::string NewSdchDictionary(const std::string& domain) {
@@ -268,10 +262,6 @@
   std::string dictionary_domain("x.y.z.google.com");
   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
 
-  SdchManager::EnableSecureSchemeSupport(false);
-  EXPECT_FALSE(AddSdchDictionary(dictionary_text,
-                                 GURL("https://" + dictionary_domain)));
-  SdchManager::EnableSecureSchemeSupport(true);
   EXPECT_TRUE(AddSdchDictionary(dictionary_text,
                                 GURL("https://" + dictionary_domain)));
 
@@ -303,7 +293,6 @@
   GURL target_url("https://" + dictionary_domain + "/test");
   // HTTPS target URL should not advertise dictionary acquired over HTTP even if
   // secure scheme support is enabled.
-  SdchManager::EnableSecureSchemeSupport(true);
   EXPECT_FALSE(sdch_manager()->GetDictionarySet(target_url));
 
   std::string client_hash;
@@ -321,7 +310,6 @@
   std::string dictionary_domain("x.y.z.google.com");
   std::string dictionary_text(NewSdchDictionary(dictionary_domain));
 
-  SdchManager::EnableSecureSchemeSupport(true);
   EXPECT_TRUE(AddSdchDictionary(dictionary_text,
                                 GURL("https://" + dictionary_domain)));
 
@@ -518,23 +506,6 @@
   EXPECT_EQ(SDCH_DICTIONARY_HASH_NOT_FOUND, problem_code);
 }
 
-TEST_F(SdchManagerTest, HttpsCorrectlySupported) {
-  GURL url("http://www.google.com");
-  GURL secure_url("https://www.google.com");
-
-  bool expect_https_support = true;
-
-  SdchProblemCode expected_code =
-      expect_https_support ? SDCH_OK : SDCH_SECURE_SCHEME_NOT_SUPPORTED;
-
-  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(url));
-  EXPECT_EQ(expected_code, sdch_manager()->IsInSupportedDomain(secure_url));
-
-  SdchManager::EnableSecureSchemeSupport(!expect_https_support);
-  EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(url));
-  EXPECT_NE(expected_code, sdch_manager()->IsInSupportedDomain(secure_url));
-}
-
 TEST_F(SdchManagerTest, ClearDictionaryData) {
   std::string dictionary_domain("x.y.z.google.com");
   GURL blacklist_url("http://bad.chromium.org");
diff --git a/net/base/sdch_problem_code_list.h b/net/base/sdch_problem_code_list.h
index f0e2d49..864f81e 100644
--- a/net/base/sdch_problem_code_list.h
+++ b/net/base/sdch_problem_code_list.h
@@ -126,7 +126,8 @@
 // SDCH is disabled.
 SDCH_PROBLEM_CODE(DISABLED, 105)
 // SDCH over https is disabled.
-SDCH_PROBLEM_CODE(SECURE_SCHEME_NOT_SUPPORTED, 106)
+// SDCH always supports secure schemes now, so this enum value is unused.
+// SDCH_PROBLEM_CODE(SECURE_SCHEME_NOT_SUPPORTED, 106)
 
 // A dictionary used notification occurred after dictionary deletion.
 SDCH_PROBLEM_CODE(DICTIONARY_USED_AFTER_DELETION, 107)
diff --git a/net/base/test_completion_callback_unittest.cc b/net/base/test_completion_callback_unittest.cc
index 35e52d7..454da5d 100644
--- a/net/base/test_completion_callback_unittest.cc
+++ b/net/base/test_completion_callback_unittest.cc
@@ -5,8 +5,10 @@
 // Illustrates how to use worker threads that issue completion callbacks
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/worker_pool.h"
 #include "net/base/completion_callback.h"
 #include "net/base/test_completion_callback.h"
@@ -80,8 +82,8 @@
   {
     base::AutoLock locked(origin_loop_lock_);
     if (origin_loop_)
-      origin_loop_->PostTask(FROM_HERE,
-                             base::Bind(&ExampleWorker::DoCallback, this));
+      origin_loop_->task_runner()->PostTask(
+          FROM_HERE, base::Bind(&ExampleWorker::DoCallback, this));
   }
 }
 
diff --git a/net/base/upload_file_element_reader_unittest.cc b/net/base/upload_file_element_reader_unittest.cc
index 38797cb..2a61dc622 100644
--- a/net/base/upload_file_element_reader_unittest.cc
+++ b/net/base/upload_file_element_reader_unittest.cc
@@ -6,8 +6,8 @@
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -32,12 +32,9 @@
         static_cast<int>(bytes_.size()),
         base::WriteFile(temp_file_path_, &bytes_[0], bytes_.size()));
 
-    reader_.reset(
-        new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                    temp_file_path_,
-                                    0,
-                                    kuint64max,
-                                    base::Time()));
+    reader_.reset(new UploadFileElementReader(
+        base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0,
+        kuint64max, base::Time()));
     TestCompletionCallback callback;
     ASSERT_EQ(ERR_IO_PENDING, reader_->Init(callback.callback()));
     EXPECT_EQ(OK, callback.WaitForResult());
@@ -180,12 +177,9 @@
 TEST_F(UploadFileElementReaderTest, Range) {
   const uint64_t kOffset = 2;
   const uint64_t kLength = bytes_.size() - kOffset * 3;
-  reader_.reset(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file_path_,
-                                  kOffset,
-                                  kLength,
-                                  base::Time()));
+  reader_.reset(new UploadFileElementReader(
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, kOffset,
+      kLength, base::Time()));
   TestCompletionCallback init_callback;
   ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
   EXPECT_EQ(OK, init_callback.WaitForResult());
@@ -211,7 +205,7 @@
   const base::Time expected_modification_time =
       info.last_modified - base::TimeDelta::FromSeconds(1);
   reader_.reset(new UploadFileElementReader(
-      base::MessageLoopProxy::current().get(), temp_file_path_, 0, kuint64max,
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0, kuint64max,
       expected_modification_time));
   TestCompletionCallback init_callback;
   ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
@@ -225,7 +219,7 @@
   const base::Time expected_modification_time =
       info.last_modified - base::TimeDelta::FromMilliseconds(900);
   reader_.reset(new UploadFileElementReader(
-      base::MessageLoopProxy::current().get(), temp_file_path_, 0, kuint64max,
+      base::ThreadTaskRunnerHandle::Get().get(), temp_file_path_, 0, kuint64max,
       expected_modification_time));
   TestCompletionCallback init_callback;
   ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
@@ -235,7 +229,7 @@
 TEST_F(UploadFileElementReaderTest, WrongPath) {
   const base::FilePath wrong_path(FILE_PATH_LITERAL("wrong_path"));
   reader_.reset(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
+      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
                                   wrong_path, 0, kuint64max, base::Time()));
   TestCompletionCallback init_callback;
   ASSERT_EQ(ERR_IO_PENDING, reader_->Init(init_callback.callback()));
diff --git a/net/cert/cert_database_mac.cc b/net/cert/cert_database_mac.cc
index c6aad551..037558c 100644
--- a/net/cert/cert_database_mac.cc
+++ b/net/cert/cert_database_mac.cc
@@ -6,6 +6,7 @@
 
 #include <Security/Security.h>
 
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/mac/mac_logging.h"
 #include "base/message_loop/message_loop.h"
@@ -32,7 +33,7 @@
         called_shutdown_(false) {
     // Ensure an associated CFRunLoop.
     DCHECK(base::MessageLoopForUI::IsCurrent());
-    task_runner_ = message_loop->message_loop_proxy();
+    task_runner_ = message_loop->task_runner();
     task_runner_->PostTask(FROM_HERE,
                            base::Bind(&Notifier::Init,
                                       base::Unretained(this)));
diff --git a/net/cert_net/nss_ocsp.cc b/net/cert_net/nss_ocsp.cc
index 1eea3eb..1297d29 100644
--- a/net/cert_net/nss_ocsp.cc
+++ b/net/cert_net/nss_ocsp.cc
@@ -19,10 +19,11 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -370,9 +371,8 @@
   void CancelLocked() {
     lock_.AssertAcquired();
     if (io_loop_) {
-      io_loop_->PostTask(
-          FROM_HERE,
-          base::Bind(&OCSPRequestSession::CancelURLRequest, this));
+      io_loop_->task_runner()->PostTask(
+          FROM_HERE, base::Bind(&OCSPRequestSession::CancelURLRequest, this));
     }
   }
 
@@ -532,7 +532,7 @@
     const tracked_objects::Location& from_here, const base::Closure& task) {
   base::AutoLock autolock(lock_);
   if (io_loop_)
-    io_loop_->PostTask(from_here, task);
+    io_loop_->task_runner()->PostTask(from_here, task);
 }
 
 void OCSPIOLoop::EnsureIOLoop() {
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index a83ec11..b474616 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -51,9 +51,9 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/profiler/scoped_tracker.h"
@@ -1362,7 +1362,7 @@
   if (initialized_ && store_.get())
     store_->Flush(callback);
   else if (!callback.is_null())
-    base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 bool CookieMonster::SetCookieWithOptions(const GURL& url,
diff --git a/net/cookies/cookie_monster_store_test.cc b/net/cookies/cookie_monster_store_test.cc
index ede98ec..bf422edd 100644
--- a/net/cookies/cookie_monster_store_test.cc
+++ b/net/cookies/cookie_monster_store_test.cc
@@ -5,8 +5,10 @@
 #include "net/cookies/cookie_monster_store_test.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/cookies/cookie_constants.h"
 #include "net/cookies/cookie_util.h"
@@ -40,7 +42,7 @@
     out_cookies = load_result_;
     loaded_ = true;
   }
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&LoadedCallbackTask::Run,
                  new LoadedCallbackTask(loaded_callback, out_cookies)));
@@ -52,7 +54,7 @@
   if (!loaded_) {
     Load(loaded_callback);
   } else {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&LoadedCallbackTask::Run,
                    new LoadedCallbackTask(loaded_callback,
@@ -76,7 +78,7 @@
 
 void MockPersistentCookieStore::Flush(const base::Closure& callback) {
   if (!callback.is_null())
-    base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void MockPersistentCookieStore::SetForceKeepSessionState() {
@@ -144,7 +146,7 @@
        it != cookies_.end(); it++)
     out_cookies.push_back(new CanonicalCookie(it->second));
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&LoadedCallbackTask::Run,
                  new LoadedCallbackTask(loaded_callback, out_cookies)));
@@ -157,7 +159,7 @@
   if (!loaded_) {
     Load(loaded_callback);
   } else {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&LoadedCallbackTask::Run,
                    new LoadedCallbackTask(loaded_callback,
@@ -188,7 +190,7 @@
 
 void MockSimplePersistentCookieStore::Flush(const base::Closure& callback) {
   if (!callback.is_null())
-    base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 void MockSimplePersistentCookieStore::SetForceKeepSessionState() {
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 61dbd09..5452f191 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -10,17 +10,20 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_samples.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "net/cookies/canonical_cookie.h"
@@ -54,7 +57,7 @@
   MOCK_METHOD1(DeleteCookie, void(const CanonicalCookie& cc));
   virtual void Flush(const base::Closure& callback) {
     if (!callback.is_null())
-      base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
   }
   MOCK_METHOD0(SetForceKeepSessionState, void());
 
@@ -637,8 +640,8 @@
 };
 
 ACTION(QuitCurrentMessageLoop) {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::MessageLoop::QuitClosure());
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::MessageLoop::QuitClosure());
 }
 
 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed,
@@ -2062,7 +2065,7 @@
 
   void Load(const LoadedCallback& loaded_callback) override {
     std::vector<CanonicalCookie*> out_cookies;
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&LoadedCallbackTask::Run,
                    new LoadedCallbackTask(loaded_callback, out_cookies)));
@@ -2445,7 +2448,7 @@
  protected:
   void RunOnOtherThread(const base::Closure& task) {
     other_thread_.Start();
-    other_thread_.message_loop()->PostTask(FROM_HERE, task);
+    other_thread_.task_runner()->PostTask(FROM_HERE, task);
     RunFor(kTimeout);
     other_thread_.Stop();
   }
diff --git a/net/cookies/cookie_store_test_callbacks.cc b/net/cookies/cookie_store_test_callbacks.cc
index 8ba1c940..afb05d1 100644
--- a/net/cookies/cookie_store_test_callbacks.cc
+++ b/net/cookies/cookie_store_test_callbacks.cc
@@ -4,7 +4,9 @@
 
 #include "net/cookies/cookie_store_test_callbacks.h"
 
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -36,7 +38,8 @@
 
   did_run_ = true;
   EXPECT_EQ(expected_loop, base::MessageLoop::current());
-  loop_to_quit_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+  loop_to_quit_->task_runner()->PostTask(FROM_HERE,
+                                         base::MessageLoop::QuitClosure());
 }
 
 StringResultCookieCallback::StringResultCookieCallback() {}
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index bcf8c89..49f9d9ac 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -5,7 +5,9 @@
 #include "net/cookies/cookie_store_test_helpers.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace net {
 
@@ -42,11 +44,9 @@
       base::Bind(&DelayedCookieMonster::SetCookiesInternalCallback,
                  base::Unretained(this)));
   DCHECK_EQ(did_run_, true);
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&DelayedCookieMonster::InvokeSetCookiesCallback,
-                 base::Unretained(this),
-                 callback),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&DelayedCookieMonster::InvokeSetCookiesCallback,
+                            base::Unretained(this), callback),
       base::TimeDelta::FromMilliseconds(kDelayedTime));
 }
 
@@ -60,11 +60,10 @@
       base::Bind(&DelayedCookieMonster::GetCookiesWithOptionsInternalCallback,
                  base::Unretained(this)));
   DCHECK_EQ(did_run_, true);
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&DelayedCookieMonster::InvokeGetCookieStringCallback,
-                 base::Unretained(this),
-                 callback),
+                 base::Unretained(this), callback),
       base::TimeDelta::FromMilliseconds(kDelayedTime));
 }
 
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index fa429fd..763b6bf 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -6,8 +6,11 @@
 #define NET_COOKIES_COOKIE_STORE_UNITTEST_H_
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_tokenizer.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/cookies/cookie_store.h"
@@ -208,7 +211,7 @@
 
   void RunFor(int ms) {
     // Runs the test thread message loop for up to |ms| milliseconds.
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&base::MessageLoop::Quit, weak_factory_->GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(ms));
@@ -1089,7 +1092,7 @@
  protected:
   void RunOnOtherThread(const base::Closure& task) {
     other_thread_.Start();
-    other_thread_.message_loop()->PostTask(FROM_HERE, task);
+    other_thread_.task_runner()->PostTask(FROM_HERE, task);
     CookieStoreTest<CookieStoreTestTraits>::RunFor(kTimeout);
     other_thread_.Stop();
   }
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index e0d7862..3739676 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -54,7 +54,7 @@
   net::TestCompletionCallback cb;
 
   scoped_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl(
-      cache_path, cache_thread.message_loop_proxy(), NULL));
+      cache_path, cache_thread.task_runner(), NULL));
   int rv = cache->Init(cb.callback());
   if (cb.GetResult(rv) != net::OK)
     return scoped_ptr<disk_cache::BackendImpl>();
@@ -1900,8 +1900,8 @@
 
   const int kRestartCount = 5;
   for (int i = 0; i < kRestartCount; ++i) {
-    cache.reset(new disk_cache::BackendImpl(
-        cache_path_, cache_thread.message_loop_proxy(), NULL));
+    cache.reset(new disk_cache::BackendImpl(cache_path_,
+                                            cache_thread.task_runner(), NULL));
     int rv = cache->Init(cb.callback());
     ASSERT_EQ(net::OK, cb.GetResult(rv));
     EXPECT_EQ(1, cache->GetEntryCount());
@@ -1942,7 +1942,7 @@
   const int kRestartCount = 5;
   for (int i = 0; i < kRestartCount; ++i) {
     scoped_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl(
-        cache_path_, cache_thread.message_loop_proxy(), NULL));
+        cache_path_, cache_thread.task_runner(), NULL));
     int rv = cache->Init(cb.callback());
     ASSERT_EQ(net::OK, cb.GetResult(rv));
     EXPECT_EQ(1, cache->GetEntryCount());
diff --git a/net/disk_cache/blockfile/backend_impl.cc b/net/disk_cache/blockfile/backend_impl.cc
index c4058ab..5133ea5 100644
--- a/net/disk_cache/blockfile/backend_impl.cc
+++ b/net/disk_cache/blockfile/backend_impl.cc
@@ -10,7 +10,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/hash.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/rand_util.h"
@@ -18,6 +18,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_info.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
@@ -1032,7 +1033,7 @@
   disabled_ = true;
 
   if (!num_refs_)
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&BackendImpl::RestartCache, GetWeakPtr(), true));
 }
 
@@ -1809,7 +1810,7 @@
   num_refs_--;
 
   if (!num_refs_ && disabled_)
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&BackendImpl::RestartCache, GetWeakPtr(), true));
 }
 
diff --git a/net/disk_cache/blockfile/eviction.cc b/net/disk_cache/blockfile/eviction.cc
index 20d17fcd..46eb2d7 100644
--- a/net/disk_cache/blockfile/eviction.cc
+++ b/net/disk_cache/blockfile/eviction.cc
@@ -30,9 +30,11 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/disk_cache/blockfile/backend_impl.h"
 #include "net/disk_cache/blockfile/disk_format.h"
@@ -147,7 +149,7 @@
     }
     if (!empty && (deleted_entries > 20 ||
                    (TimeTicks::Now() - start).InMilliseconds() > 20)) {
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::Bind(&Eviction::TrimCache, ptr_factory_.GetWeakPtr(), false));
       break;
@@ -215,9 +217,8 @@
     return;
   delay_trim_ = true;
   trim_delays_++;
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&Eviction::DelayedTrim, ptr_factory_.GetWeakPtr()),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&Eviction::DelayedTrim, ptr_factory_.GetWeakPtr()),
       base::TimeDelta::FromMilliseconds(1000));
 }
 
@@ -369,7 +370,7 @@
       }
       if (!empty && (deleted_entries > 20 ||
                      (TimeTicks::Now() - start).InMilliseconds() > 20)) {
-        base::MessageLoop::current()->PostTask(
+        base::ThreadTaskRunnerHandle::Get()->PostTask(
             FROM_HERE,
             base::Bind(&Eviction::TrimCache, ptr_factory_.GetWeakPtr(), false));
         break;
@@ -382,7 +383,7 @@
   if (empty) {
     TrimDeleted(true);
   } else if (ShouldTrimDeleted()) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&Eviction::TrimDeleted, ptr_factory_.GetWeakPtr(), empty));
   }
@@ -515,7 +516,7 @@
   }
 
   if (deleted_entries && !empty && ShouldTrimDeleted()) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&Eviction::TrimDeleted, ptr_factory_.GetWeakPtr(), false));
   }
diff --git a/net/disk_cache/blockfile/sparse_control.cc b/net/disk_cache/blockfile/sparse_control.cc
index cd2997f..08d79a8 100644
--- a/net/disk_cache/blockfile/sparse_control.cc
+++ b/net/disk_cache/blockfile/sparse_control.cc
@@ -8,10 +8,12 @@
 
 #include "base/bind.h"
 #include "base/format_macros.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -138,7 +140,7 @@
   children_map_.Set(child_id, false);
 
   // Post a task to delete the next child.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&ChildrenDeleter::DeleteChildren, this));
 }
 
@@ -361,11 +363,11 @@
   deleter->AddRef();
 
   if (buffer) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ChildrenDeleter::Start, deleter, buffer, data_len));
   } else {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ChildrenDeleter::ReadData, deleter, address, data_len));
   }
diff --git a/net/disk_cache/simple/simple_index_file_unittest.cc b/net/disk_cache/simple/simple_index_file_unittest.cc
index 0732fbc..cfff0792 100644
--- a/net/disk_cache/simple/simple_index_file_unittest.cc
+++ b/net/disk_cache/simple/simple_index_file_unittest.cc
@@ -6,10 +6,12 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/hash.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/pickle.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
@@ -274,11 +276,8 @@
   ASSERT_TRUE(cache_thread.StartWithOptions(
       base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
   disk_cache::SimpleBackendImpl* simple_cache =
-      new disk_cache::SimpleBackendImpl(cache_path,
-                                        0,
-                                        net::DISK_CACHE,
-                                        cache_thread.message_loop_proxy().get(),
-                                        NULL);
+      new disk_cache::SimpleBackendImpl(cache_path, 0, net::DISK_CACHE,
+                                        cache_thread.task_runner().get(), NULL);
   net::TestCompletionCallback cb;
   int rv = simple_cache->Init(cb.callback());
   EXPECT_EQ(net::OK, cb.GetResult(rv));
@@ -291,7 +290,7 @@
   // thread after that.
   MessageLoopHelper helper;
   CallbackTest cb_shutdown(&helper, false);
-  cache_thread.message_loop_proxy()->PostTask(
+  cache_thread.task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&CallbackTest::Run, base::Unretained(&cb_shutdown), net::OK));
   helper.WaitUntilCacheIoFinished(1);
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index 6f10355..2bd10aa 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -12,8 +12,11 @@
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_util.h"
@@ -232,11 +235,9 @@
 #endif  // defined(OS_ANDROID)
     // Ignore transient flutter of resolv.conf by delaying the signal a bit.
     const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(50);
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&Watcher::OnConfigChangedDelayed,
-                   weak_factory_.GetWeakPtr(),
-                   succeeded),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&Watcher::OnConfigChangedDelayed,
+                              weak_factory_.GetWeakPtr(), succeeded),
         kDelay);
   }
   void OnConfigChangedDelayed(bool succeeded) {
diff --git a/net/dns/dns_config_service_unittest.cc b/net/dns/dns_config_service_unittest.cc
index 7d2075fb..0ff0b91 100644
--- a/net/dns/dns_config_service_unittest.cc
+++ b/net/dns/dns_config_service_unittest.cc
@@ -7,10 +7,13 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/cancelable_callback.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_split.h"
 #include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/net_util.h"
 #include "net/dns/dns_protocol.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -148,7 +151,7 @@
 
   void WaitForConfig(base::TimeDelta timeout) {
     base::CancelableClosure closure(base::MessageLoop::QuitClosure());
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, closure.callback(), timeout);
     quit_on_config_ = true;
     base::MessageLoop::current()->Run();
diff --git a/net/dns/dns_test_util.cc b/net/dns/dns_test_util.cc
index 2ba3763..39857d79 100644
--- a/net/dns/dns_test_util.cc
+++ b/net/dns/dns_test_util.cc
@@ -8,9 +8,11 @@
 
 #include "base/big_endian.h"
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/sys_byteorder.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/dns_util.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -70,7 +72,7 @@
     if (delayed_)
       return;
     // Using WeakPtr to cleanly cancel when transaction is destroyed.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&MockTransaction::Finish, AsWeakPtr()));
   }
 
diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc
index d9286a0..f60ae26 100644
--- a/net/dns/dns_transaction.cc
+++ b/net/dns/dns_transaction.cc
@@ -10,16 +10,18 @@
 
 #include "base/big_endian.h"
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_piece.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/non_thread_safe.h"
 #include "base/timer/timer.h"
 #include "base/values.h"
@@ -605,7 +607,7 @@
 
     // Must always return result asynchronously, to avoid reentrancy.
     if (result.rv != ERR_IO_PENDING) {
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), result));
     }
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 970ec1f..a074c3e 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -281,7 +281,7 @@
   // otherwise (trial absent): return default.
   std::string group_name = base::FieldTrialList::FindFullName("AsyncDns");
   if (!group_name.empty())
-    return StartsWithASCII(group_name, "AsyncDnsNoFallback", false);
+    return base::StartsWithASCII(group_name, "AsyncDnsNoFallback", false);
   return kDefault;
 }
 
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index 4953022..4978d81 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -9,15 +9,18 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/address_list.h"
 #include "net/base/net_errors.h"
@@ -268,7 +271,7 @@
     if (completed())
       return result_;
     base::CancelableClosure closure(base::MessageLoop::QuitClosure());
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, closure.callback(), TestTimeouts::action_max_timeout());
     quit_on_complete_ = true;
     base::MessageLoop::current()->Run();
@@ -807,8 +810,8 @@
 
       // Quit after returning from OnCompleted (to give it a chance at
       // incorrectly running the cancelled tasks).
-      base::MessageLoop::current()->PostTask(FROM_HERE,
-                                             base::MessageLoop::QuitClosure());
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::MessageLoop::QuitClosure());
     }
   };
   set_handler(new MyHandler());
@@ -833,8 +836,8 @@
 
       // Quit after returning from OnCompleted (to give it a chance at
       // incorrectly running the cancelled tasks).
-      base::MessageLoop::current()->PostTask(FROM_HERE,
-                                             base::MessageLoop::QuitClosure());
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::MessageLoop::QuitClosure());
     }
   };
   set_handler(new MyHandler());
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc
index 2fe89b1..49fdd54 100644
--- a/net/dns/mdns_client_impl.cc
+++ b/net/dns/mdns_client_impl.cc
@@ -8,8 +8,10 @@
 #include <queue>
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
@@ -176,7 +178,7 @@
           << std::find(socket_handlers_.begin(), socket_handlers_.end(), loop) -
                  socket_handlers_.begin() << ", error=" << rv;
   // Post to allow deletion of this object by delegate.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&MDnsConnection::OnError, weak_ptr_factory_.GetWeakPtr(), rv));
 }
@@ -368,9 +370,9 @@
   if (!observer_list_iterator->second->might_have_observers()) {
     // Schedule the actual removal for later in case the listener removal
     // happens while iterating over the observer list.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE, base::Bind(
-            &MDnsClientImpl::Core::CleanupObserverList, AsWeakPtr(), key));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&MDnsClientImpl::Core::CleanupObserverList,
+                              AsWeakPtr(), key));
   }
 }
 
@@ -587,10 +589,10 @@
       static_cast<int>(base::Time::kMillisecondsPerSecond *
                        kListenerRefreshRatio2 * ttl_));
 
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, next_refresh_.callback(), next_refresh1 - clock_->Now());
 
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, next_refresh_.callback(), next_refresh2 - clock_->Now());
 }
 
@@ -729,9 +731,8 @@
 
   timeout_.Reset(base::Bind(&MDnsTransactionImpl::SignalTransactionOver,
                             AsWeakPtr()));
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      timeout_.callback(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, timeout_.callback(),
       base::TimeDelta::FromSeconds(MDnsTransactionTimeoutSeconds));
 
   return true;
diff --git a/net/dns/mdns_client_unittest.cc b/net/dns/mdns_client_unittest.cc
index 70514f3..7dccda12 100644
--- a/net/dns/mdns_client_unittest.cc
+++ b/net/dns/mdns_client_unittest.cc
@@ -4,8 +4,11 @@
 
 #include <queue>
 
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/timer/mock_timer.h"
@@ -524,7 +527,7 @@
 void MDnsTest::RunFor(base::TimeDelta time_period) {
   base::CancelableCallback<void()> callback(base::Bind(&MDnsTest::Stop,
                                                        base::Unretained(this)));
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, callback.callback(), time_period);
 
   base::MessageLoop::current()->Run();
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc
index 810765c..288276b 100644
--- a/net/dns/mock_host_resolver.cc
+++ b/net/dns/mock_host_resolver.cc
@@ -8,11 +8,13 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
@@ -91,7 +93,7 @@
     *handle = reinterpret_cast<RequestHandle>(id);
 
   if (!ondemand_mode_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&MockHostResolverBase::ResolveNow, AsWeakPtr(), id));
   }
@@ -130,7 +132,7 @@
   DCHECK(CalledOnValidThread());
   DCHECK(ondemand_mode_);
   for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&MockHostResolverBase::ResolveNow, AsWeakPtr(), i->first));
   }
diff --git a/net/dns/mock_mdns_socket_factory.cc b/net/dns/mock_mdns_socket_factory.cc
index 681d1ec..b241da6 100644
--- a/net/dns/mock_mdns_socket_factory.cc
+++ b/net/dns/mock_mdns_socket_factory.cc
@@ -4,6 +4,9 @@
 
 #include <algorithm>
 
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/net_errors.h"
 #include "net/dns/mock_mdns_socket_factory.h"
 
@@ -50,7 +53,8 @@
     IOBuffer* buffer, int size, IPEndPoint* address,
     const CompletionCallback& callback) {
   int rv = HandleRecvNow(buffer, size, address, callback);
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, rv));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, rv));
   return ERR_IO_PENDING;
 }
 
diff --git a/net/dns/serial_worker_unittest.cc b/net/dns/serial_worker_unittest.cc
index 18b5464..da878306 100644
--- a/net/dns/serial_worker_unittest.cc
+++ b/net/dns/serial_worker_unittest.cc
@@ -5,7 +5,9 @@
 #include "net/dns/serial_worker.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -67,9 +69,9 @@
   }
 
   void BreakNow(std::string b) {
-    message_loop_->PostTask(FROM_HERE,
-        base::Bind(&SerialWorkerTest::BreakCallback,
-                   base::Unretained(this), b));
+    message_loop_->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&SerialWorkerTest::BreakCallback,
+                              base::Unretained(this), b));
   }
 
   void RunUntilBreak(std::string b) {
diff --git a/net/extras/sqlite/sqlite_channel_id_store_unittest.cc b/net/extras/sqlite/sqlite_channel_id_store_unittest.cc
index d3a7f755..c06a42fa 100644
--- a/net/extras/sqlite/sqlite_channel_id_store_unittest.cc
+++ b/net/extras/sqlite/sqlite_channel_id_store_unittest.cc
@@ -7,9 +7,9 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "crypto/ec_private_key.h"
 #include "net/base/test_data_directory.h"
 #include "net/cert/asn1_util.h"
@@ -101,7 +101,7 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     store_ = new SQLiteChannelIDStore(
         temp_dir_.path().Append(kTestChannelIDFilename),
-        base::MessageLoopProxy::current());
+        base::ThreadTaskRunnerHandle::Get());
     ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
     Load(&channel_ids);
     ASSERT_EQ(0u, channel_ids.size());
@@ -134,7 +134,7 @@
   base::RunLoop().RunUntilIdle();
   store_ =
       new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
-                               base::MessageLoopProxy::current());
+                               base::ThreadTaskRunnerHandle::Get());
 
   // Reload and test for persistence
   Load(&channel_ids);
@@ -164,7 +164,7 @@
   channel_ids.clear();
   store_ =
       new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
-                               base::MessageLoopProxy::current());
+                               base::ThreadTaskRunnerHandle::Get());
 
   // Reload and check if the keypair has been removed.
   Load(&channel_ids);
@@ -190,7 +190,7 @@
   base::RunLoop().RunUntilIdle();
   store_ =
       new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
-                               base::MessageLoopProxy::current());
+                               base::ThreadTaskRunnerHandle::Get());
 
   // Reload and test for persistence
   Load(&channel_ids);
@@ -208,7 +208,7 @@
   channel_ids.clear();
   store_ =
       new SQLiteChannelIDStore(temp_dir_.path().Append(kTestChannelIDFilename),
-                               base::MessageLoopProxy::current());
+                               base::ThreadTaskRunnerHandle::Get());
 
   // Reload and check that only foo.com persisted in store.
   Load(&channel_ids);
@@ -264,8 +264,8 @@
     SCOPED_TRACE(i);
 
     ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
-    store_ =
-        new SQLiteChannelIDStore(v1_db_path, base::MessageLoopProxy::current());
+    store_ = new SQLiteChannelIDStore(v1_db_path,
+                                      base::ThreadTaskRunnerHandle::Get());
 
     // Load the database. Because the existing v1 certs are implicitly of type
     // RSA, which is unsupported, they're discarded.
@@ -336,8 +336,8 @@
     SCOPED_TRACE(i);
 
     ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
-    store_ =
-        new SQLiteChannelIDStore(v2_db_path, base::MessageLoopProxy::current());
+    store_ = new SQLiteChannelIDStore(v2_db_path,
+                                      base::ThreadTaskRunnerHandle::Get());
 
     // Load the database and ensure the certs can be read.
     Load(&channel_ids);
@@ -414,8 +414,8 @@
     SCOPED_TRACE(i);
 
     ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
-    store_ =
-        new SQLiteChannelIDStore(v3_db_path, base::MessageLoopProxy::current());
+    store_ = new SQLiteChannelIDStore(v3_db_path,
+                                      base::ThreadTaskRunnerHandle::Get());
 
     // Load the database and ensure the certs can be read.
     Load(&channel_ids);
@@ -508,8 +508,8 @@
     SCOPED_TRACE(i);
 
     ScopedVector<DefaultChannelIDStore::ChannelID> channel_ids;
-    store_ =
-        new SQLiteChannelIDStore(v4_db_path, base::MessageLoopProxy::current());
+    store_ = new SQLiteChannelIDStore(v4_db_path,
+                                      base::ThreadTaskRunnerHandle::Get());
 
     // Load the database and ensure the certs can be read.
     Load(&channel_ids);
diff --git a/net/filter/filter.cc b/net/filter/filter.cc
index b49aa34..0e6544b 100644
--- a/net/filter/filter.cc
+++ b/net/filter/filter.cc
@@ -184,12 +184,12 @@
 Filter::FilterType Filter::ConvertEncodingToType(
     const std::string& filter_type) {
   FilterType type_id;
-  if (LowerCaseEqualsASCII(filter_type, kDeflate)) {
+  if (base::LowerCaseEqualsASCII(filter_type, kDeflate)) {
     type_id = FILTER_TYPE_DEFLATE;
-  } else if (LowerCaseEqualsASCII(filter_type, kGZip) ||
-             LowerCaseEqualsASCII(filter_type, kXGZip)) {
+  } else if (base::LowerCaseEqualsASCII(filter_type, kGZip) ||
+             base::LowerCaseEqualsASCII(filter_type, kXGZip)) {
     type_id = FILTER_TYPE_GZIP;
-  } else if (LowerCaseEqualsASCII(filter_type, kSdch)) {
+  } else if (base::LowerCaseEqualsASCII(filter_type, kSdch)) {
     type_id = FILTER_TYPE_SDCH;
   } else {
     // Note we also consider "identity" and "uncompressed" UNSUPPORTED as
@@ -267,7 +267,7 @@
   // supported server side on paths that only send HTML content, this mode has
   // never surfaced in the wild (and is unlikely to).
   // We will gather a lot of stats as we perform the fixups
-  if (StartsWithASCII(mime_type, kTextHtml, false)) {
+  if (base::StartsWithASCII(mime_type, kTextHtml, false)) {
     // Suspicious case: Advertised dictionary, but server didn't use sdch, and
     // we're HTML tagged.
     if (encoding_types->empty()) {
diff --git a/net/ftp/ftp_directory_listing_parser_netware.cc b/net/ftp/ftp_directory_listing_parser_netware.cc
index 20716ab..e8b635d 100644
--- a/net/ftp/ftp_directory_listing_parser_netware.cc
+++ b/net/ftp/ftp_directory_listing_parser_netware.cc
@@ -40,7 +40,7 @@
     const base::Time& current_time,
     std::vector<FtpDirectoryListingEntry>* entries) {
   if (!lines.empty() &&
-          !StartsWith(lines[0], base::ASCIIToUTF16("total "), true)) {
+      !base::StartsWith(lines[0], base::ASCIIToUTF16("total "), true)) {
     return false;
   }
 
diff --git a/net/ftp/ftp_directory_listing_parser_os2.cc b/net/ftp/ftp_directory_listing_parser_os2.cc
index 094a9bdb..a393d329 100644
--- a/net/ftp/ftp_directory_listing_parser_os2.cc
+++ b/net/ftp/ftp_directory_listing_parser_os2.cc
@@ -40,12 +40,12 @@
     FtpDirectoryListingEntry entry;
     if (!base::StringToInt64(columns[0], &entry.size))
       return false;
-    if (EqualsASCII(columns[1], "DIR")) {
+    if (base::EqualsASCII(columns[1], "DIR")) {
       if (entry.size != 0)
         return false;
       entry.type = FtpDirectoryListingEntry::DIRECTORY;
       entry.size = -1;
-    } else if (EqualsASCII(columns[1], "A")) {
+    } else if (base::EqualsASCII(columns[1], "A")) {
       entry.type = FtpDirectoryListingEntry::FILE;
       if (entry.size < 0)
         return false;
diff --git a/net/ftp/ftp_directory_listing_parser_vms.cc b/net/ftp/ftp_directory_listing_parser_vms.cc
index 05e687f..fb5ee47 100644
--- a/net/ftp/ftp_directory_listing_parser_vms.cc
+++ b/net/ftp/ftp_directory_listing_parser_vms.cc
@@ -43,7 +43,7 @@
   base::SplitString(listing_parts[0], '.', &filename_parts);
   if (filename_parts.size() != 2)
     return false;
-  if (EqualsASCII(filename_parts[1], "DIR")) {
+  if (base::EqualsASCII(filename_parts[1], "DIR")) {
     *parsed_filename = base::StringToLowerASCII(filename_parts[0]);
     *type = FtpDirectoryListingEntry::DIRECTORY;
   } else {
@@ -210,7 +210,7 @@
     if (lines[i].empty())
       continue;
 
-    if (StartsWith(lines[i], base::ASCIIToUTF16("Total of "), true)) {
+    if (base::StartsWith(lines[i], base::ASCIIToUTF16("Total of "), true)) {
       // After the "total" line, all following lines must be empty.
       for (size_t j = i + 1; j < lines.size(); j++)
         if (!lines[j].empty())
diff --git a/net/ftp/ftp_directory_listing_parser_windows.cc b/net/ftp/ftp_directory_listing_parser_windows.cc
index 2a50220..f394b17 100644
--- a/net/ftp/ftp_directory_listing_parser_windows.cc
+++ b/net/ftp/ftp_directory_listing_parser_windows.cc
@@ -37,7 +37,7 @@
       return false;
 
     FtpDirectoryListingEntry entry;
-    if (EqualsASCII(columns[2], "<DIR>")) {
+    if (base::EqualsASCII(columns[2], "<DIR>")) {
       entry.type = FtpDirectoryListingEntry::DIRECTORY;
       entry.size = -1;
     } else {
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index 32ede86..139fd19f 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -958,8 +958,7 @@
       if (!ExtractPortFromEPSVResponse(response, &port))
         return Stop(ERR_INVALID_RESPONSE);
       if (IsWellKnownPort(port) ||
-          !IsPortAllowedForScheme(port, url::kFtpScheme,
-                                  PORT_OVERRIDES_IGNORED)) {
+          !IsPortAllowedForScheme(port, url::kFtpScheme)) {
         return Stop(ERR_UNSAFE_PORT);
       }
       data_connection_port_ = static_cast<uint16>(port);
@@ -997,8 +996,7 @@
       if (!ExtractPortFromPASVResponse(response, &port))
         return Stop(ERR_INVALID_RESPONSE);
       if (IsWellKnownPort(port) ||
-          !IsPortAllowedForScheme(port, url::kFtpScheme,
-                                  PORT_OVERRIDES_IGNORED)) {
+          !IsPortAllowedForScheme(port, url::kFtpScheme)) {
         return Stop(ERR_UNSAFE_PORT);
       }
       data_connection_port_ = static_cast<uint16>(port);
diff --git a/net/ftp/ftp_util.cc b/net/ftp/ftp_util.cc
index b558066..11956ba 100644
--- a/net/ftp/ftp_util.cc
+++ b/net/ftp/ftp_util.cc
@@ -333,10 +333,10 @@
     if (time.length() != 7)
       return false;
     base::string16 am_or_pm(time.substr(5, 2));
-    if (EqualsASCII(am_or_pm, "PM")) {
+    if (base::EqualsASCII(am_or_pm, "PM")) {
       if (time_exploded.hour < 12)
         time_exploded.hour += 12;
-    } else if (EqualsASCII(am_or_pm, "AM")) {
+    } else if (base::EqualsASCII(am_or_pm, "AM")) {
       if (time_exploded.hour == 12)
         time_exploded.hour = 0;
     } else {
diff --git a/net/http/failing_http_transaction_factory.cc b/net/http/failing_http_transaction_factory.cc
index 07023f2..89e5329d 100644
--- a/net/http/failing_http_transaction_factory.cc
+++ b/net/http/failing_http_transaction_factory.cc
@@ -6,8 +6,10 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/load_timing_info.h"
 #include "net/base/upload_progress.h"
 #include "net/http/http_response_info.h"
@@ -77,8 +79,8 @@
 int FailingHttpTransaction::Start(const HttpRequestInfo* request_info,
                                   const CompletionCallback& callback,
                                   const BoundNetLog& net_log)  {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(callback, error_));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, error_));
   return ERR_IO_PENDING;
 }
 
diff --git a/net/http/http_auth.cc b/net/http/http_auth.cc
index 3525114..7752d743 100644
--- a/net/http/http_auth.cc
+++ b/net/http/http_auth.cc
@@ -76,7 +76,8 @@
       HttpAuth::AUTHORIZATION_RESULT_INVALID;
   while (headers->EnumerateHeader(&iter, header_name, &challenge)) {
     HttpAuthChallengeTokenizer props(challenge.begin(), challenge.end());
-    if (!LowerCaseEqualsASCII(props.scheme(), current_scheme_name.c_str()))
+    if (!base::LowerCaseEqualsASCII(props.scheme(),
+                                    current_scheme_name.c_str()))
       continue;
     authorization_result = handler->HandleAnotherChallenge(&props);
     if (authorization_result != HttpAuth::AUTHORIZATION_RESULT_INVALID) {
diff --git a/net/http/http_auth_cache.cc b/net/http/http_auth_cache.cc
index 51f9035..106e1ec2 100644
--- a/net/http/http_auth_cache.cc
+++ b/net/http/http_auth_cache.cc
@@ -37,7 +37,7 @@
 bool IsEnclosingPath(const std::string& container, const std::string& path) {
   DCHECK(container.empty() || *(container.end() - 1) == '/');
   return ((container.empty() && path.empty()) ||
-          (!container.empty() && StartsWithASCII(path, container, true)));
+          (!container.empty() && base::StartsWithASCII(path, container, true)));
 }
 
 // Debug helper to check that |origin| arguments are properly formed.
diff --git a/net/http/http_auth_gssapi_posix.cc b/net/http/http_auth_gssapi_posix.cc
index 9b902af..388cc64 100644
--- a/net/http/http_auth_gssapi_posix.cc
+++ b/net/http/http_auth_gssapi_posix.cc
@@ -688,8 +688,8 @@
 HttpAuth::AuthorizationResult HttpAuthGSSAPI::ParseChallenge(
     HttpAuthChallengeTokenizer* tok) {
   // Verify the challenge's auth-scheme.
-  if (!LowerCaseEqualsASCII(tok->scheme(),
-                            base::StringToLowerASCII(scheme_).c_str()))
+  if (!base::LowerCaseEqualsASCII(tok->scheme(),
+                                  base::StringToLowerASCII(scheme_).c_str()))
     return HttpAuth::AUTHORIZATION_RESULT_INVALID;
 
   std::string encoded_auth_token = tok->base64_param();
diff --git a/net/http/http_auth_handler_basic.cc b/net/http/http_auth_handler_basic.cc
index b1624b8..27b892b 100644
--- a/net/http/http_auth_handler_basic.cc
+++ b/net/http/http_auth_handler_basic.cc
@@ -40,7 +40,7 @@
   realm->clear();
   HttpUtil::NameValuePairsIterator parameters = tokenizer.param_pairs();
   while (parameters.GetNext()) {
-    if (!LowerCaseEqualsASCII(parameters.name(), "realm"))
+    if (!base::LowerCaseEqualsASCII(parameters.name(), "realm"))
       continue;
 
     if (!ConvertToUtf8AndNormalize(parameters.value(), kCharsetLatin1, realm)) {
@@ -62,7 +62,7 @@
 bool HttpAuthHandlerBasic::ParseChallenge(
     HttpAuthChallengeTokenizer* challenge) {
   // Verify the challenge's auth-scheme.
-  if (!LowerCaseEqualsASCII(challenge->scheme(), "basic"))
+  if (!base::LowerCaseEqualsASCII(challenge->scheme(), "basic"))
     return false;
 
   std::string realm;
diff --git a/net/http/http_auth_handler_digest.cc b/net/http/http_auth_handler_digest.cc
index 0fbd0d3..a5f96b1 100644
--- a/net/http/http_auth_handler_digest.cc
+++ b/net/http/http_auth_handler_digest.cc
@@ -113,7 +113,7 @@
   // to differentiate between stale and rejected responses.
   // Note that the state of the current handler is not mutated - this way if
   // there is a rejection the realm hasn't changed.
-  if (!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
+  if (!base::LowerCaseEqualsASCII(challenge->scheme(), "digest"))
     return HttpAuth::AUTHORIZATION_RESULT_INVALID;
 
   HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
@@ -122,10 +122,10 @@
   // for the new challenge.
   std::string original_realm;
   while (parameters.GetNext()) {
-    if (LowerCaseEqualsASCII(parameters.name(), "stale")) {
-      if (LowerCaseEqualsASCII(parameters.value(), "true"))
+    if (base::LowerCaseEqualsASCII(parameters.name(), "stale")) {
+      if (base::LowerCaseEqualsASCII(parameters.value(), "true"))
         return HttpAuth::AUTHORIZATION_RESULT_STALE;
-    } else if (LowerCaseEqualsASCII(parameters.name(), "realm")) {
+    } else if (base::LowerCaseEqualsASCII(parameters.name(), "realm")) {
       original_realm = parameters.value();
     }
   }
@@ -199,7 +199,7 @@
   realm_ = original_realm_ = nonce_ = domain_ = opaque_ = std::string();
 
   // FAIL -- Couldn't match auth-scheme.
-  if (!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
+  if (!base::LowerCaseEqualsASCII(challenge->scheme(), "digest"))
     return false;
 
   HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
@@ -225,38 +225,38 @@
 
 bool HttpAuthHandlerDigest::ParseChallengeProperty(const std::string& name,
                                                    const std::string& value) {
-  if (LowerCaseEqualsASCII(name, "realm")) {
+  if (base::LowerCaseEqualsASCII(name, "realm")) {
     std::string realm;
     if (!ConvertToUtf8AndNormalize(value, kCharsetLatin1, &realm))
       return false;
     realm_ = realm;
     original_realm_ = value;
-  } else if (LowerCaseEqualsASCII(name, "nonce")) {
+  } else if (base::LowerCaseEqualsASCII(name, "nonce")) {
     nonce_ = value;
-  } else if (LowerCaseEqualsASCII(name, "domain")) {
+  } else if (base::LowerCaseEqualsASCII(name, "domain")) {
     domain_ = value;
-  } else if (LowerCaseEqualsASCII(name, "opaque")) {
+  } else if (base::LowerCaseEqualsASCII(name, "opaque")) {
     opaque_ = value;
-  } else if (LowerCaseEqualsASCII(name, "stale")) {
+  } else if (base::LowerCaseEqualsASCII(name, "stale")) {
     // Parse the stale boolean.
-    stale_ = LowerCaseEqualsASCII(value, "true");
-  } else if (LowerCaseEqualsASCII(name, "algorithm")) {
+    stale_ = base::LowerCaseEqualsASCII(value, "true");
+  } else if (base::LowerCaseEqualsASCII(name, "algorithm")) {
     // Parse the algorithm.
-    if (LowerCaseEqualsASCII(value, "md5")) {
+    if (base::LowerCaseEqualsASCII(value, "md5")) {
       algorithm_ = ALGORITHM_MD5;
-    } else if (LowerCaseEqualsASCII(value, "md5-sess")) {
+    } else if (base::LowerCaseEqualsASCII(value, "md5-sess")) {
       algorithm_ = ALGORITHM_MD5_SESS;
     } else {
       DVLOG(1) << "Unknown value of algorithm";
       return false;  // FAIL -- unsupported value of algorithm.
     }
-  } else if (LowerCaseEqualsASCII(name, "qop")) {
+  } else if (base::LowerCaseEqualsASCII(name, "qop")) {
     // Parse the comma separated list of qops.
     // auth is the only supported qop, and all other values are ignored.
     HttpUtil::ValuesIterator qop_values(value.begin(), value.end(), ',');
     qop_ = QOP_UNSPECIFIED;
     while (qop_values.GetNext()) {
-      if (LowerCaseEqualsASCII(qop_values.value(), "auth")) {
+      if (base::LowerCaseEqualsASCII(qop_values.value(), "auth")) {
         qop_ = QOP_AUTH;
         break;
       }
diff --git a/net/http/http_auth_handler_mock.cc b/net/http/http_auth_handler_mock.cc
index 35ed3ab..f800c19 100644
--- a/net/http/http_auth_handler_mock.cc
+++ b/net/http/http_auth_handler_mock.cc
@@ -5,8 +5,10 @@
 #include "net/http/http_auth_handler_mock.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_auth_challenge_tokenizer.h"
 #include "net/http/http_request_info.h"
@@ -60,10 +62,9 @@
       EXPECT_TRUE(callback_.is_null());
       rv = ERR_IO_PENDING;
       callback_ = callback;
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&HttpAuthHandlerMock::OnResolveCanonicalName,
-                     weak_factory_.GetWeakPtr()));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&HttpAuthHandlerMock::OnResolveCanonicalName,
+                                weak_factory_.GetWeakPtr()));
       break;
     default:
       NOTREACHED();
@@ -83,7 +84,7 @@
   // challenge for a non connection based scheme, assume it's a rejection.
   if (!is_connection_based() || challenge->base64_param().empty())
     return HttpAuth::AUTHORIZATION_RESULT_REJECT;
-  if (!LowerCaseEqualsASCII(challenge->scheme(), "mock"))
+  if (!base::LowerCaseEqualsASCII(challenge->scheme(), "mock"))
     return HttpAuth::AUTHORIZATION_RESULT_INVALID;
   return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
 }
@@ -119,10 +120,9 @@
     EXPECT_TRUE(auth_token_ == NULL);
     callback_ = callback;
     auth_token_ = auth_token;
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&HttpAuthHandlerMock::OnGenerateAuthToken,
-                   weak_factory_.GetWeakPtr()));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&HttpAuthHandlerMock::OnGenerateAuthToken,
+                              weak_factory_.GetWeakPtr()));
     return ERR_IO_PENDING;
   } else {
     if (generate_rv_ == OK)
diff --git a/net/http/http_auth_handler_ntlm.cc b/net/http/http_auth_handler_ntlm.cc
index de0fe29..51a32326 100644
--- a/net/http/http_auth_handler_ntlm.cc
+++ b/net/http/http_auth_handler_ntlm.cc
@@ -114,7 +114,7 @@
   auth_data_.clear();
 
   // Verify the challenge's auth-scheme.
-  if (!LowerCaseEqualsASCII(tok->scheme(), "ntlm"))
+  if (!base::LowerCaseEqualsASCII(tok->scheme(), "ntlm"))
     return HttpAuth::AUTHORIZATION_RESULT_INVALID;
 
   std::string base64_param = tok->base64_param();
diff --git a/net/http/http_auth_handler_ntlm_portable.cc b/net/http/http_auth_handler_ntlm_portable.cc
index 237e33a..5e1d5fa 100644
--- a/net/http/http_auth_handler_ntlm_portable.cc
+++ b/net/http/http_auth_handler_ntlm_portable.cc
@@ -261,7 +261,7 @@
   // Convert password to OEM character set.  We'll just use the native
   // filesystem charset.
   std::string passbuf = base::SysWideToNativeMB(base::UTF16ToWide(password));
-  StringToUpperASCII(&passbuf);
+  base::StringToUpperASCII(&passbuf);
   passbuf.resize(14, '\0');
 
   uint8 k1[8], k2[8];
diff --git a/net/http/http_auth_sspi_win.cc b/net/http/http_auth_sspi_win.cc
index 56b1c8c0..c935d33 100644
--- a/net/http/http_auth_sspi_win.cc
+++ b/net/http/http_auth_sspi_win.cc
@@ -283,8 +283,8 @@
 HttpAuth::AuthorizationResult HttpAuthSSPI::ParseChallenge(
     HttpAuthChallengeTokenizer* tok) {
   // Verify the challenge's auth-scheme.
-  if (!LowerCaseEqualsASCII(tok->scheme(),
-                            base::StringToLowerASCII(scheme_).c_str()))
+  if (!base::LowerCaseEqualsASCII(tok->scheme(),
+                                  base::StringToLowerASCII(scheme_).c_str()))
     return HttpAuth::AUTHORIZATION_RESULT_INVALID;
 
   std::string encoded_auth_token = tok->base64_param();
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index c3bdd30..c167c3d 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -6,27 +6,23 @@
 
 #include <algorithm>
 
-#include "base/compiler_specific.h"
-
-#if defined(OS_POSIX)
-#include <unistd.h>
-#endif
-
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/pickle.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/worker_pool.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
@@ -48,6 +44,10 @@
 #include "net/http/http_util.h"
 #include "net/quic/crypto/quic_server_info.h"
 
+#if defined(OS_POSIX)
+#include <unistd.h>
+#endif
+
 namespace {
 
 bool UseCertCache() {
@@ -1175,7 +1175,7 @@
     return;
   entry->will_process_pending_queue = true;
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&HttpCache::OnProcessPendingQueue, GetWeakPtr(), entry));
 }
@@ -1372,10 +1372,9 @@
     // go away from the callback.
     pending_op->writer = pending_item;
 
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&HttpCache::OnBackendCreated, GetWeakPtr(),
-                   result, pending_op));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&HttpCache::OnBackendCreated, GetWeakPtr(),
+                              result, pending_op));
   } else {
     building_backend_ = false;
     DeletePendingOp(pending_op);
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index e3af3f7b..183a914 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -4,6 +4,9 @@
 
 #include "net/http/http_cache_transaction.h"
 
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "build/build_config.h"
 
 #if defined(OS_POSIX)
@@ -254,7 +257,8 @@
 
     HttpUtil::ValuesIterator v(header_value.begin(), header_value.end(), ',');
     while (v.GetNext()) {
-      if (LowerCaseEqualsASCII(v.value_begin(), v.value_end(), search->value))
+      if (base::LowerCaseEqualsASCII(v.value_begin(), v.value_end(),
+                                     search->value))
         return true;
     }
   }
@@ -1384,7 +1388,7 @@
         // the cache if at all possible. See http://crbug.com/408765
         timeout_milliseconds = 25;
       }
-      base::MessageLoop::current()->PostDelayedTask(
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE,
           base::Bind(&HttpCache::Transaction::OnAddToEntryTimeout,
                      weak_factory_.GetWeakPtr(), entry_lock_waiting_since_),
@@ -2615,12 +2619,10 @@
       NetLog::TYPE_ASYNC_REVALIDATION,
       base::Bind(
           &NetLogAsyncRevalidationInfoCallback, net_log_.source(), request_));
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&HttpCache::PerformAsyncValidation,
-                 cache_,  // cache_ is a weak pointer.
-                 *request_,
-                 async_revalidation_net_log));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&HttpCache::PerformAsyncValidation,
+                            cache_,  // cache_ is a weak pointer.
+                            *request_, async_revalidation_net_log));
 }
 
 void HttpCache::Transaction::FailRangeRequest() {
diff --git a/net/http/http_content_disposition.cc b/net/http/http_content_disposition.cc
index 1563becc..06f815b 100644
--- a/net/http/http_content_disposition.cc
+++ b/net/http/http_content_disposition.cc
@@ -359,9 +359,9 @@
 
   DCHECK(std::find(type_begin, type_end, '=') == type_end);
 
-  if (LowerCaseEqualsASCII(type_begin, type_end, "inline")) {
+  if (base::LowerCaseEqualsASCII(type_begin, type_end, "inline")) {
     type_ = INLINE;
-  } else if (LowerCaseEqualsASCII(type_begin, type_end, "attachment")) {
+  } else if (base::LowerCaseEqualsASCII(type_begin, type_end, "attachment")) {
     type_ = ATTACHMENT;
   } else {
     parse_result_flags_ |= HAS_UNKNOWN_DISPOSITION_TYPE;
@@ -402,16 +402,16 @@
 
   HttpUtil::NameValuePairsIterator iter(pos, end, ';');
   while (iter.GetNext()) {
-    if (filename.empty() && LowerCaseEqualsASCII(iter.name_begin(),
-                                                 iter.name_end(),
-                                                 "filename")) {
+    if (filename.empty() &&
+        base::LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(),
+                                   "filename")) {
       DecodeFilenameValue(iter.value(), referrer_charset, &filename,
                           &parse_result_flags_);
       if (!filename.empty())
         parse_result_flags_ |= HAS_FILENAME;
-    } else if (ext_filename.empty() && LowerCaseEqualsASCII(iter.name_begin(),
-                                                            iter.name_end(),
-                                                            "filename*")) {
+    } else if (ext_filename.empty() &&
+               base::LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(),
+                                          "filename*")) {
       DecodeExtValue(iter.raw_value(), &ext_filename);
       if (!ext_filename.empty())
         parse_result_flags_ |= HAS_EXT_FILENAME;
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index c3d1f51d..4b7edeb 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -98,6 +98,7 @@
       quic_enable_connection_racing(false),
       quic_enable_non_blocking_io(false),
       quic_disable_disk_cache(false),
+      quic_prefer_aes(false),
       quic_max_number_of_lossy_connections(0),
       quic_packet_loss_threshold(1.0f),
       quic_socket_receive_buffer_size(kQuicSocketReceiveBufferSize),
@@ -147,6 +148,7 @@
           params.quic_enable_connection_racing,
           params.quic_enable_non_blocking_io,
           params.quic_disable_disk_cache,
+          params.quic_prefer_aes,
           params.quic_max_number_of_lossy_connections,
           params.quic_packet_loss_threshold,
           params.quic_socket_receive_buffer_size,
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 5ee2752..3327195 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -115,6 +115,7 @@
     bool quic_enable_connection_racing;
     bool quic_enable_non_blocking_io;
     bool quic_disable_disk_cache;
+    bool quic_prefer_aes;
     int quic_max_number_of_lossy_connections;
     float quic_packet_loss_threshold;
     int quic_socket_receive_buffer_size;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index d318cad7..39d58eb 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -22,6 +22,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_file_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/auth.h"
 #include "net/base/chunked_upload_data_stream.h"
 #include "net/base/completion_callback.h"
@@ -3802,7 +3803,7 @@
   BoundTestNetLog log;
   session_deps_.net_log = log.bound().net_log();
   scoped_refptr<HttpNetworkSession> session(
-      SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_));
+      SpdySessionDependencies::SpdyCreateSession(&session_deps_));
 
   HttpRequestInfo request1;
   request1.method = "GET";
@@ -3879,30 +3880,24 @@
     MockRead(ASYNC, 0, 10),
   };
 
-  DeterministicSocketData spdy_data(
-      spdy_reads, arraysize(spdy_reads),
-      spdy_writes, arraysize(spdy_writes));
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&spdy_data);
+  SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
+                                arraysize(spdy_writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
   ssl.SetNextProto(GetParam());
-  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
   SSLSocketDataProvider ssl2(ASYNC, OK);
-  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl2);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
   SSLSocketDataProvider ssl3(ASYNC, OK);
-  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl3);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl3);
 
   TestCompletionCallback callback;
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
   int rv = trans->Start(&request1, callback.callback(), BoundNetLog());
-  EXPECT_EQ(ERR_IO_PENDING, rv);
-  // The first connect and request, each of their responses, and the body.
-  spdy_data.RunFor(5);
-
-  rv = callback.WaitForResult();
-  EXPECT_EQ(OK, rv);
+  EXPECT_EQ(OK, callback.GetResult(rv));
 
   LoadTimingInfo load_timing_info;
   EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
@@ -3915,17 +3910,13 @@
 
   std::string response_data;
   scoped_refptr<IOBuffer> buf(new IOBuffer(256));
-  EXPECT_EQ(1, trans->Read(buf.get(), 256, callback.callback()));
+  rv = trans->Read(buf.get(), 256, callback.callback());
+  EXPECT_EQ(1, callback.GetResult(rv));
 
   scoped_ptr<HttpTransaction> trans2(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
   rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
-  EXPECT_EQ(ERR_IO_PENDING, rv);
-
-  // The second connect and request, each of their responses, and the body.
-  spdy_data.RunFor(5);
-  rv = callback.WaitForResult();
-  EXPECT_EQ(OK, rv);
+  EXPECT_EQ(OK, callback.GetResult(rv));
 
   LoadTimingInfo load_timing_info2;
   EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2));
@@ -3937,7 +3928,8 @@
   // separate stream.
   EXPECT_NE(load_timing_info.socket_log_id, load_timing_info2.socket_log_id);
 
-  EXPECT_EQ(2, trans2->Read(buf.get(), 256, callback.callback()));
+  rv = trans2->Read(buf.get(), 256, callback.callback());
+  EXPECT_EQ(2, callback.GetResult(rv));
 }
 
 // Test load timing in the case of two HTTPS (non-SPDY) requests through a SPDY
@@ -3950,7 +3942,7 @@
   BoundTestNetLog log;
   session_deps_.net_log = log.bound().net_log();
   scoped_refptr<HttpNetworkSession> session(
-      SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_));
+      SpdySessionDependencies::SpdyCreateSession(&session_deps_));
 
   HttpRequestInfo request1;
   request1.method = "GET";
@@ -4013,16 +4005,15 @@
     MockRead(ASYNC, 0, 8),
   };
 
-  DeterministicSocketData spdy_data(
-      spdy_reads, arraysize(spdy_reads),
-      spdy_writes, arraysize(spdy_writes));
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&spdy_data);
+  SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
+                                arraysize(spdy_writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
   ssl.SetNextProto(GetParam());
-  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
   SSLSocketDataProvider ssl2(ASYNC, OK);
-  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl2);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
 
   TestCompletionCallback callback;
 
@@ -4030,8 +4021,6 @@
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
   int rv = trans->Start(&request1, callback.callback(), BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
-  // The first connect and request, each of their responses, and the body.
-  spdy_data.RunFor(5);
 
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
@@ -4055,9 +4044,6 @@
   rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
-  // The second request, response, and body.  There should not be a second
-  // connect.
-  spdy_data.RunFor(3);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
 
@@ -4073,15 +4059,14 @@
 
 // Test load timing in the case of of two HTTP requests through a SPDY HTTPS
 // Proxy to different servers.
-TEST_P(HttpNetworkTransactionTest,
-       HttpsProxySpdyLoadTimingTwoHttpRequests) {
+TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyLoadTimingTwoHttpRequests) {
   // Configure against https proxy server "proxy:70".
   session_deps_.proxy_service.reset(ProxyService::CreateFixed(
       "https://proxy:70"));
   BoundTestNetLog log;
   session_deps_.net_log = log.bound().net_log();
   scoped_refptr<HttpNetworkSession> session(
-      SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_));
+      SpdySessionDependencies::SpdyCreateSession(&session_deps_));
 
   HttpRequestInfo request1;
   request1.method = "GET";
@@ -4126,25 +4111,20 @@
     MockRead(ASYNC, 0, 6),
   };
 
-  DeterministicSocketData spdy_data(
-      spdy_reads, arraysize(spdy_reads),
-      spdy_writes, arraysize(spdy_writes));
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&spdy_data);
+  SequencedSocketData spdy_data(spdy_reads, arraysize(spdy_reads), spdy_writes,
+                                arraysize(spdy_writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
   ssl.SetNextProto(GetParam());
-  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   TestCompletionCallback callback;
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
   int rv = trans->Start(&request1, callback.callback(), BoundNetLog());
-  EXPECT_EQ(ERR_IO_PENDING, rv);
-  spdy_data.RunFor(2);
-
-  rv = callback.WaitForResult();
-  EXPECT_EQ(OK, rv);
+  EXPECT_EQ(OK, callback.GetResult(rv));
 
   LoadTimingInfo load_timing_info;
   EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
@@ -4158,20 +4138,15 @@
 
   std::string response_data;
   scoped_refptr<IOBuffer> buf(new IOBuffer(256));
-  EXPECT_EQ(ERR_IO_PENDING, trans->Read(buf.get(), 256, callback.callback()));
-  spdy_data.RunFor(1);
-  EXPECT_EQ(1, callback.WaitForResult());
+  rv = trans->Read(buf.get(), 256, callback.callback());
+  EXPECT_EQ(1, callback.GetResult(rv));
   // Delete the first request, so the second one can reuse the socket.
   trans.reset();
 
   scoped_ptr<HttpTransaction> trans2(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
   rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
-  EXPECT_EQ(ERR_IO_PENDING, rv);
-
-  spdy_data.RunFor(2);
-  rv = callback.WaitForResult();
-  EXPECT_EQ(OK, rv);
+  EXPECT_EQ(OK, callback.GetResult(rv));
 
   LoadTimingInfo load_timing_info2;
   EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2));
@@ -4180,9 +4155,8 @@
   // The requests should have the same ID.
   EXPECT_EQ(load_timing_info.socket_log_id, load_timing_info2.socket_log_id);
 
-  EXPECT_EQ(ERR_IO_PENDING, trans2->Read(buf.get(), 256, callback.callback()));
-  spdy_data.RunFor(1);
-  EXPECT_EQ(2, callback.WaitForResult());
+  rv = trans2->Read(buf.get(), 256, callback.callback());
+  EXPECT_EQ(2, callback.GetResult(rv));
 }
 
 // Test the challenge-response-retry sequence through an HTTPS Proxy
@@ -8441,11 +8415,8 @@
 
   ScopedVector<UploadElementReader> element_readers;
   element_readers.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file_path,
-                                  0,
-                                  kuint64max,
-                                  base::Time()));
+      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                  temp_file_path, 0, kuint64max, base::Time()));
   ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0);
 
   HttpRequestInfo request;
@@ -8498,11 +8469,8 @@
 
   ScopedVector<UploadElementReader> element_readers;
   element_readers.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file,
-                                  0,
-                                  kuint64max,
-                                  base::Time()));
+      new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                  temp_file, 0, kuint64max, base::Time()));
   ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0);
 
   HttpRequestInfo request;
@@ -12448,9 +12416,7 @@
     MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED, 0)
   };
 
-  scoped_ptr<DeterministicSocketData> data1(
-      new DeterministicSocketData(reads1, arraysize(reads1), NULL, 0));
-  data1->SetStop(1);
+  SequencedSocketData data1(reads1, arraysize(reads1), NULL, 0);
 
   scoped_ptr<SpdyFrame> req2(
       spdy_util_.ConstructSpdyGet(https_url.c_str(), false, 1, MEDIUM));
@@ -12466,24 +12432,21 @@
     MockRead(ASYNC, OK, 3)  // EOF
   };
 
-  scoped_ptr<DeterministicSocketData> data2(
-      new DeterministicSocketData(reads2, arraysize(reads2),
-                                  writes2, arraysize(writes2)));
+  SequencedSocketData data2(reads2, arraysize(reads2), writes2,
+                            arraysize(writes2));
 
   SSLSocketDataProvider ssl1(ASYNC, OK);
   ssl1.SetNextProto(GetParam());
-  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl1);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(
-      data1.get());
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
+  session_deps_.socket_factory->AddSocketDataProvider(&data1);
 
   SSLSocketDataProvider ssl2(ASYNC, OK);
   ssl2.SetNextProto(GetParam());
-  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl2);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(
-      data2.get());
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
+  session_deps_.socket_factory->AddSocketDataProvider(&data2);
 
   scoped_refptr<HttpNetworkSession> session(
-      SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_));
+      SpdySessionDependencies::SpdyCreateSession(&session_deps_));
 
   // Start the first transaction to set up the SpdySession and verify that
   // connection was closed.
@@ -12495,7 +12458,6 @@
   TestCompletionCallback callback1;
   EXPECT_EQ(ERR_IO_PENDING,
             trans1.Start(&request1, callback1.callback(), BoundNetLog()));
-  base::MessageLoop::current()->RunUntilIdle();
   EXPECT_EQ(ERR_CONNECTION_CLOSED, callback1.WaitForResult());
 
   // Now, start the second request and make sure it succeeds.
@@ -12507,11 +12469,8 @@
   TestCompletionCallback callback2;
   EXPECT_EQ(ERR_IO_PENDING,
             trans2.Start(&request2, callback2.callback(), BoundNetLog()));
-  base::MessageLoop::current()->RunUntilIdle();
-  data2->RunFor(3);
 
-  ASSERT_TRUE(callback2.have_result());
-  EXPECT_EQ(OK, callback2.WaitForResult());
+  ASSERT_EQ(OK, callback2.WaitForResult());
   EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy);
 }
 
diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc
index 8cce583..ca206b7f 100644
--- a/net/http/http_response_body_drainer_unittest.cc
+++ b/net/http/http_response_body_drainer_unittest.cc
@@ -8,8 +8,11 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -170,7 +173,7 @@
     user_buf_ = buf;
     buf_len_ = buf_len;
     callback_ = callback;
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&MockHttpStream::CompleteRead, weak_factory_.GetWeakPtr()));
     return ERR_IO_PENDING;
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc
index d56f8f03..e729db3b 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.cc
@@ -98,12 +98,12 @@
 bool ShouldUpdateHeader(const std::string::const_iterator& name_begin,
                         const std::string::const_iterator& name_end) {
   for (size_t i = 0; i < arraysize(kNonUpdatedHeaders); ++i) {
-    if (LowerCaseEqualsASCII(name_begin, name_end, kNonUpdatedHeaders[i]))
+    if (base::LowerCaseEqualsASCII(name_begin, name_end, kNonUpdatedHeaders[i]))
       return false;
   }
   for (size_t i = 0; i < arraysize(kNonUpdatedHeaderPrefixes); ++i) {
-    if (StartsWithASCII(std::string(name_begin, name_end),
-                        kNonUpdatedHeaderPrefixes[i], false))
+    if (base::StartsWithASCII(std::string(name_begin, name_end),
+                              kNonUpdatedHeaderPrefixes[i], false))
       return false;
   }
   return true;
@@ -632,7 +632,7 @@
   // TODO: (1*DIGIT apparently means one or more digits, but we only handle 1).
   // TODO: handle leading zeros, which is allowed by the rfc1616 sec 3.1.
 
-  if ((line_end - p < 4) || !LowerCaseEqualsASCII(p, p + 4, "http")) {
+  if ((line_end - p < 4) || !base::LowerCaseEqualsASCII(p, p + 4, "http")) {
     DVLOG(1) << "missing status line";
     return HttpVersion();
   }
@@ -763,9 +763,8 @@
   void* iter = NULL;
   while (EnumerateHeader(&iter, name, &value)) {
     if (value.size() > directive_size + 1 &&
-        LowerCaseEqualsASCII(value.begin(),
-                             value.begin() + directive_size,
-                             directive.begin()) &&
+        base::LowerCaseEqualsASCII(
+            value.begin(), value.begin() + directive_size, directive.begin()) &&
         value[directive_size] == '=') {
       int64 seconds;
       base::StringToInt64(
@@ -1232,7 +1231,7 @@
     std::string token;
     while (EnumerateHeader(&iterator, header, &token)) {
       for (const KeepAliveToken& keep_alive_token : kKeepAliveTokens) {
-        if (LowerCaseEqualsASCII(token, keep_alive_token.token))
+        if (base::LowerCaseEqualsASCII(token, keep_alive_token.token))
           return keep_alive_token.keep_alive;
       }
     }
@@ -1309,9 +1308,8 @@
   std::string::const_iterator content_range_spec_end =
       content_range_spec.begin() + space_position;
   HttpUtil::TrimLWS(&content_range_spec_begin, &content_range_spec_end);
-  if (!LowerCaseEqualsASCII(content_range_spec_begin,
-                            content_range_spec_end,
-                            "bytes")) {
+  if (!base::LowerCaseEqualsASCII(content_range_spec_begin,
+                                  content_range_spec_end, "bytes")) {
     return false;
   }
 
@@ -1330,7 +1328,7 @@
   std::string byte_range_resp_spec(byte_range_resp_spec_begin,
                                    byte_range_resp_spec_end);
   // If byte-range-resp-spec != "*".
-  if (!LowerCaseEqualsASCII(byte_range_resp_spec, "*")) {
+  if (!base::LowerCaseEqualsASCII(byte_range_resp_spec, "*")) {
     size_t minus_position = byte_range_resp_spec.find('-');
     if (minus_position != std::string::npos) {
       // Obtain first-byte-pos.
@@ -1374,7 +1372,8 @@
       content_range_spec.end();
   HttpUtil::TrimLWS(&instance_length_begin, &instance_length_end);
 
-  if (LowerCaseEqualsASCII(instance_length_begin, instance_length_end, "*")) {
+  if (base::LowerCaseEqualsASCII(instance_length_begin, instance_length_end,
+                                 "*")) {
     return false;
   } else if (!base::StringToInt64(StringPiece(instance_length_begin,
                                               instance_length_end),
diff --git a/net/http/http_security_headers.cc b/net/http/http_security_headers.cc
index aff4a30..e8e3a47 100644
--- a/net/http/http_security_headers.cc
+++ b/net/http/http_security_headers.cc
@@ -199,11 +199,11 @@
       case DIRECTIVE_END:
         if (IsAsciiWhitespace(*tokenizer.token_begin()))
           continue;
-        if (LowerCaseEqualsASCII(tokenizer.token(), "max-age")) {
+        if (base::LowerCaseEqualsASCII(tokenizer.token(), "max-age")) {
           state = AFTER_MAX_AGE_LABEL;
           max_age_observed++;
-        } else if (LowerCaseEqualsASCII(tokenizer.token(),
-                                        "includesubdomains")) {
+        } else if (base::LowerCaseEqualsASCII(tokenizer.token(),
+                                              "includesubdomains")) {
           state = AFTER_INCLUDE_SUBDOMAINS;
           include_subdomains_observed++;
           include_subdomains_candidate = true;
@@ -296,20 +296,20 @@
     equals.first = Strip(equals.first);
     equals.second = Strip(equals.second);
 
-    if (LowerCaseEqualsASCII(equals.first, "max-age")) {
+    if (base::LowerCaseEqualsASCII(equals.first, "max-age")) {
       if (equals.second.empty() ||
           !MaxAgeToInt(equals.second.begin(), equals.second.end(),
                        &max_age_candidate)) {
         return false;
       }
       parsed_max_age = true;
-    } else if (LowerCaseEqualsASCII(equals.first, "pin-sha1")) {
+    } else if (base::LowerCaseEqualsASCII(equals.first, "pin-sha1")) {
       if (!ParseAndAppendPin(equals.second, HASH_VALUE_SHA1, &pins))
         return false;
-    } else if (LowerCaseEqualsASCII(equals.first, "pin-sha256")) {
+    } else if (base::LowerCaseEqualsASCII(equals.first, "pin-sha256")) {
       if (!ParseAndAppendPin(equals.second, HASH_VALUE_SHA256, &pins))
         return false;
-    } else if (LowerCaseEqualsASCII(equals.first, "includesubdomains")) {
+    } else if (base::LowerCaseEqualsASCII(equals.first, "includesubdomains")) {
       include_subdomains_candidate = true;
     } else {
       // Silently ignore unknown directives for forward compatibility.
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc
index d72e488..d5c65593 100644
--- a/net/http/http_server_properties_impl.cc
+++ b/net/http/http_server_properties_impl.cc
@@ -5,13 +5,15 @@
 #include "net/http/http_server_properties_impl.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 
 namespace net {
@@ -602,7 +604,7 @@
   base::TimeTicks now = base::TimeTicks::Now();
   base::TimeTicks when = broken_alternative_services_.front().second;
   base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(
           &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc
index 26ce850d..f1bb719 100644
--- a/net/http/http_server_properties_manager.cc
+++ b/net/http/http_server_properties_manager.cc
@@ -337,8 +337,13 @@
     bool used_quic,
     const IPAddressNumber& address) {
   DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
+  IPAddressNumber old_last_quic_addr;
+  http_server_properties_impl_->GetSupportsQuic(&old_last_quic_addr);
   http_server_properties_impl_->SetSupportsQuic(used_quic, address);
-  ScheduleUpdatePrefsOnNetworkThread(SET_SUPPORTS_QUIC);
+  IPAddressNumber new_last_quic_addr;
+  http_server_properties_impl_->GetSupportsQuic(&new_last_quic_addr);
+  if (old_last_quic_addr != new_last_quic_addr)
+    ScheduleUpdatePrefsOnNetworkThread(SET_SUPPORTS_QUIC);
 }
 
 void HttpServerPropertiesManager::SetServerNetworkStats(
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index 77c4768..e4f21419 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -10,9 +10,11 @@
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/test_simple_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/base/ip_address_number.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -106,9 +108,8 @@
     pref_service_.registry()->RegisterDictionaryPref(kTestHttpServerProperties);
     http_server_props_manager_.reset(
         new StrictMock<TestingHttpServerPropertiesManager>(
-            &pref_service_,
-            kTestHttpServerProperties,
-            base::MessageLoop::current()->message_loop_proxy()));
+            &pref_service_, kTestHttpServerProperties,
+            base::ThreadTaskRunnerHandle::Get()));
     ExpectCacheUpdate();
     base::RunLoop().RunUntilIdle();
   }
@@ -605,6 +606,8 @@
   IPAddressNumber actual_address;
   CHECK(ParseIPLiteralToNumber("127.0.0.1", &actual_address));
   http_server_props_manager_->SetSupportsQuic(true, actual_address);
+  // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once.
+  http_server_props_manager_->SetSupportsQuic(true, actual_address);
 
   // Run the task.
   base::RunLoop().RunUntilIdle();
diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc
index 35083f0..e3d35b7 100644
--- a/net/http/http_stream_factory.cc
+++ b/net/http/http_stream_factory.cc
@@ -39,7 +39,7 @@
   bool is_valid = true;
   for (size_t i = 0; i < alternate_protocol_values.size(); ++i) {
     const std::string& alternate_protocol_str = alternate_protocol_values[i];
-    if (StartsWithASCII(alternate_protocol_str, "p=", true)) {
+    if (base::StartsWithASCII(alternate_protocol_str, "p=", true)) {
       if (!base::StringToDouble(alternate_protocol_str.substr(2),
                                 &probability) ||
           probability < 0 || probability > 1) {
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 2ec9401..1ae8aa7 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -9,13 +9,16 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "net/base/connection_type_histograms.h"
@@ -214,10 +217,9 @@
   // We know we're blocked if the next_state_ is STATE_WAIT_FOR_JOB_COMPLETE.
   // Unblock |this|.
   if (next_state_ == STATE_WAIT_FOR_JOB_COMPLETE) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&HttpStreamFactoryImpl::Job::OnIOComplete,
-                   ptr_factory_.GetWeakPtr(), OK));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&HttpStreamFactoryImpl::Job::OnIOComplete,
+                              ptr_factory_.GetWeakPtr(), OK));
   }
 }
 
@@ -485,7 +487,7 @@
   DCHECK(result == OK || waiting_job_ == NULL);
 
   if (IsPreconnecting()) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&HttpStreamFactoryImpl::Job::OnPreconnectsComplete,
                    ptr_factory_.GetWeakPtr()));
@@ -497,7 +499,7 @@
     GetSSLInfo();
 
     next_state_ = STATE_WAITING_USER_ACTION;
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&HttpStreamFactoryImpl::Job::OnCertificateErrorCallback,
                    ptr_factory_.GetWeakPtr(), result, ssl_info_));
@@ -516,7 +518,7 @@
       next_state_ = STATE_WAITING_USER_ACTION;
       ProxyClientSocket* proxy_socket =
           static_cast<ProxyClientSocket*>(connection_->socket());
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::Bind(&Job::OnNeedsProxyAuthCallback, ptr_factory_.GetWeakPtr(),
                      *proxy_socket->GetConnectResponseInfo(),
@@ -525,7 +527,7 @@
     }
 
     case ERR_SSL_CLIENT_AUTH_CERT_NEEDED:
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::Bind(&Job::OnNeedsClientAuthCallback, ptr_factory_.GetWeakPtr(),
                      connection_->ssl_error_response_info().cert_request_info));
@@ -538,12 +540,11 @@
 
       ProxyClientSocket* proxy_socket =
           static_cast<ProxyClientSocket*>(connection_->socket());
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&Job::OnHttpsProxyTunnelResponseCallback,
-                     ptr_factory_.GetWeakPtr(),
-                     *proxy_socket->GetConnectResponseInfo(),
-                     proxy_socket->CreateConnectResponseStream()));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&Job::OnHttpsProxyTunnelResponseCallback,
+                                ptr_factory_.GetWeakPtr(),
+                                *proxy_socket->GetConnectResponseInfo(),
+                                proxy_socket->CreateConnectResponseStream()));
       return ERR_IO_PENDING;
     }
 
@@ -552,19 +553,17 @@
       MaybeMarkAlternativeServiceBroken();
       next_state_ = STATE_DONE;
       if (new_spdy_session_.get()) {
-        base::MessageLoop::current()->PostTask(
-            FROM_HERE,
-            base::Bind(&Job::OnNewSpdySessionReadyCallback,
-                       ptr_factory_.GetWeakPtr()));
+        base::ThreadTaskRunnerHandle::Get()->PostTask(
+            FROM_HERE, base::Bind(&Job::OnNewSpdySessionReadyCallback,
+                                  ptr_factory_.GetWeakPtr()));
       } else if (stream_factory_->for_websockets_) {
         DCHECK(websocket_stream_);
-        base::MessageLoop::current()->PostTask(
-            FROM_HERE,
-            base::Bind(&Job::OnWebSocketHandshakeStreamReadyCallback,
-                       ptr_factory_.GetWeakPtr()));
+        base::ThreadTaskRunnerHandle::Get()->PostTask(
+            FROM_HERE, base::Bind(&Job::OnWebSocketHandshakeStreamReadyCallback,
+                                  ptr_factory_.GetWeakPtr()));
       } else {
         DCHECK(stream_.get());
-        base::MessageLoop::current()->PostTask(
+        base::ThreadTaskRunnerHandle::Get()->PostTask(
             FROM_HERE,
             base::Bind(&Job::OnStreamReadyCallback, ptr_factory_.GetWeakPtr()));
       }
@@ -581,10 +580,9 @@
         // alternative service) couple as invalid.
         MaybeMarkAlternativeServiceBroken();
       }
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&Job::OnStreamFailedCallback, ptr_factory_.GetWeakPtr(),
-                     result));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&Job::OnStreamFailedCallback,
+                                ptr_factory_.GetWeakPtr(), result));
       return ERR_IO_PENDING;
   }
 }
@@ -672,8 +670,7 @@
                  &alternative_service_, priority_));
 
   // Don't connect to restricted ports.
-  if (!IsPortAllowedForScheme(server_.port(), request_info_.url.scheme(),
-                              PORT_OVERRIDES_ALLOWED)) {
+  if (!IsPortAllowedForScheme(server_.port(), request_info_.url.scheme())) {
     if (waiting_job_) {
       waiting_job_->Resume(this);
       waiting_job_ = NULL;
@@ -812,13 +809,25 @@
       // TODO(rch): support QUIC proxies for HTTPS urls.
       return ERR_NOT_IMPLEMENTED;
     }
-    HostPortPair destination = proxy_info_.is_quic()
-                                   ? proxy_info_.proxy_server().host_port_pair()
-                                   : server_;
-    bool secure_quic = using_ssl_ || proxy_info_.is_quic();
+    HostPortPair destination;
+    std::string origin_host;
+    bool secure_quic;
+    if (proxy_info_.is_quic()) {
+      // A proxy's certificate is expected to be valid for the proxy hostname.
+      destination = proxy_info_.proxy_server().host_port_pair();
+      origin_host = destination.host();
+      secure_quic = true;
+    } else {
+      // The certificate of a QUIC alternative server is expected to be valid
+      // for the origin of the request (in addition to being valid for the
+      // server itself).
+      destination = server_;
+      origin_host = origin_url_.host();
+      secure_quic = using_ssl_;
+    }
     int rv = quic_request_.Request(
-        destination, secure_quic, request_info_.privacy_mode,
-        origin_url_.host(), request_info_.method, net_log_, io_callback_);
+        destination, secure_quic, request_info_.privacy_mode, origin_host,
+        request_info_.method, net_log_, io_callback_);
     if (rv == OK) {
       using_existing_quic_session_ = true;
     } else {
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index df8db288..c3afedd 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -552,7 +552,7 @@
 // Verify that preconnects to unsafe ports are cancelled before they reach
 // the SocketPool.
 TEST_P(HttpStreamFactoryTest, PreconnectUnsafePort) {
-  ASSERT_FALSE(IsPortAllowedForScheme(7, "http", PORT_OVERRIDES_ALLOWED));
+  ASSERT_FALSE(IsPortAllowedForScheme(7, "http"));
 
   SpdySessionDependencies session_deps(
       GetParam(), ProxyService::CreateDirect());
diff --git a/net/http/http_stream_parser_unittest.cc b/net/http/http_stream_parser_unittest.cc
index 8590bb45..76f998a 100644
--- a/net/http/http_stream_parser_unittest.cc
+++ b/net/http/http_stream_parser_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/chunked_upload_data_stream.h"
 #include "net/base/elements_upload_data_stream.h"
 #include "net/base/io_buffer.h"
@@ -154,11 +155,8 @@
                                                &temp_file_path));
 
     element_readers.push_back(
-        new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                    temp_file_path,
-                                    0,
-                                    0,
-                                    base::Time()));
+        new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                    temp_file_path, 0, 0, base::Time()));
 
     scoped_ptr<UploadDataStream> body(
         new ElementsUploadDataStream(element_readers.Pass(), 0));
diff --git a/net/http/http_transaction_test_util.cc b/net/http/http_transaction_test_util.cc
index d4fa2de6..1b2960b 100644
--- a/net/http/http_transaction_test_util.cc
+++ b/net/http/http_transaction_test_util.cc
@@ -7,8 +7,11 @@
 #include <algorithm>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
 #include "net/base/load_flags.h"
@@ -459,7 +462,7 @@
 
 void MockNetworkTransaction::CallbackLater(const CompletionCallback& callback,
                                            int result) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&MockNetworkTransaction::RunCallback,
                             weak_factory_.GetWeakPtr(), callback, result));
 }
diff --git a/net/http/http_util.cc b/net/http/http_util.cc
index baa2eff1..b3819c21 100644
--- a/net/http/http_util.cc
+++ b/net/http/http_util.cc
@@ -118,13 +118,14 @@
       DCHECK(param_value_begin <= tokenizer.token_end());
       TrimLWS(&param_value_begin, &param_value_end);
 
-      if (LowerCaseEqualsASCII(param_name_begin, param_name_end, "charset")) {
+      if (base::LowerCaseEqualsASCII(param_name_begin, param_name_end,
+                                     "charset")) {
         // TODO(abarth): Refactor this function to consistently use iterators.
         charset_val = param_value_begin - begin;
         charset_end = param_value_end - begin;
         type_has_charset = true;
-      } else if (LowerCaseEqualsASCII(param_name_begin, param_name_end,
-                                      "boundary")) {
+      } else if (base::LowerCaseEqualsASCII(param_name_begin, param_name_end,
+                                            "boundary")) {
         if (boundary)
           boundary->assign(param_value_begin, param_value_end);
       }
@@ -160,9 +161,9 @@
       content_type_str != "*/*" &&
       content_type_str.find_first_of('/') != std::string::npos) {
     // Common case here is that mime_type is empty
-    bool eq = !mime_type->empty() && LowerCaseEqualsASCII(begin + type_val,
-                                                          begin + type_end,
-                                                          mime_type->data());
+    bool eq = !mime_type->empty() &&
+              base::LowerCaseEqualsASCII(begin + type_val, begin + type_end,
+                                         mime_type->data());
     if (!eq) {
       mime_type->assign(begin + type_val, begin + type_end);
       base::StringToLowerASCII(mime_type);
@@ -190,7 +191,7 @@
 
   while (it.GetNext()) {
     // Look for "Range" header.
-    if (!LowerCaseEqualsASCII(it.name(), "range"))
+    if (!base::LowerCaseEqualsASCII(it.name(), "range"))
       continue;
     ranges_specifier = it.values();
     // We just care about the first "Range" header, so break here.
@@ -219,7 +220,7 @@
 
   TrimLWS(&bytes_unit_begin, &bytes_unit_end);
   // "bytes" unit identifier is not found.
-  if (!LowerCaseEqualsASCII(bytes_unit_begin, bytes_unit_end, "bytes"))
+  if (!base::LowerCaseEqualsASCII(bytes_unit_begin, bytes_unit_end, "bytes"))
     return false;
 
   ValuesIterator byte_range_set_iterator(byte_range_set_begin,
@@ -352,8 +353,8 @@
 // static
 bool HttpUtil::IsSafeHeader(const std::string& name) {
   std::string lower_name(base::StringToLowerASCII(name));
-  if (StartsWithASCII(lower_name, "proxy-", true) ||
-      StartsWithASCII(lower_name, "sec-", true))
+  if (base::StartsWithASCII(lower_name, "proxy-", true) ||
+      base::StartsWithASCII(lower_name, "sec-", true))
     return false;
   for (size_t i = 0; i < arraysize(kForbiddenHeaderFields); ++i) {
     if (lower_name == kForbiddenHeaderFields[i])
@@ -385,8 +386,8 @@
   while (it.GetNext()) {
     bool should_remove = false;
     for (size_t i = 0; i < headers_to_remove_len; ++i) {
-      if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(),
-                               headers_to_remove[i])) {
+      if (base::LowerCaseEqualsASCII(it.name_begin(), it.name_end(),
+                                     headers_to_remove[i])) {
         should_remove = true;
         break;
       }
@@ -421,7 +422,8 @@
     "strict-transport-security"
   };
   for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) {
-    if (LowerCaseEqualsASCII(name_begin, name_end, kNonCoalescingHeaders[i]))
+    if (base::LowerCaseEqualsASCII(name_begin, name_end,
+                                   kNonCoalescingHeaders[i]))
       return true;
   }
   return false;
@@ -535,16 +537,26 @@
   if (buf_len >= http_len) {
     int i_max = std::min(buf_len - http_len, slop);
     for (int i = 0; i <= i_max; ++i) {
-      if (LowerCaseEqualsASCII(buf + i, buf + i + http_len, "http"))
+      if (base::LowerCaseEqualsASCII(buf + i, buf + i + http_len, "http"))
         return i;
     }
   }
   return -1;  // Not found
 }
 
-int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) {
-  bool was_lf = false;
+static int LocateEndOfHeadersHelper(const char* buf,
+                                    int buf_len,
+                                    int i,
+                                    bool accept_empty_header_list) {
   char last_c = '\0';
+  bool was_lf = false;
+  if (accept_empty_header_list) {
+    // Normally two line breaks signal the end of a header list. An empty header
+    // list ends with a single line break at the start of the buffer.
+    last_c = '\n';
+    was_lf = true;
+  }
+
   for (; i < buf_len; ++i) {
     char c = buf[i];
     if (c == '\n') {
@@ -559,6 +571,16 @@
   return -1;
 }
 
+int HttpUtil::LocateEndOfAdditionalHeaders(const char* buf,
+                                           int buf_len,
+                                           int i) {
+  return LocateEndOfHeadersHelper(buf, buf_len, i, true);
+}
+
+int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) {
+  return LocateEndOfHeadersHelper(buf, buf_len, i, false);
+}
+
 // In order for a line to be continuable, it must specify a
 // non-blank header-name. Line continuations are specifically for
 // header values -- do not allow headers names to span lines.
@@ -731,7 +753,7 @@
     std::string::const_iterator i = etag_header.begin();
     std::string::const_iterator j = etag_header.begin() + slash;
     TrimLWS(&i, &j);
-    if (!LowerCaseEqualsASCII(i, j, "w"))
+    if (!base::LowerCaseEqualsASCII(i, j, "w"))
       return true;
   }
 
@@ -832,7 +854,7 @@
       << "the header name must be in all lower case";
 
   while (GetNext()) {
-    if (LowerCaseEqualsASCII(name_begin_, name_end_, name)) {
+    if (base::LowerCaseEqualsASCII(name_begin_, name_end_, name)) {
       return true;
     }
   }
diff --git a/net/http/http_util.h b/net/http/http_util.h
index b1585243..79a41acd 100644
--- a/net/http/http_util.h
+++ b/net/http/http_util.h
@@ -147,10 +147,19 @@
   // 2616 defines the end-of-headers marker as a double CRLF; however, some
   // servers only send back LFs (e.g., Unix-based CGI scripts written using the
   // ASIS Apache module).  This function therefore accepts the pattern LF[CR]LF
-  // as end-of-headers (just like Mozilla).
+  // as end-of-headers (just like Mozilla). The first line of |buf| is
+  // considered the status line, even if empty.
   // The parameter |i| is the offset within |buf| to begin searching from.
   static int LocateEndOfHeaders(const char* buf, int buf_len, int i = 0);
 
+  // Same as |LocateEndOfHeaders|, but does not expect a status line, so can be
+  // used on multi-part responses or HTTP/1.x trailers.  As a result, if |buf|
+  // starts with a single [CR]LF,  it is considered an empty header list, as
+  // opposed to an empty status line above a header list.
+  static int LocateEndOfAdditionalHeaders(const char* buf,
+                                          int buf_len,
+                                          int i = 0);
+
   // Assemble "raw headers" in the format required by HttpResponseHeaders.
   // This involves normalizing line terminators, converting [CR]LF to \0 and
   // handling HTTP line continuations (i.e., lines starting with LWS are
diff --git a/net/http/http_util_unittest.cc b/net/http/http_util_unittest.cc
index 71602844..8d0a2195 100644
--- a/net/http/http_util_unittest.cc
+++ b/net/http/http_util_unittest.cc
@@ -50,8 +50,9 @@
   for (size_t i = 0; i < arraysize(unsafe_headers); ++i) {
     EXPECT_FALSE(HttpUtil::IsSafeHeader(unsafe_headers[i]))
       << unsafe_headers[i];
-    EXPECT_FALSE(HttpUtil::IsSafeHeader(StringToUpperASCII(std::string(
-        unsafe_headers[i])))) << unsafe_headers[i];
+    EXPECT_FALSE(HttpUtil::IsSafeHeader(
+        base::StringToUpperASCII(std::string(unsafe_headers[i]))))
+        << unsafe_headers[i];
   }
   static const char* const safe_headers[] = {
     "foo",
@@ -95,8 +96,9 @@
   };
   for (size_t i = 0; i < arraysize(safe_headers); ++i) {
     EXPECT_TRUE(HttpUtil::IsSafeHeader(safe_headers[i])) << safe_headers[i];
-    EXPECT_TRUE(HttpUtil::IsSafeHeader(StringToUpperASCII(std::string(
-        safe_headers[i])))) << safe_headers[i];
+    EXPECT_TRUE(HttpUtil::IsSafeHeader(
+        base::StringToUpperASCII(std::string(safe_headers[i]))))
+        << safe_headers[i];
   }
 }
 
@@ -265,12 +267,17 @@
     const char* const input;
     int expected_result;
   } tests[] = {
-    { "foo\r\nbar\r\n\r\n", 12 },
-    { "foo\nbar\n\n", 9 },
-    { "foo\r\nbar\r\n\r\njunk", 12 },
-    { "foo\nbar\n\njunk", 9 },
-    { "foo\nbar\n\r\njunk", 10 },
-    { "foo\nbar\r\n\njunk", 10 },
+      {"\r\n", -1},
+      {"\n", -1},
+      {"\r", -1},
+      {"foo", -1},
+      {"\r\n\r\n", 4},
+      {"foo\r\nbar\r\n\r\n", 12},
+      {"foo\nbar\n\n", 9},
+      {"foo\r\nbar\r\n\r\njunk", 12},
+      {"foo\nbar\n\njunk", 9},
+      {"foo\nbar\n\r\njunk", 10},
+      {"foo\nbar\r\n\njunk", 10},
   };
   for (size_t i = 0; i < arraysize(tests); ++i) {
     int input_len = static_cast<int>(strlen(tests[i].input));
@@ -279,6 +286,29 @@
   }
 }
 
+TEST(HttpUtilTest, LocateEndOfAdditionalHeaders) {
+  struct {
+    const char* const input;
+    int expected_result;
+  } tests[] = {
+      {"\r\n", 2},
+      {"\n", 1},
+      {"\r", -1},
+      {"foo", -1},
+      {"\r\n\r\n", 2},
+      {"foo\r\nbar\r\n\r\n", 12},
+      {"foo\nbar\n\n", 9},
+      {"foo\r\nbar\r\n\r\njunk", 12},
+      {"foo\nbar\n\njunk", 9},
+      {"foo\nbar\n\r\njunk", 10},
+      {"foo\nbar\r\n\njunk", 10},
+  };
+  for (size_t i = 0; i < arraysize(tests); ++i) {
+    int input_len = static_cast<int>(strlen(tests[i].input));
+    int eoh = HttpUtil::LocateEndOfAdditionalHeaders(tests[i].input, input_len);
+    EXPECT_EQ(tests[i].expected_result, eoh);
+  }
+}
 TEST(HttpUtilTest, AssembleRawHeaders) {
   struct {
     const char* const input;  // with '|' representing '\0'
diff --git a/net/http/mock_http_cache.cc b/net/http/mock_http_cache.cc
index 19ab420a..d89993c 100644
--- a/net/http/mock_http_cache.cc
+++ b/net/http/mock_http_cache.cc
@@ -5,7 +5,9 @@
 #include "net/http/mock_http_cache.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -297,7 +299,7 @@
                                   int result) {
   if (ignore_callbacks_)
     return StoreAndDeliverCallbacks(true, this, callback, result);
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&MockDiskEntry::RunCallback, this, callback, result));
 }
@@ -498,7 +500,7 @@
 
 void MockDiskCache::CallbackLater(const CompletionCallback& callback,
                                   int result) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&CallbackForwader, callback, result));
 }
 
diff --git a/net/http/transport_security_persister.cc b/net/http/transport_security_persister.cc
index 65df808..574dee03 100644
--- a/net/http/transport_security_persister.cc
+++ b/net/http/transport_security_persister.cc
@@ -10,10 +10,10 @@
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/sequenced_task_runner.h"
 #include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "crypto/sha2.h"
 #include "net/cert/x509_certificate.h"
@@ -95,7 +95,7 @@
     bool readonly)
     : transport_security_state_(state),
       writer_(profile_path.AppendASCII("TransportSecurity"), background_runner),
-      foreground_runner_(base::MessageLoop::current()->message_loop_proxy()),
+      foreground_runner_(base::ThreadTaskRunnerHandle::Get()),
       background_runner_(background_runner),
       readonly_(readonly),
       weak_ptr_factory_(this) {
diff --git a/net/http/transport_security_persister_unittest.cc b/net/http/transport_security_persister_unittest.cc
index 1d547ea..2c9419e5 100644
--- a/net/http/transport_security_persister_unittest.cc
+++ b/net/http/transport_security_persister_unittest.cc
@@ -31,10 +31,8 @@
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     persister_.reset(new TransportSecurityPersister(
-        &state_,
-        temp_dir_.path(),
-        base::MessageLoopForIO::current()->message_loop_proxy(),
-        false));
+        &state_, temp_dir_.path(),
+        base::MessageLoopForIO::current()->task_runner(), false));
   }
 
  protected:
diff --git a/net/net.gypi b/net/net.gypi
index 8de27f2c..643e470 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1097,7 +1097,6 @@
       'spdy/spdy_pinnable_buffer_piece.h',
       'spdy/spdy_prefixed_buffer_reader.cc',
       'spdy/spdy_prefixed_buffer_reader.h',
-      'spdy/spdy_priority_forest.h',
       'spdy/spdy_priority_tree.h',
       'spdy/spdy_protocol.cc',
       'spdy/spdy_protocol.h',
@@ -1679,7 +1678,6 @@
       'spdy/spdy_network_transaction_unittest.cc',
       'spdy/spdy_pinnable_buffer_piece_test.cc',
       'spdy/spdy_prefixed_buffer_reader_test.cc',
-      'spdy/spdy_priority_forest_test.cc',
       'spdy/spdy_priority_tree_test.cc',
       'spdy/spdy_protocol_test.cc',
       'spdy/spdy_proxy_client_socket_unittest.cc',
diff --git a/net/net_common.gypi b/net/net_common.gypi
index c951d36..a4a1dc4 100644
--- a/net/net_common.gypi
+++ b/net/net_common.gypi
@@ -354,8 +354,12 @@
             '$(SDKROOT)/System/Library/Frameworks/MobileCoreServices.framework',
             '$(SDKROOT)/System/Library/Frameworks/Security.framework',
             '$(SDKROOT)/System/Library/Frameworks/SystemConfiguration.framework',
-            '$(SDKROOT)/usr/lib/libresolv.dylib',
           ],
+          'xcode_settings': {
+            'OTHER_LDFLAGS': [
+              '-lresolv',
+            ],
+          },
         },
       },
     ],
diff --git a/net/proxy/dhcp_proxy_script_adapter_fetcher_win.cc b/net/proxy/dhcp_proxy_script_adapter_fetcher_win.cc
index b8317cd..23c02df7 100644
--- a/net/proxy/dhcp_proxy_script_adapter_fetcher_win.cc
+++ b/net/proxy/dhcp_proxy_script_adapter_fetcher_win.cc
@@ -6,8 +6,8 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/task_runner.h"
diff --git a/net/proxy/dhcp_proxy_script_fetcher_win.h b/net/proxy/dhcp_proxy_script_fetcher_win.h
index fbe4a61..6110a01 100644
--- a/net/proxy/dhcp_proxy_script_fetcher_win.h
+++ b/net/proxy/dhcp_proxy_script_fetcher_win.h
@@ -10,7 +10,6 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/threading/non_thread_safe.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
diff --git a/net/proxy/multi_threaded_proxy_resolver.cc b/net/proxy/multi_threaded_proxy_resolver.cc
index d735787..6c6fa699 100644
--- a/net/proxy/multi_threaded_proxy_resolver.cc
+++ b/net/proxy/multi_threaded_proxy_resolver.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
@@ -367,7 +368,7 @@
   // cancelled), it will invoke OnJobCompleted() on this thread.
   job->set_executor(this);
   job->FinishedWaitingForThread();
-  thread_->message_loop()->PostTask(
+  thread_->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&Job::Run, job, base::ThreadTaskRunnerHandle::Get()));
 }
diff --git a/net/proxy/network_delegate_error_observer_unittest.cc b/net/proxy/network_delegate_error_observer_unittest.cc
index 6b9d6b0f..2d83014 100644
--- a/net/proxy/network_delegate_error_observer_unittest.cc
+++ b/net/proxy/network_delegate_error_observer_unittest.cc
@@ -6,6 +6,8 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "net/base/net_errors.h"
@@ -89,12 +91,9 @@
   TestNetworkDelegate network_delegate;
   NetworkDelegateErrorObserver observer(
       &network_delegate, base::ThreadTaskRunnerHandle::Get().get());
-  thread.message_loop()
-      ->PostTask(FROM_HERE,
-                 base::Bind(&NetworkDelegateErrorObserver::OnPACScriptError,
-                            base::Unretained(&observer),
-                            42,
-                            base::string16()));
+  thread.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&NetworkDelegateErrorObserver::OnPACScriptError,
+                            base::Unretained(&observer), 42, base::string16()));
   thread.Stop();
   base::MessageLoop::current()->RunUntilIdle();
   ASSERT_TRUE(network_delegate.got_pac_error());
@@ -106,12 +105,9 @@
   thread.Start();
   NetworkDelegateErrorObserver observer(
       NULL, base::ThreadTaskRunnerHandle::Get().get());
-  thread.message_loop()
-      ->PostTask(FROM_HERE,
-                 base::Bind(&NetworkDelegateErrorObserver::OnPACScriptError,
-                            base::Unretained(&observer),
-                            42,
-                            base::string16()));
+  thread.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&NetworkDelegateErrorObserver::OnPACScriptError,
+                            base::Unretained(&observer), 42, base::string16()));
   thread.Stop();
   base::MessageLoop::current()->RunUntilIdle();
   // Shouldn't have crashed until here...
diff --git a/net/proxy/proxy_bypass_rules.cc b/net/proxy/proxy_bypass_rules.cc
index 5344b82..9dc40315 100644
--- a/net/proxy/proxy_bypass_rules.cc
+++ b/net/proxy/proxy_bypass_rules.cc
@@ -264,7 +264,7 @@
 
   // This is the special syntax used by WinInet's bypass list -- we allow it
   // on all platforms and interpret it the same way.
-  if (LowerCaseEqualsASCII(raw, "<local>")) {
+  if (base::LowerCaseEqualsASCII(raw, "<local>")) {
     AddRuleToBypassLocal();
     return true;
   }
@@ -328,12 +328,12 @@
 
   // Special-case hostnames that begin with a period.
   // For example, we remap ".google.com" --> "*.google.com".
-  if (StartsWithASCII(raw, ".", false))
+  if (base::StartsWithASCII(raw, ".", false))
     raw = "*" + raw;
 
   // If suffix matching was asked for, make sure the pattern starts with a
   // wildcard.
-  if (use_hostname_suffix_matching && !StartsWithASCII(raw, "*", false))
+  if (use_hostname_suffix_matching && !base::StartsWithASCII(raw, "*", false))
     raw = "*" + raw;
 
   return AddRuleForHostname(scheme, raw, port);
diff --git a/net/proxy/proxy_config_service_android_unittest.cc b/net/proxy/proxy_config_service_android_unittest.cc
index 2e4f7bb..9257486 100644
--- a/net/proxy/proxy_config_service_android_unittest.cc
+++ b/net/proxy/proxy_config_service_android_unittest.cc
@@ -54,8 +54,8 @@
   ProxyConfigServiceAndroidTestBase(const StringMap& initial_configuration)
       : configuration_(initial_configuration),
         message_loop_(base::MessageLoop::current()),
-        service_(message_loop_->message_loop_proxy(),
-                 message_loop_->message_loop_proxy(),
+        service_(message_loop_->task_runner(),
+                 message_loop_->task_runner(),
                  base::Bind(&ProxyConfigServiceAndroidTestBase::GetProperty,
                             base::Unretained(this))) {}
 
diff --git a/net/proxy/proxy_config_service_linux.cc b/net/proxy/proxy_config_service_linux.cc
index be8068d6..58ae1df 100644
--- a/net/proxy/proxy_config_service_linux.cc
+++ b/net/proxy/proxy_config_service_linux.cc
@@ -55,7 +55,7 @@
 std::string FixupProxyHostScheme(ProxyServer::Scheme scheme,
                                  std::string host) {
   if (scheme == ProxyServer::SCHEME_SOCKS5 &&
-      StartsWithASCII(host, "socks4://", false)) {
+      base::StartsWithASCII(host, "socks4://", false)) {
     // We default to socks 5, but if the user specifically set it to
     // socks4://, then use that.
     scheme = ProxyServer::SCHEME_SOCKS4;
diff --git a/net/proxy/proxy_config_service_linux_unittest.cc b/net/proxy/proxy_config_service_linux_unittest.cc
index c19b38a..63fb92c 100644
--- a/net/proxy/proxy_config_service_linux_unittest.cc
+++ b/net/proxy/proxy_config_service_linux_unittest.cc
@@ -13,7 +13,9 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
+#include "base/location.h"
 #include "base/logging.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
@@ -267,7 +269,8 @@
     io_thread_.StartWithOptions(options);
 
     // Make sure the thread started.
-    io_thread_.message_loop()->PostTask(FROM_HERE,
+    io_thread_.task_runner()->PostTask(
+        FROM_HERE,
         base::Bind(&SynchConfigGetter::Init, base::Unretained(this)));
     Wait();
   }
@@ -277,7 +280,8 @@
     // before cleaning up that thread.
     delete config_service_;
     // Clean up the IO thread.
-    io_thread_.message_loop()->PostTask(FROM_HERE,
+    io_thread_.task_runner()->PostTask(
+        FROM_HERE,
         base::Bind(&SynchConfigGetter::CleanUp, base::Unretained(this)));
     Wait();
   }
@@ -288,15 +292,15 @@
   void SetupAndInitialFetch() {
     // We pass the mock IO thread as both the IO and file threads.
     config_service_->SetupAndFetchInitialConfig(
-        base::ThreadTaskRunnerHandle::Get(), io_thread_.message_loop_proxy(),
-        io_thread_.message_loop_proxy());
+        base::ThreadTaskRunnerHandle::Get(), io_thread_.task_runner(),
+        io_thread_.task_runner());
   }
   // Synchronously gets the proxy config.
   ProxyConfigService::ConfigAvailability SyncGetLatestProxyConfig(
       ProxyConfig* config) {
-    io_thread_.message_loop()->PostTask(FROM_HERE,
-        base::Bind(&SynchConfigGetter::GetLatestConfigOnIOThread,
-                   base::Unretained(this)));
+    io_thread_.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&SynchConfigGetter::GetLatestConfigOnIOThread,
+                              base::Unretained(this)));
     Wait();
     *config = proxy_config_;
     return get_latest_config_result_;
diff --git a/net/proxy/proxy_resolver_error_observer_mojo_unittest.cc b/net/proxy/proxy_resolver_error_observer_mojo_unittest.cc
index d28bd059..3e39e7557 100644
--- a/net/proxy/proxy_resolver_error_observer_mojo_unittest.cc
+++ b/net/proxy/proxy_resolver_error_observer_mojo_unittest.cc
@@ -8,6 +8,8 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
 #include "mojo/common/common_type_converters.h"
@@ -91,7 +93,7 @@
   base::Thread other_thread("error reporting thread");
   base::string16 error(base::ASCIIToUTF16("error message"));
   other_thread.Start();
-  other_thread.message_loop()->PostTask(
+  other_thread.task_runner()->PostTask(
       FROM_HERE, base::Bind(&ProxyResolverErrorObserver::OnPACScriptError,
                             base::Unretained(&error_observer()), 123, error));
   client().event_waiter().WaitForEvent(ErrorObserverClient::ERROR_RECEIVED);
diff --git a/net/proxy/proxy_script_decider_unittest.cc b/net/proxy/proxy_script_decider_unittest.cc
index 45f5199..1c3264f 100644
--- a/net/proxy/proxy_script_decider_unittest.cc
+++ b/net/proxy/proxy_script_decider_unittest.cc
@@ -5,11 +5,14 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -736,7 +739,7 @@
   int Fetch(base::string16* utf16_text,
             const CompletionCallback& callback) override {
     callback_ = callback;
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&AsyncFailDhcpFetcher::CallbackWithFailure, AsWeakPtr()));
     return ERR_IO_PENDING;
diff --git a/net/proxy/proxy_script_fetcher_impl.cc b/net/proxy/proxy_script_fetcher_impl.cc
index 1b9ed9fe..290363be 100644
--- a/net/proxy/proxy_script_fetcher_impl.cc
+++ b/net/proxy/proxy_script_fetcher_impl.cc
@@ -5,9 +5,11 @@
 #include "net/proxy/proxy_script_fetcher_impl.h"
 
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/data_url.h"
 #include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
@@ -40,7 +42,7 @@
     "application/x-javascript-config",
   };
   for (size_t i = 0; i < arraysize(kSupportedPacMimeTypes); ++i) {
-    if (LowerCaseEqualsASCII(mime_type, kSupportedPacMimeTypes[i]))
+    if (base::LowerCaseEqualsASCII(mime_type, kSupportedPacMimeTypes[i]))
       return true;
   }
   return false;
@@ -156,11 +158,9 @@
   // Post a task to timeout this request if it takes too long.
   cur_request_id_ = ++next_id_;
 
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&ProxyScriptFetcherImpl::OnTimeout,
-                 weak_factory_.GetWeakPtr(),
-                 cur_request_id_),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&ProxyScriptFetcherImpl::OnTimeout,
+                            weak_factory_.GetWeakPtr(), cur_request_id_),
       max_duration_);
 
   // Start the request.
diff --git a/net/proxy/proxy_server.cc b/net/proxy/proxy_server.cc
index 1e8bba9..c65df31 100644
--- a/net/proxy/proxy_server.cc
+++ b/net/proxy/proxy_server.cc
@@ -21,23 +21,23 @@
 ProxyServer::Scheme GetSchemeFromPacTypeInternal(
     std::string::const_iterator begin,
     std::string::const_iterator end) {
-  if (LowerCaseEqualsASCII(begin, end, "proxy"))
+  if (base::LowerCaseEqualsASCII(begin, end, "proxy"))
     return ProxyServer::SCHEME_HTTP;
-  if (LowerCaseEqualsASCII(begin, end, "socks")) {
+  if (base::LowerCaseEqualsASCII(begin, end, "socks")) {
     // Default to v4 for compatibility. This is because the SOCKS4 vs SOCKS5
     // notation didn't originally exist, so if a client returns SOCKS they
     // really meant SOCKS4.
     return ProxyServer::SCHEME_SOCKS4;
   }
-  if (LowerCaseEqualsASCII(begin, end, "socks4"))
+  if (base::LowerCaseEqualsASCII(begin, end, "socks4"))
     return ProxyServer::SCHEME_SOCKS4;
-  if (LowerCaseEqualsASCII(begin, end, "socks5"))
+  if (base::LowerCaseEqualsASCII(begin, end, "socks5"))
     return ProxyServer::SCHEME_SOCKS5;
-  if (LowerCaseEqualsASCII(begin, end, "direct"))
+  if (base::LowerCaseEqualsASCII(begin, end, "direct"))
     return ProxyServer::SCHEME_DIRECT;
-  if (LowerCaseEqualsASCII(begin, end, "https"))
+  if (base::LowerCaseEqualsASCII(begin, end, "https"))
     return ProxyServer::SCHEME_HTTPS;
-  if (LowerCaseEqualsASCII(begin, end, "quic"))
+  if (base::LowerCaseEqualsASCII(begin, end, "quic"))
     return ProxyServer::SCHEME_QUIC;
 
   return ProxyServer::SCHEME_INVALID;
@@ -48,19 +48,19 @@
 // ProxyServer::ToURI(). If no type could be matched, returns SCHEME_INVALID.
 ProxyServer::Scheme GetSchemeFromURIInternal(std::string::const_iterator begin,
                                              std::string::const_iterator end) {
-  if (LowerCaseEqualsASCII(begin, end, "http"))
+  if (base::LowerCaseEqualsASCII(begin, end, "http"))
     return ProxyServer::SCHEME_HTTP;
-  if (LowerCaseEqualsASCII(begin, end, "socks4"))
+  if (base::LowerCaseEqualsASCII(begin, end, "socks4"))
     return ProxyServer::SCHEME_SOCKS4;
-  if (LowerCaseEqualsASCII(begin, end, "socks"))
+  if (base::LowerCaseEqualsASCII(begin, end, "socks"))
     return ProxyServer::SCHEME_SOCKS5;
-  if (LowerCaseEqualsASCII(begin, end, "socks5"))
+  if (base::LowerCaseEqualsASCII(begin, end, "socks5"))
     return ProxyServer::SCHEME_SOCKS5;
-  if (LowerCaseEqualsASCII(begin, end, "direct"))
+  if (base::LowerCaseEqualsASCII(begin, end, "direct"))
     return ProxyServer::SCHEME_DIRECT;
-  if (LowerCaseEqualsASCII(begin, end, "https"))
+  if (base::LowerCaseEqualsASCII(begin, end, "https"))
     return ProxyServer::SCHEME_HTTPS;
-  if (LowerCaseEqualsASCII(begin, end, "quic"))
+  if (base::LowerCaseEqualsASCII(begin, end, "quic"))
     return ProxyServer::SCHEME_QUIC;
   return ProxyServer::SCHEME_INVALID;
 }
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc
index 1837f91..73ba0ee 100644
--- a/net/proxy/proxy_service.cc
+++ b/net/proxy/proxy_service.cc
@@ -9,11 +9,11 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -629,10 +629,9 @@
   void StartPollTimer() {
     DCHECK(!decider_.get());
 
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&ProxyScriptDeciderPoller::DoPoll,
-                   weak_factory_.GetWeakPtr()),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&ProxyScriptDeciderPoller::DoPoll,
+                              weak_factory_.GetWeakPtr()),
         next_poll_delay_);
   }
 
@@ -677,11 +676,10 @@
       // rather than calling it directly -- this is done to avoid an ugly
       // destruction sequence, since |this| might be destroyed as a result of
       // the notification.
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::Bind(&ProxyScriptDeciderPoller::NotifyProxyServiceOfChange,
-                     weak_factory_.GetWeakPtr(),
-                     result,
+                     weak_factory_.GetWeakPtr(), result,
                      make_scoped_refptr(decider_->script_data()),
                      decider_->effective_config()));
       return;
@@ -1531,8 +1529,8 @@
 
   return linux_config_service;
 #elif defined(OS_ANDROID)
-  return new ProxyConfigServiceAndroid(
-      io_task_runner, base::MessageLoop::current()->message_loop_proxy());
+  return new ProxyConfigServiceAndroid(io_task_runner,
+                                       base::ThreadTaskRunnerHandle::Get());
 #else
   LOG(WARNING) << "Failed to choose a system proxy settings fetcher "
                   "for this platform.";
diff --git a/net/proxy/proxy_service_mojo.cc b/net/proxy/proxy_service_mojo.cc
index 243966d0..8939315 100644
--- a/net/proxy/proxy_service_mojo.cc
+++ b/net/proxy/proxy_service_mojo.cc
@@ -5,7 +5,7 @@
 #include "net/proxy/proxy_service_mojo.h"
 
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/dns/mojo_host_resolver_impl.h"
 #include "net/interfaces/proxy_resolver_service.mojom.h"
 #include "net/proxy/in_process_mojo_proxy_resolver_factory.h"
@@ -37,7 +37,7 @@
       make_scoped_ptr(new ProxyResolverFactoryMojo(
           mojo_proxy_factory, host_resolver,
           base::Bind(&NetworkDelegateErrorObserver::Create, network_delegate,
-                     base::MessageLoopProxy::current()))),
+                     base::ThreadTaskRunnerHandle::Get()))),
       net_log);
 
   // Configure fetchers to use for PAC script downloads and auto-detect.
diff --git a/net/quic/crypto/channel_id_chromium.cc b/net/quic/crypto/channel_id_chromium.cc
index 9a54e88..ab50efa8e 100644
--- a/net/quic/crypto/channel_id_chromium.cc
+++ b/net/quic/crypto/channel_id_chromium.cc
@@ -89,7 +89,7 @@
   ChannelIDService* const channel_id_service_;
 
   scoped_ptr<crypto::ECPrivateKey> channel_id_crypto_key_;
-  ChannelIDService::RequestHandle channel_id_request_handle_;
+  ChannelIDService::Request channel_id_request_;
 
   // |hostname| specifies the hostname for which we need a channel ID.
   std::string hostname_;
@@ -181,7 +181,7 @@
       hostname_, &channel_id_crypto_key_,
       base::Bind(&ChannelIDSourceChromium::Job::OnIOComplete,
                  base::Unretained(this)),
-      &channel_id_request_handle_);
+      &channel_id_request_);
 }
 
 int ChannelIDSourceChromium::Job::DoGetChannelIDKeyComplete(int result) {
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 1b4abe9..3e9468a0 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -53,6 +53,8 @@
 const QuicTag kQBIC = TAG('Q', 'B', 'I', 'C');   // TCP cubic
 
 // Connection options (COPT) values
+const QuicTag kAFCW = TAG('A', 'F', 'C', 'W');   // Auto-tune flow control
+                                                 // receive windows.
 const QuicTag kTBBR = TAG('T', 'B', 'B', 'R');   // Reduced Buffer Bloat TCP
 const QuicTag kRENO = TAG('R', 'E', 'N', 'O');   // Reno Congestion Control
 const QuicTag kBYTE = TAG('B', 'Y', 'T', 'E');   // TCP cubic or reno in bytes
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 5f825db..f62f61eb 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -5,11 +5,13 @@
 #include "net/quic/quic_client_session.h"
 
 #include "base/callback_helpers.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -155,14 +157,18 @@
     QuicConnection* connection,
     scoped_ptr<DatagramClientSocket> socket,
     QuicStreamFactory* stream_factory,
+    QuicCryptoClientStreamFactory* crypto_client_stream_factory,
     TransportSecurityState* transport_security_state,
     scoped_ptr<QuicServerInfo> server_info,
+    const QuicServerId& server_id,
     const QuicConfig& config,
+    QuicCryptoClientConfig* crypto_config,
     const char* const connection_description,
     base::TimeTicks dns_resolution_end_time,
     base::TaskRunner* task_runner,
     NetLog* net_log)
     : QuicClientSessionBase(connection, config),
+      server_id_(server_id),
       require_confirmation_(false),
       stream_factory_(stream_factory),
       socket_(socket.Pass()),
@@ -176,20 +182,6 @@
       logger_(new QuicConnectionLogger(this, connection_description, net_log_)),
       going_away_(false),
       weak_factory_(this) {
-  connection->set_debug_visitor(logger_.get());
-  IPEndPoint address;
-  if (socket && socket->GetLocalAddress(&address) == OK &&
-      address.GetFamily() == ADDRESS_FAMILY_IPV6) {
-    connection->set_max_packet_length(
-        connection->max_packet_length() - kAdditionalOverheadForIPv6);
-  }
-}
-
-void QuicClientSession::InitializeSession(
-    const QuicServerId& server_id,
-    QuicCryptoClientConfig* crypto_config,
-    QuicCryptoClientStreamFactory* crypto_client_stream_factory) {
-  server_id_ = server_id;
   crypto_stream_.reset(
       crypto_client_stream_factory ?
           crypto_client_stream_factory->CreateQuicCryptoClientStream(
@@ -197,12 +189,17 @@
           new QuicCryptoClientStream(server_id, this,
                                      new ProofVerifyContextChromium(net_log_),
                                      crypto_config));
-  QuicClientSessionBase::InitializeSession();
-  // TODO(rch): pass in full host port proxy pair
+  connection->set_debug_visitor(logger_.get());
   net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION,
                       base::Bind(NetLogQuicClientSessionCallback,
                                  &server_id,
                                  require_confirmation_));
+  IPEndPoint address;
+  if (socket && socket->GetLocalAddress(&address) == OK &&
+      address.GetFamily() == ADDRESS_FAMILY_IPV6) {
+    connection->set_max_packet_length(connection->max_packet_length() -
+                                      kAdditionalOverheadForIPv6);
+  }
 }
 
 QuicClientSession::~QuicClientSession() {
@@ -905,10 +902,9 @@
   going_away_ = true;
   DCHECK_EQ(0u, GetNumOpenStreams());
   DCHECK(!connection()->connected());
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
-                 weak_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&QuicClientSession::NotifyFactoryOfSessionClosed,
+                            weak_factory_.GetWeakPtr()));
 }
 
 void QuicClientSession::NotifyFactoryOfSessionClosed() {
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index 4300dcd8..fe7033d 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -95,21 +95,18 @@
   QuicClientSession(QuicConnection* connection,
                     scoped_ptr<DatagramClientSocket> socket,
                     QuicStreamFactory* stream_factory,
+                    QuicCryptoClientStreamFactory* crypto_client_stream_factory,
                     TransportSecurityState* transport_security_state,
                     scoped_ptr<QuicServerInfo> server_info,
+                    const QuicServerId& server_id,
                     const QuicConfig& config,
+                    QuicCryptoClientConfig* crypto_config,
                     const char* const connection_description,
                     base::TimeTicks dns_resolution_end_time,
                     base::TaskRunner* task_runner,
                     NetLog* net_log);
   ~QuicClientSession() override;
 
-  // Initialize session's connection to |server_id|.
-  void InitializeSession(
-      const QuicServerId& server_id,
-      QuicCryptoClientConfig* config,
-      QuicCryptoClientStreamFactory* crypto_client_stream_factory);
-
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index b6457ec..4c3179f 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -9,6 +9,7 @@
 #include "base/base64.h"
 #include "base/files/file_path.h"
 #include "base/rand_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/test_completion_callback.h"
 #include "net/base/test_data_directory.h"
 #include "net/cert/cert_verify_result.h"
@@ -45,18 +46,21 @@
                                                SupportedVersions(GetParam()))),
         session_(connection_,
                  GetSocket().Pass(),
-                 nullptr,
+                 /*stream_factory=*/nullptr,
+                 /*crypto_client_stream_factory=*/nullptr,
                  &transport_security_state_,
                  make_scoped_ptr((QuicServerInfo*)nullptr),
+                 QuicServerId(kServerHostname,
+                              kServerPort,
+                              /*is_secure=*/false,
+                              PRIVACY_MODE_DISABLED),
                  DefaultQuicConfig(),
+                 &crypto_config_,
                  "CONNECTION_UNKNOWN",
                  base::TimeTicks::Now(),
-                 base::MessageLoop::current()->message_loop_proxy().get(),
+                 base::ThreadTaskRunnerHandle::Get().get(),
                  &net_log_) {
-    session_.InitializeSession(QuicServerId(kServerHostname, kServerPort,
-                                            /*is_secure=*/false,
-                                            PRIVACY_MODE_DISABLED),
-        &crypto_config_, nullptr);
+    session_.Initialize();
     // Advance the time, because timers do not like uninitialized times.
     connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 5f17af5..48aa7c12 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -907,7 +907,7 @@
 
   if (!last_stream_frames_.empty()) {
     visitor_->OnStreamFrames(last_stream_frames_);
-    if (!connected_ && !FLAGS_quic_stop_early) {
+    if (!connected_ && FLAGS_quic_stop_early_2) {
       return;
     }
   }
@@ -919,44 +919,44 @@
   // feedback.
   if (!last_window_update_frames_.empty()) {
     visitor_->OnWindowUpdateFrames(last_window_update_frames_);
-    if (!connected_ && !FLAGS_quic_stop_early) {
+    if (!connected_ && FLAGS_quic_stop_early_2) {
       return;
     }
   }
   if (!last_blocked_frames_.empty()) {
     visitor_->OnBlockedFrames(last_blocked_frames_);
-    if (!connected_ && !FLAGS_quic_stop_early) {
+    if (!connected_ && FLAGS_quic_stop_early_2) {
       return;
     }
   }
   for (size_t i = 0; i < last_goaway_frames_.size(); ++i) {
     visitor_->OnGoAway(last_goaway_frames_[i]);
-    if (!connected_ && !FLAGS_quic_stop_early) {
+    if (!connected_ && FLAGS_quic_stop_early_2) {
       return;
     }
   }
   for (size_t i = 0; i < last_rst_frames_.size(); ++i) {
     visitor_->OnRstStream(last_rst_frames_[i]);
-    if (!connected_ && !FLAGS_quic_stop_early) {
+    if (!connected_ && FLAGS_quic_stop_early_2) {
       return;
     }
   }
   for (size_t i = 0; i < last_ack_frames_.size(); ++i) {
     ProcessAckFrame(last_ack_frames_[i]);
-    if (!connected_ && !FLAGS_quic_stop_early) {
+    if (!connected_ && FLAGS_quic_stop_early_2) {
       return;
     }
   }
   for (size_t i = 0; i < last_stop_waiting_frames_.size(); ++i) {
     ProcessStopWaitingFrame(last_stop_waiting_frames_[i]);
-    if (!connected_ && !FLAGS_quic_stop_early) {
+    if (!connected_ && FLAGS_quic_stop_early_2) {
       return;
     }
   }
   if (!last_close_frames_.empty()) {
     CloseConnection(last_close_frames_[0].error_code, true);
     DCHECK(!connected_);
-    if (!FLAGS_quic_stop_early) {
+    if (FLAGS_quic_stop_early_2) {
       return;
     }
   }
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 4fc872aa..2dcf783 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -30,21 +30,22 @@
 class QuicCryptoClientStreamTest : public ::testing::Test {
  public:
   QuicCryptoClientStreamTest()
-      : connection_(new PacketSavingConnection(Perspective::IS_CLIENT)),
-        session_(new TestClientSession(connection_, DefaultQuicConfig())),
-        server_id_(kServerHostname, kServerPort, false, PRIVACY_MODE_DISABLED),
-        stream_(new QuicCryptoClientStream(server_id_,
-                                           session_.get(),
-                                           nullptr,
-                                           &crypto_config_)) {
-    session_->SetCryptoStream(stream_.get());
+      : server_id_(kServerHostname, kServerPort, false, PRIVACY_MODE_DISABLED) {
+    CreateConnection();
+  }
+
+  void CreateConnection() {
+    connection_ = new PacketSavingConnection(Perspective::IS_CLIENT);
     // Advance the time, because timers do not like uninitialized times.
     connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+
+    session_.reset(new TestClientSession(connection_, DefaultQuicConfig(),
+                                         server_id_, &crypto_config_));
   }
 
   void CompleteCryptoHandshake() {
-    stream_->CryptoConnect();
-    CryptoTestUtils::HandshakeWithFakeServer(connection_, stream_.get());
+    stream()->CryptoConnect();
+    CryptoTestUtils::HandshakeWithFakeServer(connection_, stream());
   }
 
   void ConstructHandshakeMessage() {
@@ -52,24 +53,25 @@
     message_data_.reset(framer.ConstructHandshakeMessage(message_));
   }
 
+  QuicCryptoClientStream* stream() { return session_->GetCryptoStream(); }
+
   PacketSavingConnection* connection_;
   scoped_ptr<TestClientSession> session_;
   QuicServerId server_id_;
-  scoped_ptr<QuicCryptoClientStream> stream_;
   CryptoHandshakeMessage message_;
   scoped_ptr<QuicData> message_data_;
   QuicCryptoClientConfig crypto_config_;
 };
 
 TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) {
-  EXPECT_FALSE(stream_->encryption_established());
-  EXPECT_FALSE(stream_->handshake_confirmed());
+  EXPECT_FALSE(stream()->encryption_established());
+  EXPECT_FALSE(stream()->handshake_confirmed());
 }
 
 TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) {
   CompleteCryptoHandshake();
-  EXPECT_TRUE(stream_->encryption_established());
-  EXPECT_TRUE(stream_->handshake_confirmed());
+  EXPECT_TRUE(stream()->encryption_established());
+  EXPECT_TRUE(stream()->handshake_confirmed());
 }
 
 TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) {
@@ -79,18 +81,18 @@
       QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE));
   message_.set_tag(kCHLO);
   ConstructHandshakeMessage();
-  stream_->ProcessRawData(message_data_->data(), message_data_->length());
+  stream()->ProcessRawData(message_data_->data(), message_data_->length());
 }
 
 TEST_F(QuicCryptoClientStreamTest, BadMessageType) {
-  stream_->CryptoConnect();
+  stream()->CryptoConnect();
 
   message_.set_tag(kCHLO);
   ConstructHandshakeMessage();
 
   EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(
         QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "Expected REJ"));
-  stream_->ProcessRawData(message_data_->data(), message_data_->length());
+  stream()->ProcessRawData(message_data_->data(), message_data_->length());
 }
 
 TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
@@ -103,39 +105,35 @@
             config->MaxStreamsPerConnection());
 
   const QuicCryptoNegotiatedParameters& crypto_params(
-      stream_->crypto_negotiated_params());
+      stream()->crypto_negotiated_params());
   EXPECT_EQ(crypto_config_.aead[0], crypto_params.aead);
   EXPECT_EQ(crypto_config_.kexs[0], crypto_params.key_exchange);
 }
 
 TEST_F(QuicCryptoClientStreamTest, InvalidHostname) {
-  QuicServerId server_id("invalid", 80, false, PRIVACY_MODE_DISABLED);
-  stream_.reset(new QuicCryptoClientStream(server_id, session_.get(), nullptr,
-                                           &crypto_config_));
-  session_->SetCryptoStream(stream_.get());
+  server_id_ =
+      QuicServerId("invalid", kServerPort, false, PRIVACY_MODE_DISABLED);
+
+  CreateConnection();
 
   CompleteCryptoHandshake();
-  EXPECT_TRUE(stream_->encryption_established());
-  EXPECT_TRUE(stream_->handshake_confirmed());
+  EXPECT_TRUE(stream()->encryption_established());
+  EXPECT_TRUE(stream()->handshake_confirmed());
 }
 
 TEST_F(QuicCryptoClientStreamTest, ExpiredServerConfig) {
   // Seed the config with a cached server config.
   CompleteCryptoHandshake();
 
-  connection_ = new PacketSavingConnection(Perspective::IS_CLIENT);
-  session_.reset(new TestClientSession(connection_, DefaultQuicConfig()));
-  stream_.reset(new QuicCryptoClientStream(server_id_, session_.get(), nullptr,
-                                           &crypto_config_));
-
-  session_->SetCryptoStream(stream_.get());
+  // Recreate connection with the new config.
+  CreateConnection();
 
   // Advance time 5 years to ensure that we pass the expiry time of the cached
   // server config.
   connection_->AdvanceTime(
       QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
 
-  stream_->CryptoConnect();
+  stream()->CryptoConnect();
   // Check that a client hello was sent.
   ASSERT_EQ(1u, connection_->encrypted_packets_.size());
 }
@@ -179,7 +177,7 @@
 
   scoped_ptr<QuicData> data(
       CryptoFramer::ConstructHandshakeMessage(server_config_update));
-  stream_->ProcessRawData(data->data(), data->length());
+  stream()->ProcessRawData(data->data(), data->length());
 
   // Make sure that the STK and SCFG are cached correctly.
   EXPECT_EQ("xstk", state->source_address_token());
@@ -197,7 +195,7 @@
   server_config_update.set_tag(kSCUP);
   scoped_ptr<QuicData> data(
       CryptoFramer::ConstructHandshakeMessage(server_config_update));
-  stream_->ProcessRawData(data->data(), data->length());
+  stream()->ProcessRawData(data->data(), data->length());
 }
 
 class QuicCryptoClientStreamStatelessTest : public ::testing::Test {
@@ -207,54 +205,49 @@
                               QuicRandom::GetInstance()),
         server_id_(kServerHostname, kServerPort, false, PRIVACY_MODE_DISABLED) {
     TestClientSession* client_session = nullptr;
-    QuicCryptoClientStream* client_stream = nullptr;
-    SetupCryptoClientStreamForTest(server_id_,
-                                   /* supports_stateless_rejects= */ true,
-                                   QuicTime::Delta::FromSeconds(100000),
-                                   &client_crypto_config_, &client_connection_,
-                                   &client_session, &client_stream);
+    CreateClientSessionForTest(server_id_,
+                               /* supports_stateless_rejects= */ true,
+                               QuicTime::Delta::FromSeconds(100000),
+                               &client_crypto_config_, &client_connection_,
+                               &client_session);
     CHECK(client_session);
-    CHECK(client_stream);
     client_session_.reset(client_session);
-    client_stream_.reset(client_stream);
+  }
+
+  QuicCryptoServerStream* server_stream() {
+    return server_session_->GetCryptoStream();
   }
 
   void AdvanceHandshakeWithFakeServer() {
-    client_stream_->CryptoConnect();
-    CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream_.get(),
-                                      0, server_connection_,
-                                      server_stream_.get(), 0);
+    client_session_->GetCryptoStream()->CryptoConnect();
+    CryptoTestUtils::AdvanceHandshake(client_connection_,
+                                      client_session_->GetCryptoStream(), 0,
+                                      server_connection_, server_stream(), 0);
   }
 
   // Initializes the server_stream_ for stateless rejects.
   void InitializeFakeStatelessRejectServer() {
     TestServerSession* server_session = nullptr;
-    QuicCryptoServerStream* server_stream = nullptr;
-    SetupCryptoServerStreamForTest(server_id_,
-                                   QuicTime::Delta::FromSeconds(100000),
-                                   &server_crypto_config_, &server_connection_,
-                                   &server_session, &server_stream);
+    CreateServerSessionForTest(server_id_, QuicTime::Delta::FromSeconds(100000),
+                               &server_crypto_config_, &server_connection_,
+                               &server_session);
     CHECK(server_session);
-    CHECK(server_stream);
     server_session_.reset(server_session);
-    server_stream_.reset(server_stream);
     CryptoTestUtils::SetupCryptoServerConfigForTest(
         server_connection_->clock(), server_connection_->random_generator(),
         server_session_->config(), &server_crypto_config_);
-    server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+    server_stream()->set_use_stateless_rejects_if_peer_supported(true);
   }
 
   // Client crypto stream state
   PacketSavingConnection* client_connection_;
   scoped_ptr<TestClientSession> client_session_;
-  scoped_ptr<QuicCryptoClientStream> client_stream_;
   QuicCryptoClientConfig client_crypto_config_;
 
   // Server crypto stream state
   PacketSavingConnection* server_connection_;
   scoped_ptr<TestServerSession> server_session_;
   QuicCryptoServerConfig server_crypto_config_;
-  scoped_ptr<QuicCryptoServerStream> server_stream_;
   QuicServerId server_id_;
 };
 
@@ -271,11 +264,11 @@
   InitializeFakeStatelessRejectServer();
   AdvanceHandshakeWithFakeServer();
 
-  EXPECT_EQ(1, server_stream_->num_handshake_messages());
-  EXPECT_EQ(0, server_stream_->num_handshake_messages_with_server_nonces());
+  EXPECT_EQ(1, server_stream()->num_handshake_messages());
+  EXPECT_EQ(0, server_stream()->num_handshake_messages_with_server_nonces());
 
-  EXPECT_FALSE(client_stream_->encryption_established());
-  EXPECT_FALSE(client_stream_->handshake_confirmed());
+  EXPECT_FALSE(client_session_->GetCryptoStream()->encryption_established());
+  EXPECT_FALSE(client_session_->GetCryptoStream()->handshake_confirmed());
   // Even though the handshake was not complete, the cached client_state is
   // complete, and can be used for a subsequent successful handshake.
   EXPECT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0)));
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index 2a51402d..f47c03b 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -96,33 +96,34 @@
   // called multiple times.
   void InitializeServer() {
     TestServerSession* server_session = nullptr;
-    QuicCryptoServerStream* server_stream = nullptr;
-    SetupCryptoServerStreamForTest(server_id_,
-                                   QuicTime::Delta::FromSeconds(100000),
-                                   &server_crypto_config_, &server_connection_,
-                                   &server_session, &server_stream);
+    CreateServerSessionForTest(server_id_, QuicTime::Delta::FromSeconds(100000),
+                               &server_crypto_config_, &server_connection_,
+                               &server_session);
     CHECK(server_session);
-    CHECK(server_stream);
     server_session_.reset(server_session);
-    server_stream_.reset(server_stream);
     CryptoTestUtils::SetupCryptoServerConfigForTest(
         server_connection_->clock(), server_connection_->random_generator(),
         server_session_->config(), &server_crypto_config_);
   }
 
+  QuicCryptoServerStream* server_stream() {
+    return server_session_->GetCryptoStream();
+  }
+
+  QuicCryptoClientStream* client_stream() {
+    return client_session_->GetCryptoStream();
+  }
+
   // Initializes a fake client, and all its associated state, for
   // testing.  May be called multiple times.
   void InitializeFakeClient(bool supports_stateless_rejects) {
     TestClientSession* client_session = nullptr;
-    QuicCryptoClientStream* client_stream = nullptr;
-    SetupCryptoClientStreamForTest(server_id_, supports_stateless_rejects,
-                                   QuicTime::Delta::FromSeconds(100000),
-                                   &client_crypto_config_, &client_connection_,
-                                   &client_session, &client_stream);
+    CreateClientSessionForTest(server_id_, supports_stateless_rejects,
+                               QuicTime::Delta::FromSeconds(100000),
+                               &client_crypto_config_, &client_connection_,
+                               &client_session);
     CHECK(client_session);
-    CHECK(client_stream);
     client_session_.reset(client_session);
-    client_stream_.reset(client_stream);
   }
 
   bool AsyncStrikeRegisterVerification() {
@@ -136,24 +137,21 @@
 
   int CompleteCryptoHandshake() {
     CHECK(server_connection_);
-    CHECK(server_stream_ != nullptr);
+    CHECK(server_session_ != nullptr);
     return CryptoTestUtils::HandshakeWithFakeClient(
-        server_connection_, server_stream_.get(), client_options_);
+        server_connection_, server_stream(), client_options_);
   }
 
   // Performs a single round of handshake message-exchange between the
   // client and server.
   void AdvanceHandshakeWithFakeClient() {
     CHECK(server_connection_);
-    CHECK(server_stream_ != nullptr);
     CHECK(client_session_ != nullptr);
-    CHECK(client_stream_ != nullptr);
 
     EXPECT_CALL(*client_session_, OnProofValid(_)).Times(testing::AnyNumber());
-    client_stream_->CryptoConnect();
-    CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream_.get(),
-                                      0, server_connection_,
-                                      server_stream_.get(), 0);
+    client_stream()->CryptoConnect();
+    CryptoTestUtils::AdvanceHandshake(client_connection_, client_stream(), 0,
+                                      server_connection_, server_stream(), 0);
   }
 
  protected:
@@ -161,14 +159,12 @@
   PacketSavingConnection* server_connection_;
   scoped_ptr<TestServerSession> server_session_;
   QuicCryptoServerConfig server_crypto_config_;
-  scoped_ptr<QuicCryptoServerStream> server_stream_;
   QuicServerId server_id_;
 
   // Client state
   PacketSavingConnection* client_connection_;
   QuicCryptoClientConfig client_crypto_config_;
   scoped_ptr<TestClientSession> client_session_;
-  scoped_ptr<QuicCryptoClientStream> client_stream_;
 
   CryptoHandshakeMessage message_;
   scoped_ptr<QuicData> message_data_;
@@ -179,13 +175,13 @@
 INSTANTIATE_TEST_CASE_P(Tests, QuicCryptoServerStreamTest, testing::Bool());
 
 TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) {
-  EXPECT_FALSE(server_stream_->encryption_established());
-  EXPECT_FALSE(server_stream_->handshake_confirmed());
+  EXPECT_FALSE(server_stream()->encryption_established());
+  EXPECT_FALSE(server_stream()->handshake_confirmed());
 }
 
 TEST_P(QuicCryptoServerStreamTest, NotInitiallySendingStatelessRejects) {
-  EXPECT_FALSE(server_stream_->use_stateless_rejects_if_peer_supported());
-  EXPECT_FALSE(server_stream_->peer_supports_stateless_rejects());
+  EXPECT_FALSE(server_stream()->use_stateless_rejects_if_peer_supported());
+  EXPECT_FALSE(server_stream()->peer_supports_stateless_rejects());
 }
 
 TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) {
@@ -194,21 +190,21 @@
   //   * One to get a source-address token and certificates.
   //   * One to complete the handshake.
   EXPECT_EQ(2, CompleteCryptoHandshake());
-  EXPECT_TRUE(server_stream_->encryption_established());
-  EXPECT_TRUE(server_stream_->handshake_confirmed());
+  EXPECT_TRUE(server_stream()->encryption_established());
+  EXPECT_TRUE(server_stream()->handshake_confirmed());
 }
 
 TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) {
   ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
                               true);
-  server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+  server_stream()->set_use_stateless_rejects_if_peer_supported(true);
 
   InitializeFakeClient(/* supports_stateless_rejects= */ true);
   AdvanceHandshakeWithFakeClient();
 
   // Check the server to make the sure the handshake did not succeed.
-  EXPECT_FALSE(server_stream_->encryption_established());
-  EXPECT_FALSE(server_stream_->handshake_confirmed());
+  EXPECT_FALSE(server_stream()->encryption_established());
+  EXPECT_FALSE(server_stream()->handshake_confirmed());
 
   // Check the client state to make sure that it received a server-designated
   // connection id.
@@ -233,16 +229,16 @@
 TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) {
   ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
                               true);
-  server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+  server_stream()->set_use_stateless_rejects_if_peer_supported(true);
 
   InitializeFakeClient(/* supports_stateless_rejects= */ true);
   AdvanceHandshakeWithFakeClient();
 
   // On the first round, encryption will not be established.
-  EXPECT_FALSE(server_stream_->encryption_established());
-  EXPECT_FALSE(server_stream_->handshake_confirmed());
-  EXPECT_EQ(1, server_stream_->num_handshake_messages());
-  EXPECT_EQ(0, server_stream_->num_handshake_messages_with_server_nonces());
+  EXPECT_FALSE(server_stream()->encryption_established());
+  EXPECT_FALSE(server_stream()->handshake_confirmed());
+  EXPECT_EQ(1, server_stream()->num_handshake_messages());
+  EXPECT_EQ(0, server_stream()->num_handshake_messages_with_server_nonces());
 
   // Now check the client state.
   QuicCryptoClientConfig::CachedState* client_state =
@@ -261,11 +257,11 @@
   // Now create new client and server streams with the existing config
   // and try the handshake again (0-RTT handshake).
   InitializeServer();
-  server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+  server_stream()->set_use_stateless_rejects_if_peer_supported(true);
 
   InitializeFakeClient(/* supports_stateless_rejects= */ true);
 
-  client_stream_->CryptoConnect();
+  client_stream()->CryptoConnect();
 
   // In the stateless case, the second handshake contains a server-nonce, so the
   // AsyncStrikeRegisterVerification() case will still succeed (unlike a 0-RTT
@@ -273,16 +269,16 @@
   AdvanceHandshakeWithFakeClient();
 
   // On the second round, encryption will be established.
-  EXPECT_TRUE(server_stream_->encryption_established());
-  EXPECT_TRUE(server_stream_->handshake_confirmed());
-  EXPECT_EQ(2, server_stream_->num_handshake_messages());
-  EXPECT_EQ(1, server_stream_->num_handshake_messages_with_server_nonces());
+  EXPECT_TRUE(server_stream()->encryption_established());
+  EXPECT_TRUE(server_stream()->handshake_confirmed());
+  EXPECT_EQ(2, server_stream()->num_handshake_messages());
+  EXPECT_EQ(1, server_stream()->num_handshake_messages_with_server_nonces());
 }
 
 TEST_P(QuicCryptoServerStreamTest, NoStatelessRejectIfNoClientSupport) {
   ValueRestore<bool> old_flag(&FLAGS_enable_quic_stateless_reject_support,
                               true);
-  server_stream_->set_use_stateless_rejects_if_peer_supported(true);
+  server_stream()->set_use_stateless_rejects_if_peer_supported(true);
 
   // The server is configured to use stateless rejects, but the client does not
   // support it.
@@ -290,8 +286,8 @@
   AdvanceHandshakeWithFakeClient();
 
   // Check the server to make the sure the handshake did not succeed.
-  EXPECT_FALSE(server_stream_->encryption_established());
-  EXPECT_FALSE(server_stream_->handshake_confirmed());
+  EXPECT_FALSE(server_stream()->encryption_established());
+  EXPECT_FALSE(server_stream()->handshake_confirmed());
 
   // Check the client state to make sure that it did not receive a
   // server-designated connection id.
@@ -314,42 +310,42 @@
   InitializeFakeClient(/* supports_stateless_rejects= */ false);
   InitializeServer();
 
-  client_stream_->CryptoConnect();
+  client_stream()->CryptoConnect();
 
   if (AsyncStrikeRegisterVerification()) {
-    EXPECT_FALSE(client_stream_->handshake_confirmed());
-    EXPECT_FALSE(server_stream_->handshake_confirmed());
+    EXPECT_FALSE(client_stream()->handshake_confirmed());
+    EXPECT_FALSE(server_stream()->handshake_confirmed());
 
     // Advance the handshake.  Expect that the server will be stuck waiting for
     // client nonce verification to complete.
     pair<size_t, size_t> messages_moved = CryptoTestUtils::AdvanceHandshake(
-        client_connection_, client_stream_.get(), 0, server_connection_,
-        server_stream_.get(), 0);
+        client_connection_, client_stream(), 0, server_connection_,
+        server_stream(), 0);
     EXPECT_EQ(1u, messages_moved.first);
     EXPECT_EQ(0u, messages_moved.second);
     EXPECT_EQ(1, strike_register_client_->PendingVerifications());
-    EXPECT_FALSE(client_stream_->handshake_confirmed());
-    EXPECT_FALSE(server_stream_->handshake_confirmed());
+    EXPECT_FALSE(client_stream()->handshake_confirmed());
+    EXPECT_FALSE(server_stream()->handshake_confirmed());
 
     // The server handshake completes once the nonce verification completes.
     strike_register_client_->RunPendingVerifications();
-    EXPECT_FALSE(client_stream_->handshake_confirmed());
-    EXPECT_TRUE(server_stream_->handshake_confirmed());
+    EXPECT_FALSE(client_stream()->handshake_confirmed());
+    EXPECT_TRUE(server_stream()->handshake_confirmed());
 
     messages_moved = CryptoTestUtils::AdvanceHandshake(
-        client_connection_, client_stream_.get(), messages_moved.first,
-        server_connection_, server_stream_.get(), messages_moved.second);
+        client_connection_, client_stream(), messages_moved.first,
+        server_connection_, server_stream(), messages_moved.second);
     EXPECT_EQ(1u, messages_moved.first);
     EXPECT_EQ(1u, messages_moved.second);
-    EXPECT_TRUE(client_stream_->handshake_confirmed());
-    EXPECT_TRUE(server_stream_->handshake_confirmed());
+    EXPECT_TRUE(client_stream()->handshake_confirmed());
+    EXPECT_TRUE(server_stream()->handshake_confirmed());
   } else {
     CryptoTestUtils::CommunicateHandshakeMessages(
-        client_connection_, client_stream_.get(), server_connection_,
-        server_stream_.get());
+        client_connection_, client_stream(), server_connection_,
+        server_stream());
   }
 
-  EXPECT_EQ(1, client_stream_->num_sent_client_hellos());
+  EXPECT_EQ(1, client_stream()->num_sent_client_hellos());
 }
 
 TEST_P(QuicCryptoServerStreamTest, MessageAfterHandshake) {
@@ -359,8 +355,8 @@
       SendConnectionClose(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE));
   message_.set_tag(kCHLO);
   ConstructHandshakeMessage();
-  server_stream_->ProcessRawData(message_data_->data(),
-                                 message_data_->length());
+  server_stream()->ProcessRawData(message_data_->data(),
+                                  message_data_->length());
 }
 
 TEST_P(QuicCryptoServerStreamTest, BadMessageType) {
@@ -368,8 +364,8 @@
   ConstructHandshakeMessage();
   EXPECT_CALL(*server_connection_,
               SendConnectionClose(QUIC_INVALID_CRYPTO_MESSAGE_TYPE));
-  server_stream_->ProcessRawData(message_data_->data(),
-                                 message_data_->length());
+  server_stream()->ProcessRawData(message_data_->data(),
+                                  message_data_->length());
 }
 
 TEST_P(QuicCryptoServerStreamTest, WithoutCertificates) {
@@ -379,34 +375,34 @@
   // Only 2 client hellos need to be sent in the no-certs case: one to get the
   // source-address token and the second to finish.
   EXPECT_EQ(2, CompleteCryptoHandshake());
-  EXPECT_TRUE(server_stream_->encryption_established());
-  EXPECT_TRUE(server_stream_->handshake_confirmed());
+  EXPECT_TRUE(server_stream()->encryption_established());
+  EXPECT_TRUE(server_stream()->handshake_confirmed());
 }
 
 TEST_P(QuicCryptoServerStreamTest, ChannelID) {
   client_options_.channel_id_enabled = true;
   client_options_.channel_id_source_async = false;
   // CompleteCryptoHandshake verifies
-  // server_stream_->crypto_negotiated_params().channel_id is correct.
+  // server_stream()->crypto_negotiated_params().channel_id is correct.
   EXPECT_EQ(2, CompleteCryptoHandshake());
-  EXPECT_TRUE(server_stream_->encryption_established());
-  EXPECT_TRUE(server_stream_->handshake_confirmed());
+  EXPECT_TRUE(server_stream()->encryption_established());
+  EXPECT_TRUE(server_stream()->handshake_confirmed());
 }
 
 TEST_P(QuicCryptoServerStreamTest, ChannelIDAsync) {
   client_options_.channel_id_enabled = true;
   client_options_.channel_id_source_async = true;
   // CompleteCryptoHandshake verifies
-  // server_stream_->crypto_negotiated_params().channel_id is correct.
+  // server_stream()->crypto_negotiated_params().channel_id is correct.
   EXPECT_EQ(2, CompleteCryptoHandshake());
-  EXPECT_TRUE(server_stream_->encryption_established());
-  EXPECT_TRUE(server_stream_->handshake_confirmed());
+  EXPECT_TRUE(server_stream()->encryption_established());
+  EXPECT_TRUE(server_stream()->handshake_confirmed());
 }
 
 TEST_P(QuicCryptoServerStreamTest, OnlySendSCUPAfterHandshakeComplete) {
   // An attempt to send a SCUP before completing handshake should fail.
-  server_stream_->SendServerConfigUpdate(nullptr);
-  EXPECT_EQ(0, server_stream_->num_server_config_update_messages_sent());
+  server_stream()->SendServerConfigUpdate(nullptr);
+  EXPECT_EQ(0, server_stream()->num_server_config_update_messages_sent());
 }
 
 TEST_P(QuicCryptoServerStreamTest, DoesPeerSupportStatelessRejects) {
diff --git a/net/quic/quic_data_writer.h b/net/quic/quic_data_writer.h
index 762c3aa..052ade81 100644
--- a/net/quic/quic_data_writer.h
+++ b/net/quic/quic_data_writer.h
@@ -10,7 +10,6 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
-#include "base/port.h"
 #include "base/strings/string_piece.h"
 #include "net/base/int128.h"
 #include "net/base/net_export.h"
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index cf3b262..f36b667 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -42,6 +42,9 @@
 // Enables server-side support for QUIC stateless rejects.
 bool FLAGS_enable_quic_stateless_reject_support = false;
 
-// If true, stop processing quic data as soon as the connection is closed rather
-// than processing a full packet.
-bool FLAGS_quic_stop_early = true;
+// If true, flow controller may grow the receive window size if necessary.
+bool FLAGS_quic_auto_tune_receive_window = true;
+
+// If true, stop processing quic data as soon as the connection is
+// closed rather than processing a full packet.
+bool FLAGS_quic_stop_early_2 = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index 30bf0ae8..c72be26 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -18,6 +18,7 @@
 NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_seconds;
 NET_EXPORT_PRIVATE extern int64 FLAGS_quic_time_wait_list_max_connections;
 NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_stateless_reject_support;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_stop_early;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_auto_tune_receive_window;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_stop_early_2;
 
 #endif  // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc
index af79b956..699f836 100644
--- a/net/quic/quic_flow_controller.cc
+++ b/net/quic/quic_flow_controller.cc
@@ -11,6 +11,11 @@
 
 namespace net {
 
+namespace {
+const QuicByteCount kStreamReceiveWindowLimit = 16 * 1024 * 1024;   // 16 MB
+const QuicByteCount kSessionReceiveWindowLimit = 24 * 1024 * 1024;  // 24 MB
+}
+
 #define ENDPOINT \
   (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ")
 
@@ -19,22 +24,28 @@
                                        Perspective perspective,
                                        QuicStreamOffset send_window_offset,
                                        QuicStreamOffset receive_window_offset,
-                                       QuicByteCount max_receive_window)
+                                       bool should_auto_tune_receive_window)
     : connection_(connection),
       id_(id),
       perspective_(perspective),
-      bytes_consumed_(0),
-      highest_received_byte_offset_(0),
       bytes_sent_(0),
       send_window_offset_(send_window_offset),
+      bytes_consumed_(0),
+      highest_received_byte_offset_(0),
       receive_window_offset_(receive_window_offset),
-      max_receive_window_(max_receive_window),
-      last_blocked_send_window_offset_(0) {
+      receive_window_size_(receive_window_offset),
+      auto_tune_receive_window_(should_auto_tune_receive_window),
+      last_blocked_send_window_offset_(0),
+      prev_window_update_time_(QuicTime::Zero()) {
+  receive_window_size_limit_ = (id_ == kConnectionLevelId)
+                                   ? kSessionReceiveWindowLimit
+                                   : kStreamReceiveWindowLimit;
+
   DVLOG(1) << ENDPOINT << "Created flow controller for stream " << id_
            << ", setting initial receive window offset to: "
            << receive_window_offset_
-           << ", max receive window to: "
-           << max_receive_window_
+           << ", max receive window to: " << receive_window_size_
+           << ", max receive window limit to: " << receive_window_size_limit_
            << ", setting send window offset to: " << send_window_offset_;
 }
 
@@ -87,28 +98,102 @@
   return false;
 }
 
+void QuicFlowController::MaybeIncreaseMaxWindowSize() {
+  // Core of receive window auto tuning.  This method should be called before a
+  // WINDOW_UPDATE frame is sent.  Ideally, window updates should occur close to
+  // once per RTT.  If a window update happens much faster than RTT, it implies
+  // that the flow control window is imposing a bottleneck.  To prevent this,
+  // this method will increase the receive window size (subject to a reasonable
+  // upper bound).  For simplicity this algorithm is deliberately asymmetric, in
+  // that it may increase window size but never decreases.
+
+  if (!FLAGS_quic_auto_tune_receive_window) {
+    return;
+  }
+
+  // Keep track of timing between successive window updates.
+  QuicTime now = connection_->clock()->ApproximateNow();
+  QuicTime prev = prev_window_update_time_;
+  prev_window_update_time_ = now;
+  if (!prev.IsInitialized()) {
+    DVLOG(1) << ENDPOINT << "first window update for stream " << id_;
+    return;
+  }
+
+  if (!auto_tune_receive_window_) {
+    return;
+  }
+
+  // Get outbound RTT.
+  QuicTime::Delta rtt =
+      connection_->sent_packet_manager().GetRttStats()->smoothed_rtt();
+  if (rtt.IsZero()) {
+    DVLOG(1) << ENDPOINT << "rtt zero for stream " << id_;
+    return;
+  }
+
+  // Now we can compare timing of window updates with RTT.
+  QuicTime::Delta since_last = now.Subtract(prev);
+  QuicTime::Delta two_rtt = rtt.Multiply(2);
+
+  if (since_last >= two_rtt) {
+    // If interval between window updates is sufficiently large, there
+    // is no need to increase receive_window_size_.
+    return;
+  }
+
+  QuicByteCount old_window = receive_window_size_;
+  receive_window_size_ *= 2;
+  receive_window_size_ =
+      std::min(receive_window_size_, receive_window_size_limit_);
+
+  if (receive_window_size_ > old_window) {
+    DVLOG(1) << ENDPOINT << "New max window increase for stream " << id_
+             << " after " << since_last.ToMicroseconds() << " us, and RTT is "
+             << rtt.ToMicroseconds()
+             << "us. max wndw: " << receive_window_size_;
+  } else {
+    // TODO(ckrasic) - add a varz to track this (?).
+    DVLOG(1) << ENDPOINT << "Max window at limit for stream " << id_
+             << " after " << since_last.ToMicroseconds() << " us, and RTT is "
+             << rtt.ToMicroseconds()
+             << "us. Limit size: " << receive_window_size_;
+  }
+}
+
+QuicByteCount QuicFlowController::WindowUpdateThreshold() {
+  return receive_window_size_ / 2;
+}
+
 void QuicFlowController::MaybeSendWindowUpdate() {
   // Send WindowUpdate to increase receive window if
   // (receive window offset - consumed bytes) < (max window / 2).
   // This is behaviour copied from SPDY.
-  DCHECK_LT(bytes_consumed_, receive_window_offset_);
+  DCHECK_LE(bytes_consumed_, receive_window_offset_);
   QuicStreamOffset available_window = receive_window_offset_ - bytes_consumed_;
-  QuicByteCount threshold = (max_receive_window_ / 2);
+  QuicByteCount threshold = WindowUpdateThreshold();
 
-  if (available_window < threshold) {
-    // Update our receive window.
-    receive_window_offset_ += (max_receive_window_ - available_window);
-
-    DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_
-             << ", consumed bytes: " << bytes_consumed_
+  if (available_window >= threshold) {
+    DVLOG(1) << ENDPOINT << "Not sending WindowUpdate for stream " << id_
              << ", available window: " << available_window
-             << ", and threshold: " << threshold
-             << ", and max recvw: " << max_receive_window_
-             << ". New receive window offset is: " << receive_window_offset_;
-
-    // Inform the peer of our new receive window.
-    connection_->SendWindowUpdate(id_, receive_window_offset_);
+             << ">= threshold: " << threshold;
+    return;
   }
+
+  MaybeIncreaseMaxWindowSize();
+
+  // Update our receive window.
+  receive_window_offset_ += (receive_window_size_ - available_window);
+
+  DVLOG(1) << ENDPOINT << "Sending WindowUpdate frame for stream " << id_
+           << ", consumed bytes: " << bytes_consumed_
+           << ", available window: " << available_window
+           << ", and threshold: " << threshold
+           << ", and receive window size: " << receive_window_size_
+           << ". New receive window offset is: " << receive_window_offset_;
+
+  // Inform the peer of our new receive window.
+  connection_->SendWindowUpdate(id_, receive_window_offset_);
 }
 
 void QuicFlowController::MaybeSendBlocked() {
diff --git a/net/quic/quic_flow_controller.h b/net/quic/quic_flow_controller.h
index afa022b1..f1973f2 100644
--- a/net/quic/quic_flow_controller.h
+++ b/net/quic/quic_flow_controller.h
@@ -30,7 +30,8 @@
                      Perspective perspective,
                      QuicStreamOffset send_window_offset,
                      QuicStreamOffset receive_window_offset,
-                     QuicByteCount max_receive_window);
+                     bool should_auto_tune_receive_window);
+
   ~QuicFlowController() {}
 
   // Called when we see a new highest received byte offset from the peer, either
@@ -68,12 +69,26 @@
     return highest_received_byte_offset_;
   }
 
+  void set_receive_window_size_limit(QuicByteCount receive_window_size_limit) {
+    DCHECK_GE(receive_window_size_limit, receive_window_size_limit_);
+    receive_window_size_limit_ = receive_window_size_limit;
+  }
+
+  void set_auto_tune_receive_window(bool enable) {
+    auto_tune_receive_window_ = enable;
+  }
+
+  bool auto_tune_receive_window() { return auto_tune_receive_window_; }
+
  private:
   friend class test::QuicFlowControllerPeer;
 
   // Send a WINDOW_UPDATE frame if appropriate.
   void MaybeSendWindowUpdate();
 
+  // Auto-tune the max receive window size.
+  void MaybeIncreaseMaxWindowSize();
+
   // The parent connection, used to send connection close on flow control
   // violation, and WINDOW_UPDATE and BLOCKED frames when appropriate.
   // Not owned.
@@ -86,6 +101,33 @@
   // Tracks if this is owned by a server or a client.
   Perspective perspective_;
 
+  // Tracks number of bytes sent to the peer.
+  QuicByteCount bytes_sent_;
+
+  // The absolute offset in the outgoing byte stream. If this offset is reached
+  // then we become flow control blocked until we receive a WINDOW_UPDATE.
+  QuicStreamOffset send_window_offset_;
+
+  // Overview of receive flow controller.
+  //
+  // 0=...===1=======2-------3 ...... FIN
+  //         |<--- <= 4  --->|
+  //
+
+  // 1) bytes_consumed_ - moves forward when data is read out of the
+  //    stream.
+  //
+  // 2) highest_received_byte_offset_ - moves when data is received
+  //    from the peer.
+  //
+  // 3) receive_window_offset_ - moves when WINDOW_UPDATE is sent.
+  //
+  // 4) receive_window_size_ - maximum allowed unread data (3 - 1).
+  //    This value may be increased by auto-tuning.
+  //
+  // 5) receive_window_size_limit_ - limit on receive_window_size_;
+  //    auto-tuning will not increase window size beyond this limit.
+
   // Track number of bytes received from the peer, which have been consumed
   // locally.
   QuicByteCount bytes_consumed_;
@@ -94,24 +136,31 @@
   // highest offset in a data frame, or a final value in a RST.
   QuicStreamOffset highest_received_byte_offset_;
 
-  // Tracks number of bytes sent to the peer.
-  QuicByteCount bytes_sent_;
-
-  // The absolute offset in the outgoing byte stream. If this offset is reached
-  // then we become flow control blocked until we receive a WINDOW_UPDATE.
-  QuicStreamOffset send_window_offset_;
 
   // The absolute offset in the incoming byte stream. The peer should never send
   // us bytes which are beyond this offset.
   QuicStreamOffset receive_window_offset_;
 
   // Largest size the receive window can grow to.
-  QuicByteCount max_receive_window_;
+  QuicByteCount receive_window_size_;
+
+  // Upper limit on receive_window_size_;
+  QuicByteCount receive_window_size_limit_;
+
+  // Used to dynamically enable receive window auto-tuning.
+  bool auto_tune_receive_window_;
+
+  // Send window update when receive window size drops below this.
+  QuicByteCount WindowUpdateThreshold();
 
   // Keep track of the last time we sent a BLOCKED frame. We should only send
   // another when the number of bytes we have sent has changed.
   QuicStreamOffset last_blocked_send_window_offset_;
 
+  // Keep time of the last time a window update was sent.  We use this
+  // as part of the receive window auto tuning.
+  QuicTime prev_window_update_time_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicFlowController);
 };
 
diff --git a/net/quic/quic_flow_controller_test.cc b/net/quic/quic_flow_controller_test.cc
index 4562a14..dffbd56d7 100644
--- a/net/quic/quic_flow_controller_test.cc
+++ b/net/quic/quic_flow_controller_test.cc
@@ -6,9 +6,11 @@
 
 #include "base/format_macros.h"
 #include "base/strings/stringprintf.h"
+#include "net/quic/quic_flags.h"
 #include "net/quic/quic_utils.h"
 #include "net/quic/test_tools/quic_connection_peer.h"
 #include "net/quic/test_tools/quic_flow_controller_peer.h"
+#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
 #include "net/quic/test_tools/quic_test_utils.h"
 #include "net/test/gtest_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -16,26 +18,27 @@
 namespace net {
 namespace test {
 
+// Receive window auto-tuning uses RTT in its logic.
+const int64 kRtt = 100;
+
 class QuicFlowControllerTest : public ::testing::Test {
  public:
   QuicFlowControllerTest()
       : stream_id_(1234),
         send_window_(kInitialSessionFlowControlWindowForTest),
         receive_window_(kInitialSessionFlowControlWindowForTest),
-        max_receive_window_(kInitialSessionFlowControlWindowForTest),
         connection_(Perspective::IS_CLIENT) {}
 
   void Initialize() {
-    flow_controller_.reset(new QuicFlowController(
-        &connection_, stream_id_, Perspective::IS_CLIENT, send_window_,
-        receive_window_, max_receive_window_));
+    flow_controller_.reset(
+        new QuicFlowController(&connection_, stream_id_, Perspective::IS_CLIENT,
+                               send_window_, receive_window_, false));
   }
 
  protected:
   QuicStreamId stream_id_;
   QuicByteCount send_window_;
   QuicByteCount receive_window_;
-  QuicByteCount max_receive_window_;
   scoped_ptr<QuicFlowController> flow_controller_;
   MockConnection connection_;
 };
@@ -147,5 +150,225 @@
   flow_controller_->MaybeSendBlocked();
 }
 
+TEST_F(QuicFlowControllerTest, ReceivingBytesFastIncreasesFlowWindow) {
+  ValueRestore<bool> old_flag(&FLAGS_quic_auto_tune_receive_window, true);
+  // This test will generate two WINDOW_UPDATE frames.
+  EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+  Initialize();
+  flow_controller_->set_auto_tune_receive_window(true);
+
+  // Make sure clock is inititialized.
+  connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+  QuicSentPacketManager* manager =
+      QuicConnectionPeer::GetSentPacketManager(&connection_);
+
+  RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager);
+  rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+                       QuicTime::Delta::Zero(), QuicTime::Zero());
+
+  EXPECT_FALSE(flow_controller_->IsBlocked());
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  QuicByteCount threshold =
+      QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+  QuicStreamOffset receive_offset = threshold + 1;
+  // Receive some bytes, updating highest received offset, but not enough to
+  // fill flow control receive window.
+  EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  // Consume enough bytes to send a WINDOW_UPDATE frame.
+  flow_controller_->AddBytesConsumed(threshold + 1);
+  // Result is that once again we have a fully open receive window.
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  // Move time forward, but by less than two RTTs.  Then receive and consume
+  // some more, forcing a second WINDOW_UPDATE with an increased max window
+  // size.
+  connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt - 1));
+  receive_offset += threshold + 1;
+  EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+  flow_controller_->AddBytesConsumed(threshold + 1);
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  QuicByteCount new_threshold =
+      QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+  EXPECT_GT(new_threshold, threshold);
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytesFastStatusQuo) {
+  ValueRestore<bool> old_flag(&FLAGS_quic_auto_tune_receive_window, false);
+  // This test will generate two WINDOW_UPDATE frames.
+  EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+  Initialize();
+  flow_controller_->set_auto_tune_receive_window(true);
+
+  // Make sure clock is inititialized.
+  connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+  QuicSentPacketManager* manager =
+      QuicConnectionPeer::GetSentPacketManager(&connection_);
+
+  RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager);
+  rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+                       QuicTime::Delta::Zero(), QuicTime::Zero());
+
+  EXPECT_FALSE(flow_controller_->IsBlocked());
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  QuicByteCount threshold =
+      QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+  QuicStreamOffset receive_offset = threshold + 1;
+  // Receive some bytes, updating highest received offset, but not enough to
+  // fill flow control receive window.
+  EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  // Consume enough bytes to send a WINDOW_UPDATE frame.
+  flow_controller_->AddBytesConsumed(threshold + 1);
+  // Result is that once again we have a fully open receive window.
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  // Move time forward, but by less than two RTTs.  Then receive and consume
+  // some more, forcing a second WINDOW_UPDATE with an increased max window
+  // size.
+  connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt - 1));
+  receive_offset += threshold + 1;
+  EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+  flow_controller_->AddBytesConsumed(threshold + 1);
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  QuicByteCount new_threshold =
+      QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+  EXPECT_EQ(new_threshold, threshold);
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytesNormalStableFlowWindow) {
+  ValueRestore<bool> old_flag(&FLAGS_quic_auto_tune_receive_window, true);
+  // This test will generate two WINDOW_UPDATE frames.
+  EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+  Initialize();
+  flow_controller_->set_auto_tune_receive_window(true);
+
+  // Make sure clock is inititialized.
+  connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+  QuicSentPacketManager* manager =
+      QuicConnectionPeer::GetSentPacketManager(&connection_);
+  RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager);
+  rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+                       QuicTime::Delta::Zero(), QuicTime::Zero());
+
+  EXPECT_FALSE(flow_controller_->IsBlocked());
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  QuicByteCount threshold =
+      QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+  QuicStreamOffset receive_offset = threshold + 1;
+  // Receive some bytes, updating highest received offset, but not enough to
+  // fill flow control receive window.
+  EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  flow_controller_->AddBytesConsumed(threshold + 1);
+
+  // Result is that once again we have a fully open receive window.
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  // Move time forward, but by more than two RTTs.  Then receive and consume
+  // some more, forcing a second WINDOW_UPDATE with unchanged max window size.
+  connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt + 1));
+
+  receive_offset += threshold + 1;
+  EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+
+  flow_controller_->AddBytesConsumed(threshold + 1);
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+
+  QuicByteCount new_threshold =
+      QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+  EXPECT_EQ(new_threshold, threshold);
+}
+
+TEST_F(QuicFlowControllerTest, ReceivingBytesNormalStatusQuo) {
+  ValueRestore<bool> old_flag(&FLAGS_quic_auto_tune_receive_window, false);
+  // This test will generate two WINDOW_UPDATE frames.
+  EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(2);
+
+  Initialize();
+  flow_controller_->set_auto_tune_receive_window(true);
+
+  // Make sure clock is inititialized.
+  connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+
+  QuicSentPacketManager* manager =
+      QuicConnectionPeer::GetSentPacketManager(&connection_);
+  RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager);
+  rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kRtt),
+                       QuicTime::Delta::Zero(), QuicTime::Zero());
+
+  EXPECT_FALSE(flow_controller_->IsBlocked());
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  QuicByteCount threshold =
+      QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+  QuicStreamOffset receive_offset = threshold + 1;
+  // Receive some bytes, updating highest received offset, but not enough to
+  // fill flow control receive window.
+  EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest - receive_offset,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  flow_controller_->AddBytesConsumed(threshold + 1);
+
+  // Result is that once again we have a fully open receive window.
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+  EXPECT_EQ(kInitialSessionFlowControlWindowForTest,
+            QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get()));
+
+  // Move time forward, but by more than two RTTs.  Then receive and consume
+  // some more, forcing a second WINDOW_UPDATE with unchanged max window size.
+  connection_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2 * kRtt + 1));
+
+  receive_offset += threshold + 1;
+  EXPECT_TRUE(flow_controller_->UpdateHighestReceivedOffset(receive_offset));
+
+  flow_controller_->AddBytesConsumed(threshold + 1);
+  EXPECT_FALSE(flow_controller_->FlowControlViolation());
+
+  QuicByteCount new_threshold =
+      QuicFlowControllerPeer::WindowUpdateThreshold(flow_controller_.get());
+
+  EXPECT_EQ(new_threshold, threshold);
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 26eb314..babdea4 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -135,15 +135,6 @@
 
 }  // namespace
 
-bool QuicFramerVisitorInterface::OnWindowUpdateFrame(
-    const QuicWindowUpdateFrame& frame) {
-  return true;
-}
-
-bool QuicFramerVisitorInterface::OnBlockedFrame(const QuicBlockedFrame& frame) {
-  return true;
-}
-
 QuicFramer::QuicFramer(const QuicVersionVector& supported_versions,
                        QuicTime creation_time,
                        Perspective perspective)
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc
index 9f3b59f..04bccf5 100644
--- a/net/quic/quic_headers_stream_test.cc
+++ b/net/quic/quic_headers_stream_test.cc
@@ -66,12 +66,10 @@
                                    SpdyStreamId promised_stream_id,
                                    bool end));
   MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end));
-  MOCK_METHOD6(OnAltSvc, void(SpdyStreamId stream_id,
-                              uint32 max_age,
-                              uint16 port,
-                              StringPiece protocol_id,
-                              StringPiece host,
-                              StringPiece origin));
+  MOCK_METHOD3(OnAltSvc,
+               void(SpdyStreamId stream_id,
+                    StringPiece origin,
+                    const SpdyAltSvcWireFormat::AlternativeService& altsvc));
   MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
 };
 
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index ed42db6..639135c2 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "base/thread_task_runner_handle.h"
 #include "net/base/chunked_upload_data_stream.h"
 #include "net/base/elements_upload_data_stream.h"
 #include "net/base/net_errors.h"
@@ -207,14 +208,15 @@
     connection_->set_visitor(&visitor_);
     connection_->SetSendAlgorithm(send_algorithm_);
     session_.reset(new QuicClientSession(
-        connection_, scoped_ptr<DatagramClientSocket>(socket), nullptr,
+        connection_, scoped_ptr<DatagramClientSocket>(socket),
+        /*stream_factory=*/nullptr, &crypto_client_stream_factory_,
         &transport_security_state_, make_scoped_ptr((QuicServerInfo*)nullptr),
-        DefaultQuicConfig(), "CONNECTION_UNKNOWN", base::TimeTicks::Now(),
-        base::MessageLoop::current()->message_loop_proxy().get(), nullptr));
-    session_->InitializeSession(
         QuicServerId(kDefaultServerHostName, kDefaultServerPort,
                      /*is_secure=*/false, PRIVACY_MODE_DISABLED),
-        &crypto_config_, &crypto_client_stream_factory_);
+        DefaultQuicConfig(), &crypto_config_, "CONNECTION_UNKNOWN",
+        base::TimeTicks::Now(), base::ThreadTaskRunnerHandle::Get().get(),
+        nullptr));
+    session_->Initialize();
     session_->GetCryptoStream()->CryptoConnect();
     EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
     stream_.reset(use_closing_stream_ ?
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 631d4d1c..0720f8b 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -477,6 +477,48 @@
   SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
 }
 
+// Regression test for https://crbug.com/492458.  Test that for an HTTP
+// connection through a QUIC proxy, the certificate exhibited by the proxy is
+// checked against the proxy hostname, not the origin hostname.
+TEST_P(QuicNetworkTransactionTest, QuicProxyWithCert) {
+  const std::string origin_host = "news.example.com";
+  const std::string proxy_host = "www.example.org";
+
+  params_.enable_quic_for_proxies = true;
+  proxy_service_.reset(
+      ProxyService::CreateFixedFromPacResult("QUIC " + proxy_host + ":70"));
+
+  maker_.set_hostname(origin_host);
+  MockQuicData mock_quic_data;
+  mock_quic_data.AddWrite(
+      ConstructRequestHeadersPacket(1, kClientDataStreamId1, true, true,
+                                    GetRequestHeaders("GET", "http", "/")));
+  mock_quic_data.AddRead(ConstructResponseHeadersPacket(
+      1, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK")));
+  mock_quic_data.AddRead(
+      ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
+  mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
+  mock_quic_data.AddRead(SYNCHRONOUS, 0);
+  mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+  scoped_refptr<X509Certificate> cert(
+      ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem"));
+  ASSERT_TRUE(cert.get());
+  // This certificate is valid for the proxy, but not for the origin.
+  bool common_name_fallback_used;
+  EXPECT_TRUE(cert->VerifyNameMatch(proxy_host, &common_name_fallback_used));
+  EXPECT_FALSE(cert->VerifyNameMatch(origin_host, &common_name_fallback_used));
+  ProofVerifyDetailsChromium verify_details;
+  verify_details.cert_verify_result.verified_cert = cert;
+  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
+
+  request_.url = GURL("http://" + origin_host);
+  AddHangingNonAlternateProtocolSocketData();
+  CreateSessionWithNextProtos();
+  AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
+  SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
+}
+
 TEST_P(QuicNetworkTransactionTest, ForceQuicWithErrorConnecting) {
   params_.origin_to_force_quic_on =
       HostPortPair::FromString("www.google.com:80");
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 6e82b9b..0238a4c 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -375,6 +375,29 @@
   CheckPacketContains(contents, 0);
 }
 
+// Test the behavior of ConsumeData when the data consumed is for the crypto
+// handshake stream.  Ensure that the packet is always sent and padded even if
+// the generator operates in batch mode.
+TEST_P(QuicPacketGeneratorTest, ConsumeData_Handshake) {
+  delegate_.SetCanWriteAnything();
+  generator_.StartBatchOperations();
+
+  EXPECT_CALL(delegate_, OnSerializedPacket(_))
+      .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
+  QuicConsumedData consumed = generator_.ConsumeData(
+      kCryptoStreamId, MakeIOVector("foo"), 0, false, MAY_FEC_PROTECT, nullptr);
+  EXPECT_EQ(3u, consumed.bytes_consumed);
+  EXPECT_FALSE(generator_.HasQueuedFrames());
+
+  PacketContents contents;
+  contents.num_stream_frames = 1;
+  CheckPacketContains(contents, 0);
+
+  ASSERT_EQ(1u, packets_.size());
+  ASSERT_EQ(kDefaultMaxPacketSize, generator_.max_packet_length());
+  EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].packet->length());
+}
+
 TEST_P(QuicPacketGeneratorTest, ConsumeData_EmptyData) {
   EXPECT_DFATAL(generator_.ConsumeData(kHeadersStreamId, MakeIOVector(""), 0,
                                        false, MAY_FEC_PROTECT, nullptr),
@@ -431,13 +454,13 @@
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
     if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-        FEC_ANY_TRIGGER) {
-      EXPECT_CALL(delegate_, OnSerializedPacket(_))
-          .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-    } else {
+        FEC_ALARM_TRIGGER) {
       // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER, but FEC
       // group is closed.
       EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+    } else {
+      EXPECT_CALL(delegate_, OnSerializedPacket(_))
+          .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
     }
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
@@ -455,12 +478,12 @@
   CheckPacketHasSingleStreamFrame(0);
   CheckPacketHasSingleStreamFrame(1);
   if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-      FEC_ANY_TRIGGER) {
-    // FEC packet is sent when send policy is FEC_ANY_TRIGGER.
+      FEC_ALARM_TRIGGER) {
+    // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER.
+    CheckPacketHasSingleStreamFrame(2);
+  } else {
     CheckPacketIsFec(2, 1);
     CheckPacketHasSingleStreamFrame(3);
-  } else {
-    CheckPacketHasSingleStreamFrame(2);
   }
   EXPECT_TRUE(creator_->IsFecProtected());
 
@@ -477,22 +500,22 @@
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
     if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-        FEC_ANY_TRIGGER) {
+        FEC_ALARM_TRIGGER) {
+      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+    } else {
       EXPECT_CALL(delegate_, OnSerializedPacket(_))
           .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-    } else {
-      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
     }
   }
   consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, MAY_FEC_PROTECT,
                                     nullptr);
   EXPECT_EQ(1u, consumed.bytes_consumed);
   if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-      FEC_ANY_TRIGGER) {
+      FEC_ALARM_TRIGGER) {
+    CheckPacketHasSingleStreamFrame(3);
+  } else {
     CheckPacketHasSingleStreamFrame(4);
     CheckPacketIsFec(5, 4);
-  } else {
-    CheckPacketHasSingleStreamFrame(3);
   }
   EXPECT_FALSE(creator_->IsFecProtected());
 }
@@ -792,11 +815,11 @@
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
     if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-        FEC_ANY_TRIGGER) {
+        FEC_ALARM_TRIGGER) {
+      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+    } else {
       EXPECT_CALL(delegate_, OnSerializedPacket(_))
           .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-    } else {
-      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
     }
   }
   consumed = generator_.ConsumeData(7, CreateData(kDefaultMaxPacketSize), 0,
@@ -836,11 +859,12 @@
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
     if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-        FEC_ANY_TRIGGER) {
+        FEC_ALARM_TRIGGER) {
+      // If FEC send policy is FEC_ALARM_TRIGGER, FEC group is closed.
+      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+    } else {
       EXPECT_CALL(delegate_, OnSerializedPacket(_))
           .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-    } else {
-      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
     }
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
@@ -860,11 +884,11 @@
   CheckPacketHasSingleStreamFrame(1);
   CheckPacketHasSingleStreamFrame(2);
   if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-      FEC_ANY_TRIGGER) {
+      FEC_ALARM_TRIGGER) {
+    CheckPacketHasSingleStreamFrame(3);
+  } else {
     CheckPacketIsFec(3, /*fec_group=*/2u);
     CheckPacketHasSingleStreamFrame(4);
-  } else {
-    CheckPacketHasSingleStreamFrame(3);
   }
 
   // Calling OnFecTimeout should emit the pending FEC packet.
@@ -872,10 +896,10 @@
       .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
   generator_.OnFecTimeout();
   if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-      FEC_ANY_TRIGGER) {
-    CheckPacketIsFec(5, /*fec_group=*/5u);
-  } else {
+      FEC_ALARM_TRIGGER) {
     CheckPacketIsFec(4, /*fec_group=*/4u);
+  } else {
+    CheckPacketIsFec(5, /*fec_group=*/5u);
   }
 
   // Send one unprotected data packet.
@@ -888,10 +912,10 @@
   EXPECT_FALSE(creator_->IsFecProtected());
   // Verify that one unprotected data packet was sent.
   if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-      FEC_ANY_TRIGGER) {
-    CheckPacketContains(contents, 6);
-  } else {
+      FEC_ALARM_TRIGGER) {
     CheckPacketContains(contents, 5);
+  } else {
+    CheckPacketContains(contents, 6);
   }
 }
 
@@ -1018,11 +1042,11 @@
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
     if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-        FEC_ANY_TRIGGER) {
+        FEC_ALARM_TRIGGER) {
+      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+    } else {
       EXPECT_CALL(delegate_, OnSerializedPacket(_))
           .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-    } else {
-      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
     }
   }
   consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, MAY_FEC_PROTECT,
@@ -1075,11 +1099,11 @@
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
     if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-        FEC_ANY_TRIGGER) {
+        FEC_ALARM_TRIGGER) {
+      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+    } else {
       EXPECT_CALL(delegate_, OnSerializedPacket(_))
           .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-    } else {
-      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
     }
   }
   consumed = generator_.ConsumeData(5, CreateData(data_len), 0, true,
@@ -1113,13 +1137,13 @@
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
     if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-        FEC_ANY_TRIGGER) {
-      EXPECT_CALL(delegate_, OnSerializedPacket(_))
-          .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-    } else {
+        FEC_ALARM_TRIGGER) {
       // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER, but FEC
       // group is closed.
       EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+    } else {
+      EXPECT_CALL(delegate_, OnSerializedPacket(_))
+          .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
     }
     // Fin Packet.
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
@@ -1134,13 +1158,14 @@
   CheckPacketHasSingleStreamFrame(0);
   CheckPacketHasSingleStreamFrame(1);
   if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-      FEC_ANY_TRIGGER) {
+      FEC_ALARM_TRIGGER) {
+    // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER.
+    CheckPacketHasSingleStreamFrame(2);
+  } else {
     // FEC packet is sent after 2 packets and when send policy is
     // FEC_ANY_TRIGGER.
     CheckPacketIsFec(2, 1);
     CheckPacketHasSingleStreamFrame(3);
-  } else {
-    CheckPacketHasSingleStreamFrame(2);
   }
   EXPECT_TRUE(creator_->IsFecProtected());
 
@@ -1153,11 +1178,11 @@
     // FEC_ANY_TRIGGER. When policy is FEC_ALARM_TRIGGER, FEC group is closed
     // and FEC packet is not sent.
     if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-        FEC_ANY_TRIGGER) {
+        FEC_ALARM_TRIGGER) {
+      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+    } else {
       EXPECT_CALL(delegate_, OnSerializedPacket(_))
           .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-    } else {
-      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
     }
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
@@ -1167,11 +1192,11 @@
     // FEC_ANY_TRIGGER. When policy is FEC_ALARM_TRIGGER, FEC group is closed
     // and FEC packet is not sent.
     if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-        FEC_ANY_TRIGGER) {
+        FEC_ALARM_TRIGGER) {
+      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
+    } else {
       EXPECT_CALL(delegate_, OnSerializedPacket(_))
           .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket));
-    } else {
-      EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1);
     }
   }
   consumed = generator_.ConsumeData(7, CreateData(data_len), 0, true,
@@ -1180,7 +1205,11 @@
   EXPECT_TRUE(consumed.fin_consumed);
   EXPECT_FALSE(generator_.HasQueuedFrames());
   if (QuicPacketGeneratorPeer::GetFecSendPolicy(&generator_) ==
-      FEC_ANY_TRIGGER) {
+      FEC_ALARM_TRIGGER) {
+    CheckPacketHasSingleStreamFrame(3);
+    CheckPacketHasSingleStreamFrame(4);
+    CheckPacketHasSingleStreamFrame(5);
+  } else {
     CheckPacketHasSingleStreamFrame(4);
     // FEC packet is sent after 2 packets and when send policy is
     // FEC_ANY_TRIGGER.
@@ -1190,10 +1219,6 @@
     // FEC packet is sent after 2 packets and when send policy is
     // FEC_ANY_TRIGGER.
     CheckPacketIsFec(8, 7);
-  } else {
-    CheckPacketHasSingleStreamFrame(3);
-    CheckPacketHasSingleStreamFrame(4);
-    CheckPacketHasSingleStreamFrame(5);
   }
   EXPECT_TRUE(creator_->IsFecProtected());
 }
diff --git a/net/quic/quic_packet_reader.cc b/net/quic/quic_packet_reader.cc
index dd67539d..88b584d 100644
--- a/net/quic/quic_packet_reader.cc
+++ b/net/quic/quic_packet_reader.cc
@@ -4,8 +4,10 @@
 
 #include "net/quic/quic_packet_reader.h"
 
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/net_errors.h"
 
 namespace net {
@@ -45,7 +47,7 @@
     // Data was read, process it.
     // Schedule the work through the message loop to 1) prevent infinite
     // recursion and 2) avoid blocking the thread for too long.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&QuicPacketReader::OnReadComplete,
                               weak_factory_.GetWeakPtr(), rv));
   } else {
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 0c325e0..df482a8f 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -73,20 +73,20 @@
 QuicPacketPublicHeader::~QuicPacketPublicHeader() {}
 
 QuicPacketHeader::QuicPacketHeader()
-    : fec_flag(false),
+    : packet_sequence_number(0),
+      fec_flag(false),
       entropy_flag(false),
       entropy_hash(0),
-      packet_sequence_number(0),
       is_in_fec_group(NOT_IN_FEC_GROUP),
       fec_group(0) {
 }
 
 QuicPacketHeader::QuicPacketHeader(const QuicPacketPublicHeader& header)
     : public_header(header),
+      packet_sequence_number(0),
       fec_flag(false),
       entropy_flag(false),
       entropy_hash(0),
-      packet_sequence_number(0),
       is_in_fec_group(NOT_IN_FEC_GROUP),
       fec_group(0) {
 }
@@ -627,11 +627,11 @@
     QuicEncryptedPacket* packet,
     QuicPacketEntropyHash entropy_hash,
     RetransmittableFrames* retransmittable_frames)
-    : sequence_number(sequence_number),
-      sequence_number_length(sequence_number_length),
-      packet(packet),
-      entropy_hash(entropy_hash),
+    : packet(packet),
       retransmittable_frames(retransmittable_frames),
+      sequence_number(sequence_number),
+      sequence_number_length(sequence_number_length),
+      entropy_hash(entropy_hash),
       is_fec_packet(false) {
 }
 
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 3f69ce3..3be0b14 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -625,10 +625,10 @@
       std::ostream& os, const QuicPacketHeader& s);
 
   QuicPacketPublicHeader public_header;
+  QuicPacketSequenceNumber packet_sequence_number;
   bool fec_flag;
   bool entropy_flag;
   QuicPacketEntropyHash entropy_hash;
-  QuicPacketSequenceNumber packet_sequence_number;
   InFecGroup is_in_fec_group;
   QuicFecGroupNumber fec_group;
 };
@@ -1023,11 +1023,11 @@
                    RetransmittableFrames* retransmittable_frames);
   ~SerializedPacket();
 
+  QuicEncryptedPacket* packet;
+  RetransmittableFrames* retransmittable_frames;
   QuicPacketSequenceNumber sequence_number;
   QuicSequenceNumberLength sequence_number_length;
-  QuicEncryptedPacket* packet;
   QuicPacketEntropyHash entropy_hash;
-  RetransmittableFrames* retransmittable_frames;
   bool is_fec_packet;
 
   // Optional notifiers which will be informed when this packet has been ACKed.
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 1f78b32..fc0365b 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -110,13 +110,16 @@
                        perspective(),
                        kMinimumFlowControlSendWindow,
                        config_.GetInitialSessionFlowControlWindowToSend(),
-                       config_.GetInitialSessionFlowControlWindowToSend()),
+                       false),
       goaway_received_(false),
       goaway_sent_(false),
       has_pending_handshake_(false) {
 }
 
-void QuicSession::InitializeSession() {
+void QuicSession::Initialize() {
+  // Crypto stream must exist when Initialize is called.
+  DCHECK(GetCryptoStream());
+
   connection_->set_visitor(visitor_shim_.get());
   connection_->SetFromConfig(config_);
   headers_stream_.reset(new QuicHeadersStream(this));
@@ -467,6 +470,11 @@
     max_streams =
         max(max_streams + kMaxStreamsMinimumIncrement,
             static_cast<uint32>(max_streams * kMaxStreamsMultiplier));
+
+    if (config_.HasReceivedConnectionOptions() &&
+        ContainsQuicTag(config_.ReceivedConnectionOptions(), kAFCW)) {
+      EnableAutoTuneReceiveWindow();
+    }
   }
   set_max_open_streams(max_streams);
 
@@ -482,6 +490,16 @@
   }
 }
 
+void QuicSession::EnableAutoTuneReceiveWindow() {
+  flow_controller_.set_auto_tune_receive_window(true);
+  // Inform all existing streams about the new window.
+  GetCryptoStream()->flow_controller()->set_auto_tune_receive_window(true);
+  headers_stream_->flow_controller()->set_auto_tune_receive_window(true);
+  for (auto const& kv : stream_map_) {
+    kv.second->flow_controller()->set_auto_tune_receive_window(true);
+  }
+}
+
 void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) {
   if (new_window < kMinimumFlowControlSendWindow) {
     LOG(ERROR) << "Peer sent us an invalid stream flow control send window: "
@@ -496,9 +514,8 @@
   // Inform all existing streams about the new window.
   GetCryptoStream()->UpdateSendWindowOffset(new_window);
   headers_stream_->UpdateSendWindowOffset(new_window);
-  for (DataStreamMap::iterator it = stream_map_.begin();
-       it != stream_map_.end(); ++it) {
-    it->second->UpdateSendWindowOffset(new_window);
+  for (auto const& kv : stream_map_) {
+    kv.second->UpdateSendWindowOffset(new_window);
   }
 }
 
@@ -729,9 +746,8 @@
       GetCryptoStream()->flow_controller()->IsBlocked()) {
     return true;
   }
-  for (DataStreamMap::iterator it = stream_map_.begin();
-       it != stream_map_.end(); ++it) {
-    if (it->second->flow_controller()->IsBlocked()) {
+  for (auto const& kv : stream_map_) {
+    if (kv.second->flow_controller()->IsBlocked()) {
       return true;
     }
   }
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 4a401bf2..9a8bee3 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -56,7 +56,7 @@
   };
 
   QuicSession(QuicConnection* connection, const QuicConfig& config);
-  void InitializeSession();
+  virtual void Initialize();
 
   ~QuicSession() override;
 
@@ -284,6 +284,10 @@
   // control window in a negotiated config. Closes the connection if invalid.
   void OnNewSessionFlowControlWindow(QuicStreamOffset new_window);
 
+  // Called in OnConfigNegotiated when auto-tuning is enabled for flow
+  // control receive windows.
+  void EnableAutoTuneReceiveWindow();
+
   // Keep track of highest received byte offset of locally closed streams, while
   // waiting for a definitive final highest offset from the peer.
   std::map<QuicStreamId, QuicStreamOffset>
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index b4df636..a9a1c91 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -125,7 +125,7 @@
       : QuicSession(connection, DefaultQuicConfig()),
         crypto_stream_(this),
         writev_consumes_all_data_(false) {
-    InitializeSession();
+    Initialize();
   }
 
   TestCryptoStream* GetCryptoStream() override { return &crypto_stream_; }
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 23d02cd..dde1639e 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -8,15 +8,16 @@
 #include <set>
 
 #include "base/cpu.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_verifier.h"
@@ -553,6 +554,7 @@
     bool enable_connection_racing,
     bool enable_non_blocking_io,
     bool disable_disk_cache,
+    bool prefer_aes,
     int max_number_of_lossy_connections,
     float packet_loss_threshold,
     int socket_receive_buffer_size,
@@ -578,6 +580,7 @@
       enable_connection_racing_(enable_connection_racing),
       enable_non_blocking_io_(enable_non_blocking_io),
       disable_disk_cache_(disable_disk_cache),
+      prefer_aes_(prefer_aes),
       max_number_of_lossy_connections_(max_number_of_lossy_connections),
       packet_loss_threshold_(packet_loss_threshold),
       socket_receive_buffer_size_(socket_receive_buffer_size),
@@ -602,7 +605,7 @@
   bool has_aes_hardware_support = cpu.has_aesni() && cpu.has_avx();
   UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.PreferAesGcm",
                         has_aes_hardware_support);
-  if (has_aes_hardware_support)
+  if (has_aes_hardware_support || prefer_aes_)
     crypto_config_.PreferAesGcm();
   if (!IsEcdsaSupported())
     crypto_config_.DisableEcdsa();
@@ -655,7 +658,7 @@
   // TODO(rtenneti): |task_runner_| is used by the Job. Initialize task_runner_
   // in the constructor after WebRequestActionWithThreadsTest.* tests are fixed.
   if (!task_runner_)
-    task_runner_ = base::MessageLoop::current()->message_loop_proxy().get();
+    task_runner_ = base::ThreadTaskRunnerHandle::Get().get();
 
   QuicServerInfo* quic_server_info = nullptr;
   if (quic_server_info_factory_) {
@@ -1073,9 +1076,9 @@
   DefaultPacketWriterFactory packet_writer_factory(socket.get());
 
   if (!helper_.get()) {
-    helper_.reset(new QuicConnectionHelper(
-        base::MessageLoop::current()->message_loop_proxy().get(),
-        clock_.get(), random_generator_));
+    helper_.reset(
+        new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
+                                 clock_.get(), random_generator_));
   }
 
   QuicConnection* connection = new QuicConnection(
@@ -1106,16 +1109,15 @@
   }
 
   *session = new QuicClientSession(
-      connection, socket.Pass(), this, transport_security_state_,
-      server_info.Pass(), config, network_connection_.GetDescription(),
-      dns_resolution_end_time,
-      base::MessageLoop::current()->message_loop_proxy().get(),
+      connection, socket.Pass(), this, quic_crypto_client_stream_factory_,
+      transport_security_state_, server_info.Pass(), server_id, config,
+      &crypto_config_, network_connection_.GetDescription(),
+      dns_resolution_end_time, base::ThreadTaskRunnerHandle::Get().get(),
       net_log.net_log());
 
   all_sessions_[*session] = server_id;  // owning pointer
 
-  (*session)->InitializeSession(server_id,  &crypto_config_,
-                                quic_crypto_client_stream_factory_);
+  (*session)->Initialize();
   bool closed_during_initialize =
       !ContainsKey(all_sessions_, *session) ||
       !(*session)->connection()->connected();
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 185da1f..25e03ea 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -115,6 +115,7 @@
       bool enable_connection_racing,
       bool enable_non_blocking_io,
       bool disable_disk_cache,
+      bool prefer_aes,
       int max_number_of_lossy_connections,
       float packet_loss_threshold,
       int socket_receive_buffer_size,
@@ -345,6 +346,9 @@
   // Set if we do not want to load server config from the disk cache.
   bool disable_disk_cache_;
 
+  // Set if AES-GCM should be preferred, even if there is no hardware support.
+  bool prefer_aes_;
+
   // Set if we want to disable QUIC when there is high packet loss rate.
   // Specifies the maximum number of connections with high packet loss in a row
   // after which QUIC will be disabled.
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index bc85df2..d5bdfee 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -6,6 +6,7 @@
 
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/test_data_directory.h"
 #include "net/cert/cert_verifier.h"
 #include "net/dns/mock_host_resolver.h"
@@ -198,7 +199,7 @@
         cert_verifier_(CertVerifier::CreateDefault()),
         channel_id_service_(
             new ChannelIDService(new DefaultChannelIDStore(nullptr),
-                                 base::MessageLoopProxy::current())),
+                                 base::ThreadTaskRunnerHandle::Get())),
         factory_(&host_resolver_,
                  &socket_factory_,
                  base::WeakPtr<HttpServerProperties>(),
@@ -218,6 +219,7 @@
                  /*enable_connection_racing=*/false,
                  /*enable_non_blocking_io=*/true,
                  /*disable_disk_cache=*/false,
+                 /*prefer_aes=*/false,
                  /*max_number_of_lossy_connections=*/0,
                  /*packet_loss_threshold=*/1.0f,
                  /*receive_buffer_size=*/0,
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index d64f01091..0d190908 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -133,7 +133,7 @@
                        perspective_,
                        GetReceivedFlowControlWindow(session),
                        GetInitialStreamFlowControlWindowToSend(session),
-                       GetInitialStreamFlowControlWindowToSend(session)),
+                       session_->flow_controller()->auto_tune_receive_window()),
       connection_flow_controller_(session_->flow_controller()),
       stream_contributes_to_connection_flow_control_(true) {
 }
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 45d94d5..ba3bce7 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -181,25 +181,23 @@
     QuicCryptoClientStream* client) {
   PacketSavingConnection* server_conn = new PacketSavingConnection(
       Perspective::IS_SERVER, client_conn->supported_versions());
-  TestSession server_session(server_conn, DefaultQuicConfig());
-  server_session.InitializeSession();
+
+  QuicConfig config = DefaultQuicConfig();
   QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING,
                                        QuicRandom::GetInstance());
+  SetupCryptoServerConfigForTest(server_conn->clock(),
+                                 server_conn->random_generator(), &config,
+                                 &crypto_config);
 
-  SetupCryptoServerConfigForTest(
-      server_session.connection()->clock(),
-      server_session.connection()->random_generator(),
-      server_session.config(), &crypto_config);
-
-  QuicCryptoServerStream server(&crypto_config, &server_session);
-  server_session.SetCryptoStream(&server);
+  TestServerSession server_session(server_conn, config, &crypto_config);
 
   // The client's handshake must have been started already.
   CHECK_NE(0u, client_conn->encrypted_packets_.size());
 
-  CommunicateHandshakeMessages(client_conn, client, server_conn, &server);
+  CommunicateHandshakeMessages(client_conn, client, server_conn,
+                               server_session.GetCryptoStream());
 
-  CompareClientAndServerKeys(client, &server);
+  CompareClientAndServerKeys(client, server_session.GetCryptoStream());
 
   return client->num_sent_client_hellos();
 }
@@ -213,14 +211,8 @@
       new PacketSavingConnection(Perspective::IS_CLIENT);
   // Advance the time, because timers do not like uninitialized times.
   client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1));
-  TestClientSession client_session(client_conn, DefaultQuicConfig());
-  QuicCryptoClientConfig crypto_config;
 
-  if (!options.dont_verify_certs) {
-    // TODO(wtc): replace this with ProofVerifierForTesting() when we have
-    // a working ProofSourceForTesting().
-    crypto_config.SetProofVerifier(FakeProofVerifierForTesting());
-  }
+  QuicCryptoClientConfig crypto_config;
   bool is_https = false;
   AsyncTestChannelIDSource* async_channel_id_source = nullptr;
   if (options.channel_id_enabled) {
@@ -235,18 +227,22 @@
   }
   QuicServerId server_id(kServerHostname, kServerPort, is_https,
                          PRIVACY_MODE_DISABLED);
-  QuicCryptoClientStream client(server_id, &client_session,
-                                ProofVerifyContextForTesting(),
-                                &crypto_config);
-  client_session.SetCryptoStream(&client);
+  if (!options.dont_verify_certs) {
+    // TODO(wtc): replace this with ProofVerifierForTesting() when we have
+    // a working ProofSourceForTesting().
+    crypto_config.SetProofVerifier(FakeProofVerifierForTesting());
+  }
+  TestClientSession client_session(client_conn, DefaultQuicConfig(), server_id,
+                                   &crypto_config);
 
-  client.CryptoConnect();
+  client_session.GetCryptoStream()->CryptoConnect();
   CHECK_EQ(1u, client_conn->encrypted_packets_.size());
 
   CommunicateHandshakeMessagesAndRunCallbacks(
-      client_conn, &client, server_conn, server, async_channel_id_source);
+      client_conn, client_session.GetCryptoStream(), server_conn, server,
+      async_channel_id_source);
 
-  CompareClientAndServerKeys(&client, server);
+  CompareClientAndServerKeys(client_session.GetCryptoStream(), server);
 
   if (options.channel_id_enabled) {
     scoped_ptr<ChannelIDKey> channel_id_key;
@@ -255,11 +251,12 @@
     EXPECT_EQ(QUIC_SUCCESS, status);
     EXPECT_EQ(channel_id_key->SerializeKey(),
               server->crypto_negotiated_params().channel_id);
-    EXPECT_EQ(options.channel_id_source_async,
-              client.WasChannelIDSourceCallbackRun());
+    EXPECT_EQ(
+        options.channel_id_source_async,
+        client_session.GetCryptoStream()->WasChannelIDSourceCallbackRun());
   }
 
-  return client.num_sent_client_hellos();
+  return client_session.GetCryptoStream()->num_sent_client_hellos();
 }
 
 // static
diff --git a/net/quic/test_tools/quic_flow_controller_peer.cc b/net/quic/test_tools/quic_flow_controller_peer.cc
index d6a10987..602aaf8 100644
--- a/net/quic/test_tools/quic_flow_controller_peer.cc
+++ b/net/quic/test_tools/quic_flow_controller_peer.cc
@@ -30,7 +30,7 @@
 void QuicFlowControllerPeer::SetMaxReceiveWindow(
   QuicFlowController* flow_controller,
   QuicByteCount window_size) {
-  flow_controller->max_receive_window_ = window_size;
+  flow_controller->receive_window_size_ = window_size;
 }
 
 // static
@@ -58,5 +58,11 @@
          flow_controller->highest_received_byte_offset_;
 }
 
+// static
+QuicByteCount QuicFlowControllerPeer::WindowUpdateThreshold(
+    QuicFlowController* flow_controller) {
+  return flow_controller->WindowUpdateThreshold();
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/test_tools/quic_flow_controller_peer.h b/net/quic/test_tools/quic_flow_controller_peer.h
index 4270d96..3d7c9d0 100644
--- a/net/quic/test_tools/quic_flow_controller_peer.h
+++ b/net/quic/test_tools/quic_flow_controller_peer.h
@@ -33,6 +33,9 @@
 
   static QuicByteCount ReceiveWindowSize(QuicFlowController* flow_controller);
 
+  static QuicByteCount WindowUpdateThreshold(
+      QuicFlowController* flow_controller);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicFlowControllerPeer);
 };
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 549dae5..7036d57 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -17,6 +17,7 @@
 #include "net/quic/quic_framer.h"
 #include "net/quic/quic_packet_creator.h"
 #include "net/quic/quic_utils.h"
+#include "net/quic/test_tools/crypto_test_utils.h"
 #include "net/quic/test_tools/quic_connection_peer.h"
 #include "net/spdy/spdy_frame_builder.h"
 #include "net/tools/quic/quic_per_connection_packet_writer.h"
@@ -339,7 +340,8 @@
 
 MockSession::MockSession(QuicConnection* connection)
     : QuicSession(connection, DefaultQuicConfig()) {
-  InitializeSession();
+  crypto_stream_.reset(new QuicCryptoStream(this));
+  Initialize();
   ON_CALL(*this, WritevData(_, _, _, _, _, _))
       .WillByDefault(testing::Return(QuicConsumedData(0, false)));
 }
@@ -347,46 +349,37 @@
 MockSession::~MockSession() {
 }
 
-TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
-    : QuicSession(connection, config),
-      crypto_stream_(nullptr) {
-  InitializeSession();
+TestServerSession::TestServerSession(
+    QuicConnection* connection,
+    const QuicConfig& config,
+    const QuicCryptoServerConfig* crypto_config)
+    : QuicSession(connection, config) {
+  crypto_stream_.reset(new QuicCryptoServerStream(crypto_config, this));
+  Initialize();
 }
 
-TestSession::~TestSession() {}
-
-void TestSession::SetCryptoStream(QuicCryptoStream* stream) {
-  crypto_stream_ = stream;
+TestServerSession::~TestServerSession() {
 }
 
-QuicCryptoStream* TestSession::GetCryptoStream() {
-  return crypto_stream_;
+QuicCryptoServerStream* TestServerSession::GetCryptoStream() {
+  return crypto_stream_.get();
 }
 
 TestClientSession::TestClientSession(QuicConnection* connection,
-                                     const QuicConfig& config)
-    : QuicClientSessionBase(connection, config),
-      crypto_stream_(nullptr) {
-  EXPECT_CALL(*this, OnProofValid(_)).Times(AnyNumber());
-  InitializeSession();
+                                     const QuicConfig& config,
+                                     const QuicServerId& server_id,
+                                     QuicCryptoClientConfig* crypto_config)
+    : QuicClientSessionBase(connection, config) {
+  crypto_stream_.reset(new QuicCryptoClientStream(
+      server_id, this, CryptoTestUtils::ProofVerifyContextForTesting(),
+      crypto_config));
+  Initialize();
 }
 
 TestClientSession::~TestClientSession() {}
 
-void TestClientSession::SetCryptoStream(QuicCryptoStream* stream) {
-  crypto_stream_ = stream;
-}
-
-QuicCryptoStream* TestClientSession::GetCryptoStream() {
-  return crypto_stream_;
-}
-
-TestServerSession::TestServerSession(const QuicConfig& config,
-                                     QuicConnection* connection)
-    : QuicServerSession(config, connection, nullptr) {
-}
-
-TestServerSession::~TestServerSession() {
+QuicCryptoClientStream* TestClientSession::GetCryptoStream() {
+  return crypto_stream_.get();
 }
 
 MockPacketWriter::MockPacketWriter() {
@@ -795,18 +788,15 @@
 MockQuicConnectionDebugVisitor::~MockQuicConnectionDebugVisitor() {
 }
 
-void SetupCryptoClientStreamForTest(
-    QuicServerId server_id,
-    bool supports_stateless_rejects,
-    QuicTime::Delta connection_start_time,
-    QuicCryptoClientConfig* crypto_client_config,
-    PacketSavingConnection** client_connection,
-    TestClientSession** client_session,
-    QuicCryptoClientStream** client_stream) {
+void CreateClientSessionForTest(QuicServerId server_id,
+                                bool supports_stateless_rejects,
+                                QuicTime::Delta connection_start_time,
+                                QuicCryptoClientConfig* crypto_client_config,
+                                PacketSavingConnection** client_connection,
+                                TestClientSession** client_session) {
   CHECK(crypto_client_config);
   CHECK(client_connection);
   CHECK(client_session);
-  CHECK(client_stream);
   CHECK(!connection_start_time.IsZero())
       << "Connections must start at non-zero times, otherwise the "
       << "strike-register will be unhappy.";
@@ -815,35 +805,26 @@
                           ? DefaultQuicConfigStatelessRejects()
                           : DefaultQuicConfig();
   *client_connection = new PacketSavingConnection(Perspective::IS_CLIENT);
-  *client_session = new TestClientSession(*client_connection, config);
-  *client_stream = new QuicCryptoClientStream(server_id, *client_session,
-                                              nullptr, crypto_client_config);
-  (*client_session)->SetCryptoStream(*client_stream);
+  *client_session = new TestClientSession(*client_connection, config, server_id,
+                                          crypto_client_config);
   (*client_connection)->AdvanceTime(connection_start_time);
 }
 
-// Setup or create?
-void SetupCryptoServerStreamForTest(
-    QuicServerId server_id,
-    QuicTime::Delta connection_start_time,
-    QuicCryptoServerConfig* server_crypto_config,
-    PacketSavingConnection** server_connection,
-    TestServerSession** server_session,
-    QuicCryptoServerStream** server_stream) {
+void CreateServerSessionForTest(QuicServerId server_id,
+                                QuicTime::Delta connection_start_time,
+                                QuicCryptoServerConfig* server_crypto_config,
+                                PacketSavingConnection** server_connection,
+                                TestServerSession** server_session) {
   CHECK(server_crypto_config);
   CHECK(server_connection);
   CHECK(server_session);
-  CHECK(server_stream);
   CHECK(!connection_start_time.IsZero())
       << "Connections must start at non-zero times, otherwise the "
       << "strike-register will be unhappy.";
 
   *server_connection = new PacketSavingConnection(Perspective::IS_SERVER);
-  *server_session =
-      new TestServerSession(DefaultQuicConfig(), *server_connection);
-  *server_stream =
-      new QuicCryptoServerStream(server_crypto_config, *server_session);
-  (*server_session)->InitializeSession(server_crypto_config);
+  *server_session = new TestServerSession(
+      *server_connection, DefaultQuicConfig(), server_crypto_config);
 
   // We advance the clock initially because the default time is zero and the
   // strike register worries that we've just overflowed a uint32 time.
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 55570748..fa97422 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -426,9 +426,11 @@
  public:
   explicit MockSession(QuicConnection* connection);
   ~MockSession() override;
+
+  QuicCryptoStream* GetCryptoStream() { return crypto_stream_.get(); }
+
   MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer));
   MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
-  MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*());
   MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
   MOCK_METHOD6(WritevData,
                QuicConsumedData(QuicStreamId id,
@@ -452,30 +454,35 @@
   using QuicSession::ActivateStream;
 
  private:
+  scoped_ptr<QuicCryptoStream> crypto_stream_;
+
   DISALLOW_COPY_AND_ASSIGN(MockSession);
 };
 
-class TestSession : public QuicSession {
+class TestServerSession : public QuicSession {
  public:
-  TestSession(QuicConnection* connection, const QuicConfig& config);
-  ~TestSession() override;
+  TestServerSession(QuicConnection* connection,
+                    const QuicConfig& config,
+                    const QuicCryptoServerConfig* crypto_config);
+  ~TestServerSession() override;
 
   MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
   MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
 
-  void SetCryptoStream(QuicCryptoStream* stream);
-
-  QuicCryptoStream* GetCryptoStream() override;
+  QuicCryptoServerStream* GetCryptoStream() override;
 
  private:
-  QuicCryptoStream* crypto_stream_;
+  scoped_ptr<QuicCryptoServerStream> crypto_stream_;
 
-  DISALLOW_COPY_AND_ASSIGN(TestSession);
+  DISALLOW_COPY_AND_ASSIGN(TestServerSession);
 };
 
 class TestClientSession : public QuicClientSessionBase {
  public:
-  TestClientSession(QuicConnection* connection, const QuicConfig& config);
+  TestClientSession(QuicConnection* connection,
+                    const QuicConfig& config,
+                    const QuicServerId& server_id,
+                    QuicCryptoClientConfig* crypto_config);
   ~TestClientSession() override;
 
   // QuicClientSessionBase
@@ -488,12 +495,10 @@
   MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
   MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
 
-  void SetCryptoStream(QuicCryptoStream* stream);
-
-  QuicCryptoStream* GetCryptoStream() override;
+  QuicCryptoClientStream* GetCryptoStream() override;
 
  private:
-  QuicCryptoStream* crypto_stream_;
+  scoped_ptr<QuicCryptoClientStream> crypto_stream_;
 
   DISALLOW_COPY_AND_ASSIGN(TestClientSession);
 };
@@ -715,17 +720,7 @@
                void(const QuicPacketHeader&, StringPiece payload));
 };
 
-class TestServerSession : public tools::QuicServerSession {
- public:
-  TestServerSession(const QuicConfig& config, QuicConnection* connection);
-  ~TestServerSession() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestServerSession);
-};
-
-// Creates and sets up a QuicCryptoClientStream for testing, and all
-// its associated state.
+// Creates a client session for testing.
 //
 // server_id: The server id associated with this stream.
 // supports_stateless_rejects:  Does this client support stateless rejects.
@@ -739,19 +734,14 @@
 //   client_session.
 // client_session: Pointer reference for the newly created client
 //   session.  The new object will be owned by the caller.
-// client_stream: Pointer reference for the newly created crypto
-//   client stream.  The new object will be owned by the caller.
-void SetupCryptoClientStreamForTest(
-    QuicServerId server_id,
-    bool supports_stateless_rejects,
-    QuicTime::Delta connection_start_time,
-    QuicCryptoClientConfig* crypto_client_config,
-    PacketSavingConnection** client_connection,
-    TestClientSession** client_session,
-    QuicCryptoClientStream** client_stream);
+void CreateClientSessionForTest(QuicServerId server_id,
+                                bool supports_stateless_rejects,
+                                QuicTime::Delta connection_start_time,
+                                QuicCryptoClientConfig* crypto_client_config,
+                                PacketSavingConnection** client_connection,
+                                TestClientSession** client_session);
 
-// Creates and sets up a QuicCryptoServerStream for testing, and all
-// its associated state.
+// Creates a server session for testing.
 //
 // server_id: The server id associated with this stream.
 // connection_start_time: The time to set for the connection clock.
@@ -764,15 +754,11 @@
 //   server_session.
 // server_session: Pointer reference for the newly created server
 //   session.  The new object will be owned by the caller.
-// server_stream: Pointer reference for the newly created crypto
-//   server stream.  The new object will be owned by the caller.
-void SetupCryptoServerStreamForTest(
-    QuicServerId server_id,
-    QuicTime::Delta connection_start_time,
-    QuicCryptoServerConfig* crypto_server_config,
-    PacketSavingConnection** server_connection,
-    TestServerSession** server_session,
-    QuicCryptoServerStream** server_stream);
+void CreateServerSessionForTest(QuicServerId server_id,
+                                QuicTime::Delta connection_start_time,
+                                QuicCryptoServerConfig* crypto_server_config,
+                                PacketSavingConnection** server_connection,
+                                TestServerSession** server_session);
 
 }  // namespace test
 }  // namespace net
diff --git a/net/sdch/sdch_owner_unittest.cc b/net/sdch/sdch_owner_unittest.cc
index 788a992..345d5b5d 100644
--- a/net/sdch/sdch_owner_unittest.cc
+++ b/net/sdch/sdch_owner_unittest.cc
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/location.h"
 #include "base/memory/memory_pressure_listener.h"
 #include "base/prefs/testing_pref_store.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/simple_test_clock.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/base/sdch_manager.h"
 #include "net/log/net_log.h"
@@ -95,7 +98,7 @@
   }
 
   void Start() override {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&URLRequestErrorCountingJob::StartAsync,
                               weak_factory_.GetWeakPtr()));
   }
diff --git a/net/server/http_server.cc b/net/server/http_server.cc
index f849e70..a3c4b529 100644
--- a/net/server/http_server.cc
+++ b/net/server/http_server.cc
@@ -8,12 +8,13 @@
 #include "base/compiler_specific.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_byteorder.h"
+#include "base/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "net/base/net_errors.h"
 #include "net/server/http_connection.h"
@@ -35,7 +36,7 @@
   DCHECK(server_socket_);
   // Start accepting connections in next run loop in case when delegate is not
   // ready to get callbacks.
-  base::MessageLoopProxy::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&HttpServer::DoAcceptLoop, weak_ptr_factory_.GetWeakPtr()));
 }
@@ -115,7 +116,7 @@
   // connection. Instead of referencing connection with ID all the time,
   // destroys the connection in next run loop to make sure any pending
   // callbacks in the call stack return.
-  base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, connection);
+  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, connection);
 }
 
 int HttpServer::GetLocalAddress(IPEndPoint* address) {
diff --git a/net/server/http_server_unittest.cc b/net/server/http_server_unittest.cc
index c2426a3..09b6bf4c 100644
--- a/net/server/http_server_unittest.cc
+++ b/net/server/http_server_unittest.cc
@@ -11,15 +11,16 @@
 #include "base/callback_helpers.h"
 #include "base/compiler_specific.h"
 #include "base/format_macros.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/address_list.h"
 #include "net/base/io_buffer.h"
@@ -58,10 +59,9 @@
 bool RunLoopWithTimeout(base::RunLoop* run_loop) {
   bool timed_out = false;
   base::WeakPtrFactory<bool> timed_out_weak_factory(&timed_out);
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&SetTimedOutAndQuitLoop,
-                 timed_out_weak_factory.GetWeakPtr(),
+      base::Bind(&SetTimedOutAndQuitLoop, timed_out_weak_factory.GetWeakPtr(),
                  run_loop->QuitClosure()),
       base::TimeDelta::FromSeconds(1));
   run_loop->Run();
@@ -270,9 +270,8 @@
   ASSERT_EQ("/test", GetRequest(0).path);
   ASSERT_EQ("", GetRequest(0).data);
   ASSERT_EQ(0u, GetRequest(0).headers.size());
-  ASSERT_TRUE(StartsWithASCII(GetRequest(0).peer.ToString(),
-                              "127.0.0.1",
-                              true));
+  ASSERT_TRUE(
+      base::StartsWithASCII(GetRequest(0).peer.ToString(), "127.0.0.1", true));
 }
 
 TEST_F(HttpServerTest, RequestWithHeaders) {
@@ -420,7 +419,7 @@
   TestURLFetcherDelegate delegate(run_loop.QuitClosure());
 
   scoped_refptr<URLRequestContextGetter> request_context_getter(
-      new TestURLRequestContextGetter(base::MessageLoopProxy::current()));
+      new TestURLRequestContextGetter(base::ThreadTaskRunnerHandle::Get()));
   scoped_ptr<URLFetcher> fetcher =
       URLFetcher::Create(GURL(base::StringPrintf("http://127.0.0.1:%d/test",
                                                  server_address_.port())),
@@ -443,7 +442,7 @@
 
   std::string response;
   ASSERT_TRUE(client.ReadResponse(&response));
-  ASSERT_TRUE(StartsWithASCII(response, "HTTP/1.1 200 OK", true));
+  ASSERT_TRUE(base::StartsWithASCII(response, "HTTP/1.1 200 OK", true));
   ASSERT_TRUE(EndsWith(response, "Response!", true));
 }
 
@@ -592,7 +591,7 @@
   server_->Send200(client_connection_id, "Content for /test", "text/plain");
   std::string response1;
   ASSERT_TRUE(client.ReadResponse(&response1));
-  ASSERT_TRUE(StartsWithASCII(response1, "HTTP/1.1 200 OK", true));
+  ASSERT_TRUE(base::StartsWithASCII(response1, "HTTP/1.1 200 OK", true));
   ASSERT_TRUE(EndsWith(response1, "Content for /test", true));
 
   client.Send("GET /test2 HTTP/1.1\r\n\r\n");
@@ -603,7 +602,7 @@
   server_->Send404(client_connection_id);
   std::string response2;
   ASSERT_TRUE(client.ReadResponse(&response2));
-  ASSERT_TRUE(StartsWithASCII(response2, "HTTP/1.1 404 Not Found", true));
+  ASSERT_TRUE(base::StartsWithASCII(response2, "HTTP/1.1 404 Not Found", true));
 
   client.Send("GET /test3 HTTP/1.1\r\n\r\n");
   ASSERT_TRUE(RunUntilRequestsReceived(3));
@@ -613,7 +612,7 @@
   server_->Send200(client_connection_id, "Content for /test3", "text/plain");
   std::string response3;
   ASSERT_TRUE(client.ReadResponse(&response3));
-  ASSERT_TRUE(StartsWithASCII(response3, "HTTP/1.1 200 OK", true));
+  ASSERT_TRUE(base::StartsWithASCII(response3, "HTTP/1.1 200 OK", true));
   ASSERT_TRUE(EndsWith(response3, "Content for /test3", true));
 }
 
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 6baffc6..a42dfd4 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -8,10 +8,12 @@
 
 #include "base/compiler_specific.h"
 #include "base/format_macros.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "net/base/net_errors.h"
@@ -286,7 +288,7 @@
     // re-entrancy issues if the socket pool is doing something else at the
     // time.
     if (group->CanUseAdditionalSocketSlot(max_sockets_per_group_)) {
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::Bind(
               &ClientSocketPoolBaseHelper::TryToCloseSocketsInLayeredPools,
@@ -1128,10 +1130,9 @@
     ClientSocketHandle* handle, const CompletionCallback& callback, int rv) {
   CHECK(!ContainsKey(pending_callback_map_, handle));
   pending_callback_map_[handle] = CallbackResultPair(callback, rv);
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&ClientSocketPoolBaseHelper::InvokeUserCallback,
-                 weak_factory_.GetWeakPtr(), handle));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&ClientSocketPoolBaseHelper::InvokeUserCallback,
+                            weak_factory_.GetWeakPtr(), handle));
 }
 
 void ClientSocketPoolBaseHelper::InvokeUserCallback(
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 4930011..2ac1881 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -9,14 +9,17 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
 #include "base/values.h"
 #include "net/base/load_timing_info.h"
@@ -327,24 +330,20 @@
         // abstract time for the purpose of unittests. Unfortunately, we have
         // a lot of third-party components that directly call the various
         // time functions, so this change would be rather invasive.
-        base::MessageLoop::current()->PostDelayedTask(
+        base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
             FROM_HERE,
             base::Bind(base::IgnoreResult(&TestConnectJob::DoConnect),
-                       weak_factory_.GetWeakPtr(),
-                       true /* successful */,
-                       true /* async */,
-                       false /* recoverable */),
+                       weak_factory_.GetWeakPtr(), true /* successful */,
+                       true /* async */, false /* recoverable */),
             base::TimeDelta::FromMilliseconds(kPendingConnectDelay));
         return ERR_IO_PENDING;
       case kMockPendingFailingJob:
         set_load_state(LOAD_STATE_CONNECTING);
-        base::MessageLoop::current()->PostDelayedTask(
+        base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
             FROM_HERE,
             base::Bind(base::IgnoreResult(&TestConnectJob::DoConnect),
-                       weak_factory_.GetWeakPtr(),
-                       false /* error */,
-                       true  /* async */,
-                       false /* recoverable */),
+                       weak_factory_.GetWeakPtr(), false /* error */,
+                       true /* async */, false /* recoverable */),
             base::TimeDelta::FromMilliseconds(2));
         return ERR_IO_PENDING;
       case kMockWaitingJob:
@@ -357,13 +356,11 @@
                          true /* recoverable */);
       case kMockPendingRecoverableJob:
         set_load_state(LOAD_STATE_CONNECTING);
-        base::MessageLoop::current()->PostDelayedTask(
+        base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
             FROM_HERE,
             base::Bind(base::IgnoreResult(&TestConnectJob::DoConnect),
-                       weak_factory_.GetWeakPtr(),
-                       false /* error */,
-                       true  /* async */,
-                       true  /* recoverable */),
+                       weak_factory_.GetWeakPtr(), false /* error */,
+                       true /* async */, true /* recoverable */),
             base::TimeDelta::FromMilliseconds(2));
         return ERR_IO_PENDING;
       case kMockAdditionalErrorStateJob:
@@ -373,13 +370,11 @@
       case kMockPendingAdditionalErrorStateJob:
         set_load_state(LOAD_STATE_CONNECTING);
         store_additional_error_state_ = true;
-        base::MessageLoop::current()->PostDelayedTask(
+        base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
             FROM_HERE,
             base::Bind(base::IgnoreResult(&TestConnectJob::DoConnect),
-                       weak_factory_.GetWeakPtr(),
-                       false /* error */,
-                       true  /* async */,
-                       false /* recoverable */),
+                       weak_factory_.GetWeakPtr(), false /* error */,
+                       true /* async */, false /* recoverable */),
             base::TimeDelta::FromMilliseconds(2));
         return ERR_IO_PENDING;
       case kMockUnreadDataJob: {
@@ -3655,9 +3650,8 @@
   // the backup job a pending job instead of a waiting job, so it
   // *would* complete if it were created.
   connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       base::TimeDelta::FromSeconds(1));
   base::MessageLoop::current()->Run();
   EXPECT_FALSE(pool_->HasGroup("a"));
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 78c7ae0e..e263680 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -11,9 +11,11 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/address_family.h"
 #include "net/base/address_list.h"
@@ -351,7 +353,7 @@
       read_state_ = PAUSED;
       return MockRead(SYNCHRONOUS, ERR_IO_PENDING);
     }
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&SequencedSocketData::OnReadComplete,
                               weak_factory_.GetWeakPtr()));
     CHECK_NE(COMPLETING, write_state_);
@@ -393,7 +395,7 @@
     }
 
     NET_TRACE(1, " *** ") << "Posting task to complete write";
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&SequencedSocketData::OnWriteComplete,
                               weak_factory_.GetWeakPtr()));
     CHECK_NE(COMPLETING, read_state_);
@@ -459,7 +461,7 @@
 
   NET_TRACE(1, " ****** ") << "Posting task to complete read: "
                            << sequence_number_;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&SequencedSocketData::OnReadComplete,
                             weak_factory_.GetWeakPtr()));
   CHECK_NE(COMPLETING, write_state_);
@@ -477,7 +479,7 @@
 
   NET_TRACE(1, " ****** ") << "Posting task to complete write: "
                            << sequence_number_;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&SequencedSocketData::OnWriteComplete,
                             weak_factory_.GetWeakPtr()));
   CHECK_NE(COMPLETING, read_state_);
@@ -910,12 +912,9 @@
 
 void MockClientSocket::RunCallbackAsync(const CompletionCallback& callback,
                                         int result) {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&MockClientSocket::RunCallback,
-                 weak_factory_.GetWeakPtr(),
-                 callback,
-                 result));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&MockClientSocket::RunCallback,
+                            weak_factory_.GetWeakPtr(), callback, result));
 }
 
 void MockClientSocket::RunCallback(const CompletionCallback& callback,
@@ -1725,12 +1724,9 @@
 
 void MockUDPClientSocket::RunCallbackAsync(const CompletionCallback& callback,
                                            int result) {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&MockUDPClientSocket::RunCallback,
-                 weak_factory_.GetWeakPtr(),
-                 callback,
-                 result));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&MockUDPClientSocket::RunCallback,
+                            weak_factory_.GetWeakPtr(), callback, result));
 }
 
 void MockUDPClientSocket::RunCallback(const CompletionCallback& callback,
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 0fd0a06..baf87446 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -699,7 +699,7 @@
 
   // The service for retrieving Channel ID keys.  May be NULL.
   ChannelIDService* channel_id_service_;
-  ChannelIDService::RequestHandle channel_id_request_handle_;
+  ChannelIDService::Request channel_id_request_;
 
   // The information about NSS task runner.
   int unhandled_buffer_size_;
@@ -954,7 +954,7 @@
 
   network_handshake_state_.Reset();
 
-  channel_id_request_handle_.Cancel();
+  channel_id_request_.Cancel();
 }
 
 int SSLClientSocketNSS::Core::Read(IOBuffer* buf, int buf_len,
@@ -2213,7 +2213,7 @@
   int rv = channel_id_service_->GetOrCreateChannelID(
       host, &channel_id_key_,
       base::Bind(&Core::OnGetChannelIDComplete, base::Unretained(this)),
-      &channel_id_request_handle_);
+      &channel_id_request_);
 
   if (rv != ERR_IO_PENDING && !OnNSSTaskRunner()) {
     nss_task_runner_->PostTask(
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 4c80290a..d06f5ac 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -513,7 +513,7 @@
   channel_id_sent_ = false;
   handshake_completed_ = false;
   certificate_verified_ = false;
-  channel_id_request_handle_.Cancel();
+  channel_id_request_.Cancel();
   ssl_failure_state_ = SSL_FAILURE_NONE;
 }
 
@@ -1031,7 +1031,7 @@
       host_and_port_.host(), &channel_id_key_,
       base::Bind(&SSLClientSocketOpenSSL::OnHandshakeIOComplete,
                  base::Unretained(this)),
-      &channel_id_request_handle_);
+      &channel_id_request_);
 }
 
 int SSLClientSocketOpenSSL::DoChannelIDLookupComplete(int result) {
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h
index 9ff5b54f2..fd7a68a 100644
--- a/net/socket/ssl_client_socket_openssl.h
+++ b/net/socket/ssl_client_socket_openssl.h
@@ -303,7 +303,7 @@
   // True if the initial handshake's certificate has been verified.
   bool certificate_verified_;
   // The request handle for |channel_id_service_|.
-  ChannelIDService::RequestHandle channel_id_request_handle_;
+  ChannelIDService::Request channel_id_request_;
   SSLFailureState ssl_failure_state_;
 
   TransportSecurityState* transport_security_state_;
diff --git a/net/socket/ssl_client_socket_openssl_unittest.cc b/net/socket/ssl_client_socket_openssl_unittest.cc
index 0a08f8c7..3a8b52c 100644
--- a/net/socket/ssl_client_socket_openssl_unittest.cc
+++ b/net/socket/ssl_client_socket_openssl_unittest.cc
@@ -16,7 +16,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/values.h"
 #include "crypto/openssl_util.h"
 #include "crypto/scoped_openssl_types.h"
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 8d6bb1b..7dcb7059d 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -5,8 +5,10 @@
 #include "net/socket/ssl_client_socket.h"
 
 #include "base/callback_helpers.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/address_list.h"
@@ -654,7 +656,7 @@
   int GetChannelID(const std::string& server_identifier,
                    scoped_ptr<crypto::ECPrivateKey>* key_result,
                    const GetChannelIDCallback& callback) override {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(callback, ERR_UNEXPECTED, server_identifier, nullptr));
     return ERR_IO_PENDING;
@@ -1134,16 +1136,7 @@
     rv = callback.WaitForResult();
 
   log.GetEntries(&entries);
-  // Because the handshake is aborted during the CertificateRequest, the server
-  // may still send the ServerHelloDone afterwards. As a result, the SSL_CONNECT
-  // may not be the last entry. See http://crbug.com/54445. Because of this, use
-  // ExpectLogContainsSomewhere, rather than LogContainsEndEvent, to avoid
-  // assuming particular details about the read (e.g. assuming there will only
-  // be one extra read, when there might be more).
-  //
-  // TODO(davidben): Is this still possible with memio_GetReadRequest?
-  ExpectLogContainsSomewhere(
-      entries, 0, NetLog::TYPE_SSL_CONNECT, NetLog::PHASE_END);
+  EXPECT_TRUE(LogContainsEndEvent(entries, -1, NetLog::TYPE_SSL_CONNECT));
   EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
   EXPECT_FALSE(sock->IsConnected());
 }
@@ -1492,7 +1485,7 @@
   // TODO(davidben): Avoid the arbitrary timeout?
   int old_write_count = raw_counting_socket->write_count();
   base::RunLoop loop;
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, loop.QuitClosure(), base::TimeDelta::FromMilliseconds(100));
   loop.Run();
   EXPECT_EQ(old_write_count, raw_counting_socket->write_count());
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
index 84663eb..b99f834 100644
--- a/net/socket/ssl_server_socket_unittest.cc
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -22,7 +22,10 @@
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "crypto/nss_util.h"
 #include "crypto/rsa_private_key.h"
 #include "net/base/address_list.h"
@@ -94,7 +97,7 @@
         return ERR_CONNECTION_RESET;
       write_called_after_close_ = true;
       write_callback_ = callback;
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(&FakeDataChannel::DoWriteCallback,
                                 weak_factory_.GetWeakPtr()));
       return ERR_IO_PENDING;
@@ -103,7 +106,7 @@
     data_.push(new DrainableIOBuffer(
         new StringIOBuffer(std::string(buf->data(), buf_len)),
         buf_len));
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&FakeDataChannel::DoReadCallback,
                               weak_factory_.GetWeakPtr()));
     return buf_len;
@@ -546,7 +549,7 @@
   client_ret = write_callback.GetResult(client_ret);
   EXPECT_GT(client_ret, 0);
 
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, base::MessageLoop::QuitClosure(),
       base::TimeDelta::FromMilliseconds(10));
   base::MessageLoop::current()->Run();
diff --git a/net/socket/transport_client_socket_pool_test_util.cc b/net/socket/transport_client_socket_pool_test_util.cc
index 352fd87..c13ffdd14 100644
--- a/net/socket/transport_client_socket_pool_test_util.cc
+++ b/net/socket/transport_client_socket_pool_test_util.cc
@@ -6,9 +6,12 @@
 
 #include <string>
 
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/load_timing_info.h"
 #include "net/base/load_timing_info_test_util.h"
@@ -189,8 +192,8 @@
       net::NetLog* net_log) {
     scoped_ptr<MockTriggerableClientSocket> socket(
         new MockTriggerableClientSocket(addrlist, should_connect, net_log));
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           socket->GetConnectCallback());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  socket->GetConnectCallback());
     return socket.Pass();
   }
 
@@ -201,7 +204,7 @@
       net::NetLog* net_log) {
     scoped_ptr<MockTriggerableClientSocket> socket(
         new MockTriggerableClientSocket(addrlist, should_connect, net_log));
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, socket->GetConnectCallback(), delay);
     return socket.Pass();
   }
diff --git a/net/socket/websocket_endpoint_lock_manager.cc b/net/socket/websocket_endpoint_lock_manager.cc
index caddd8d..8a218dfb6 100644
--- a/net/socket/websocket_endpoint_lock_manager.cc
+++ b/net/socket/websocket_endpoint_lock_manager.cc
@@ -7,8 +7,10 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/net_errors.h"
 #include "net/log/net_log.h"
 
@@ -127,7 +129,7 @@
   DVLOG(3) << "Delaying " << unlock_delay_.InMilliseconds()
            << "ms before unlocking endpoint " << endpoint.ToString();
   ++pending_unlock_count_;
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&WebSocketEndpointLockManager::DelayedUnlockEndpoint,
                  weak_factory_.GetWeakPtr(), endpoint),
diff --git a/net/socket/websocket_transport_client_socket_pool.cc b/net/socket/websocket_transport_client_socket_pool.cc
index 1991194..4a7da5c 100644
--- a/net/socket/websocket_transport_client_socket_pool.cc
+++ b/net/socket/websocket_transport_client_socket_pool.cc
@@ -7,9 +7,12 @@
 #include <algorithm>
 
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "net/base/net_errors.h"
@@ -506,13 +509,10 @@
     int rv) {
   DCHECK(!pending_callbacks_.count(handle));
   pending_callbacks_.insert(handle);
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&WebSocketTransportClientSocketPool::InvokeUserCallback,
-                 weak_factory_.GetWeakPtr(),
-                 handle,
-                 callback,
-                 rv));
+                 weak_factory_.GetWeakPtr(), handle, callback, rv));
 }
 
 void WebSocketTransportClientSocketPool::InvokeUserCallback(
diff --git a/net/socket/websocket_transport_client_socket_pool_unittest.cc b/net/socket/websocket_transport_client_socket_pool_unittest.cc
index 47a2558..477fdb3 100644
--- a/net/socket/websocket_transport_client_socket_pool_unittest.cc
+++ b/net/socket/websocket_transport_client_socket_pool_unittest.cc
@@ -10,10 +10,12 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/location.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/load_timing_info.h"
@@ -42,8 +44,8 @@
 void RunLoopForTimePeriod(base::TimeDelta period) {
   base::RunLoop run_loop;
   base::Closure quit_closure(run_loop.QuitClosure());
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE, quit_closure, period);
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, quit_closure,
+                                                       period);
   run_loop.Run();
 }
 
diff --git a/net/spdy/mock_spdy_framer_visitor.h b/net/spdy/mock_spdy_framer_visitor.h
index ea59d7d..6437651f 100644
--- a/net/spdy/mock_spdy_framer_visitor.h
+++ b/net/spdy/mock_spdy_framer_visitor.h
@@ -52,12 +52,10 @@
                                    SpdyStreamId promised_stream_id,
                                    bool end));
   MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end));
-  MOCK_METHOD6(OnAltSvc, void(SpdyStreamId stream_id,
-                              uint32 max_age,
-                              uint16 port,
-                              base::StringPiece protocol_id,
-                              base::StringPiece host,
-                              base::StringPiece origin));
+  MOCK_METHOD3(OnAltSvc,
+               void(SpdyStreamId stream_id,
+                    base::StringPiece origin,
+                    const SpdyAltSvcWireFormat::AlternativeService& altsvc));
   MOCK_METHOD4(OnPriority,
                void(SpdyStreamId stream_id,
                     SpdyStreamId parent_stream_id,
diff --git a/net/spdy/spdy_alt_svc_wire_format.cc b/net/spdy/spdy_alt_svc_wire_format.cc
index a1e73617..95f08c44 100644
--- a/net/spdy/spdy_alt_svc_wire_format.cc
+++ b/net/spdy/spdy_alt_svc_wire_format.cc
@@ -36,19 +36,16 @@
 
 // static
 bool SpdyAltSvcWireFormat::ParseHeaderFieldValue(StringPiece value,
-                                                 std::string* protocol_id,
-                                                 std::string* host,
-                                                 uint16* port,
-                                                 uint32* max_age,
-                                                 double* p) {
-  *max_age = 86400;
-  *p = 1.0;
+                                                 AlternativeService* altsvc) {
+  altsvc->max_age = 86400;
+  altsvc->p = 1.0;
 
   StringPiece::const_iterator c = value.begin();
   StringPiece::const_iterator percent_encoded_protocol_id_end =
       std::find(c, value.end(), '=');
   if (percent_encoded_protocol_id_end == c ||
-      !PercentDecode(c, percent_encoded_protocol_id_end, protocol_id)) {
+      !PercentDecode(c, percent_encoded_protocol_id_end,
+                     &(altsvc->protocol_id))) {
     return false;
   }
   c = percent_encoded_protocol_id_end;
@@ -76,7 +73,8 @@
     return false;
   }
   DCHECK_EQ('"', *c);
-  if (!ParseAltAuthority(alt_authority_begin, c, host, port)) {
+  if (!ParseAltAuthority(alt_authority_begin, c, &(altsvc->host),
+                         &(altsvc->port))) {
     return false;
   }
   ++c;
@@ -111,11 +109,12 @@
       return false;
     }
     if (parameter_name.compare("ma") == 0) {
-      if (!ParsePositiveInteger32(parameter_value_begin, c, max_age)) {
+      if (!ParsePositiveInteger32(parameter_value_begin, c,
+                                  &(altsvc->max_age))) {
         return false;
       }
     } else if (parameter_name.compare("p") == 0) {
-      if (!ParseProbability(parameter_value_begin, c, p)) {
+      if (!ParseProbability(parameter_value_begin, c, &(altsvc->p))) {
         return false;
       }
     }
@@ -127,16 +126,12 @@
 
 // static
 std::string SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
-    const std::string& protocol_id,
-    const std::string& host,
-    uint16 port,
-    uint32 max_age,
-    double p) {
+    const AlternativeService& altsvc) {
   const char kNibbleToHex[] = "0123456789ABCDEF";
   std::string value;
   // Percent escape protocol id according to
   // http://tools.ietf.org/html/rfc7230#section-3.2.6.
-  for (char c : protocol_id) {
+  for (char c : altsvc.protocol_id) {
     if (isalnum(c)) {
       value.push_back(c);
       continue;
@@ -168,18 +163,18 @@
   }
   value.push_back('=');
   value.push_back('"');
-  for (char c : host) {
+  for (char c : altsvc.host) {
     if (c == '"' || c == '\\') {
       value.push_back('\\');
     }
     value.push_back(c);
   }
-  base::StringAppendF(&value, ":%d\"", port);
-  if (max_age != 86400) {
-    base::StringAppendF(&value, "; ma=%d", max_age);
+  base::StringAppendF(&value, ":%d\"", altsvc.port);
+  if (altsvc.max_age != 86400) {
+    base::StringAppendF(&value, "; ma=%d", altsvc.max_age);
   }
-  if (p != 1.0) {
-    base::StringAppendF(&value, "; p=%.2f", p);
+  if (altsvc.p != 1.0) {
+    base::StringAppendF(&value, "; p=%.2f", altsvc.p);
   }
   return value;
 }
diff --git a/net/spdy/spdy_alt_svc_wire_format.h b/net/spdy/spdy_alt_svc_wire_format.h
index eb79f8a..b86141f 100644
--- a/net/spdy/spdy_alt_svc_wire_format.h
+++ b/net/spdy/spdy_alt_svc_wire_format.h
@@ -24,18 +24,24 @@
 
 class NET_EXPORT_PRIVATE SpdyAltSvcWireFormat {
  public:
+  struct AlternativeService {
+    std::string protocol_id;
+    std::string host;
+    uint16 port = 0;
+    uint32 max_age = 0;
+    double p = 1.0;
+
+    bool operator==(const AlternativeService& other) const {
+      return protocol_id == other.protocol_id && host == other.host &&
+             port == other.port && max_age == other.max_age && p == other.p;
+    }
+  };
+
   friend class test::SpdyAltSvcWireFormatPeer;
   static bool ParseHeaderFieldValue(StringPiece value,
-                                    std::string* protocol_id,
-                                    std::string* host,
-                                    uint16* port,
-                                    uint32* max_age,
-                                    double* p);
-  static std::string SerializeHeaderFieldValue(const std::string& protocol_id,
-                                               const std::string& host,
-                                               uint16 port,
-                                               uint32 max_age,
-                                               double p);
+                                    AlternativeService* altsvc);
+  static std::string SerializeHeaderFieldValue(
+      const AlternativeService& altsvc);
 
  private:
   static void SkipWhiteSpace(StringPiece::const_iterator* c,
diff --git a/net/spdy/spdy_alt_svc_wire_format_test.cc b/net/spdy/spdy_alt_svc_wire_format_test.cc
index 1ecd53b..532ba66 100644
--- a/net/spdy/spdy_alt_svc_wire_format_test.cc
+++ b/net/spdy/spdy_alt_svc_wire_format_test.cc
@@ -117,19 +117,14 @@
       header_field_value.append(" ");
     }
 
-    std::string protocol_id;
-    std::string host;
-    uint16 port = 0;
-    uint32 max_age = 0;
-    double p = 0.0;
-
-    ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(
-        header_field_value, &protocol_id, &host, &port, &max_age, &p));
-    EXPECT_EQ("a=b%c", protocol_id);
-    EXPECT_EQ(expected_host, host);
-    EXPECT_EQ(42, port);
-    EXPECT_EQ(expected_max_age, max_age);
-    EXPECT_DOUBLE_EQ(expected_p, p);
+    SpdyAltSvcWireFormat::AlternativeService altsvc;
+    ASSERT_TRUE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(header_field_value,
+                                                            &altsvc));
+    EXPECT_EQ("a=b%c", altsvc.protocol_id);
+    EXPECT_EQ(expected_host, altsvc.host);
+    EXPECT_EQ(42, altsvc.port);
+    EXPECT_EQ(expected_max_age, altsvc.max_age);
+    EXPECT_DOUBLE_EQ(expected_p, altsvc.p);
   }
 }
 
@@ -137,26 +132,27 @@
 // parameter.
 TEST(SpdyAltSvcWireFormatTest, SerializeHeaderFieldValue) {
   for (int i = 0; i < 1 << 3; ++i) {
+    SpdyAltSvcWireFormat::AlternativeService altsvc;
+    altsvc.protocol_id = "a=b%c";
+    altsvc.port = 42;
     std::string expected_header_field_value = "a%3Db%25c=\"";
-    std::string host;
     if (i & 1 << 0) {
-      host = "foo\"bar\\baz";
+      altsvc.host = "foo\"bar\\baz";
       expected_header_field_value.append("foo\\\"bar\\\\baz");
     }
     expected_header_field_value.append(":42\"");
-    int max_age = 86400;
+    altsvc.max_age = 86400;
     if (i & 1 << 1) {
-      max_age = 1111;
+      altsvc.max_age = 1111;
       expected_header_field_value.append("; ma=1111");
     }
-    double p = 1.0;
+    altsvc.p = 1.0;
     if (i & 1 << 2) {
-      p = 0.33;
+      altsvc.p = 0.33;
       expected_header_field_value.append("; p=0.33");
     }
     EXPECT_EQ(expected_header_field_value,
-              SpdyAltSvcWireFormat::SerializeHeaderFieldValue("a=b%c", host, 42,
-                                                              max_age, p));
+              SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc));
   }
 }
 
@@ -164,11 +160,7 @@
 // invalid percent encoding, unmatched quotation mark, empty port, non-numeric
 // characters in numeric fields, negative or larger than 1.0 probability.
 TEST(SpdyAltSvcWireFormatTest, ParseHeaderFieldValueInvalid) {
-  std::string protocol_id;
-  std::string host;
-  uint16 port;
-  uint32 max_age;
-  double p;
+  SpdyAltSvcWireFormat::AlternativeService altsvc;
   const char* invalid_field_value_array[] = {"", "a%", "a%x", "a%b", "a%9z",
       "a=", "a=\"", "a=\"b\"", "a=\":\"", "a=\"c:\"", "a=\"c:foo\"",
       "a=\"c:42foo\"", "a=\"b:42\"bar", "a=\"b:42\" ; m",
@@ -177,7 +169,7 @@
       "a=\"b:42\" ; p=..", "a=\"b:42\" ; p=1.05"};
   for (const char* invalid_field_value : invalid_field_value_array) {
     EXPECT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(
-        invalid_field_value, &protocol_id, &host, &port, &max_age, &p))
+        invalid_field_value, &altsvc))
         << invalid_field_value;
   }
 }
@@ -186,17 +178,13 @@
 // before closing quotation mark, without trying to access memory beyond the end
 // of the input.
 TEST(SpdyAltSvcWireFormatTest, ParseTruncatedHeaderFieldValue) {
-  std::string protocol_id;
-  std::string host;
-  uint16 port;
-  uint32 max_age;
-  double p;
+  SpdyAltSvcWireFormat::AlternativeService altsvc;
   const char* field_value_array[] = {
       "p=\":137\"", "p=\"foo:137\"", "p%25=\"foo\\\"bar\\\\baz:137\""};
   for (std::string field_value : field_value_array) {
     for (size_t len = 1; len < field_value.size(); ++len) {
       EXPECT_FALSE(SpdyAltSvcWireFormat::ParseHeaderFieldValue(
-          field_value.substr(0, len), &protocol_id, &host, &port, &max_age, &p))
+          field_value.substr(0, len), &altsvc))
           << len;
     }
   }
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index e0dd61d..44e9197 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -11,7 +11,6 @@
 #include "base/lazy_instance.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/third_party/valgrind/memcheck.h"
-#include "net/spdy/spdy_alt_svc_wire_format.h"
 #include "net/spdy/spdy_frame_builder.h"
 #include "net/spdy/spdy_frame_reader.h"
 #include "net/spdy/spdy_bitmasks.h"
@@ -2057,21 +2056,14 @@
   StringPiece value(altsvc_scratch_.buffer.get() + reader.GetBytesConsumed(),
                     altsvc_scratch_.buffer_length - reader.GetBytesConsumed());
 
-  string protocol_id;
-  string host;
-  uint16 port;
-  uint32 max_age;
-  double p;
-  bool success = SpdyAltSvcWireFormat::ParseHeaderFieldValue(
-      value, &protocol_id, &host, &port, &max_age, &p);
-  if (!success || protocol_id.length() == 0) {
+  SpdyAltSvcWireFormat::AlternativeService altsvc;
+  bool success = SpdyAltSvcWireFormat::ParseHeaderFieldValue(value, &altsvc);
+  if (!success || altsvc.protocol_id.length() == 0) {
     set_error(SPDY_INVALID_CONTROL_FRAME);
     return 0;
   }
 
-  // TODO(bnc): Pass on |p|.
-  visitor_->OnAltSvc(current_frame_stream_id_, max_age, port, protocol_id, host,
-                     origin);
+  visitor_->OnAltSvc(current_frame_stream_id_, origin, altsvc);
   CHANGE_STATE(SPDY_AUTO_RESET);
   return len;
 }
@@ -2777,10 +2769,8 @@
 
   size_t size = GetAltSvcMinimumSize();
   size += altsvc.origin().length();
-  // TODO(bnc): Add probability to SpdyAltSvcIR and pass it on.
-  string value = SpdyAltSvcWireFormat::SerializeHeaderFieldValue(
-      altsvc.protocol_id(), altsvc.host(), altsvc.port(), altsvc.max_age(),
-      1.0);
+  string value =
+      SpdyAltSvcWireFormat::SerializeHeaderFieldValue(altsvc.altsvc());
   size += value.length();
 
   SpdyFrameBuilder builder(size, protocol_version());
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index 9dec83b1e..73e03a5d 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -20,6 +20,7 @@
 #include "net/base/net_export.h"
 #include "net/spdy/hpack_decoder.h"
 #include "net/spdy/hpack_encoder.h"
+#include "net/spdy/spdy_alt_svc_wire_format.h"
 #include "net/spdy/spdy_header_block.h"
 #include "net/spdy/spdy_protocol.h"
 
@@ -267,12 +268,10 @@
   virtual void OnContinuation(SpdyStreamId stream_id, bool end) = 0;
 
   // Called when an ALTSVC frame has been parsed.
-  virtual void OnAltSvc(SpdyStreamId stream_id,
-                        uint32 max_age,
-                        uint16 port,
-                        base::StringPiece protocol_id,
-                        base::StringPiece host,
-                        base::StringPiece origin) {}
+  virtual void OnAltSvc(
+      SpdyStreamId stream_id,
+      base::StringPiece origin,
+      const SpdyAltSvcWireFormat::AlternativeService& altsvc) {}
 
   // Called when a PRIORITY frame is received.
   virtual void OnPriority(SpdyStreamId stream_id,
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index d14a5765..103af39 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -427,20 +427,19 @@
     ++continuation_count_;
   }
 
-  void OnAltSvc(SpdyStreamId stream_id,
-                uint32 max_age,
-                uint16 port,
-                StringPiece protocol_id,
-                StringPiece host,
-                StringPiece origin) override {
+  void OnAltSvc(
+      SpdyStreamId stream_id,
+      StringPiece origin,
+      const SpdyAltSvcWireFormat::AlternativeService& altsvc) override {
     test_altsvc_ir_.set_stream_id(stream_id);
-    test_altsvc_ir_.set_max_age(max_age);
-    test_altsvc_ir_.set_port(port);
-    test_altsvc_ir_.set_protocol_id(protocol_id.as_string());
-    test_altsvc_ir_.set_host(host.as_string());
     if (origin.length() > 0) {
       test_altsvc_ir_.set_origin(origin.as_string());
     }
+    test_altsvc_ir_.set_protocol_id(altsvc.protocol_id);
+    test_altsvc_ir_.set_host(altsvc.host);
+    test_altsvc_ir_.set_port(altsvc.port);
+    test_altsvc_ir_.set_max_age(altsvc.max_age);
+    test_altsvc_ir_.set_p(altsvc.p);
     ++altsvc_count_;
   }
 
@@ -5694,19 +5693,20 @@
   SpdyFramer framer(spdy_version_);
   framer.set_visitor(&visitor);
 
-  EXPECT_CALL(visitor, OnAltSvc(kStreamId,
-                                10,
-                                443,
-                                StringPiece("pid"),
-                                StringPiece("h1"),
-                                StringPiece("o1")));
+  SpdyAltSvcWireFormat::AlternativeService altsvc;
+  altsvc.protocol_id = "p\"=i:d";
+  altsvc.host = "h_\\o\"st";
+  altsvc.port = 443;
+  altsvc.max_age = 10;
+  altsvc.p = 1.0;
+  EXPECT_CALL(visitor, OnAltSvc(kStreamId, StringPiece("o_r|g!n"), altsvc));
 
   SpdyAltSvcIR altsvc_ir(1);
   altsvc_ir.set_max_age(10);
   altsvc_ir.set_port(443);
-  altsvc_ir.set_protocol_id("pid");
-  altsvc_ir.set_host("h1");
-  altsvc_ir.set_origin("o1");
+  altsvc_ir.set_protocol_id("p\"=i:d");
+  altsvc_ir.set_host("h_\\o\"st");
+  altsvc_ir.set_origin("o_r|g!n");
   scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir));
   framer.ProcessInput(frame->data(), frame->size());
 
@@ -5726,16 +5726,19 @@
   SpdyFramer framer(spdy_version_);
   framer.set_visitor(&visitor);
 
-  EXPECT_CALL(visitor,
-              OnAltSvc(kStreamId, 10, 443, StringPiece("p\"=i:d"),
-                       StringPiece("h_\\o\"st"), StringPiece("o_r|g!n")));
+  SpdyAltSvcWireFormat::AlternativeService altsvc;
+  altsvc.protocol_id = "p\"=i:d";
+  altsvc.host = "h_\\o\"st";
+  altsvc.port = 443;
+  altsvc.max_age = 10;
+  altsvc.p = 1.0;
+  EXPECT_CALL(visitor, OnAltSvc(kStreamId, StringPiece(""), altsvc));
 
   SpdyAltSvcIR altsvc_ir(1);
   altsvc_ir.set_max_age(10);
   altsvc_ir.set_port(443);
   altsvc_ir.set_protocol_id("p\"=i:d");
   altsvc_ir.set_host("h_\\o\"st");
-  altsvc_ir.set_origin("o_r|g!n");
   scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(altsvc_ir));
   framer.ProcessInput(frame->data(), frame->size());
 
@@ -5779,8 +5782,13 @@
   SpdyFramer framer(spdy_version_);
   framer.set_visitor(&visitor);
 
-  EXPECT_CALL(visitor, OnAltSvc(kStreamId, 10, 443, StringPiece("pid"),
-                                StringPiece("h1"), StringPiece("")));
+  SpdyAltSvcWireFormat::AlternativeService altsvc;
+  altsvc.protocol_id = "pid";
+  altsvc.host = "h1";
+  altsvc.port = 443;
+  altsvc.max_age = 10;
+  altsvc.p = 1.0;
+  EXPECT_CALL(visitor, OnAltSvc(kStreamId, StringPiece(""), altsvc));
 
   SpdyAltSvcIR altsvc_ir(1);
   altsvc_ir.set_max_age(10);
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index d87d68b..f3da77b 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -8,9 +8,11 @@
 #include <list>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_util.h"
@@ -447,7 +449,7 @@
   more_read_data_pending_ = false;
   buffered_read_callback_pending_ = true;
   const base::TimeDelta kBufferTime = base::TimeDelta::FromMilliseconds(1);
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::Bind(base::IgnoreResult(&SpdyHttpStream::DoBufferedReadCallback),
                  weak_factory_.GetWeakPtr()),
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index a57e4965..b71353b9 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -5,7 +5,7 @@
 #include "net/spdy/spdy_http_stream.h"
 
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "crypto/ec_private_key.h"
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index f393a9de..a67a23a 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_piece.h"
 #include "base/test/test_file_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/auth.h"
 #include "net/base/chunked_upload_data_stream.h"
 #include "net/base/elements_upload_data_stream.h"
@@ -470,12 +471,9 @@
                base::WriteFile(file_path, kUploadData, kUploadDataSize));
 
       ScopedVector<UploadElementReader> element_readers;
-      element_readers.push_back(
-          new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                      file_path,
-                                      0,
-                                      kUploadDataSize,
-                                      base::Time()));
+      element_readers.push_back(new UploadFileElementReader(
+          base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
+          kUploadDataSize, base::Time()));
       upload_data_stream_.reset(
           new ElementsUploadDataStream(element_readers.Pass(), 0));
 
@@ -498,12 +496,9 @@
     CHECK(base::MakeFileUnreadable(file_path));
 
     ScopedVector<UploadElementReader> element_readers;
-    element_readers.push_back(
-        new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                    file_path,
-                                    0,
-                                    kUploadDataSize,
-                                    base::Time()));
+    element_readers.push_back(new UploadFileElementReader(
+        base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
+        kUploadDataSize, base::Time()));
     upload_data_stream_.reset(
         new ElementsUploadDataStream(element_readers.Pass(), 0));
 
@@ -528,12 +523,9 @@
       ScopedVector<UploadElementReader> element_readers;
       element_readers.push_back(
           new UploadBytesElementReader(kUploadData, kFileRangeOffset));
-      element_readers.push_back(
-          new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                      file_path,
-                                      kFileRangeOffset,
-                                      kFileRangeLength,
-                                      base::Time()));
+      element_readers.push_back(new UploadFileElementReader(
+          base::ThreadTaskRunnerHandle::Get().get(), file_path,
+          kFileRangeOffset, kFileRangeLength, base::Time()));
       element_readers.push_back(new UploadBytesElementReader(
           kUploadData + kFileRangeOffset + kFileRangeLength,
           kUploadDataSize - (kFileRangeOffset + kFileRangeLength)));
diff --git a/net/spdy/spdy_priority_forest.h b/net/spdy/spdy_priority_forest.h
deleted file mode 100644
index 8624bbfe..0000000
--- a/net/spdy/spdy_priority_forest.h
+++ /dev/null
@@ -1,528 +0,0 @@
-// Copyright (c) 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.
-
-#ifndef NET_SPDY_SPDY_PRIORITY_FOREST_H_
-#define NET_SPDY_SPDY_PRIORITY_FOREST_H_
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/rand_util.h"
-
-namespace net {
-
-// This data structure implements the SPDY prioriziation data structures
-// defined in this document: http://go/spdy4-prioritization
-//
-// Nodes can be added and removed, and dependencies between them defined.  Each
-// node can have at most one parent and at most one child (forming a list), but
-// there can be multiple lists, with each list root having its own priority.
-// Individual nodes can also be marked as ready to read/write, and then the
-// whole structure can be queried to pick the next node to read/write out of
-// those ready.
-//
-// The NodeId and Priority types must be POD that support comparison (most
-// likely, they will be numbers).
-template <typename NodeId, typename Priority>
-class SpdyPriorityForest {
- public:
-  SpdyPriorityForest();
-  ~SpdyPriorityForest();
-
-  // Return the number of nodes currently in the forest.
-  int num_nodes() const;
-
-  // Return true if the forest contains a node with the given ID.
-  bool NodeExists(NodeId node_id) const;
-
-  // Add a new root node to the forest, with the given priority.  Returns true
-  // on success, or false if the node_id already exists within the forest.
-  bool AddRootNode(NodeId node_id, Priority priority);
-
-  // Add a new node to the forest, with the given parent.  Returns true on
-  // success.  Returns false and has no effect if the new node already exists,
-  // or if the parent doesn't exist, or if the parent already has a child.
-  bool AddNonRootNode(NodeId node_id, NodeId parent_id, bool unordered);
-
-  // Remove an existing node from the forest.  Returns true on success, or
-  // false if the node doesn't exist.
-  bool RemoveNode(NodeId node_id);
-
-  // Get the priority of the given node.  If the node doesn't exist, or is not
-  // a root node (and thus has no priority), returns Priority().
-  Priority GetPriority(NodeId node_id) const;
-
-  // Get the parent of the given node.  If the node doesn't exist, or is a root
-  // node (and thus has no parent), returns NodeId().
-  NodeId GetParent(NodeId node_id) const;
-
-  // Determine if the given node is unordered with respect to its parent.  If
-  // the node doesn't exist, or is a root node (and thus has no parent),
-  // returns false.
-  bool IsNodeUnordered(NodeId node_id) const;
-
-  // Get the child of the given node.  If the node doesn't exist, or has no
-  // child, returns NodeId().
-  NodeId GetChild(NodeId node_id) const;
-
-  // Set the priority of the given node.  If the node was not already a root
-  // node, this makes it a root node.  Returns true on success, or false if the
-  // node doesn't exist.
-  bool SetPriority(NodeId node_id, Priority priority);
-
-  // Set the parent of the given node.  If the node was a root node, this makes
-  // it no longer a root.  Returns true on success.  Returns false and has no
-  // effect if (1) the node and/or the parent doesn't exist, (2) the new parent
-  // already has a different child than the node, or (3) if the new parent is a
-  // descendant of the node (so this would have created a cycle).
-  bool SetParent(NodeId node_id, NodeId parent_id, bool unordered);
-
-  // Check if a node is marked as ready to read.  Returns false if the node
-  // doesn't exist.
-  bool IsMarkedReadyToRead(NodeId node_id) const;
-  // Mark the node as ready or not ready to read.  Returns true on success, or
-  // false if the node doesn't exist.
-  bool MarkReadyToRead(NodeId node_id);
-  bool MarkNoLongerReadyToRead(NodeId node_id);
-  // Return the ID of the next node that we should read, or return NodeId() if
-  // no node in the forest is ready to read.
-  NodeId NextNodeToRead();
-
-  // Check if a node is marked as ready to write.  Returns false if the node
-  // doesn't exist.
-  bool IsMarkedReadyToWrite(NodeId node_id) const;
-  // Mark the node as ready or not ready to write.  Returns true on success, or
-  // false if the node doesn't exist.
-  bool MarkReadyToWrite(NodeId node_id);
-  bool MarkNoLongerReadyToWrite(NodeId node_id);
-  // Return the ID of the next node that we should write, or return NodeId() if
-  // no node in the forest is ready to write.
-  NodeId NextNodeToWrite();
-
-  // Return true if all internal invariants hold (useful for unit tests).
-  // Unless there are bugs, this should always return true.
-  bool ValidateInvariantsForTests() const;
-
- private:
-  enum NodeType { ROOT_NODE, NONROOT_ORDERED, NONROOT_UNORDERED };
-  struct Node {
-    Node() : type(ROOT_NODE), flags(0), child() {
-      depends_on.priority = Priority();
-    }
-    NodeType type;
-    unsigned int flags;  // bitfield of flags
-    union {
-      Priority priority;  // used for root nodes
-      NodeId parent_id;  // used for non-root nodes
-    } depends_on;
-    NodeId child;  // node ID of child (or NodeId() for no child)
-  };
-
-  typedef base::hash_map<NodeId, Node> NodeMap;
-
-  // Constants for the Node.flags bitset:
-  // kReadToRead: set for nodes that are ready for reading
-  static const unsigned int kReadyToRead = (1 << 0);
-  // kReadToWrite: set for nodes that are ready for writing
-  static const unsigned int kReadyToWrite = (1 << 1);
-
-  // Common code for IsMarkedReadyToRead and IsMarkedReadyToWrite.
-  bool IsMarked(NodeId node_id, unsigned int flag) const;
-  // Common code for MarkReadyToRead and MarkReadyToWrite.
-  bool Mark(NodeId node_id, unsigned int flag);
-  // Common code for MarkNoLongerReadyToRead and MarkNoLongerReadyToWrite.
-  bool Unmark(NodeId node_id, unsigned int flag);
-  // Common code for NextNodeToRead and NextNodeToWrite;
-  NodeId FirstMarkedNode(unsigned int flag);
-  // Get the given node, or return NULL if it doesn't exist.
-  const Node* FindNode(NodeId node_id) const;
-
-  NodeMap all_nodes_;  // maps from node IDs to Node objects
-
-  DISALLOW_COPY_AND_ASSIGN(SpdyPriorityForest);
-};
-
-template <typename NodeId, typename Priority>
-SpdyPriorityForest<NodeId, Priority>::SpdyPriorityForest() {}
-
-template <typename NodeId, typename Priority>
-SpdyPriorityForest<NodeId, Priority>::~SpdyPriorityForest() {}
-
-template <typename NodeId, typename Priority>
-int SpdyPriorityForest<NodeId, Priority>::num_nodes() const {
-  return all_nodes_.size();
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::NodeExists(NodeId node_id) const {
-  return all_nodes_.count(node_id) != 0;
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::AddRootNode(
-    NodeId node_id, Priority priority) {
-  if (NodeExists(node_id)) {
-    return false;
-  }
-  Node* new_node = &all_nodes_[node_id];
-  new_node->type = ROOT_NODE;
-  new_node->depends_on.priority = priority;
-  return true;
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::AddNonRootNode(
-    NodeId node_id, NodeId parent_id, bool unordered) {
-  if (NodeExists(node_id) || !NodeExists(parent_id)) {
-    return false;
-  }
-
-  Node* parent = &all_nodes_[parent_id];
-  if (parent->child != NodeId()) {
-    return false;
-  }
-
-  Node* new_node = &all_nodes_[node_id];
-  new_node->type = (unordered ? NONROOT_UNORDERED : NONROOT_ORDERED);
-  new_node->depends_on.parent_id = parent_id;
-  parent->child = node_id;
-  return true;
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::RemoveNode(NodeId node_id) {
-  if (!NodeExists(node_id)) {
-    return false;
-  }
-  const Node& node = all_nodes_[node_id];
-
-  // If the node to be removed is not a root node, we need to change its
-  // parent's child ID.
-  if (node.type != ROOT_NODE) {
-    DCHECK(NodeExists(node.depends_on.parent_id));
-    Node* parent = &all_nodes_[node.depends_on.parent_id];
-    DCHECK_EQ(node_id, parent->child);
-    parent->child = node.child;
-  }
-
-  // If the node has a child, we need to change the child's priority or parent.
-  if (node.child != NodeId()) {
-    DCHECK(NodeExists(node.child));
-    Node* child = &all_nodes_[node.child];
-    DCHECK_NE(ROOT_NODE, child->type);
-    DCHECK_EQ(node_id, child->depends_on.parent_id);
-    // Make the child's new depends_on be the node's depends_on (whether that
-    // be a priority or a parent node ID).
-    child->depends_on = node.depends_on;
-    // If the removed node was a root, its child is now a root.  Otherwise, the
-    // child will be be unordered if and only if it was already unordered and
-    // the removed not is also not ordered.
-    if (node.type == ROOT_NODE) {
-      child->type = ROOT_NODE;
-    } else if (node.type == NONROOT_ORDERED) {
-      child->type = NONROOT_ORDERED;
-    }
-  }
-
-  // Delete the node.
-  all_nodes_.erase(node_id);
-  return true;
-}
-
-template <typename NodeId, typename Priority>
-Priority SpdyPriorityForest<NodeId, Priority>::GetPriority(
-    NodeId node_id) const {
-  const Node* node = FindNode(node_id);
-  if (node != NULL && node->type == ROOT_NODE) {
-    return node->depends_on.priority;
-  } else {
-    return Priority();
-  }
-}
-
-template <typename NodeId, typename Priority>
-NodeId SpdyPriorityForest<NodeId, Priority>::GetParent(NodeId node_id) const {
-  const Node* node = FindNode(node_id);
-  if (node != NULL && node->type != ROOT_NODE) {
-    return node->depends_on.parent_id;
-  } else {
-    return NodeId();
-  }
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::IsNodeUnordered(
-    NodeId node_id) const {
-  const Node* node = FindNode(node_id);
-  return node != NULL && node->type == NONROOT_UNORDERED;
-}
-
-template <typename NodeId, typename Priority>
-NodeId SpdyPriorityForest<NodeId, Priority>::GetChild(NodeId node_id) const {
-  const Node* node = FindNode(node_id);
-  if (node != NULL) {
-    return node->child;
-  } else {
-    return NodeId();
-  }
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::SetPriority(
-    NodeId node_id, Priority priority) {
-  if (!NodeExists(node_id)) {
-    return false;
-  }
-
-  Node* node = &all_nodes_[node_id];
-  // If this is not already a root node, we need to make it be a root node.
-  if (node->type != ROOT_NODE) {
-    DCHECK(NodeExists(node->depends_on.parent_id));
-    Node* parent = &all_nodes_[node->depends_on.parent_id];
-    parent->child = NodeId();
-    node->type = ROOT_NODE;
-  }
-
-  node->depends_on.priority = priority;
-  return true;
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::SetParent(
-    NodeId node_id, NodeId parent_id, bool unordered) {
-  if (!NodeExists(node_id) || !NodeExists(parent_id)) {
-    return false;
-  }
-
-  Node* node = &all_nodes_[node_id];
-  Node* new_parent = &all_nodes_[parent_id];
-  // If the new parent is already the node's parent, all we have to do is
-  // update the node type and we're done.
-  if (new_parent->child == node_id) {
-    node->type = (unordered ? NONROOT_UNORDERED : NONROOT_ORDERED);
-    return true;
-  }
-  // Otherwise, if the new parent already has a child, we fail.
-  if (new_parent->child != NodeId()) {
-    return false;
-  }
-
-  // Next, make sure we won't create a cycle.
-  if (node_id == parent_id) return false;
-  Node* last = node;
-  NodeId last_id = node_id;
-  while (last->child != NodeId()) {
-    if (last->child == parent_id) return false;
-    last_id = last->child;
-    DCHECK(NodeExists(last_id));
-    last = &all_nodes_[last_id];
-  }
-
-  // If the node is not a root, we need clear its old parent's child field
-  // (unless the old parent is the same as the new parent).
-  if (node->type != ROOT_NODE) {
-    const NodeId old_parent_id = node->depends_on.parent_id;
-    DCHECK(NodeExists(old_parent_id));
-    DCHECK(old_parent_id != parent_id);
-    Node* old_parent = &all_nodes_[old_parent_id];
-    DCHECK_EQ(node_id, old_parent->child);
-    old_parent->child = NodeId();
-  }
-
-  // Make the change.
-  node->type = (unordered ? NONROOT_UNORDERED : NONROOT_ORDERED);
-  node->depends_on.parent_id = parent_id;
-  new_parent->child = node_id;
-  return true;
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::IsMarkedReadyToRead(
-    NodeId node_id) const {
-  return IsMarked(node_id, kReadyToRead);
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::MarkReadyToRead(NodeId node_id) {
-  return Mark(node_id, kReadyToRead);
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::MarkNoLongerReadyToRead(
-    NodeId node_id) {
-  return Unmark(node_id, kReadyToRead);
-}
-
-template <typename NodeId, typename Priority>
-NodeId SpdyPriorityForest<NodeId, Priority>::NextNodeToRead() {
-  return FirstMarkedNode(kReadyToRead);
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::IsMarkedReadyToWrite(
-    NodeId node_id) const {
-  return IsMarked(node_id, kReadyToWrite);
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::MarkReadyToWrite(NodeId node_id) {
-  return Mark(node_id, kReadyToWrite);
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::MarkNoLongerReadyToWrite(
-    NodeId node_id) {
-  return Unmark(node_id, kReadyToWrite);
-}
-
-template <typename NodeId, typename Priority>
-NodeId SpdyPriorityForest<NodeId, Priority>::NextNodeToWrite() {
-  return FirstMarkedNode(kReadyToWrite);
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::IsMarked(
-    NodeId node_id, unsigned int flag) const {
-  const Node* node = FindNode(node_id);
-  return node != NULL && (node->flags & flag) != 0;
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::Mark(
-    NodeId node_id, unsigned int flag) {
-  if (!NodeExists(node_id)) {
-    return false;
-  }
-  all_nodes_[node_id].flags |= flag;
-  return true;
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::Unmark(
-    NodeId node_id, unsigned int flag) {
-  if (!NodeExists(node_id)) {
-    return false;
-  }
-  all_nodes_[node_id].flags &= ~flag;
-  return true;
-}
-
-template <typename NodeId, typename Priority>
-NodeId SpdyPriorityForest<NodeId, Priority>::FirstMarkedNode(
-    unsigned int flag) {
-  // TODO(mdsteele): This is an *incredibly* stupid brute force solution.
-
-  // Get all root nodes that have at least one marked child.
-  uint64 total_weight = 0;
-  std::map<uint64, NodeId> roots;  // maps cumulative weight to root node ID
-  for (typename NodeMap::const_iterator iter = all_nodes_.begin();
-       iter != all_nodes_.end(); ++iter) {
-    const NodeId root_id = iter->first;
-    const Node& root = iter->second;
-    if (root.type == ROOT_NODE) {
-      // See if there is at least one marked node in this root's chain.
-      for (const Node* node = &root; ; node = &all_nodes_[node->child]) {
-        if ((node->flags & flag) != 0) {
-          total_weight += static_cast<uint64>(root.depends_on.priority);
-          roots[total_weight] = root_id;
-          break;
-        }
-        if (node->child == NodeId()) {
-          break;
-        }
-        DCHECK(NodeExists(node->child));
-      }
-    }
-  }
-
-  // If there are no ready nodes, then return NodeId().
-  if (total_weight == 0) {
-    DCHECK(roots.empty());
-    return NodeId();
-  } else {
-    DCHECK(!roots.empty());
-  }
-
-  // Randomly select a tree to use.
-  typename std::map<uint64, NodeId>::const_iterator root_iter =
-      roots.upper_bound(base::RandGenerator(total_weight));
-  DCHECK(root_iter != roots.end());
-  const NodeId root_id = root_iter->second;
-
-  // Find the first node in the chain that is ready.
-  NodeId node_id = root_id;
-  while (true) {
-    DCHECK(NodeExists(node_id));
-    Node* node = &all_nodes_[node_id];
-    if ((node->flags & flag) != 0) {
-      // There might be more nodes that are ready and that are linked to this
-      // one in an unordered chain.  Find all of them, then pick one randomly.
-      std::vector<NodeId> group;
-      group.push_back(node_id);
-      for (Node* next = node; next->child != NodeId();) {
-        DCHECK(NodeExists(next->child));
-        Node *child = &all_nodes_[next->child];
-        DCHECK_NE(ROOT_NODE, child->type);
-        if (child->type != NONROOT_UNORDERED) {
-          break;
-        }
-        if ((child->flags & flag) != 0) {
-          group.push_back(next->child);
-        }
-        next = child;
-      }
-      return group[base::RandGenerator(group.size())];
-    }
-    node_id = node->child;
-  }
-}
-
-template <typename NodeId, typename Priority>
-const typename SpdyPriorityForest<NodeId, Priority>::Node*
-SpdyPriorityForest<NodeId, Priority>::FindNode(NodeId node_id) const {
-  typename NodeMap::const_iterator iter = all_nodes_.find(node_id);
-  if (iter == all_nodes_.end()) {
-    return NULL;
-  }
-  return &iter->second;
-}
-
-template <typename NodeId, typename Priority>
-bool SpdyPriorityForest<NodeId, Priority>::ValidateInvariantsForTests() const {
-  for (typename NodeMap::const_iterator iter = all_nodes_.begin();
-       iter != all_nodes_.end(); ++iter) {
-    const NodeId node_id = iter->first;
-    const Node& node = iter->second;
-    if (node.type != ROOT_NODE &&
-        (!NodeExists(node.depends_on.parent_id) ||
-         GetChild(node.depends_on.parent_id) != node_id)) {
-      return false;
-    }
-    if (node.child != NodeId()) {
-      if (!NodeExists(node.child) || node_id != GetParent(node.child)) {
-        return false;
-      }
-    }
-
-    NodeId child_id = node.child;
-    int count = 0;
-    while (child_id != NodeId()) {
-      if (count > num_nodes() || node_id == child_id) {
-        return false;
-      }
-      child_id = GetChild(child_id);
-      ++count;
-    }
-  }
-  return true;
-}
-
-}  // namespace net
-
-#endif  // NET_SPDY_SPDY_PRIORITY_FOREST_H_
diff --git a/net/spdy/spdy_priority_forest_test.cc b/net/spdy/spdy_priority_forest_test.cc
deleted file mode 100644
index 58b21d4..0000000
--- a/net/spdy/spdy_priority_forest_test.cc
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright (c) 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.
-
-#include "net/spdy/spdy_priority_forest.h"
-
-#include "base/basictypes.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-TEST(SpdyPriorityForestTest, AddAndRemoveNodes) {
-  SpdyPriorityForest<uint32,int16> forest;
-  EXPECT_EQ(0, forest.num_nodes());
-  EXPECT_FALSE(forest.NodeExists(1));
-
-  EXPECT_TRUE(forest.AddRootNode(1, 1000));
-  EXPECT_EQ(1, forest.num_nodes());
-  ASSERT_TRUE(forest.NodeExists(1));
-  EXPECT_EQ(1000, forest.GetPriority(1));
-  EXPECT_FALSE(forest.NodeExists(5));
-
-  EXPECT_TRUE(forest.AddRootNode(5, 50));
-  EXPECT_FALSE(forest.AddRootNode(5, 500));
-  EXPECT_EQ(2, forest.num_nodes());
-  EXPECT_TRUE(forest.NodeExists(1));
-  ASSERT_TRUE(forest.NodeExists(5));
-  EXPECT_EQ(50, forest.GetPriority(5));
-  EXPECT_FALSE(forest.NodeExists(13));
-
-  EXPECT_TRUE(forest.AddRootNode(13, 130));
-  EXPECT_EQ(3, forest.num_nodes());
-  EXPECT_TRUE(forest.NodeExists(1));
-  EXPECT_TRUE(forest.NodeExists(5));
-  ASSERT_TRUE(forest.NodeExists(13));
-  EXPECT_EQ(130, forest.GetPriority(13));
-
-  EXPECT_TRUE(forest.RemoveNode(5));
-  EXPECT_FALSE(forest.RemoveNode(5));
-  EXPECT_EQ(2, forest.num_nodes());
-  EXPECT_TRUE(forest.NodeExists(1));
-  EXPECT_FALSE(forest.NodeExists(5));
-  EXPECT_TRUE(forest.NodeExists(13));
-
-  // The parent node 19 doesn't exist, so this should fail:
-  EXPECT_FALSE(forest.AddNonRootNode(7, 19, false));
-  // This should succed, creating node 7:
-  EXPECT_TRUE(forest.AddNonRootNode(7, 13, false));
-  // Now node 7 already exists, so this should fail:
-  EXPECT_FALSE(forest.AddNonRootNode(7, 1, false));
-  // Node 13 already has a child (7), so this should fail:
-  EXPECT_FALSE(forest.AddNonRootNode(17, 13, false));
-
-  ASSERT_TRUE(forest.ValidateInvariantsForTests());
-}
-
-TEST(SpdyPriorityForestTest, SetParent) {
-  SpdyPriorityForest<uint32,int16> forest;
-  forest.AddRootNode(1, 1000);
-  forest.AddNonRootNode(2, 1, false);
-  forest.AddNonRootNode(3, 2, false);
-  forest.AddNonRootNode(5, 3, false);
-  forest.AddNonRootNode(7, 5, false);
-  forest.AddNonRootNode(9, 7, false);
-  forest.AddRootNode(11, 2000);
-  forest.AddNonRootNode(13, 11, false);
-  // We can't set the parent of a nonexistent node, or set the parent of an
-  // existing node to a nonexistent node.
-  EXPECT_FALSE(forest.SetParent(99, 13, false));
-  EXPECT_FALSE(forest.SetParent(5, 99, false));
-  // We can't make a node a child a node that already has a child:
-  EXPECT_FALSE(forest.SetParent(13, 7, false));
-  EXPECT_FALSE(forest.SetParent(3, 11, false));
-  // These would create cycles:
-  EXPECT_FALSE(forest.SetParent(11, 13, false));
-  EXPECT_FALSE(forest.SetParent(1, 9, false));
-  EXPECT_FALSE(forest.SetParent(3, 9, false));
-  // But this change is legit:
-  EXPECT_EQ(7u, forest.GetChild(5));
-  EXPECT_TRUE(forest.SetParent(7, 13, false));
-  EXPECT_EQ(0u, forest.GetChild(5));
-  EXPECT_EQ(13u, forest.GetParent(7));
-  EXPECT_EQ(7u, forest.GetChild(13));
-  // So is this change (now that 9 is no longer a descendant of 1):
-  EXPECT_TRUE(forest.SetParent(1, 9, false));
-  EXPECT_EQ(9u, forest.GetParent(1));
-  EXPECT_EQ(1u, forest.GetChild(9));
-  // We must allow setting the parent of a node to its same parent (even though
-  // that parent of course has a child already), so that we can change
-  // orderedness.
-  EXPECT_EQ(1u, forest.GetParent(2));
-  EXPECT_EQ(2u, forest.GetChild(1));
-  EXPECT_FALSE(forest.IsNodeUnordered(2));
-  EXPECT_TRUE(forest.SetParent(2, 1, true));
-  EXPECT_EQ(1u, forest.GetParent(2));
-  EXPECT_EQ(2u, forest.GetChild(1));
-  EXPECT_TRUE(forest.IsNodeUnordered(2));
-
-  ASSERT_TRUE(forest.ValidateInvariantsForTests());
-}
-
-TEST(SpdyPriorityForestTest, RemoveNodesFromMiddleOfChain) {
-  SpdyPriorityForest<uint32,int16> forest;
-  forest.AddRootNode(1, 1000);
-  forest.AddNonRootNode(2, 1, false);
-  forest.AddNonRootNode(3, 2, true);
-  forest.AddNonRootNode(5, 3, false);
-  forest.AddNonRootNode(7, 5, true);
-  forest.AddNonRootNode(9, 7, true);
-
-  // Remove a node from the middle, with unordered links on both sides.  The
-  // new merged link should also be unordered.
-  EXPECT_TRUE(forest.NodeExists(7));
-  EXPECT_EQ(7u, forest.GetChild(5));
-  EXPECT_EQ(7u, forest.GetParent(9));
-  EXPECT_TRUE(forest.IsNodeUnordered(9));
-  EXPECT_TRUE(forest.RemoveNode(7));
-  EXPECT_FALSE(forest.NodeExists(7));
-  EXPECT_EQ(9u, forest.GetChild(5));
-  EXPECT_EQ(5u, forest.GetParent(9));
-  EXPECT_TRUE(forest.IsNodeUnordered(9));
-
-  // Remove another node from the middle, with an unordered link on only one
-  // side.  The new merged link should be ordered.
-  EXPECT_TRUE(forest.NodeExists(2));
-  EXPECT_EQ(2u, forest.GetChild(1));
-  EXPECT_EQ(2u, forest.GetParent(3));
-  EXPECT_FALSE(forest.IsNodeUnordered(2));
-  EXPECT_TRUE(forest.IsNodeUnordered(3));
-  EXPECT_TRUE(forest.RemoveNode(2));
-  EXPECT_FALSE(forest.NodeExists(2));
-  EXPECT_EQ(3u, forest.GetChild(1));
-  EXPECT_EQ(1u, forest.GetParent(3));
-  EXPECT_FALSE(forest.IsNodeUnordered(3));
-
-  // Try removing the root.
-  EXPECT_TRUE(forest.NodeExists(1));
-  EXPECT_EQ(0u, forest.GetParent(1));
-  EXPECT_EQ(1000, forest.GetPriority(1));
-  EXPECT_EQ(1u, forest.GetParent(3));
-  EXPECT_EQ(0, forest.GetPriority(3));
-  EXPECT_TRUE(forest.RemoveNode(1));
-  EXPECT_FALSE(forest.NodeExists(1));
-  EXPECT_EQ(0u, forest.GetParent(3));
-  EXPECT_EQ(1000, forest.GetPriority(3));
-
-  // Now try removing the tail.
-  EXPECT_TRUE(forest.NodeExists(9));
-  EXPECT_EQ(9u, forest.GetChild(5));
-  EXPECT_TRUE(forest.RemoveNode(9));
-  EXPECT_FALSE(forest.NodeExists(9));
-  EXPECT_EQ(0u, forest.GetChild(5));
-
-  ASSERT_TRUE(forest.ValidateInvariantsForTests());
-}
-
-TEST(SpdyPriorityForestTest, MergeOrderedAndUnorderedLinks1) {
-  SpdyPriorityForest<uint32,int16> forest;
-  forest.AddRootNode(1, 1000);
-  forest.AddNonRootNode(2, 1, true);
-  forest.AddNonRootNode(3, 2, false);
-
-  EXPECT_EQ(2u, forest.GetChild(1));
-  EXPECT_EQ(3u, forest.GetChild(2));
-  EXPECT_EQ(1u, forest.GetParent(2));
-  EXPECT_EQ(2u, forest.GetParent(3));
-  EXPECT_TRUE(forest.IsNodeUnordered(2));
-  EXPECT_FALSE(forest.IsNodeUnordered(3));
-  EXPECT_TRUE(forest.RemoveNode(2));
-  EXPECT_FALSE(forest.NodeExists(2));
-  EXPECT_EQ(3u, forest.GetChild(1));
-  EXPECT_EQ(1u, forest.GetParent(3));
-  EXPECT_FALSE(forest.IsNodeUnordered(3));
-
-  ASSERT_TRUE(forest.ValidateInvariantsForTests());
-}
-
-TEST(SpdyPriorityForestTest, MergeOrderedAndUnorderedLinks2) {
-  SpdyPriorityForest<uint32,int16> forest;
-  forest.AddRootNode(1, 1000);
-  forest.AddNonRootNode(2, 1, false);
-  forest.AddNonRootNode(3, 2, true);
-
-  EXPECT_EQ(2u, forest.GetChild(1));
-  EXPECT_EQ(3u, forest.GetChild(2));
-  EXPECT_EQ(1u, forest.GetParent(2));
-  EXPECT_EQ(2u, forest.GetParent(3));
-  EXPECT_FALSE(forest.IsNodeUnordered(2));
-  EXPECT_TRUE(forest.IsNodeUnordered(3));
-  EXPECT_TRUE(forest.RemoveNode(2));
-  EXPECT_FALSE(forest.NodeExists(2));
-  EXPECT_EQ(3u, forest.GetChild(1));
-  EXPECT_EQ(1u, forest.GetParent(3));
-  EXPECT_FALSE(forest.IsNodeUnordered(3));
-
-  ASSERT_TRUE(forest.ValidateInvariantsForTests());
-}
-
-TEST(SpdyPriorityForestTest, WeightedSelectionOfForests) {
-  SpdyPriorityForest<uint32,int16> forest;
-  forest.AddRootNode(1, 10);
-  forest.AddRootNode(3, 20);
-  forest.AddRootNode(5, 70);
-  EXPECT_EQ(70, forest.GetPriority(5));
-  EXPECT_TRUE(forest.SetPriority(5, 40));
-  EXPECT_FALSE(forest.SetPriority(7, 80));
-  EXPECT_EQ(40, forest.GetPriority(5));
-  forest.AddNonRootNode(7, 3, false);
-  EXPECT_FALSE(forest.IsMarkedReadyToRead(1));
-  EXPECT_TRUE(forest.MarkReadyToRead(1));
-  EXPECT_TRUE(forest.IsMarkedReadyToRead(1));
-  EXPECT_TRUE(forest.MarkReadyToRead(5));
-  EXPECT_TRUE(forest.MarkReadyToRead(7));
-  EXPECT_FALSE(forest.MarkReadyToRead(99));
-
-  int counts[8] = {0};
-  for (int i = 0; i < 7000; ++i) {
-    const uint32 node_id = forest.NextNodeToRead();
-    ASSERT_TRUE(node_id == 1 || node_id == 5 || node_id == 7)
-        << "node_id is " << node_id;
-    ++counts[node_id];
-  }
-
-  // In theory, these could fail even if the weighted random selection is
-  // implemented correctly, but it's very unlikely.
-  EXPECT_GE(counts[1],  800); EXPECT_LE(counts[1], 1200);
-  EXPECT_GE(counts[7], 1600); EXPECT_LE(counts[7], 2400);
-  EXPECT_GE(counts[5], 3200); EXPECT_LE(counts[5], 4800);
-
-  // If we unmark all but one node, then we know for sure that that node will
-  // be selected next.
-  EXPECT_TRUE(forest.MarkNoLongerReadyToRead(1));
-  EXPECT_TRUE(forest.MarkNoLongerReadyToRead(7));
-  EXPECT_FALSE(forest.MarkNoLongerReadyToRead(99));
-  EXPECT_EQ(5u, forest.NextNodeToRead());
-
-  ASSERT_TRUE(forest.ValidateInvariantsForTests());
-}
-
-TEST(SpdyPriorityForestTest, SelectionBetweenUnorderedNodes) {
-  SpdyPriorityForest<uint32,int16> forest;
-  forest.AddRootNode(1, 1000);
-  forest.AddNonRootNode(2, 1, false);
-  forest.AddNonRootNode(3, 2, true);
-  forest.AddNonRootNode(4, 3, true);
-  forest.AddNonRootNode(5, 4, true);
-  forest.AddNonRootNode(6, 5, true);
-  forest.AddNonRootNode(7, 6, false);
-  EXPECT_FALSE(forest.IsMarkedReadyToWrite(2));
-  EXPECT_TRUE(forest.MarkReadyToWrite(2));
-  EXPECT_TRUE(forest.IsMarkedReadyToWrite(2));
-  EXPECT_TRUE(forest.MarkReadyToWrite(4));
-  EXPECT_TRUE(forest.MarkReadyToWrite(6));
-  EXPECT_TRUE(forest.MarkReadyToWrite(7));
-  EXPECT_FALSE(forest.MarkReadyToWrite(99));
-
-  int counts[8] = {0};
-  for (int i = 0; i < 6000; ++i) {
-    const uint32 node_id = forest.NextNodeToWrite();
-    ASSERT_TRUE(node_id == 2 || node_id == 4 || node_id == 6)
-        << "node_id is " << node_id;
-    ++counts[node_id];
-  }
-
-  // In theory, these could fail even if the random selection is implemented
-  // correctly, but it's very unlikely.
-  EXPECT_GE(counts[2], 1600); EXPECT_LE(counts[2], 2400);
-  EXPECT_GE(counts[4], 1600); EXPECT_LE(counts[4], 2400);
-  EXPECT_GE(counts[6], 1600); EXPECT_LE(counts[6], 2400);
-
-  // Once we unmark that group of nodes, the next node up should be node 7,
-  // which has an ordered dependency on said group.
-  EXPECT_TRUE(forest.MarkNoLongerReadyToWrite(2));
-  EXPECT_TRUE(forest.MarkNoLongerReadyToWrite(4));
-  EXPECT_TRUE(forest.MarkNoLongerReadyToWrite(6));
-  EXPECT_FALSE(forest.MarkNoLongerReadyToWrite(99));
-  EXPECT_EQ(7u, forest.NextNodeToWrite());
-
-  ASSERT_TRUE(forest.ValidateInvariantsForTests());
-}
-
-}  // namespace net
diff --git a/net/spdy/spdy_protocol.cc b/net/spdy/spdy_protocol.cc
index 58a6b2d..76e9c6e 100644
--- a/net/spdy/spdy_protocol.cc
+++ b/net/spdy/spdy_protocol.cc
@@ -842,9 +842,8 @@
 }
 
 SpdyAltSvcIR::SpdyAltSvcIR(SpdyStreamId stream_id)
-    : SpdyFrameWithStreamIdIR(stream_id),
-      max_age_(0),
-      port_(0) {}
+    : SpdyFrameWithStreamIdIR(stream_id) {
+}
 
 void SpdyAltSvcIR::Visit(SpdyFrameVisitor* visitor) const {
   return visitor->VisitAltSvc(*this);
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h
index 0301067..809acd6 100644
--- a/net/spdy/spdy_protocol.h
+++ b/net/spdy/spdy_protocol.h
@@ -23,6 +23,7 @@
 #include "base/strings/string_piece.h"
 #include "base/sys_byteorder.h"
 #include "net/base/net_export.h"
+#include "net/spdy/spdy_alt_svc_wire_format.h"
 #include "net/spdy/spdy_bitmasks.h"
 
 namespace net {
@@ -969,30 +970,30 @@
  public:
   explicit SpdyAltSvcIR(SpdyStreamId stream_id);
 
-  uint32 max_age() const { return max_age_; }
-  uint16 port() const { return port_; }
-  SpdyProtocolId protocol_id() const {
-    return protocol_id_;
-  }
-  std::string host() const { return host_; }
   std::string origin() const { return origin_; }
-
-  void set_max_age(uint32 max_age) { max_age_ = max_age; }
-  void set_port(uint16 port) { port_ = port; }
-  void set_protocol_id(SpdyProtocolId protocol_id) {
-    protocol_id_ = protocol_id;
+  const SpdyAltSvcWireFormat::AlternativeService& altsvc() const {
+    return altsvc_;
   }
-  void set_host(std::string host) { host_ = host; }
+  SpdyProtocolId protocol_id() const { return altsvc_.protocol_id; }
+  std::string host() const { return altsvc_.host; }
+  uint16 port() const { return altsvc_.port; }
+  uint32 max_age() const { return altsvc_.max_age; }
+  double p() const { return altsvc_.p; }
+
   void set_origin(std::string origin) { origin_ = origin; }
+  void set_protocol_id(SpdyProtocolId protocol_id) {
+    altsvc_.protocol_id = protocol_id;
+  }
+  void set_host(std::string host) { altsvc_.host = host; }
+  void set_port(uint16 port) { altsvc_.port = port; }
+  void set_max_age(uint32 max_age) { altsvc_.max_age = max_age; }
+  void set_p(double p) { altsvc_.p = p; }
 
   void Visit(SpdyFrameVisitor* visitor) const override;
 
  private:
-  uint32 max_age_;
-  uint16 port_;
-  SpdyProtocolId protocol_id_;
-  std::string host_;
   std::string origin_;
+  SpdyAltSvcWireFormat::AlternativeService altsvc_;
   DISALLOW_COPY_AND_ASSIGN(SpdyAltSvcIR);
 };
 
diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc
index 3f351b2..39fbd60 100644
--- a/net/spdy/spdy_proxy_client_socket.cc
+++ b/net/spdy/spdy_proxy_client_socket.cc
@@ -9,8 +9,11 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback_helpers.h"
+#include "base/location.h"
 #include "base/logging.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/base/auth.h"
 #include "net/base/io_buffer.h"
@@ -487,12 +490,10 @@
 
   // Proxy write callbacks result in deep callback chains. Post to allow the
   // stream's write callback chain to unwind (see crbug.com/355511).
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&SpdyProxyClientSocket::RunCallback,
-                 write_callback_weak_factory_.GetWeakPtr(),
-                 ResetAndReturn(&write_callback_),
-                 rv));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&SpdyProxyClientSocket::RunCallback,
+                            write_callback_weak_factory_.GetWeakPtr(),
+                            ResetAndReturn(&write_callback_), rv));
 }
 
 void SpdyProxyClientSocket::OnClose(int status)  {
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 69c5542..dab2aec 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -10,17 +10,19 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "crypto/ec_private_key.h"
@@ -771,10 +773,10 @@
   pool_ = pool;
 
   // Bootstrap the read loop.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(&SpdySession::PumpReadLoop,
-                 weak_factory_.GetWeakPtr(), READ_STATE_DO_READ, OK));
+      base::Bind(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(),
+                 READ_STATE_DO_READ, OK));
 }
 
 bool SpdySession::VerifyDomainAuthentication(const std::string& domain) {
@@ -976,11 +978,9 @@
     // Note that this post can race with other stream creations, and it's
     // possible that the un-stalled stream will be stalled again if it loses.
     // TODO(jgraettinger): Provide stronger ordering guarantees.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&SpdySession::CompleteStreamRequest,
-                   weak_factory_.GetWeakPtr(),
-                   pending_request));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&SpdySession::CompleteStreamRequest,
+                              weak_factory_.GetWeakPtr(), pending_request));
   }
 }
 
@@ -1391,10 +1391,10 @@
 
     if (bytes_read_without_yielding > kMaxReadBytesWithoutYielding) {
       read_state_ = READ_STATE_DO_READ;
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
-          base::Bind(&SpdySession::PumpReadLoop,
-                     weak_factory_.GetWeakPtr(), READ_STATE_DO_READ, OK));
+          base::Bind(&SpdySession::PumpReadLoop, weak_factory_.GetWeakPtr(),
+                     READ_STATE_DO_READ, OK));
       result = ERR_IO_PENDING;
       break;
     }
@@ -1906,10 +1906,10 @@
   if (write_state_ == WRITE_STATE_IDLE) {
     CHECK(!in_flight_write_);
     write_state_ = WRITE_STATE_DO_WRITE;
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(&SpdySession::PumpWriteLoop,
-                   weak_factory_.GetWeakPtr(), WRITE_STATE_DO_WRITE, OK));
+        base::Bind(&SpdySession::PumpWriteLoop, weak_factory_.GetWeakPtr(),
+                   WRITE_STATE_DO_WRITE, OK));
   }
 }
 
@@ -2933,10 +2933,10 @@
     return;
 
   check_ping_status_pending_ = true;
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(),
-                 time_func_()), hung_interval_);
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&SpdySession::CheckPingStatus,
+                            weak_factory_.GetWeakPtr(), time_func_()),
+      hung_interval_);
 }
 
 void SpdySession::CheckPingStatus(base::TimeTicks last_check_time) {
@@ -2959,10 +2959,9 @@
   }
 
   // Check the status of connection after a delay.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&SpdySession::CheckPingStatus, weak_factory_.GetWeakPtr(),
-                 now),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&SpdySession::CheckPingStatus,
+                            weak_factory_.GetWeakPtr(), now),
       delay);
 }
 
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index 0ffbeaf1..e9de936 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -6,11 +6,13 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/spdy/spdy_buffer_producer.h"
 #include "net/spdy/spdy_http_utils.h"
@@ -131,9 +133,8 @@
 
   if (io_state_ == STATE_HALF_CLOSED_LOCAL_UNCLAIMED) {
     DCHECK_EQ(type_, SPDY_PUSH_STREAM);
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&SpdyStream::PushedStreamReplay, GetWeakPtr()));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&SpdyStream::PushedStreamReplay, GetWeakPtr()));
   }
 }
 
diff --git a/net/ssl/channel_id_service.cc b/net/ssl/channel_id_service.cc
index 986b4f41..b9d53f5 100644
--- a/net/ssl/channel_id_service.cc
+++ b/net/ssl/channel_id_service.cc
@@ -15,11 +15,12 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "crypto/ec_private_key.h"
 #include "net/base/net_errors.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
@@ -108,64 +109,6 @@
 
 }  // namespace
 
-// Represents the output and result callback of a request.
-class ChannelIDServiceRequest {
- public:
-  ChannelIDServiceRequest(base::TimeTicks request_start,
-                          const CompletionCallback& callback,
-                          scoped_ptr<crypto::ECPrivateKey>* key)
-      : request_start_(request_start), callback_(callback), key_(key) {}
-
-  // Ensures that the result callback will never be made.
-  void Cancel() {
-    RecordGetChannelIDResult(ASYNC_CANCELLED);
-    callback_.Reset();
-  }
-
-  // Copies the contents of |key| to the caller's output argument and calls the
-  // callback.
-  void Post(int error, scoped_ptr<crypto::ECPrivateKey> key) {
-    switch (error) {
-      case OK: {
-        base::TimeDelta request_time = base::TimeTicks::Now() - request_start_;
-        UMA_HISTOGRAM_CUSTOM_TIMES("DomainBoundCerts.GetCertTimeAsync",
-                                   request_time,
-                                   base::TimeDelta::FromMilliseconds(1),
-                                   base::TimeDelta::FromMinutes(5),
-                                   50);
-        RecordGetChannelIDTime(request_time);
-        RecordGetChannelIDResult(ASYNC_SUCCESS);
-        break;
-      }
-      case ERR_KEY_GENERATION_FAILED:
-        RecordGetChannelIDResult(ASYNC_FAILURE_KEYGEN);
-        break;
-      case ERR_PRIVATE_KEY_EXPORT_FAILED:
-        RecordGetChannelIDResult(ASYNC_FAILURE_EXPORT_KEY);
-        break;
-      case ERR_INSUFFICIENT_RESOURCES:
-        RecordGetChannelIDResult(WORKER_FAILURE);
-        break;
-      default:
-        RecordGetChannelIDResult(ASYNC_FAILURE_UNKNOWN);
-        break;
-    }
-    if (!callback_.is_null()) {
-      if (key)
-        *key_ = key.Pass();
-      callback_.Run(error);
-    }
-    delete this;
-  }
-
-  bool canceled() const { return callback_.is_null(); }
-
- private:
-  base::TimeTicks request_start_;
-  CompletionCallback callback_;
-  scoped_ptr<crypto::ECPrivateKey>* key_;
-};
-
 // ChannelIDServiceWorker runs on a worker thread and takes care of the
 // blocking process of performing key generation. Will take care of deleting
 // itself once Start() is called.
@@ -176,19 +119,17 @@
       int,
       scoped_ptr<ChannelIDStore::ChannelID>)> WorkerDoneCallback;
 
-  ChannelIDServiceWorker(
-      const std::string& server_identifier,
-      const WorkerDoneCallback& callback)
+  ChannelIDServiceWorker(const std::string& server_identifier,
+                         const WorkerDoneCallback& callback)
       : server_identifier_(server_identifier),
-        origin_loop_(base::MessageLoopProxy::current()),
-        callback_(callback) {
-  }
+        origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+        callback_(callback) {}
 
   // Starts the worker on |task_runner|. If the worker fails to start, such as
   // if the task runner is shutting down, then it will take care of deleting
   // itself.
   bool Start(const scoped_refptr<base::TaskRunner>& task_runner) {
-    DCHECK(origin_loop_->RunsTasksOnCurrentThread());
+    DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
 
     return task_runner->PostTask(
         FROM_HERE,
@@ -211,13 +152,13 @@
     // destructors run.
     PR_DetachThread();
 #endif
-    origin_loop_->PostTask(FROM_HERE,
-                           base::Bind(callback_, server_identifier_, error,
-                                      base::Passed(&channel_id)));
+    origin_task_runner_->PostTask(
+        FROM_HERE, base::Bind(callback_, server_identifier_, error,
+                              base::Passed(&channel_id)));
   }
 
   const std::string server_identifier_;
-  scoped_refptr<base::SequencedTaskRunner> origin_loop_;
+  scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
   WorkerDoneCallback callback_;
 
   DISALLOW_COPY_AND_ASSIGN(ChannelIDServiceWorker);
@@ -225,19 +166,16 @@
 
 // A ChannelIDServiceJob is a one-to-one counterpart of an
 // ChannelIDServiceWorker. It lives only on the ChannelIDService's
-// origin message loop.
+// origin task runner's thread.
 class ChannelIDServiceJob {
  public:
   ChannelIDServiceJob(bool create_if_missing)
       : create_if_missing_(create_if_missing) {
   }
 
-  ~ChannelIDServiceJob() {
-    if (!requests_.empty())
-      DeleteAllCanceled();
-  }
+  ~ChannelIDServiceJob() { DCHECK(requests_.empty()); }
 
-  void AddRequest(ChannelIDServiceRequest* request,
+  void AddRequest(ChannelIDService::Request* request,
                   bool create_if_missing = false) {
     create_if_missing_ |= create_if_missing;
     requests_.push_back(request);
@@ -249,70 +187,98 @@
 
   bool CreateIfMissing() const { return create_if_missing_; }
 
+  void CancelRequest(ChannelIDService::Request* req) {
+    auto it = std::find(requests_.begin(), requests_.end(), req);
+    if (it != requests_.end())
+      requests_.erase(it);
+  }
+
  private:
   void PostAll(int error, scoped_ptr<crypto::ECPrivateKey> key) {
-    std::vector<ChannelIDServiceRequest*> requests;
+    std::vector<ChannelIDService::Request*> requests;
     requests_.swap(requests);
 
-    for (std::vector<ChannelIDServiceRequest*>::iterator
-         i = requests.begin(); i != requests.end(); i++) {
+    for (std::vector<ChannelIDService::Request*>::iterator i = requests.begin();
+         i != requests.end(); i++) {
       scoped_ptr<crypto::ECPrivateKey> key_copy;
       if (key)
         key_copy.reset(key->Copy());
       (*i)->Post(error, key_copy.Pass());
-      // Post() causes the ChannelIDServiceRequest to delete itself.
     }
   }
 
-  void DeleteAllCanceled() {
-    for (std::vector<ChannelIDServiceRequest*>::iterator
-         i = requests_.begin(); i != requests_.end(); i++) {
-      if ((*i)->canceled()) {
-        delete *i;
-      } else {
-        LOG(DFATAL) << "ChannelIDServiceRequest leaked!";
-      }
-    }
-  }
-
-  std::vector<ChannelIDServiceRequest*> requests_;
+  std::vector<ChannelIDService::Request*> requests_;
   bool create_if_missing_;
 };
 
 // static
 const char ChannelIDService::kEPKIPassword[] = "";
 
-ChannelIDService::RequestHandle::RequestHandle()
-    : service_(NULL),
-      request_(NULL) {}
+ChannelIDService::Request::Request() : service_(NULL) {
+}
 
-ChannelIDService::RequestHandle::~RequestHandle() {
+ChannelIDService::Request::~Request() {
   Cancel();
 }
 
-void ChannelIDService::RequestHandle::Cancel() {
-  if (request_) {
-    service_->CancelRequest(request_);
-    request_ = NULL;
+void ChannelIDService::Request::Cancel() {
+  if (service_) {
+    RecordGetChannelIDResult(ASYNC_CANCELLED);
     callback_.Reset();
+    job_->CancelRequest(this);
+
+    service_ = NULL;
   }
 }
 
-void ChannelIDService::RequestHandle::RequestStarted(
+void ChannelIDService::Request::RequestStarted(
     ChannelIDService* service,
-    ChannelIDServiceRequest* request,
-    const CompletionCallback& callback) {
-  DCHECK(request_ == NULL);
+    base::TimeTicks request_start,
+    const CompletionCallback& callback,
+    scoped_ptr<crypto::ECPrivateKey>* key,
+    ChannelIDServiceJob* job) {
+  DCHECK(service_ == NULL);
   service_ = service;
-  request_ = request;
+  request_start_ = request_start;
   callback_ = callback;
+  key_ = key;
+  job_ = job;
 }
 
-void ChannelIDService::RequestHandle::OnRequestComplete(int result) {
-  request_ = NULL;
-  // Running the callback might delete |this|, so we can't touch any of our
+void ChannelIDService::Request::Post(int error,
+                                     scoped_ptr<crypto::ECPrivateKey> key) {
+  switch (error) {
+    case OK: {
+      base::TimeDelta request_time = base::TimeTicks::Now() - request_start_;
+      UMA_HISTOGRAM_CUSTOM_TIMES("DomainBoundCerts.GetCertTimeAsync",
+                                 request_time,
+                                 base::TimeDelta::FromMilliseconds(1),
+                                 base::TimeDelta::FromMinutes(5), 50);
+      RecordGetChannelIDTime(request_time);
+      RecordGetChannelIDResult(ASYNC_SUCCESS);
+      break;
+    }
+    case ERR_KEY_GENERATION_FAILED:
+      RecordGetChannelIDResult(ASYNC_FAILURE_KEYGEN);
+      break;
+    case ERR_PRIVATE_KEY_EXPORT_FAILED:
+      RecordGetChannelIDResult(ASYNC_FAILURE_EXPORT_KEY);
+      break;
+    case ERR_INSUFFICIENT_RESOURCES:
+      RecordGetChannelIDResult(WORKER_FAILURE);
+      break;
+    default:
+      RecordGetChannelIDResult(ASYNC_FAILURE_UNKNOWN);
+      break;
+  }
+  service_ = NULL;
+  DCHECK(!callback_.is_null());
+  if (key)
+    *key_ = key.Pass();
+  // Running the callback might delete |this| (e.g. the callback cleans up
+  // resources created for the request), so we can't touch any of our
   // members afterwards. Reset callback_ first.
-  base::ResetAndReturn(&callback_).Run(result);
+  base::ResetAndReturn(&callback_).Run(error);
 }
 
 ChannelIDService::ChannelIDService(
@@ -345,7 +311,7 @@
     const std::string& host,
     scoped_ptr<crypto::ECPrivateKey>* key,
     const CompletionCallback& callback,
-    RequestHandle* out_req) {
+    Request* out_req) {
   DVLOG(1) << __FUNCTION__ << " " << host;
   DCHECK(CalledOnValidThread());
   base::TimeTicks request_start = base::TimeTicks::Now();
@@ -389,12 +355,8 @@
     ChannelIDServiceJob* job = new ChannelIDServiceJob(create_if_missing);
     inflight_[domain] = job;
 
-    ChannelIDServiceRequest* request = new ChannelIDServiceRequest(
-        request_start, base::Bind(&RequestHandle::OnRequestComplete,
-                                  base::Unretained(out_req)),
-        key);
-    job->AddRequest(request);
-    out_req->RequestStarted(this, request, callback);
+    job->AddRequest(out_req);
+    out_req->RequestStarted(this, request_start, callback, key, job);
     return ERR_IO_PENDING;
   }
 
@@ -404,7 +366,7 @@
 int ChannelIDService::GetChannelID(const std::string& host,
                                    scoped_ptr<crypto::ECPrivateKey>* key,
                                    const CompletionCallback& callback,
-                                   RequestHandle* out_req) {
+                                   Request* out_req) {
   DVLOG(1) << __FUNCTION__ << " " << host;
   DCHECK(CalledOnValidThread());
   base::TimeTicks request_start = base::TimeTicks::Now();
@@ -449,7 +411,7 @@
   if (err == OK) {
     // Async DB lookup found a valid channel ID.
     key_store_hits_++;
-    // ChannelIDServiceRequest::Post will do the histograms and stuff.
+    // ChannelIDService::Request::Post will do the histograms and stuff.
     HandleResult(OK, server_identifier, key.Pass());
     return;
   }
@@ -478,11 +440,6 @@
   return channel_id_store_.get();
 }
 
-void ChannelIDService::CancelRequest(ChannelIDServiceRequest* req) {
-  DCHECK(CalledOnValidThread());
-  req->Cancel();
-}
-
 void ChannelIDService::GeneratedChannelID(
     const std::string& server_identifier,
     int error,
@@ -521,7 +478,7 @@
     scoped_ptr<crypto::ECPrivateKey>* key,
     bool create_if_missing,
     const CompletionCallback& callback,
-    RequestHandle* out_req) {
+    Request* out_req) {
   ChannelIDServiceJob* job = NULL;
   std::map<std::string, ChannelIDServiceJob*>::const_iterator j =
       inflight_.find(domain);
@@ -532,12 +489,8 @@
     job = j->second;
     inflight_joins_++;
 
-    ChannelIDServiceRequest* request = new ChannelIDServiceRequest(
-        request_start, base::Bind(&RequestHandle::OnRequestComplete,
-                                  base::Unretained(out_req)),
-        key);
-    job->AddRequest(request, create_if_missing);
-    out_req->RequestStarted(this, request, callback);
+    job->AddRequest(out_req, create_if_missing);
+    out_req->RequestStarted(this, request_start, callback, key, job);
     return true;
   }
   return false;
@@ -548,7 +501,7 @@
                                       scoped_ptr<crypto::ECPrivateKey>* key,
                                       bool create_if_missing,
                                       const CompletionCallback& callback,
-                                      RequestHandle* out_req) {
+                                      Request* out_req) {
   // Check if a channel ID key already exists for this domain.
   int err = channel_id_store_->GetChannelID(
       domain, key, base::Bind(&ChannelIDService::GotChannelID,
@@ -570,12 +523,8 @@
     ChannelIDServiceJob* job = new ChannelIDServiceJob(create_if_missing);
     inflight_[domain] = job;
 
-    ChannelIDServiceRequest* request = new ChannelIDServiceRequest(
-        request_start, base::Bind(&RequestHandle::OnRequestComplete,
-                                  base::Unretained(out_req)),
-        key);
-    job->AddRequest(request);
-    out_req->RequestStarted(this, request, callback);
+    job->AddRequest(out_req);
+    out_req->RequestStarted(this, request_start, callback, key, job);
     return ERR_IO_PENDING;
   }
 
diff --git a/net/ssl/channel_id_service.h b/net/ssl/channel_id_service.h
index a622602..abb22fa 100644
--- a/net/ssl/channel_id_service.h
+++ b/net/ssl/channel_id_service.h
@@ -29,7 +29,6 @@
 namespace net {
 
 class ChannelIDServiceJob;
-class ChannelIDServiceRequest;
 class ChannelIDServiceWorker;
 
 // A class for creating and fetching Channel IDs.
@@ -39,29 +38,34 @@
 class NET_EXPORT ChannelIDService
     : NON_EXPORTED_BASE(public base::NonThreadSafe) {
  public:
-  class NET_EXPORT RequestHandle {
+  class NET_EXPORT Request {
    public:
-    RequestHandle();
-    ~RequestHandle();
+    Request();
+    ~Request();
 
     // Cancel the request.  Does nothing if the request finished or was already
     // cancelled.
     void Cancel();
 
-    bool is_active() const { return request_ != NULL; }
+    bool is_active() const { return !callback_.is_null(); }
 
    private:
     friend class ChannelIDService;
+    friend class ChannelIDServiceJob;
 
     void RequestStarted(ChannelIDService* service,
-                        ChannelIDServiceRequest* request,
-                        const CompletionCallback& callback);
+                        base::TimeTicks request_start,
+                        const CompletionCallback& callback,
+                        scoped_ptr<crypto::ECPrivateKey>* key,
+                        ChannelIDServiceJob* job);
 
-    void OnRequestComplete(int result);
+    void Post(int error, scoped_ptr<crypto::ECPrivateKey> key);
 
     ChannelIDService* service_;
-    ChannelIDServiceRequest* request_;
+    base::TimeTicks request_start_;
     CompletionCallback callback_;
+    scoped_ptr<crypto::ECPrivateKey>* key_;
+    ChannelIDServiceJob* job_;
   };
 
   // Password used on EncryptedPrivateKeyInfo data stored in EC private_key
@@ -94,13 +98,11 @@
   // could not be completed immediately, in which case the result code will
   // be passed to the callback when available.
   //
-  // |*out_req| will be initialized with a handle to the async request. This
-  // RequestHandle object must be cancelled or destroyed before the
-  // ChannelIDService is destroyed.
+  // |*out_req| will be initialized with a handle to the async request.
   int GetOrCreateChannelID(const std::string& host,
                            scoped_ptr<crypto::ECPrivateKey>* key,
                            const CompletionCallback& callback,
-                           RequestHandle* out_req);
+                           Request* out_req);
 
   // Fetches the channel ID for the specified host if one exists.
   // Returns OK if successful, ERR_FILE_NOT_FOUND if none exists, or an error
@@ -116,13 +118,11 @@
   // request arrives for the same domain, the GetChannelID request will
   // not complete until a new channel ID is created.
   //
-  // |*out_req| will be initialized with a handle to the async request. This
-  // RequestHandle object must be cancelled or destroyed before the
-  // ChannelIDService is destroyed.
+  // |*out_req| will be initialized with a handle to the async request.
   int GetChannelID(const std::string& host,
                    scoped_ptr<crypto::ECPrivateKey>* key,
                    const CompletionCallback& callback,
-                   RequestHandle* out_req);
+                   Request* out_req);
 
   // Returns the backing ChannelIDStore.
   ChannelIDStore* GetChannelIDStore();
@@ -135,11 +135,6 @@
   uint64 workers_created() const { return workers_created_; }
 
  private:
-  // Cancels the specified request. |req| is the handle stored by
-  // GetChannelID(). After a request is canceled, its completion
-  // callback will not be called.
-  void CancelRequest(ChannelIDServiceRequest* req);
-
   void GotChannelID(int err,
                     const std::string& server_identifier,
                     scoped_ptr<crypto::ECPrivateKey> key);
@@ -159,7 +154,7 @@
                              scoped_ptr<crypto::ECPrivateKey>* key,
                              bool create_if_missing,
                              const CompletionCallback& callback,
-                             RequestHandle* out_req);
+                             Request* out_req);
 
   // Looks for the channel ID for |domain| in this service's store.
   // Returns OK if it can be found synchronously, ERR_IO_PENDING if the
@@ -170,7 +165,7 @@
                       scoped_ptr<crypto::ECPrivateKey>* key,
                       bool create_if_missing,
                       const CompletionCallback& callback,
-                      RequestHandle* out_req);
+                      Request* out_req);
 
   scoped_ptr<ChannelIDStore> channel_id_store_;
   scoped_refptr<base::TaskRunner> task_runner_;
diff --git a/net/ssl/channel_id_service_unittest.cc b/net/ssl/channel_id_service_unittest.cc
index 4ecef89..2a2ec962 100644
--- a/net/ssl/channel_id_service_unittest.cc
+++ b/net/ssl/channel_id_service_unittest.cc
@@ -8,11 +8,13 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "crypto/ec_private_key.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -95,7 +97,7 @@
     crypto::ECPrivateKey* key) {
   if (err == OK)
     channel_id_count_ = 1;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(callback_, err, server_identifier_,
                  base::Passed(make_scoped_ptr(key ? key->Copy() : nullptr))));
@@ -104,10 +106,8 @@
 class ChannelIDServiceTest : public testing::Test {
  public:
   ChannelIDServiceTest()
-      : service_(new ChannelIDService(
-            new DefaultChannelIDStore(NULL),
-            base::MessageLoopProxy::current())) {
-  }
+      : service_(new ChannelIDService(new DefaultChannelIDStore(NULL),
+                                      base::ThreadTaskRunnerHandle::Get())) {}
 
  protected:
   scoped_ptr<ChannelIDService> service_;
@@ -137,15 +137,14 @@
 
   int error;
   TestCompletionCallback callback;
-  ChannelIDService::RequestHandle request_handle;
+  ChannelIDService::Request request;
 
   // Synchronous completion, because the store is initialized.
   scoped_ptr<crypto::ECPrivateKey> key;
   EXPECT_EQ(0, service_->channel_id_count());
-  error =
-      service_->GetChannelID(host, &key, callback.callback(), &request_handle);
+  error = service_->GetChannelID(host, &key, callback.callback(), &request);
   EXPECT_EQ(ERR_FILE_NOT_FOUND, error);
-  EXPECT_FALSE(request_handle.is_active());
+  EXPECT_FALSE(request.is_active());
   EXPECT_EQ(0, service_->channel_id_count());
   EXPECT_FALSE(key);
 }
@@ -155,35 +154,34 @@
 
   int error;
   TestCompletionCallback callback;
-  ChannelIDService::RequestHandle request_handle;
+  ChannelIDService::Request request;
 
   // Asynchronous completion.
   scoped_ptr<crypto::ECPrivateKey> key1;
   EXPECT_EQ(0, service_->channel_id_count());
   error = service_->GetOrCreateChannelID(host, &key1, callback.callback(),
-                                         &request_handle);
+                                         &request);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
+  EXPECT_TRUE(request.is_active());
   error = callback.WaitForResult();
   EXPECT_EQ(OK, error);
   EXPECT_EQ(1, service_->channel_id_count());
   EXPECT_TRUE(key1);
-  EXPECT_FALSE(request_handle.is_active());
+  EXPECT_FALSE(request.is_active());
 
   // Synchronous completion.
   scoped_ptr<crypto::ECPrivateKey> key2;
   error = service_->GetOrCreateChannelID(host, &key2, callback.callback(),
-                                         &request_handle);
-  EXPECT_FALSE(request_handle.is_active());
+                                         &request);
+  EXPECT_FALSE(request.is_active());
   EXPECT_EQ(OK, error);
   EXPECT_EQ(1, service_->channel_id_count());
   EXPECT_TRUE(KeysEqual(key1.get(), key2.get()));
 
   // Synchronous get.
   scoped_ptr<crypto::ECPrivateKey> key3;
-  error =
-      service_->GetChannelID(host, &key3, callback.callback(), &request_handle);
-  EXPECT_FALSE(request_handle.is_active());
+  error = service_->GetChannelID(host, &key3, callback.callback(), &request);
+  EXPECT_FALSE(request.is_active());
   EXPECT_EQ(OK, error);
   EXPECT_EQ(1, service_->channel_id_count());
   EXPECT_TRUE(KeysEqual(key1.get(), key3.get()));
@@ -196,15 +194,15 @@
 TEST_F(ChannelIDServiceTest, StoreChannelIDs) {
   int error;
   TestCompletionCallback callback;
-  ChannelIDService::RequestHandle request_handle;
+  ChannelIDService::Request request;
 
   std::string host1("encrypted.google.com");
   scoped_ptr<crypto::ECPrivateKey> key1;
   EXPECT_EQ(0, service_->channel_id_count());
   error = service_->GetOrCreateChannelID(host1, &key1, callback.callback(),
-                                         &request_handle);
+                                         &request);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
+  EXPECT_TRUE(request.is_active());
   error = callback.WaitForResult();
   EXPECT_EQ(OK, error);
   EXPECT_EQ(1, service_->channel_id_count());
@@ -212,9 +210,9 @@
   std::string host2("www.verisign.com");
   scoped_ptr<crypto::ECPrivateKey> key2;
   error = service_->GetOrCreateChannelID(host2, &key2, callback.callback(),
-                                         &request_handle);
+                                         &request);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
+  EXPECT_TRUE(request.is_active());
   error = callback.WaitForResult();
   EXPECT_EQ(OK, error);
   EXPECT_EQ(2, service_->channel_id_count());
@@ -222,9 +220,9 @@
   std::string host3("www.twitter.com");
   scoped_ptr<crypto::ECPrivateKey> key3;
   error = service_->GetOrCreateChannelID(host3, &key3, callback.callback(),
-                                         &request_handle);
+                                         &request);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
+  EXPECT_TRUE(request.is_active());
   error = callback.WaitForResult();
   EXPECT_EQ(OK, error);
   EXPECT_EQ(3, service_->channel_id_count());
@@ -241,21 +239,21 @@
 
   scoped_ptr<crypto::ECPrivateKey> key1;
   TestCompletionCallback callback1;
-  ChannelIDService::RequestHandle request_handle1;
+  ChannelIDService::Request request1;
 
   scoped_ptr<crypto::ECPrivateKey> key2;
   TestCompletionCallback callback2;
-  ChannelIDService::RequestHandle request_handle2;
+  ChannelIDService::Request request2;
 
   error = service_->GetOrCreateChannelID(host, &key1, callback1.callback(),
-                                         &request_handle1);
+                                         &request1);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle1.is_active());
+  EXPECT_TRUE(request1.is_active());
   // Should join with the original request.
   error = service_->GetOrCreateChannelID(host, &key2, callback2.callback(),
-                                         &request_handle2);
+                                         &request2);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle2.is_active());
+  EXPECT_TRUE(request2.is_active());
 
   error = callback1.WaitForResult();
   EXPECT_EQ(OK, error);
@@ -275,21 +273,20 @@
 
   scoped_ptr<crypto::ECPrivateKey> key1;
   TestCompletionCallback callback1;
-  ChannelIDService::RequestHandle request_handle1;
+  ChannelIDService::Request request1;
 
   scoped_ptr<crypto::ECPrivateKey> key2;
   TestCompletionCallback callback2;
-  ChannelIDService::RequestHandle request_handle2;
+  ChannelIDService::Request request2;
 
   error = service_->GetOrCreateChannelID(host, &key1, callback1.callback(),
-                                         &request_handle1);
+                                         &request1);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle1.is_active());
+  EXPECT_TRUE(request1.is_active());
   // Should join with the original request.
-  error = service_->GetChannelID(host, &key2, callback2.callback(),
-                                 &request_handle2);
+  error = service_->GetChannelID(host, &key2, callback2.callback(), &request2);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle2.is_active());
+  EXPECT_TRUE(request2.is_active());
 
   error = callback1.WaitForResult();
   EXPECT_EQ(OK, error);
@@ -308,14 +305,14 @@
   std::string host("encrypted.google.com");
   scoped_ptr<crypto::ECPrivateKey> key;
   int error;
-  ChannelIDService::RequestHandle request_handle;
+  ChannelIDService::Request request;
 
   error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest),
-                                         &request_handle);
+                                         &request);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
-  request_handle.Cancel();
-  EXPECT_FALSE(request_handle.is_active());
+  EXPECT_TRUE(request.is_active());
+  request.Cancel();
+  EXPECT_FALSE(request.is_active());
 
   // Wait for reply from ChannelIDServiceWorker to be posted back to the
   // ChannelIDService.
@@ -326,19 +323,21 @@
   EXPECT_EQ(1, service_->channel_id_count());
 }
 
-// Tests that destructing the RequestHandle cancels the request.
+// Tests that destructing the Request cancels the request.
 TEST_F(ChannelIDServiceTest, CancelRequestByHandleDestruction) {
   std::string host("encrypted.google.com");
   scoped_ptr<crypto::ECPrivateKey> key;
   int error;
-  {
-    ChannelIDService::RequestHandle request_handle;
+  scoped_ptr<ChannelIDService::Request> request(
+      new ChannelIDService::Request());
 
-    error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest),
-                                           &request_handle);
-    EXPECT_EQ(ERR_IO_PENDING, error);
-    EXPECT_TRUE(request_handle.is_active());
-  }
+  error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest),
+                                         request.get());
+  EXPECT_EQ(ERR_IO_PENDING, error);
+  EXPECT_TRUE(request->is_active());
+
+  // Delete the Request object.
+  request.reset();
 
   // Wait for reply from ChannelIDServiceWorker to be posted back to the
   // ChannelIDService.
@@ -353,15 +352,15 @@
   std::string host("encrypted.google.com");
   scoped_ptr<crypto::ECPrivateKey> key;
   int error;
-  ChannelIDService::RequestHandle request_handle;
+  ChannelIDService::Request request;
 
   error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest),
-                                         &request_handle);
+                                         &request);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
+  EXPECT_TRUE(request.is_active());
 
   // Cancel request and destroy the ChannelIDService.
-  request_handle.Cancel();
+  request.Cancel();
   service_.reset();
 
   // ChannelIDServiceWorker should not post anything back to the
@@ -384,13 +383,13 @@
   std::string host("encrypted.google.com");
   scoped_ptr<crypto::ECPrivateKey> key;
   int error;
-  ChannelIDService::RequestHandle request_handle;
+  ChannelIDService::Request request;
 
   error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest),
-                                         &request_handle);
+                                         &request);
   // If we got here without crashing or a valgrind error, it worked.
   ASSERT_EQ(ERR_INSUFFICIENT_RESOURCES, error);
-  EXPECT_FALSE(request_handle.is_active());
+  EXPECT_FALSE(request.is_active());
 }
 
 // Tests that simultaneous creation of different certs works.
@@ -400,32 +399,32 @@
   std::string host1("encrypted.google.com");
   scoped_ptr<crypto::ECPrivateKey> key1;
   TestCompletionCallback callback1;
-  ChannelIDService::RequestHandle request_handle1;
+  ChannelIDService::Request request1;
 
   std::string host2("foo.com");
   scoped_ptr<crypto::ECPrivateKey> key2;
   TestCompletionCallback callback2;
-  ChannelIDService::RequestHandle request_handle2;
+  ChannelIDService::Request request2;
 
   std::string host3("bar.com");
   scoped_ptr<crypto::ECPrivateKey> key3;
   TestCompletionCallback callback3;
-  ChannelIDService::RequestHandle request_handle3;
+  ChannelIDService::Request request3;
 
   error = service_->GetOrCreateChannelID(host1, &key1, callback1.callback(),
-                                         &request_handle1);
+                                         &request1);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle1.is_active());
+  EXPECT_TRUE(request1.is_active());
 
   error = service_->GetOrCreateChannelID(host2, &key2, callback2.callback(),
-                                         &request_handle2);
+                                         &request2);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle2.is_active());
+  EXPECT_TRUE(request2.is_active());
 
   error = service_->GetOrCreateChannelID(host3, &key3, callback3.callback(),
-                                         &request_handle3);
+                                         &request3);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle3.is_active());
+  EXPECT_TRUE(request3.is_active());
 
   error = callback1.WaitForResult();
   EXPECT_EQ(OK, error);
@@ -449,22 +448,22 @@
 TEST_F(ChannelIDServiceTest, AsyncStoreGetOrCreateNoChannelIDsInStore) {
   MockChannelIDStoreWithAsyncGet* mock_store =
       new MockChannelIDStoreWithAsyncGet();
-  service_ = scoped_ptr<ChannelIDService>(new ChannelIDService(
-      mock_store, base::MessageLoopProxy::current()));
+  service_ = scoped_ptr<ChannelIDService>(
+      new ChannelIDService(mock_store, base::ThreadTaskRunnerHandle::Get()));
 
   std::string host("encrypted.google.com");
 
   int error;
   TestCompletionCallback callback;
-  ChannelIDService::RequestHandle request_handle;
+  ChannelIDService::Request request;
 
   // Asynchronous completion with no certs in the store.
   scoped_ptr<crypto::ECPrivateKey> key;
   EXPECT_EQ(0, service_->channel_id_count());
-  error = service_->GetOrCreateChannelID(host, &key, callback.callback(),
-                                         &request_handle);
+  error =
+      service_->GetOrCreateChannelID(host, &key, callback.callback(), &request);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
+  EXPECT_TRUE(request.is_active());
 
   mock_store->CallGetChannelIDCallbackWithResult(ERR_FILE_NOT_FOUND, nullptr);
 
@@ -472,28 +471,27 @@
   EXPECT_EQ(OK, error);
   EXPECT_EQ(1, service_->channel_id_count());
   EXPECT_TRUE(key);
-  EXPECT_FALSE(request_handle.is_active());
+  EXPECT_FALSE(request.is_active());
 }
 
 TEST_F(ChannelIDServiceTest, AsyncStoreGetNoChannelIDsInStore) {
   MockChannelIDStoreWithAsyncGet* mock_store =
       new MockChannelIDStoreWithAsyncGet();
-  service_ = scoped_ptr<ChannelIDService>(new ChannelIDService(
-      mock_store, base::MessageLoopProxy::current()));
+  service_ = scoped_ptr<ChannelIDService>(
+      new ChannelIDService(mock_store, base::ThreadTaskRunnerHandle::Get()));
 
   std::string host("encrypted.google.com");
 
   int error;
   TestCompletionCallback callback;
-  ChannelIDService::RequestHandle request_handle;
+  ChannelIDService::Request request;
 
   // Asynchronous completion with no certs in the store.
   scoped_ptr<crypto::ECPrivateKey> key;
   EXPECT_EQ(0, service_->channel_id_count());
-  error =
-      service_->GetChannelID(host, &key, callback.callback(), &request_handle);
+  error = service_->GetChannelID(host, &key, callback.callback(), &request);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
+  EXPECT_TRUE(request.is_active());
 
   mock_store->CallGetChannelIDCallbackWithResult(ERR_FILE_NOT_FOUND, nullptr);
 
@@ -502,28 +500,28 @@
   EXPECT_EQ(0, service_->channel_id_count());
   EXPECT_EQ(0u, service_->workers_created());
   EXPECT_FALSE(key);
-  EXPECT_FALSE(request_handle.is_active());
+  EXPECT_FALSE(request.is_active());
 }
 
 TEST_F(ChannelIDServiceTest, AsyncStoreGetOrCreateOneCertInStore) {
   MockChannelIDStoreWithAsyncGet* mock_store =
       new MockChannelIDStoreWithAsyncGet();
-  service_ = scoped_ptr<ChannelIDService>(new ChannelIDService(
-      mock_store, base::MessageLoopProxy::current()));
+  service_ = scoped_ptr<ChannelIDService>(
+      new ChannelIDService(mock_store, base::ThreadTaskRunnerHandle::Get()));
 
   std::string host("encrypted.google.com");
 
   int error;
   TestCompletionCallback callback;
-  ChannelIDService::RequestHandle request_handle;
+  ChannelIDService::Request request;
 
   // Asynchronous completion with a cert in the store.
   scoped_ptr<crypto::ECPrivateKey> key;
   EXPECT_EQ(0, service_->channel_id_count());
-  error = service_->GetOrCreateChannelID(host, &key, callback.callback(),
-                                         &request_handle);
+  error =
+      service_->GetOrCreateChannelID(host, &key, callback.callback(), &request);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
+  EXPECT_TRUE(request.is_active());
 
   scoped_ptr<crypto::ECPrivateKey> expected_key(crypto::ECPrivateKey::Create());
   mock_store->CallGetChannelIDCallbackWithResult(OK, expected_key.get());
@@ -538,29 +536,28 @@
   EXPECT_EQ(0u, service_->workers_created());
   EXPECT_TRUE(key);
   EXPECT_TRUE(KeysEqual(expected_key.get(), key.get()));
-  EXPECT_FALSE(request_handle.is_active());
+  EXPECT_FALSE(request.is_active());
 }
 
 TEST_F(ChannelIDServiceTest, AsyncStoreGetOneCertInStore) {
   MockChannelIDStoreWithAsyncGet* mock_store =
       new MockChannelIDStoreWithAsyncGet();
-  service_ = scoped_ptr<ChannelIDService>(new ChannelIDService(
-      mock_store, base::MessageLoopProxy::current()));
+  service_ = scoped_ptr<ChannelIDService>(
+      new ChannelIDService(mock_store, base::ThreadTaskRunnerHandle::Get()));
 
   std::string host("encrypted.google.com");
 
   int error;
   TestCompletionCallback callback;
-  ChannelIDService::RequestHandle request_handle;
+  ChannelIDService::Request request;
 
   // Asynchronous completion with a cert in the store.
   scoped_ptr<crypto::ECPrivateKey> key;
   std::string private_key, spki;
   EXPECT_EQ(0, service_->channel_id_count());
-  error =
-      service_->GetChannelID(host, &key, callback.callback(), &request_handle);
+  error = service_->GetChannelID(host, &key, callback.callback(), &request);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
+  EXPECT_TRUE(request.is_active());
 
   scoped_ptr<crypto::ECPrivateKey> expected_key(crypto::ECPrivateKey::Create());
   mock_store->CallGetChannelIDCallbackWithResult(OK, expected_key.get());
@@ -574,14 +571,14 @@
   // created.
   EXPECT_EQ(0u, service_->workers_created());
   EXPECT_TRUE(KeysEqual(expected_key.get(), key.get()));
-  EXPECT_FALSE(request_handle.is_active());
+  EXPECT_FALSE(request.is_active());
 }
 
 TEST_F(ChannelIDServiceTest, AsyncStoreGetThenCreateNoCertsInStore) {
   MockChannelIDStoreWithAsyncGet* mock_store =
       new MockChannelIDStoreWithAsyncGet();
-  service_ = scoped_ptr<ChannelIDService>(new ChannelIDService(
-      mock_store, base::MessageLoopProxy::current()));
+  service_ = scoped_ptr<ChannelIDService>(
+      new ChannelIDService(mock_store, base::ThreadTaskRunnerHandle::Get()));
 
   std::string host("encrypted.google.com");
 
@@ -589,23 +586,22 @@
 
   // Asynchronous get with no certs in the store.
   TestCompletionCallback callback1;
-  ChannelIDService::RequestHandle request_handle1;
+  ChannelIDService::Request request1;
   scoped_ptr<crypto::ECPrivateKey> key1;
   EXPECT_EQ(0, service_->channel_id_count());
-  error = service_->GetChannelID(host, &key1, callback1.callback(),
-                                 &request_handle1);
+  error = service_->GetChannelID(host, &key1, callback1.callback(), &request1);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle1.is_active());
+  EXPECT_TRUE(request1.is_active());
 
   // Asynchronous get/create with no certs in the store.
   TestCompletionCallback callback2;
-  ChannelIDService::RequestHandle request_handle2;
+  ChannelIDService::Request request2;
   scoped_ptr<crypto::ECPrivateKey> key2;
   EXPECT_EQ(0, service_->channel_id_count());
   error = service_->GetOrCreateChannelID(host, &key2, callback2.callback(),
-                                         &request_handle2);
+                                         &request2);
   EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle2.is_active());
+  EXPECT_TRUE(request2.is_active());
 
   mock_store->CallGetChannelIDCallbackWithResult(ERR_FILE_NOT_FOUND, nullptr);
 
@@ -623,8 +619,8 @@
   EXPECT_EQ(1u, service_->inflight_joins());
   EXPECT_TRUE(key1);
   EXPECT_TRUE(KeysEqual(key1.get(), key2.get()));
-  EXPECT_FALSE(request_handle1.is_active());
-  EXPECT_FALSE(request_handle2.is_active());
+  EXPECT_FALSE(request1.is_active());
+  EXPECT_FALSE(request2.is_active());
 }
 
 }  // namespace
diff --git a/net/ssl/default_channel_id_store_unittest.cc b/net/ssl/default_channel_id_store_unittest.cc
index c51b332..fce807f 100644
--- a/net/ssl/default_channel_id_store_unittest.cc
+++ b/net/ssl/default_channel_id_store_unittest.cc
@@ -10,9 +10,12 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "crypto/ec_private_key.h"
 #include "net/base/net_errors.h"
 #include "net/test/channel_id_test_util.h"
@@ -93,7 +96,7 @@
         new DefaultChannelIDStore::ChannelID(it->second));
   }
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(loaded_callback, base::Passed(&channel_ids)));
 }
 
diff --git a/net/ssl/openssl_platform_key_win.cc b/net/ssl/openssl_platform_key_win.cc
index 6ee6b5a..d394f18 100644
--- a/net/ssl/openssl_platform_key_win.cc
+++ b/net/ssl/openssl_platform_key_win.cc
@@ -43,15 +43,14 @@
 namespace {
 
 using NCryptFreeObjectFunc = SECURITY_STATUS(WINAPI*)(NCRYPT_HANDLE);
-using NCryptSignHashFunc =
-    SECURITY_STATUS(WINAPI*)(NCRYPT_KEY_HANDLE,  // hKey
-                             VOID*,  // pPaddingInfo
-                             PBYTE,  // pbHashValue
-                             DWORD,  // cbHashValue
-                             PBYTE,  // pbSignature
-                             DWORD,  // cbSignature
-                             DWORD*,  // pcbResult
-                             DWORD);  // dwFlags
+using NCryptSignHashFunc = SECURITY_STATUS(WINAPI*)(NCRYPT_KEY_HANDLE,  // hKey
+                                                    VOID*,   // pPaddingInfo
+                                                    BYTE*,   // pbHashValue
+                                                    DWORD,   // cbHashValue
+                                                    BYTE*,   // pbSignature
+                                                    DWORD,   // cbSignature
+                                                    DWORD*,  // pcbResult
+                                                    DWORD);  // dwFlags
 
 class CNGFunctions {
  public:
@@ -196,7 +195,7 @@
   // correct size. Some smartcards are buggy and do not write to it on the
   // second call.
   ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()(
-      key, padding, const_cast<PBYTE>(in), in_len, out, signature_len,
+      key, padding, const_cast<BYTE*>(in), in_len, out, signature_len,
       &signature_len, flags);
   if (FAILED(ncrypt_status)) {
     LOG(ERROR) << "NCryptSignHash failed: " << ncrypt_status;
diff --git a/net/ssl/ssl_cipher_suite_names.cc b/net/ssl/ssl_cipher_suite_names.cc
index 87a3259..6a2dff1 100644
--- a/net/ssl/ssl_cipher_suite_names.cc
+++ b/net/ssl/ssl_cipher_suite_names.cc
@@ -349,7 +349,8 @@
                           uint16* cipher_suite) {
   int value = 0;
   if (cipher_string.size() == 6 &&
-      StartsWithASCII(cipher_string, "0x", false /* case insensitive */) &&
+      base::StartsWithASCII(cipher_string, "0x",
+                            false /* case insensitive */) &&
       base::HexStringToInt(cipher_string, &value)) {
     *cipher_suite = static_cast<uint16>(value);
     return true;
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc
index e747c94..e90ff2c 100644
--- a/net/test/embedded_test_server/embedded_test_server.cc
+++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -7,12 +7,14 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
 #include "base/process/process_metrics.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
@@ -194,7 +196,7 @@
 }
 
 void EmbeddedTestServer::InitializeOnIOThread() {
-  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+  DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
   DCHECK(!Started());
 
   SocketDescriptor socket_descriptor =
@@ -215,13 +217,13 @@
 }
 
 void EmbeddedTestServer::ListenOnIOThread() {
-  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+  DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
   DCHECK(Started());
   listen_socket_->ListenOnIOThread();
 }
 
 void EmbeddedTestServer::ShutdownOnIOThread() {
-  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+  DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
 
   listen_socket_.reset();
   STLDeleteContainerPairSecondPointers(connections_.begin(),
@@ -231,7 +233,7 @@
 
 void EmbeddedTestServer::HandleRequest(HttpConnection* connection,
                                scoped_ptr<HttpRequest> request) {
-  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+  DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
 
   bool request_handled = false;
 
@@ -261,7 +263,7 @@
 
 GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const {
   DCHECK(Started()) << "You must start the server first.";
-  DCHECK(StartsWithASCII(relative_url, "/", true /* case_sensitive */))
+  DCHECK(base::StartsWithASCII(relative_url, "/", true /* case_sensitive */))
       << relative_url;
   return base_url_.Resolve(relative_url);
 }
@@ -288,7 +290,7 @@
 void EmbeddedTestServer::DidAccept(
     StreamListenSocket* server,
     scoped_ptr<StreamListenSocket> connection) {
-  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+  DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
 
   HttpConnection* http_connection = new HttpConnection(
       connection.Pass(),
@@ -301,7 +303,7 @@
 void EmbeddedTestServer::DidRead(StreamListenSocket* connection,
                          const char* data,
                          int length) {
-  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+  DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
 
   HttpConnection* http_connection = FindConnection(connection);
   if (http_connection == NULL) {
@@ -312,7 +314,7 @@
 }
 
 void EmbeddedTestServer::DidClose(StreamListenSocket* connection) {
-  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+  DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
 
   HttpConnection* http_connection = FindConnection(connection);
   if (http_connection == NULL) {
@@ -325,7 +327,7 @@
 
 HttpConnection* EmbeddedTestServer::FindConnection(
     StreamListenSocket* socket) {
-  DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+  DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
 
   std::map<StreamListenSocket*, HttpConnection*>::iterator it =
       connections_.find(socket);
@@ -337,11 +339,12 @@
 
 bool EmbeddedTestServer::PostTaskToIOThreadAndWait(
     const base::Closure& closure) {
-  // Note that PostTaskAndReply below requires base::MessageLoopProxy::current()
-  // to return a loop for posting the reply task. However, in order to make
-  // EmbeddedTestServer universally usable, it needs to cope with the situation
-  // where it's running on a thread on which a message loop is not (yet)
-  // available or as has been destroyed already.
+  // Note that PostTaskAndReply below requires
+  // base::ThreadTaskRunnerHandle::Get() to return a task runner for posting
+  // the reply task. However, in order to make EmbeddedTestServer universally
+  // usable, it needs to cope with the situation where it's running on a thread
+  // on which a message loop is not (yet) available or as has been destroyed
+  // already.
   //
   // To handle this situation, create temporary message loop to support the
   // PostTaskAndReply operation if the current thread as no message loop.
@@ -350,8 +353,8 @@
     temporary_loop.reset(new base::MessageLoop());
 
   base::RunLoop run_loop;
-  if (!io_thread_->message_loop_proxy()->PostTaskAndReply(
-          FROM_HERE, closure, run_loop.QuitClosure())) {
+  if (!io_thread_->task_runner()->PostTaskAndReply(FROM_HERE, closure,
+                                                   run_loop.QuitClosure())) {
     return false;
   }
   run_loop.Run();
diff --git a/net/test/embedded_test_server/embedded_test_server_unittest.cc b/net/test/embedded_test_server/embedded_test_server_unittest.cc
index b5d72f2..7a47e9b2 100644
--- a/net/test/embedded_test_server/embedded_test_server_unittest.cc
+++ b/net/test/embedded_test_server/embedded_test_server_unittest.cc
@@ -5,6 +5,7 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
 #include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread.h"
 #include "net/http/http_response_headers.h"
@@ -55,8 +56,8 @@
     thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
     ASSERT_TRUE(io_thread_.StartWithOptions(thread_options));
 
-    request_context_getter_ = new TestURLRequestContextGetter(
-        io_thread_.message_loop_proxy());
+    request_context_getter_ =
+        new TestURLRequestContextGetter(io_thread_.task_runner());
 
     server_.reset(new EmbeddedTestServer);
     ASSERT_TRUE(server_->InitializeAndWaitUntilReady());
@@ -261,7 +262,7 @@
     base::Thread::Options thread_options;
     thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
     ASSERT_TRUE(io_thread.StartWithOptions(thread_options));
-    io_thread_runner = io_thread.message_loop_proxy();
+    io_thread_runner = io_thread.task_runner();
 
     scoped_ptr<base::MessageLoop> loop;
     if (message_loop_present_on_initialize_)
@@ -280,7 +281,7 @@
     scoped_ptr<URLFetcher> fetcher =
         URLFetcher::Create(server.GetURL("/test?q=foo"), URLFetcher::GET, this);
     fetcher->SetRequestContext(
-        new TestURLRequestContextGetter(loop->message_loop_proxy()));
+        new TestURLRequestContextGetter(loop->task_runner()));
     fetcher->Start();
     loop->Run();
     fetcher.reset();
diff --git a/net/test/embedded_test_server/tcp_listen_socket_unittest.cc b/net/test/embedded_test_server/tcp_listen_socket_unittest.cc
index ba803f33..662d46514 100644
--- a/net/test/embedded_test_server/tcp_listen_socket_unittest.cc
+++ b/net/test/embedded_test_server/tcp_listen_socket_unittest.cc
@@ -8,7 +8,9 @@
 #include <sys/types.h>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
 #include "base/sys_byteorder.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
@@ -35,7 +37,8 @@
   thread_->StartWithOptions(options);
   loop_ = reinterpret_cast<base::MessageLoopForIO*>(thread_->message_loop());
 
-  loop_->PostTask(FROM_HERE, base::Bind(&TCPListenSocketTester::Listen, this));
+  loop_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&TCPListenSocketTester::Listen, this));
 
   // verify Listen succeeded
   NextAction();
@@ -77,8 +80,8 @@
   NextAction();
   ASSERT_EQ(ACTION_CLOSE, last_action_.type());
 
-  loop_->PostTask(FROM_HERE,
-                  base::Bind(&TCPListenSocketTester::Shutdown, this));
+  loop_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&TCPListenSocketTester::Shutdown, this));
   NextAction();
   ASSERT_EQ(ACTION_SHUTDOWN, last_action_.type());
 
@@ -169,8 +172,8 @@
 }
 
 void TCPListenSocketTester::TestServerSend() {
-  loop_->PostTask(FROM_HERE,
-                  base::Bind(&TCPListenSocketTester::SendFromTester, this));
+  loop_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&TCPListenSocketTester::SendFromTester, this));
   NextAction();
   ASSERT_EQ(ACTION_SEND, last_action_.type());
   const int buf_len = 200;
@@ -196,8 +199,8 @@
   // Send multiple writes. Since no reading is occurring the data should be
   // buffered in TCPListenSocket.
   for (int i = 0; i < send_count; ++i) {
-    loop_->PostTask(FROM_HERE,
-                    base::Bind(&TCPListenSocketTester::SendFromTester, this));
+    loop_->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&TCPListenSocketTester::SendFromTester, this));
     NextAction();
     ASSERT_EQ(ACTION_SEND, last_action_.type());
   }
diff --git a/net/test/url_request/url_request_failed_job.cc b/net/test/url_request/url_request_failed_job.cc
index ce7ecb3..e4ac6a6 100644
--- a/net/test/url_request/url_request_failed_job.cc
+++ b/net/test/url_request/url_request_failed_job.cc
@@ -5,10 +5,12 @@
 #include "net/test/url_request/url_request_failed_job.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/net_errors.h"
 #include "net/base/url_util.h"
 #include "net/http/http_response_headers.h"
@@ -124,7 +126,7 @@
   DCHECK_EQ(READ_ASYNC, phase_);
   DCHECK_NE(ERR_IO_PENDING, net_error_);
 
-  base::MessageLoopProxy::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&URLRequestFailedJob::NotifyDone, weak_factory_.GetWeakPtr(),
                  URLRequestStatus(URLRequestStatus::FAILED, net_error_)));
diff --git a/net/test/url_request/url_request_mock_data_job.cc b/net/test/url_request/url_request_mock_data_job.cc
index 5425816..9549242 100644
--- a/net/test/url_request/url_request_mock_data_job.cc
+++ b/net/test/url_request/url_request_mock_data_job.cc
@@ -5,9 +5,11 @@
 #include "net/test/url_request/url_request_mock_data_job.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/io_buffer.h"
 #include "net/base/url_util.h"
 #include "net/http/http_request_headers.h"
@@ -94,7 +96,7 @@
 void URLRequestMockDataJob::Start() {
   // Start reading asynchronously so that all error reporting and data
   // callbacks happen as they would for network requests.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&URLRequestMockDataJob::StartAsync,
                             weak_factory_.GetWeakPtr()));
 }
diff --git a/net/test/url_request/url_request_slow_download_job.cc b/net/test/url_request/url_request_slow_download_job.cc
index d736097..2d9049f 100644
--- a/net/test/url_request/url_request_slow_download_job.cc
+++ b/net/test/url_request/url_request_slow_download_job.cc
@@ -6,10 +6,12 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
@@ -59,7 +61,7 @@
     URLRequestSlowDownloadJob::pending_requests_ = LAZY_INSTANCE_INITIALIZER;
 
 void URLRequestSlowDownloadJob::Start() {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&URLRequestSlowDownloadJob::StartAsync,
                             weak_factory_.GetWeakPtr()));
 }
@@ -115,9 +117,11 @@
 }
 
 void URLRequestSlowDownloadJob::StartAsync() {
-  if (LowerCaseEqualsASCII(kFinishDownloadUrl, request_->url().spec().c_str()))
+  if (base::LowerCaseEqualsASCII(kFinishDownloadUrl,
+                                 request_->url().spec().c_str()))
     URLRequestSlowDownloadJob::FinishPendingRequests();
-  if (LowerCaseEqualsASCII(kErrorDownloadUrl, request_->url().spec().c_str()))
+  if (base::LowerCaseEqualsASCII(kErrorDownloadUrl,
+                                 request_->url().spec().c_str()))
     URLRequestSlowDownloadJob::ErrorPendingRequests();
 
   NotifyHeadersComplete();
@@ -178,9 +182,10 @@
 bool URLRequestSlowDownloadJob::ReadRawData(IOBuffer* buf,
                                             int buf_size,
                                             int* bytes_read) {
-  if (LowerCaseEqualsASCII(kFinishDownloadUrl,
-                           request_->url().spec().c_str()) ||
-      LowerCaseEqualsASCII(kErrorDownloadUrl, request_->url().spec().c_str())) {
+  if (base::LowerCaseEqualsASCII(kFinishDownloadUrl,
+                                 request_->url().spec().c_str()) ||
+      base::LowerCaseEqualsASCII(kErrorDownloadUrl,
+                                 request_->url().spec().c_str())) {
     VLOG(10) << __FUNCTION__ << " called w/ kFinish/ErrorDownloadUrl.";
     *bytes_read = 0;
     return true;
@@ -196,7 +201,7 @@
       buffer_ = buf;
       buffer_size_ = buf_size;
       SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
-      base::MessageLoop::current()->PostDelayedTask(
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE, base::Bind(&URLRequestSlowDownloadJob::CheckDoneStatus,
                                 weak_factory_.GetWeakPtr()),
           base::TimeDelta::FromMilliseconds(100));
@@ -225,7 +230,7 @@
     NotifyDone(
         URLRequestStatus(URLRequestStatus::FAILED, ERR_CONNECTION_RESET));
   } else {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, base::Bind(&URLRequestSlowDownloadJob::CheckDoneStatus,
                               weak_factory_.GetWeakPtr()),
         base::TimeDelta::FromMilliseconds(100));
@@ -247,9 +252,10 @@
     HttpResponseInfo* info) const {
   // Send back mock headers.
   std::string raw_headers;
-  if (LowerCaseEqualsASCII(kFinishDownloadUrl,
-                           request_->url().spec().c_str()) ||
-      LowerCaseEqualsASCII(kErrorDownloadUrl, request_->url().spec().c_str())) {
+  if (base::LowerCaseEqualsASCII(kFinishDownloadUrl,
+                                 request_->url().spec().c_str()) ||
+      base::LowerCaseEqualsASCII(kErrorDownloadUrl,
+                                 request_->url().spec().c_str())) {
     raw_headers.append(
         "HTTP/1.1 200 OK\n"
         "Content-type: text/plain\n");
@@ -259,7 +265,8 @@
         "Content-type: application/octet-stream\n"
         "Cache-Control: max-age=0\n");
 
-    if (LowerCaseEqualsASCII(kKnownSizeUrl, request_->url().spec().c_str())) {
+    if (base::LowerCaseEqualsASCII(kKnownSizeUrl,
+                                   request_->url().spec().c_str())) {
       raw_headers.append(base::StringPrintf(
           "Content-Length: %d\n", kFirstDownloadSize + kSecondDownloadSize));
     }
diff --git a/net/tools/balsa/balsa_frame.cc b/net/tools/balsa/balsa_frame.cc
index d8590bb..1105c80 100644
--- a/net/tools/balsa/balsa_frame.cc
+++ b/net/tools/balsa/balsa_frame.cc
@@ -21,7 +21,6 @@
 #include <vector>
 
 #include "base/logging.h"
-#include "base/port.h"
 #include "base/strings/string_piece.h"
 #include "net/tools/balsa/balsa_enums.h"
 #include "net/tools/balsa/balsa_headers.h"
diff --git a/net/tools/balsa/balsa_frame.h b/net/tools/balsa/balsa_frame.h
index 5198dd18..27f27ea 100644
--- a/net/tools/balsa/balsa_frame.h
+++ b/net/tools/balsa/balsa_frame.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
-#include "base/port.h"
 #include "net/tools/balsa/balsa_enums.h"
 #include "net/tools/balsa/balsa_headers.h"
 #include "net/tools/balsa/balsa_visitor_interface.h"
diff --git a/net/tools/balsa/balsa_headers.cc b/net/tools/balsa/balsa_headers.cc
index c1daa42..1bb684a 100644
--- a/net/tools/balsa/balsa_headers.cc
+++ b/net/tools/balsa/balsa_headers.cc
@@ -12,7 +12,6 @@
 
 #include "base/containers/hash_tables.h"
 #include "base/logging.h"
-#include "base/port.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "net/tools/balsa/balsa_enums.h"
diff --git a/net/tools/balsa/balsa_headers.h b/net/tools/balsa/balsa_headers.h
index 72f90c7..3edcf677 100644
--- a/net/tools/balsa/balsa_headers.h
+++ b/net/tools/balsa/balsa_headers.h
@@ -13,7 +13,6 @@
 #include <vector>
 
 #include "base/logging.h"
-#include "base/port.h"
 #include "base/strings/string_piece.h"
 #include "net/tools/balsa/balsa_enums.h"
 #include "net/tools/balsa/string_piece_utils.h"
diff --git a/net/tools/balsa/string_piece_utils.h b/net/tools/balsa/string_piece_utils.h
index 12fc69b..cab48fb 100644
--- a/net/tools/balsa/string_piece_utils.h
+++ b/net/tools/balsa/string_piece_utils.h
@@ -7,7 +7,6 @@
 
 #include <ctype.h>
 
-#include "base/port.h"
 #include "base/strings/string_piece.h"
 
 namespace net {
diff --git a/net/tools/crash_cache/crash_cache.cc b/net/tools/crash_cache/crash_cache.cc
index 34eaafa..2b518036 100644
--- a/net/tools/crash_cache/crash_cache.cc
+++ b/net/tools/crash_cache/crash_cache.cc
@@ -139,8 +139,8 @@
                  disk_cache::Backend** cache,
                  net::TestCompletionCallback* cb) {
   int size = 1024 * 1024;
-  disk_cache::BackendImpl* backend = new disk_cache::BackendImpl(
-      path, thread->message_loop_proxy().get(), NULL);
+  disk_cache::BackendImpl* backend =
+      new disk_cache::BackendImpl(path, thread->task_runner().get(), NULL);
   backend->SetMaxSize(size);
   backend->SetType(net::DISK_CACHE);
   backend->SetFlags(disk_cache::kNoRandom);
@@ -266,7 +266,7 @@
 
   // Work with a tiny index table (16 entries).
   disk_cache::BackendImpl* cache = new disk_cache::BackendImpl(
-      path, 0xf, cache_thread->message_loop_proxy().get(), NULL);
+      path, 0xf, cache_thread->task_runner().get(), NULL);
   if (!cache->SetMaxSize(0x100000))
     return GENERIC;
 
diff --git a/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc b/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc
index f129ef2..745a032 100644
--- a/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc
+++ b/net/tools/disk_cache_memory_test/disk_cache_memory_test.cc
@@ -16,13 +16,12 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/cache_type.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/disk_cache.h"
@@ -97,7 +96,7 @@
       base::Unretained(&succeeded));
   const int net_error = CreateCacheBackend(
       spec.cache_type, spec.backend_type, spec.path, 0, false,
-      base::MessageLoopProxy::current(), NULL, &backend, callback);
+      base::ThreadTaskRunnerHandle::Get(), NULL, &backend, callback);
   if (net_error == net::OK)
     callback.Run(net::OK);
   else
diff --git a/net/tools/dump_cache/simple_cache_dumper.cc b/net/tools/dump_cache/simple_cache_dumper.cc
index dd5ecbf..948de6a 100644
--- a/net/tools/dump_cache/simple_cache_dumper.cc
+++ b/net/tools/dump_cache/simple_cache_dumper.cc
@@ -9,7 +9,6 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/threading/thread.h"
 #include "net/base/cache_type.h"
 #include "net/base/io_buffer.h"
@@ -122,15 +121,8 @@
   DCHECK(!cache_);
   state_ = STATE_CREATE_CACHE_COMPLETE;
   return disk_cache::CreateCacheBackend(
-      DISK_CACHE,
-      CACHE_BACKEND_DEFAULT,
-      input_path_,
-      0,
-      false,
-      cache_thread_->message_loop_proxy().get(),
-      NULL,
-      &cache_,
-      io_callback_);
+      DISK_CACHE, CACHE_BACKEND_DEFAULT, input_path_, 0, false,
+      cache_thread_->task_runner().get(), NULL, &cache_, io_callback_);
 }
 
 int SimpleCacheDumper::DoCreateCacheComplete(int rv) {
diff --git a/net/tools/gdig/gdig.cc b/net/tools/gdig/gdig.cc
index 285668b5..634c3979b 100644
--- a/net/tools/gdig/gdig.cc
+++ b/net/tools/gdig/gdig.cc
@@ -11,13 +11,16 @@
 #include "base/cancelable_callback.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/address_list.h"
 #include "net/base/ip_endpoint.h"
@@ -389,7 +392,7 @@
                                                base::Unretained(this)));
     timeout_closure_.Reset(base::Bind(&GDig::OnTimeout,
                                       base::Unretained(this)));
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, timeout_closure_.callback(), config_timeout_);
   }
 }
@@ -445,9 +448,8 @@
     const ReplayLogEntry& entry = replay_log_[replay_log_index_];
     if (time_since_start < entry.start_time) {
       // Delay call to next time and return.
-      base::MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          base::Bind(&GDig::ReplayNextEntry, base::Unretained(this)),
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+          FROM_HERE, base::Bind(&GDig::ReplayNextEntry, base::Unretained(this)),
           entry.start_time - time_since_start);
       return;
     }
diff --git a/net/tools/get_server_time/get_server_time.cc b/net/tools/get_server_time/get_server_time.cc
index fe1c124..abf759e 100644
--- a/net/tools/get_server_time/get_server_time.cc
+++ b/net/tools/get_server_time/get_server_time.cc
@@ -240,7 +240,7 @@
       // The URLFetcher will take a reference on the object, and hence
       // implicitly take ownership.
       new net::TrivialURLRequestContextGetter(url_request_context.get(),
-                                              main_loop.message_loop_proxy()));
+                                              main_loop.task_runner()));
   const base::Time start_time = base::Time::Now();
   const base::TimeTicks start_ticks = base::TimeTicks::Now();
 
diff --git a/net/tools/net_watcher/net_watcher.cc b/net/tools/net_watcher/net_watcher.cc
index 02c373a..03d8d93 100644
--- a/net/tools/net_watcher/net_watcher.cc
+++ b/net/tools/net_watcher/net_watcher.cc
@@ -187,8 +187,7 @@
   // Use the network loop as the file loop also.
   scoped_ptr<net::ProxyConfigService> proxy_config_service(
       net::ProxyService::CreateSystemProxyConfigService(
-          network_loop.message_loop_proxy(),
-          network_loop.message_loop_proxy()));
+          network_loop.task_runner(), network_loop.task_runner()));
 
   // Uses |network_change_notifier|.
   net::NetworkChangeNotifier::AddIPAddressObserver(&net_watcher);
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index a2c95225..430dbe03 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -657,8 +657,7 @@
   string body;
   GenerateBody(&body, 20480);
 
-  HTTPMessage request(HttpConstants::HTTP_1_1,
-                      HttpConstants::POST, "/foo");
+  HTTPMessage request(HttpConstants::HTTP_1_1, HttpConstants::POST, "/foo");
   request.AddBody(body, true);
 
   EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index 30236df..24ce0007 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -195,6 +195,14 @@
   return session_->connection()->connected();
 }
 
+QuicClientSession* QuicClient::CreateQuicClientSession(
+    const QuicConfig& config,
+    QuicConnection* connection,
+    const QuicServerId& server_id,
+    QuicCryptoClientConfig* crypto_config) {
+  return new QuicClientSession(config, connection, server_id_, &crypto_config_);
+}
+
 void QuicClient::StartConnect() {
   DCHECK(initialized_);
   DCHECK(!connected());
@@ -203,19 +211,20 @@
 
   DummyPacketWriterFactory factory(writer);
 
-  session_.reset(new QuicClientSession(
+  session_.reset(CreateQuicClientSession(
       config_,
       new QuicConnection(GenerateConnectionId(), server_address_, helper_.get(),
                          factory,
                          /* owns_writer= */ false, Perspective::IS_CLIENT,
-                         server_id_.is_https(), supported_versions_)));
+                         server_id_.is_https(), supported_versions_),
+      server_id_, &crypto_config_));
 
   // Reset |writer_| after |session_| so that the old writer outlives the old
   // session.
   if (writer_.get() != writer) {
     writer_.reset(writer);
   }
-  session_->InitializeSession(server_id_, &crypto_config_);
+  session_->Initialize();
   session_->CryptoConnect();
 }
 
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index dc9abe7..fd511cc 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -199,6 +199,12 @@
                          IPEndPoint* server_address,
                          IPAddressNumber* client_ip);
 
+  virtual QuicClientSession* CreateQuicClientSession(
+      const QuicConfig& config,
+      QuicConnection* connection,
+      const QuicServerId& server_id,
+      QuicCryptoClientConfig* crypto_config);
+
   EpollServer* epoll_server() { return epoll_server_; }
 
   // If the socket has been created, then unregister and close() the FD.
diff --git a/net/tools/quic/quic_client_session.cc b/net/tools/quic/quic_client_session.cc
index 92eec04..0b99420 100644
--- a/net/tools/quic/quic_client_session.cc
+++ b/net/tools/quic/quic_client_session.cc
@@ -15,21 +15,18 @@
 namespace tools {
 
 QuicClientSession::QuicClientSession(const QuicConfig& config,
-                                     QuicConnection* connection)
-    : QuicClientSessionBase(connection, config), respect_goaway_(true) {
+                                     QuicConnection* connection,
+                                     const QuicServerId& server_id,
+                                     QuicCryptoClientConfig* crypto_config)
+    : QuicClientSessionBase(connection, config),
+      crypto_stream_(
+          new QuicCryptoClientStream(server_id, this, nullptr, crypto_config)),
+      respect_goaway_(true) {
 }
 
 QuicClientSession::~QuicClientSession() {
 }
 
-void QuicClientSession::InitializeSession(
-    const QuicServerId& server_id,
-    QuicCryptoClientConfig* crypto_config) {
-  crypto_stream_.reset(
-      new QuicCryptoClientStream(server_id, this, nullptr, crypto_config));
-  QuicClientSessionBase::InitializeSession();
-}
-
 void QuicClientSession::OnProofValid(
     const QuicCryptoClientConfig::CachedState& /*cached*/) {}
 
diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h
index 3438a23..3722868b 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -25,12 +25,12 @@
 
 class QuicClientSession : public QuicClientSessionBase {
  public:
-  QuicClientSession(const QuicConfig& config, QuicConnection* connection);
+  QuicClientSession(const QuicConfig& config,
+                    QuicConnection* connection,
+                    const QuicServerId& server_id,
+                    QuicCryptoClientConfig* crypto_config);
   ~QuicClientSession() override;
 
-  void InitializeSession(const QuicServerId& server_id,
-                         QuicCryptoClientConfig* config);
-
   // QuicSession methods:
   QuicSpdyClientStream* CreateOutgoingDataStream() override;
   QuicCryptoClientStream* GetCryptoStream() override;
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 6dc80a0..d7f4101 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -45,10 +45,11 @@
   ToolsQuicClientSessionTest()
       : connection_(new PacketSavingConnection(Perspective::IS_CLIENT,
                                                SupportedVersions(GetParam()))) {
-    session_.reset(new QuicClientSession(DefaultQuicConfig(), connection_));
-    session_->InitializeSession(
+    session_.reset(new QuicClientSession(
+        DefaultQuicConfig(), connection_,
         QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
-        &crypto_config_);
+        &crypto_config_));
+    session_->Initialize();
     // Advance the time, because timers do not like uninitialized times.
     connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 9447c22..71031f7 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -470,8 +470,9 @@
       /* owns_writer= */ true, Perspective::IS_SERVER,
       crypto_config_->HasProofSource(), supported_versions_);
 
-  QuicServerSession* session = new QuicServerSession(config_, connection, this);
-  session->InitializeSession(crypto_config_);
+  QuicServerSession* session =
+      new QuicServerSession(config_, connection, this, crypto_config_);
+  session->Initialize();
   if (FLAGS_quic_session_map_threshold_for_stateless_rejects != -1 &&
       session_map_.size() >=
           static_cast<size_t>(
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 95b0030f..bf942109 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -46,8 +46,11 @@
 
 class TestServerSession : public QuicServerSession {
  public:
-  TestServerSession(const QuicConfig& config, QuicConnection* connection)
-      : QuicServerSession(config, connection, nullptr) {}
+  TestServerSession(const QuicConfig& config,
+                    QuicConnection* connection,
+                    const QuicCryptoServerConfig* crypto_config)
+      : QuicServerSession(config, connection, nullptr, crypto_config),
+        crypto_stream_(QuicServerSession::GetCryptoStream()) {}
   ~TestServerSession() override{};
 
   MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer));
@@ -110,10 +113,11 @@
                                  const QuicConfig& config,
                                  QuicConnectionId connection_id,
                                  const IPEndPoint& client_address,
+                                 const QuicCryptoServerConfig* crypto_config,
                                  TestServerSession** session) {
   MockServerConnection* connection =
       new MockServerConnection(connection_id, dispatcher);
-  *session = new TestServerSession(config, connection);
+  *session = new TestServerSession(config, connection, crypto_config);
   connection->set_visitor(*session);
   ON_CALL(*connection, SendConnectionClose(_)).WillByDefault(
       WithoutArgs(Invoke(
@@ -209,15 +213,17 @@
   server_address_ = IPEndPoint(net::test::Any4(), 5);
 
   EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, client_address))
-      .WillOnce(testing::Return(
-          CreateSession(&dispatcher_, config_, 1, client_address, &session1_)));
+      .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 1,
+                                              client_address, &crypto_config_,
+                                              &session1_)));
   ProcessPacket(client_address, 1, true, "foo");
   EXPECT_EQ(client_address, dispatcher_.current_client_address());
   EXPECT_EQ(server_address_, dispatcher_.current_server_address());
 
   EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, client_address))
-      .WillOnce(testing::Return(
-          CreateSession(&dispatcher_, config_, 2, client_address, &session2_)));
+      .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 2,
+                                              client_address, &crypto_config_,
+                                              &session2_)));
   ProcessPacket(client_address, 2, true, "bar");
 
   EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
@@ -231,8 +237,9 @@
   IPEndPoint client_address(net::test::Loopback4(), 1);
 
   EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
-      .WillOnce(testing::Return(
-          CreateSession(&dispatcher_, config_, 1, client_address, &session1_)));
+      .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 1,
+                                              client_address, &crypto_config_,
+                                              &session1_)));
 
   ProcessPacket(client_address, 1, true, "foo");
 
@@ -249,8 +256,9 @@
   IPEndPoint client_address(net::test::Loopback4(), 1);
   QuicConnectionId connection_id = 1;
   EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, _, client_address))
-      .WillOnce(testing::Return(CreateSession(
-          &dispatcher_, config_, connection_id, client_address, &session1_)));
+      .WillOnce(testing::Return(CreateSession(&dispatcher_, config_,
+                                              connection_id, client_address,
+                                              &crypto_config_, &session1_)));
   ProcessPacket(client_address, connection_id, true, "foo");
 
   // Close the connection by sending public reset packet.
@@ -401,7 +409,7 @@
       QuicConnectionId connection_id,
       const IPEndPoint& client_address) {
     CreateSession(&dispatcher_, config_, connection_id, client_address,
-                  &session1_);
+                  &crypto_config_, &session1_);
 
     crypto_stream1_ = new MockQuicCryptoServerStream(crypto_config_, session1_);
     session1_->SetCryptoStream(crypto_stream1_);
@@ -437,8 +445,9 @@
   server_address_ = IPEndPoint(net::test::Any4(), 5);
 
   EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, client_address))
-      .WillOnce(testing::Return(
-          CreateSession(&dispatcher_, config_, 1, client_address, &session1_)));
+      .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 1,
+                                              client_address, &crypto_config_,
+                                              &session1_)));
   // A packet whose sequence number is the largest that is allowed to start a
   // connection.
   ProcessPacket(client_address, connection_id, true, "data",
@@ -577,12 +586,14 @@
 
     EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
         .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 1,
-                                                client_address, &session1_)));
+                                                client_address, &crypto_config_,
+                                                &session1_)));
     ProcessPacket(client_address, 1, true, "foo");
 
     EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
         .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 2,
-                                                client_address, &session2_)));
+                                                client_address, &crypto_config_,
+                                                &session2_)));
     ProcessPacket(client_address, 2, true, "bar");
 
     blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(&dispatcher_);
diff --git a/net/tools/quic/quic_in_memory_cache.cc b/net/tools/quic/quic_in_memory_cache.cc
index cb90bb5..8bf1713e 100644
--- a/net/tools/quic/quic_in_memory_cache.cc
+++ b/net/tools/quic/quic_in_memory_cache.cc
@@ -35,6 +35,9 @@
     StringPiece path) const {
   ResponseMap::const_iterator it = responses_.find(GetKey(host, path));
   if (it == responses_.end()) {
+    if (default_response_.get()) {
+      return default_response_.get();
+    }
     return nullptr;
   }
   return it->second;
@@ -55,6 +58,10 @@
   AddResponse(host, path, response_headers, body);
 }
 
+void QuicInMemoryCache::AddDefaultResponse(Response* response) {
+  default_response_.reset(response);
+}
+
 void QuicInMemoryCache::AddResponse(StringPiece host,
                                     StringPiece path,
                                     const SpdyHeaderBlock& response_headers,
@@ -121,9 +128,9 @@
     if (response_headers->GetNormalizedHeader("X-Original-Url", &base)) {
       response_headers->RemoveHeader("X-Original-Url");
       // Remove the protocol so we can add it below.
-      if (StartsWithASCII(base, "https://", false)) {
+      if (base::StartsWithASCII(base, "https://", false)) {
         base = base.substr(8);
-      } else if (StartsWithASCII(base, "http://", false)) {
+      } else if (base::StartsWithASCII(base, "http://", false)) {
         base = base.substr(7);
       }
     } else {
diff --git a/net/tools/quic/quic_in_memory_cache.h b/net/tools/quic/quic_in_memory_cache.h
index a14e540..e10e02d1 100644
--- a/net/tools/quic/quic_in_memory_cache.h
+++ b/net/tools/quic/quic_in_memory_cache.h
@@ -44,9 +44,6 @@
     const SpdyHeaderBlock& headers() const { return headers_; }
     const StringPiece body() const { return StringPiece(body_); }
 
-   private:
-    friend class QuicInMemoryCache;
-
     void set_response_type(SpecialResponseType response_type) {
       response_type_ = response_type;
     }
@@ -57,6 +54,7 @@
       body.CopyToString(&body_);
     }
 
+   private:
     SpecialResponseType response_type_;
     SpdyHeaderBlock headers_;
     std::string body_;
@@ -91,6 +89,10 @@
                           base::StringPiece path,
                           SpecialResponseType response_type);
 
+  // Sets a default response in case of cache misses.  Takes ownership of
+  // 'response'.
+  void AddDefaultResponse(Response* response);
+
   // |cache_cirectory| can be generated using `wget -p --save-headers <url>`.
   void InitializeFromDirectory(const std::string& cache_directory);
 
@@ -116,6 +118,9 @@
   // Cached responses.
   ResponseMap responses_;
 
+  // The default response for cache misses, if set.
+  scoped_ptr<Response> default_response_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicInMemoryCache);
 };
 
diff --git a/net/tools/quic/quic_in_memory_cache_test.cc b/net/tools/quic/quic_in_memory_cache_test.cc
index d93a344..534edff 100644
--- a/net/tools/quic/quic_in_memory_cache_test.cc
+++ b/net/tools/quic/quic_in_memory_cache_test.cc
@@ -10,6 +10,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
+#include "net/spdy/spdy_framer.h"
 #include "net/tools/balsa/balsa_headers.h"
 #include "net/tools/quic/quic_in_memory_cache.h"
 #include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
@@ -94,6 +95,43 @@
   EXPECT_LT(0U, response->body().length());
 }
 
+TEST_F(QuicInMemoryCacheTest, DefaultResponse) {
+  // Verify GetResponse returns nullptr when no default is set.
+  QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
+  const QuicInMemoryCache::Response* response =
+      cache->GetResponse("www.google.com", "/");
+  ASSERT_FALSE(response);
+
+  // Add a default response.
+  SpdyHeaderBlock response_headers;
+  response_headers[":version"] = "HTTP/1.1";
+  response_headers[":status"] = "200 OK";
+  response_headers["content-length"] = "0";
+  QuicInMemoryCache::Response* default_response =
+      new QuicInMemoryCache::Response;
+  default_response->set_headers(response_headers);
+  cache->AddDefaultResponse(default_response);
+
+  // Now we should get the default response for the original request.
+  response = cache->GetResponse("www.google.com", "/");
+  ASSERT_TRUE(response);
+  ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+  EXPECT_EQ("200 OK", response->headers().find(":status")->second);
+
+  // Now add a set response for / and make sure it is returned
+  cache->AddSimpleResponse("www.google.com", "/", 302, "foo", "");
+  response = cache->GetResponse("www.google.com", "/");
+  ASSERT_TRUE(response);
+  ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+  EXPECT_EQ("302 foo", response->headers().find(":status")->second);
+
+  // We should get the default response for other requests.
+  response = cache->GetResponse("www.google.com", "/asd");
+  ASSERT_TRUE(response);
+  ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
+  EXPECT_EQ("200 OK", response->headers().find(":status")->second);
+}
+
 }  // namespace test
 }  // namespace tools
 }  // namespace net
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 8999397..10d95e8dd 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -14,10 +14,13 @@
 namespace net {
 namespace tools {
 
-QuicServerSession::QuicServerSession(const QuicConfig& config,
-                                     QuicConnection* connection,
-                                     QuicServerSessionVisitor* visitor)
+QuicServerSession::QuicServerSession(
+    const QuicConfig& config,
+    QuicConnection* connection,
+    QuicServerSessionVisitor* visitor,
+    const QuicCryptoServerConfig* crypto_config)
     : QuicSession(connection, config),
+      crypto_config_(crypto_config),
       visitor_(visitor),
       bandwidth_resumption_enabled_(false),
       bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
@@ -27,10 +30,9 @@
 
 QuicServerSession::~QuicServerSession() {}
 
-void QuicServerSession::InitializeSession(
-    const QuicCryptoServerConfig* crypto_config) {
-  QuicSession::InitializeSession();
-  crypto_stream_.reset(CreateQuicCryptoServerStream(crypto_config));
+void QuicServerSession::Initialize() {
+  crypto_stream_.reset(CreateQuicCryptoServerStream(crypto_config_));
+  QuicSession::Initialize();
 }
 
 QuicCryptoServerStream* QuicServerSession::CreateQuicCryptoServerStream(
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index dc63341..757cab69 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -52,9 +52,11 @@
 
 class QuicServerSession : public QuicSession {
  public:
+  // |crypto_config| must outlive the session.
   QuicServerSession(const QuicConfig& config,
                     QuicConnection* connection,
-                    QuicServerSessionVisitor* visitor);
+                    QuicServerSessionVisitor* visitor,
+                    const QuicCryptoServerConfig* crypto_config);
 
   // Override the base class to notify the owner of the connection close.
   void OnConnectionClosed(QuicErrorCode error, bool from_peer) override;
@@ -66,8 +68,7 @@
 
   ~QuicServerSession() override;
 
-  // |crypto_config| must outlive the session.
-  virtual void InitializeSession(const QuicCryptoServerConfig* crypto_config);
+  void Initialize() override;
 
   const QuicCryptoServerStream* crypto_stream() const {
     return crypto_stream_.get();
@@ -118,6 +119,7 @@
  private:
   friend class test::QuicServerSessionPeer;
 
+  const QuicCryptoServerConfig* crypto_config_;
   scoped_ptr<QuicCryptoServerStream> crypto_stream_;
   QuicServerSessionVisitor* visitor_;
 
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 4716e81..1df0dc6 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -78,12 +78,13 @@
 
     connection_ = new StrictMock<MockConnection>(Perspective::IS_SERVER,
                                                  SupportedVersions(GetParam()));
-    session_.reset(new QuicServerSession(config_, connection_, &owner_));
+    session_.reset(
+        new QuicServerSession(config_, connection_, &owner_, &crypto_config_));
     MockClock clock;
     handshake_message_.reset(crypto_config_.AddDefaultConfig(
         QuicRandom::GetInstance(), &clock,
         QuicCryptoServerConfig::ConfigOptions()));
-    session_->InitializeSession(&crypto_config_);
+    session_->Initialize();
     visitor_ = QuicConnectionPeer::GetVisitor(connection_);
   }
 
@@ -266,7 +267,7 @@
 TEST_P(QuicServerSessionTest, GetStreamDisconnected) {
   // Don't create new streams if the connection is disconnected.
   QuicConnectionPeer::CloseConnection(connection_);
-  EXPECT_DFATAL(QuicServerSessionPeer::GetIncomingDataStream(session_.get(), 4),
+  EXPECT_DFATAL(QuicServerSessionPeer::GetIncomingDataStream(session_.get(), 5),
                 "ShouldCreateIncomingDataStream called when disconnected");
 }
 
diff --git a/net/tools/quic/quic_simple_client.cc b/net/tools/quic/quic_simple_client.cc
index e29a7a3..9ba6e69 100644
--- a/net/tools/quic/quic_simple_client.cc
+++ b/net/tools/quic/quic_simple_client.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_request_info.h"
 #include "net/http/http_response_info.h"
@@ -144,6 +145,14 @@
   return session_->connection()->connected();
 }
 
+QuicClientSession* QuicSimpleClient::CreateQuicClientSession(
+    const QuicConfig& config,
+    QuicConnection* connection,
+    const QuicServerId& server_id,
+    QuicCryptoClientConfig* crypto_config) {
+  return new QuicClientSession(config, connection, server_id_, &crypto_config_);
+}
+
 void QuicSimpleClient::StartConnect() {
   DCHECK(initialized_);
   DCHECK(!connected());
@@ -157,8 +166,9 @@
                                    Perspective::IS_CLIENT,
                                    server_id_.is_https(),
                                    supported_versions_);
-  session_.reset(new QuicClientSession(config_, connection_));
-  session_->InitializeSession(server_id_, &crypto_config_);
+  session_.reset(CreateQuicClientSession(config_, connection_, server_id_,
+                                         &crypto_config_));
+  session_->Initialize();
   session_->CryptoConnect();
 }
 
@@ -297,10 +307,8 @@
 }
 
 QuicConnectionHelper* QuicSimpleClient::CreateQuicConnectionHelper() {
-  return new QuicConnectionHelper(
-      base::MessageLoop::current()->message_loop_proxy().get(),
-      &clock_,
-      QuicRandom::GetInstance());
+  return new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(),
+                                  &clock_, QuicRandom::GetInstance());
 }
 
 QuicPacketWriter* QuicSimpleClient::CreateQuicPacketWriter() {
diff --git a/net/tools/quic/quic_simple_client.h b/net/tools/quic/quic_simple_client.h
index 1e63a878..cb709709 100644
--- a/net/tools/quic/quic_simple_client.h
+++ b/net/tools/quic/quic_simple_client.h
@@ -189,6 +189,12 @@
   virtual QuicConnectionHelper* CreateQuicConnectionHelper();
   virtual QuicPacketWriter* CreateQuicPacketWriter();
 
+  virtual QuicClientSession* CreateQuicClientSession(
+      const QuicConfig& config,
+      QuicConnection* connection,
+      const QuicServerId& server_id,
+      QuicCryptoClientConfig* crypto_config);
+
  private:
   friend class net::tools::test::QuicClientPeer;
 
diff --git a/net/tools/quic/quic_simple_server.cc b/net/tools/quic/quic_simple_server.cc
index bbdb823f..f7fc942 100644
--- a/net/tools/quic/quic_simple_server.cc
+++ b/net/tools/quic/quic_simple_server.cc
@@ -6,6 +6,9 @@
 
 #include <string.h>
 
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
 #include "net/quic/crypto/crypto_handshake.h"
@@ -62,7 +65,7 @@
 
 QuicSimpleServer::QuicSimpleServer(const QuicConfig& config,
                                    const QuicVersionVector& supported_versions)
-    : helper_(base::MessageLoop::current()->message_loop_proxy().get(),
+    : helper_(base::ThreadTaskRunnerHandle::Get().get(),
               &clock_,
               QuicRandom::GetInstance()),
       config_(config),
@@ -190,11 +193,9 @@
     synchronous_read_count_ = 0;
     // Schedule the processing through the message loop to 1) prevent infinite
     // recursion and 2) avoid blocking the thread for too long.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&QuicSimpleServer::OnReadComplete,
-                   weak_factory_.GetWeakPtr(),
-                   result));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&QuicSimpleServer::OnReadComplete,
+                              weak_factory_.GetWeakPtr(), result));
   } else {
     OnReadComplete(result);
   }
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc
index 7e30c92..9503a45 100644
--- a/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -33,11 +33,12 @@
       : connection_(
             new StrictMock<MockConnection>(Perspective::IS_CLIENT,
                                            SupportedVersions(GetParam()))),
-        session_(DefaultQuicConfig(), connection_),
+        session_(DefaultQuicConfig(),
+                 connection_,
+                 QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
+                 &crypto_config_),
         body_("hello world") {
-    session_.InitializeSession(
-        QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
-        &crypto_config_);
+    session_.Initialize();
 
     headers_.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "Ok");
     headers_.ReplaceOrAppendHeader("content-length", "11");
@@ -55,12 +56,12 @@
   }
 
   StrictMock<MockConnection>* connection_;
+  QuicCryptoClientConfig crypto_config_;
   QuicClientSession session_;
   scoped_ptr<QuicSpdyClientStream> stream_;
   BalsaHeaders headers_;
   string headers_string_;
   string body_;
-  QuicCryptoClientConfig crypto_config_;
 };
 
 INSTANTIATE_TEST_CASE_P(Tests, QuicSpdyClientStreamTest,
diff --git a/net/tools/quic/synchronous_host_resolver.cc b/net/tools/quic/synchronous_host_resolver.cc
index aa96719..44d2cad5 100644
--- a/net/tools/quic/synchronous_host_resolver.cc
+++ b/net/tools/quic/synchronous_host_resolver.cc
@@ -5,7 +5,10 @@
 #include "net/tools/quic/synchronous_host_resolver.h"
 
 #include "base/at_exit.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/simple_thread.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_errors.h"
@@ -86,9 +89,8 @@
 
 void ResolverThread::OnResolutionComplete(int rv) {
   rv_ = rv;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure());
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::MessageLoop::QuitClosure());
 }
 
 }  // namespace
diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc
index 4c5a8d2..69b571d 100644
--- a/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -32,22 +32,6 @@
   return ack;
 }
 
-TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
-    : QuicSession(connection, config),
-      crypto_stream_(nullptr) {
-  InitializeSession();
-}
-
-TestSession::~TestSession() {}
-
-void TestSession::SetCryptoStream(QuicCryptoStream* stream) {
-  crypto_stream_ = stream;
-}
-
-QuicCryptoStream* TestSession::GetCryptoStream() {
-  return crypto_stream_;
-}
-
 MockPacketWriter::MockPacketWriter() {
 }
 
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index dac5f5c..3fe48f5 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -40,24 +40,6 @@
 QuicAckFrame MakeAckFrameWithNackRanges(size_t num_nack_ranges,
                                         QuicPacketSequenceNumber least_unacked);
 
-class TestSession : public QuicSession {
- public:
-  TestSession(QuicConnection* connection, const QuicConfig& config);
-  ~TestSession() override;
-
-  MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
-  MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
-
-  void SetCryptoStream(QuicCryptoStream* stream);
-
-  QuicCryptoStream* GetCryptoStream() override;
-
- private:
-  QuicCryptoStream* crypto_stream_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestSession);
-};
-
 class MockPacketWriter : public QuicPacketWriter {
  public:
   MockPacketWriter();
diff --git a/net/tools/stress_cache/stress_cache.cc b/net/tools/stress_cache/stress_cache.cc
index d67ebdd..0706d4c 100644
--- a/net/tools/stress_cache/stress_cache.cc
+++ b/net/tools/stress_cache/stress_cache.cc
@@ -22,11 +22,13 @@
 #include "base/command_line.h"
 #include "base/debug/debugger.h"
 #include "base/files/file_path.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
 #include "base/process/process.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -112,10 +114,8 @@
           base::Thread::Options(base::MessageLoop::TYPE_IO, 0)))
     return;
 
-  disk_cache::BackendImpl* cache =
-      new disk_cache::BackendImpl(path, mask,
-                                  cache_thread.message_loop_proxy().get(),
-                                  NULL);
+  disk_cache::BackendImpl* cache = new disk_cache::BackendImpl(
+      path, mask, cache_thread.task_runner().get(), NULL);
   cache->SetMaxSize(cache_size);
   cache->SetFlags(disk_cache::kNoLoadProtection);
 
@@ -215,7 +215,7 @@
 
 void RunSoon(base::MessageLoop* target_loop) {
   const base::TimeDelta kTaskDelay = base::TimeDelta::FromSeconds(10);
-  target_loop->PostDelayedTask(
+  target_loop->task_runner()->PostDelayedTask(
       FROM_HERE, base::Bind(&CrashCallback), kTaskDelay);
 }
 
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc
index 4cbec73..3e31f9e 100644
--- a/net/udp/udp_socket_unittest.cc
+++ b/net/udp/udp_socket_unittest.cc
@@ -9,11 +9,13 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
@@ -202,7 +204,7 @@
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
   // Client sends to the server.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&UDPSocketTest::WriteSocketIgnoreResult,
                  base::Unretained(this), client.get(), simple_message));
diff --git a/net/url_request/ftp_protocol_handler.cc b/net/url_request/ftp_protocol_handler.cc
index 418b6f6..a55fc47 100644
--- a/net/url_request/ftp_protocol_handler.cc
+++ b/net/url_request/ftp_protocol_handler.cc
@@ -30,8 +30,7 @@
   DCHECK_EQ("ftp", request->url().scheme());
 
   if (!IsPortAllowedForScheme(request->url().EffectiveIntPort(),
-                              request->url().scheme(),
-                              PORT_OVERRIDES_ALLOWED)) {
+                              request->url().scheme())) {
     return new URLRequestErrorJob(request, network_delegate, ERR_UNSAFE_PORT);
   }
 
diff --git a/net/url_request/test_url_fetcher_factory.cc b/net/url_request/test_url_fetcher_factory.cc
index 207d285..4125921 100644
--- a/net/url_request/test_url_fetcher_factory.cc
+++ b/net/url_request/test_url_fetcher_factory.cc
@@ -9,8 +9,10 @@
 #include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/io_buffer.h"
@@ -359,7 +361,7 @@
 FakeURLFetcher::~FakeURLFetcher() {}
 
 void FakeURLFetcher::Start() {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&FakeURLFetcher::RunDelegate, weak_factory_.GetWeakPtr()));
 }
diff --git a/net/url_request/url_fetcher.h b/net/url_request/url_fetcher.h
index 8d2c1b5..691ee7d 100644
--- a/net/url_request/url_fetcher.h
+++ b/net/url_request/url_fetcher.h
@@ -19,7 +19,6 @@
 
 namespace base {
 class FilePath;
-class MessageLoopProxy;
 class SequencedTaskRunner;
 class TaskRunner;
 class TimeDelta;
diff --git a/net/url_request/url_fetcher_impl.cc b/net/url_request/url_fetcher_impl.cc
index 6358473..73e78536 100644
--- a/net/url_request/url_fetcher_impl.cc
+++ b/net/url_request/url_fetcher_impl.cc
@@ -5,7 +5,6 @@
 #include "net/url_request/url_fetcher_impl.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/sequenced_task_runner.h"
 #include "net/base/upload_data_stream.h"
 #include "net/url_request/url_fetcher_core.h"
diff --git a/net/url_request/url_fetcher_impl_unittest.cc b/net/url_request/url_fetcher_impl_unittest.cc
index a76eaa4..ef7c307 100644
--- a/net/url_request/url_fetcher_impl_unittest.cc
+++ b/net/url_request/url_fetcher_impl_unittest.cc
@@ -10,13 +10,14 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
 #include "crypto/nss_util.h"
@@ -306,7 +307,7 @@
   CreateSameThreadContextGetter() {
     return scoped_refptr<FetcherTestURLRequestContextGetter>(
         new FetcherTestURLRequestContextGetter(
-            base::MessageLoopProxy::current(), hanging_url().host()));
+            base::ThreadTaskRunnerHandle::Get(), hanging_url().host()));
   }
 
   // Creates a URLRequestContextGetter with a URLRequestContext that lives on
@@ -360,12 +361,12 @@
         URLFetcher::GET, CreateSameThreadContextGetter());
     if (save_to_temporary_file) {
       delegate->fetcher()->SaveResponseToTemporaryFile(
-          scoped_refptr<base::MessageLoopProxy>(
-              base::MessageLoopProxy::current()));
+          scoped_refptr<base::SingleThreadTaskRunner>(
+              base::ThreadTaskRunnerHandle::Get()));
     } else {
       delegate->fetcher()->SaveResponseToFileAtPath(
-          requested_out_path, scoped_refptr<base::MessageLoopProxy>(
-                                  base::MessageLoopProxy::current()));
+          requested_out_path, scoped_refptr<base::SingleThreadTaskRunner>(
+                                  base::ThreadTaskRunnerHandle::Get()));
     }
     delegate->StartFetcherAndWait();
 
@@ -682,7 +683,7 @@
                          CreateSameThreadContextGetter());
   delegate.fetcher()->SetUploadFilePath("application/x-www-form-urlencoded",
                                         upload_path, 0, kuint64max,
-                                        base::MessageLoopProxy::current());
+                                        base::ThreadTaskRunnerHandle::Get());
   delegate.StartFetcherAndWait();
 
   EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success());
@@ -705,7 +706,7 @@
                          CreateSameThreadContextGetter());
   delegate.fetcher()->SetUploadFilePath("application/x-www-form-urlencoded",
                                         upload_path, kRangeStart, kRangeLength,
-                                        base::MessageLoopProxy::current());
+                                        base::ThreadTaskRunnerHandle::Get());
   delegate.StartFetcherAndWait();
 
   EXPECT_TRUE(delegate.fetcher()->GetStatus().is_success());
@@ -1133,8 +1134,8 @@
   scoped_refptr<FetcherTestURLRequestContextGetter> context_getter(
       CreateCrossThreadContextGetter());
   context_getter->set_on_destruction_callback(base::Bind(
-      base::IgnoreResult(&base::MessageLoopProxy::PostTask),
-      base::MessageLoopProxy::current(), FROM_HERE, run_loop_.QuitClosure()));
+      base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask),
+      base::ThreadTaskRunnerHandle::Get(), FROM_HERE, run_loop_.QuitClosure()));
   delegate.CreateFetcher(hanging_url(), URLFetcher::GET, context_getter);
 
   // The getter won't be destroyed if the test holds on to a reference to it.
@@ -1155,8 +1156,8 @@
   scoped_refptr<FetcherTestURLRequestContextGetter> context_getter(
       CreateCrossThreadContextGetter());
   context_getter->set_on_destruction_callback(base::Bind(
-      base::IgnoreResult(&base::MessageLoopProxy::PostTask),
-      base::MessageLoopProxy::current(), FROM_HERE, run_loop_.QuitClosure()));
+      base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask),
+      base::ThreadTaskRunnerHandle::Get(), FROM_HERE, run_loop_.QuitClosure()));
   delegate.CreateFetcher(url, URLFetcher::GET, context_getter);
 
   // Register an entry for test url using a sliding window of 400 seconds, and
@@ -1364,8 +1365,8 @@
       test_server_->GetURL(std::string(kTestServerFilePrefix) + kFileToFetch),
       URLFetcher::GET, CreateSameThreadContextGetter());
   delegate.fetcher()->SaveResponseToFileAtPath(
-      out_path,
-      scoped_refptr<base::MessageLoopProxy>(base::MessageLoopProxy::current()));
+      out_path, scoped_refptr<base::SingleThreadTaskRunner>(
+                    base::ThreadTaskRunnerHandle::Get()));
   delegate.StartFetcherAndWait();
 
   EXPECT_FALSE(delegate.fetcher()->GetStatus().is_success());
diff --git a/net/url_request/url_fetcher_response_writer_unittest.cc b/net/url_request/url_fetcher_response_writer_unittest.cc
index e9f9380..e6c1696 100644
--- a/net/url_request/url_fetcher_response_writer_unittest.cc
+++ b/net/url_request/url_fetcher_response_writer_unittest.cc
@@ -6,8 +6,8 @@
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -57,8 +57,8 @@
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     file_path_ = temp_dir_.path().AppendASCII("test.txt");
-    writer_.reset(new URLFetcherFileWriter(
-        base::MessageLoopProxy::current(), file_path_));
+    writer_.reset(new URLFetcherFileWriter(base::ThreadTaskRunnerHandle::Get(),
+                                           file_path_));
     buf_ = new StringIOBuffer(kData);
   }
 
@@ -145,8 +145,8 @@
 class URLFetcherFileWriterTemporaryFileTest : public PlatformTest {
  protected:
   void SetUp() override {
-    writer_.reset(new URLFetcherFileWriter(
-        base::MessageLoopProxy::current(), base::FilePath()));
+    writer_.reset(new URLFetcherFileWriter(base::ThreadTaskRunnerHandle::Get(),
+                                           base::FilePath()));
     buf_ = new StringIOBuffer(kData);
   }
 
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index e10fe4ea..254f65766 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -557,7 +557,10 @@
       has_notified_completion_(false),
       received_response_content_length_(0),
       creation_time_(base::TimeTicks::Now()),
-      notified_before_network_start_(false) {
+      notified_before_network_start_(false),
+      // TODO(mmenke):  Remove this after we figure out current causes of
+      // http://crbug.com/498289.
+      stack_trace_(new base::debug::StackTrace()) {
   // Sanity check out environment.
   DCHECK(base::MessageLoop::current())
       << "The current base::MessageLoop must exist";
@@ -871,6 +874,7 @@
 
   status_ = URLRequestStatus();
   is_pending_ = false;
+  proxy_server_ = HostPortPair();
 }
 
 void URLRequest::OrphanJob() {
@@ -1178,10 +1182,7 @@
 }
 
 void URLRequest::set_stack_trace(const base::debug::StackTrace& stack_trace) {
-  base::debug::StackTrace* stack_trace_copy =
-      new base::debug::StackTrace(NULL, 0);
-  *stack_trace_copy = stack_trace;
-  stack_trace_.reset(stack_trace_copy);
+  stack_trace_.reset(new base::debug::StackTrace(stack_trace));
 }
 
 const base::debug::StackTrace* URLRequest::stack_trace() const {
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index a2b2f6b..4176689 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -816,14 +816,14 @@
   // populated during Start(), and the rest are populated in OnResponseReceived.
   LoadTimingInfo load_timing_info_;
 
-  scoped_ptr<const base::debug::StackTrace> stack_trace_;
-
   // Keeps track of whether or not OnBeforeNetworkStart has been called yet.
   bool notified_before_network_start_;
 
   // The proxy server used for this request, if any.
   HostPortPair proxy_server_;
 
+  scoped_ptr<const base::debug::StackTrace> stack_trace_;
+
   DISALLOW_COPY_AND_ASSIGN(URLRequest);
 };
 
diff --git a/net/url_request/url_request_about_job.cc b/net/url_request/url_request_about_job.cc
index 52a069a76..5619316 100644
--- a/net/url_request/url_request_about_job.cc
+++ b/net/url_request/url_request_about_job.cc
@@ -10,7 +10,9 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace net {
 
@@ -23,7 +25,7 @@
 void URLRequestAboutJob::Start() {
   // Start reading asynchronously so that all error reporting and data
   // callbacks happen as they would for network requests.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&URLRequestAboutJob::StartAsync, weak_factory_.GetWeakPtr()));
 }
diff --git a/net/url_request/url_request_error_job.cc b/net/url_request/url_request_error_job.cc
index 0b2749b..efbf424 100644
--- a/net/url_request/url_request_error_job.cc
+++ b/net/url_request/url_request_error_job.cc
@@ -6,7 +6,9 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/net_errors.h"
 #include "net/url_request/url_request_status.h"
 
@@ -21,7 +23,7 @@
 URLRequestErrorJob::~URLRequestErrorJob() {}
 
 void URLRequestErrorJob::Start() {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&URLRequestErrorJob::StartAsync, weak_factory_.GetWeakPtr()));
 }
diff --git a/net/url_request/url_request_file_dir_job.cc b/net/url_request/url_request_file_dir_job.cc
index da586f3..ce6ef75 100644
--- a/net/url_request/url_request_file_dir_job.cc
+++ b/net/url_request/url_request_file_dir_job.cc
@@ -6,9 +6,11 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -45,10 +47,9 @@
 void URLRequestFileDirJob::Start() {
   // Start reading asynchronously so that all error reporting and data
   // callbacks happen as they would for network requests.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&URLRequestFileDirJob::StartAsync,
-                 weak_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestFileDirJob::StartAsync,
+                            weak_factory_.GetWeakPtr()));
 }
 
 void URLRequestFileDirJob::Kill() {
diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc
index 864001e..17bc642d 100644
--- a/net/url_request/url_request_file_job.cc
+++ b/net/url_request/url_request_file_job.cc
@@ -140,7 +140,7 @@
 #if defined(OS_WIN)
   // Follow a Windows shortcut.
   // We just resolve .lnk file, ignore others.
-  if (!LowerCaseEqualsASCII(file_path_.Extension(), ".lnk"))
+  if (!base::LowerCaseEqualsASCII(file_path_.Extension(), ".lnk"))
     return false;
 
   base::FilePath new_path = file_path_;
@@ -161,8 +161,9 @@
 
 Filter* URLRequestFileJob::SetupFilter() const {
   // Bug 9936 - .svgz files needs to be decompressed.
-  return LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")
-      ? Filter::GZipFactory() : NULL;
+  return base::LowerCaseEqualsASCII(file_path_.Extension(), ".svgz")
+             ? Filter::GZipFactory()
+             : NULL;
 }
 
 bool URLRequestFileJob::GetMimeType(std::string* mime_type) const {
diff --git a/net/url_request/url_request_file_job_unittest.cc b/net/url_request/url_request_file_job_unittest.cc
index 427ed3d0..06acd32 100644
--- a/net/url_request/url_request_file_job_unittest.cc
+++ b/net/url_request/url_request_file_job_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "net/base/filename_util.h"
 #include "net/base/net_util.h"
@@ -74,10 +75,7 @@
       URLRequest* request,
       NetworkDelegate* network_delegate) const override {
     URLRequestFileJobWithCallbacks* job = new URLRequestFileJobWithCallbacks(
-        request,
-        network_delegate,
-        path_,
-        base::MessageLoop::current()->message_loop_proxy());
+        request, network_delegate, path_, base::ThreadTaskRunnerHandle::Get());
     observer_->OnJobCreated(job);
     return job;
   }
diff --git a/net/url_request/url_request_ftp_job.cc b/net/url_request/url_request_ftp_job.cc
index 09c6f0f..2305c784 100644
--- a/net/url_request/url_request_ftp_job.cc
+++ b/net/url_request/url_request_ftp_job.cc
@@ -5,8 +5,10 @@
 #include "net/url_request/url_request_ftp_job.h"
 
 #include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/auth.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
@@ -239,10 +241,9 @@
 }
 
 void URLRequestFtpJob::OnStartCompletedAsync(int result) {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&URLRequestFtpJob::OnStartCompleted,
-                 weak_factory_.GetWeakPtr(), result));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestFtpJob::OnStartCompleted,
+                            weak_factory_.GetWeakPtr(), result));
 }
 
 void URLRequestFtpJob::OnReadCompleted(int result) {
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 2415711d..9e0cfde 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -10,12 +10,14 @@
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/file_version_info.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "net/base/host_port_pair.h"
@@ -321,7 +323,7 @@
     SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url());
     if (rv != SDCH_OK) {
       // If SDCH is just disabled, it is not a real error.
-      if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) {
+      if (rv != SDCH_DISABLED) {
         SdchManager::SdchErrorRecovery(rv);
         request()->net_log().AddEvent(
             NetLog::TYPE_SDCH_DECODING_ERROR,
@@ -510,10 +512,9 @@
 
   // The transaction started synchronously, but we need to notify the
   // URLRequest delegate via the message loop.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&URLRequestHttpJob::OnStartCompleted,
-                 weak_factory_.GetWeakPtr(), rv));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestHttpJob::OnStartCompleted,
+                            weak_factory_.GetWeakPtr(), rv));
 }
 
 void URLRequestHttpJob::AddExtraHeaders() {
@@ -538,7 +539,7 @@
       if (rv != SDCH_OK) {
         advertise_sdch = false;
         // If SDCH is just disabled, it is not a real error.
-        if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) {
+        if (rv != SDCH_DISABLED) {
           SdchManager::SdchErrorRecovery(rv);
           request()->net_log().AddEvent(
               NetLog::TYPE_SDCH_DECODING_ERROR,
@@ -1204,10 +1205,9 @@
   //
   // We have to do this via InvokeLater to avoid "recursing" the consumer.
   //
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&URLRequestHttpJob::OnStartCompleted,
-                 weak_factory_.GetWeakPtr(), OK));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestHttpJob::OnStartCompleted,
+                            weak_factory_.GetWeakPtr(), OK));
 }
 
 void URLRequestHttpJob::ContinueWithCertificate(
@@ -1229,10 +1229,9 @@
 
   // The transaction started synchronously, but we need to notify the
   // URLRequest delegate via the message loop.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&URLRequestHttpJob::OnStartCompleted,
-                 weak_factory_.GetWeakPtr(), rv));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestHttpJob::OnStartCompleted,
+                            weak_factory_.GetWeakPtr(), rv));
 }
 
 void URLRequestHttpJob::ContinueDespiteLastError() {
@@ -1255,10 +1254,9 @@
 
   // The transaction started synchronously, but we need to notify the
   // URLRequest delegate via the message loop.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&URLRequestHttpJob::OnStartCompleted,
-                 weak_factory_.GetWeakPtr(), rv));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestHttpJob::OnStartCompleted,
+                            weak_factory_.GetWeakPtr(), rv));
 }
 
 void URLRequestHttpJob::ResumeNetworkStart() {
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index 40672cb..6b1c81d9 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -6,11 +6,13 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/power_monitor/power_monitor.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/base/auth.h"
 #include "net/base/host_port_pair.h"
@@ -545,10 +547,9 @@
 
   // Complete this notification later.  This prevents us from re-entering the
   // delegate if we're done because of a synchronous call.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&URLRequestJob::CompleteNotifyDone,
-                 weak_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestJob::CompleteNotifyDone,
+                            weak_factory_.GetWeakPtr()));
 }
 
 void URLRequestJob::CompleteNotifyDone() {
diff --git a/net/url_request/url_request_job_factory_impl_unittest.cc b/net/url_request/url_request_job_factory_impl_unittest.cc
index 235e329..e480755 100644
--- a/net/url_request/url_request_job_factory_impl_unittest.cc
+++ b/net/url_request/url_request_job_factory_impl_unittest.cc
@@ -5,8 +5,11 @@
 #include "net/url_request/url_request_job_factory_impl.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/request_priority.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_job.h"
@@ -29,7 +32,7 @@
   void Start() override {
     // Start reading asynchronously so that all error reporting and data
     // callbacks happen as they would for network requests.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&MockURLRequestJob::StartAsync, weak_factory_.GetWeakPtr()));
   }
diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc
index b2392e8f..39c21b7 100644
--- a/net/url_request/url_request_job_manager.cc
+++ b/net/url_request/url_request_job_manager.cc
@@ -143,7 +143,7 @@
 // static
 bool URLRequestJobManager::SupportsScheme(const std::string& scheme) {
   for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i) {
-    if (LowerCaseEqualsASCII(scheme, kBuiltinFactories[i].scheme))
+    if (base::LowerCaseEqualsASCII(scheme, kBuiltinFactories[i].scheme))
       return true;
   }
 
diff --git a/net/url_request/url_request_redirect_job.cc b/net/url_request/url_request_redirect_job.cc
index 9056546..b127220 100644
--- a/net/url_request/url_request_redirect_job.cc
+++ b/net/url_request/url_request_redirect_job.cc
@@ -8,9 +8,11 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/base/load_timing_info.h"
 #include "net/base/net_errors.h"
@@ -58,10 +60,9 @@
   request()->net_log().AddEvent(
       NetLog::TYPE_URL_REQUEST_REDIRECT_JOB,
       NetLog::StringCallback("reason", &redirect_reason_));
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&URLRequestRedirectJob::StartAsync,
-                 weak_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestRedirectJob::StartAsync,
+                            weak_factory_.GetWeakPtr()));
 }
 
 bool URLRequestRedirectJob::CopyFragmentOnRedirect(const GURL& location) const {
diff --git a/net/url_request/url_request_simple_job.cc b/net/url_request/url_request_simple_job.cc
index bbb9178..2f2fb875 100644
--- a/net/url_request/url_request_simple_job.cc
+++ b/net/url_request/url_request_simple_job.cc
@@ -8,8 +8,10 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/worker_pool.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -41,7 +43,7 @@
 void URLRequestSimpleJob::Start() {
   // Start reading asynchronously so that all error reporting and data
   // callbacks happen as they would for network requests.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&URLRequestSimpleJob::StartAsync, weak_factory_.GetWeakPtr()));
 }
diff --git a/net/url_request/url_request_test_job.cc b/net/url_request/url_request_test_job.cc
index ecf39431..9ca0f5af 100644
--- a/net/url_request/url_request_test_job.cc
+++ b/net/url_request/url_request_test_job.cc
@@ -10,8 +10,10 @@
 #include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
@@ -176,9 +178,9 @@
 void URLRequestTestJob::Start() {
   // Start reading asynchronously so that all error reporting and data
   // callbacks happen as they would for network requests.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&URLRequestTestJob::StartAsync,
-                            weak_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&URLRequestTestJob::StartAsync, weak_factory_.GetWeakPtr()));
 }
 
 void URLRequestTestJob::StartAsync() {
@@ -330,7 +332,7 @@
 
 void URLRequestTestJob::AdvanceJob() {
   if (auto_advance_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&URLRequestTestJob::ProcessNextOperation,
                               weak_factory_.GetWeakPtr()));
     return;
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index 9ed2227..bbff202 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -5,8 +5,11 @@
 #include "net/url_request/url_request_test_util.h"
 
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/threading/worker_pool.h"
 #include "net/base/host_port_pair.h"
@@ -196,8 +199,8 @@
   received_redirect_count_++;
   if (quit_on_redirect_) {
     *defer_redirect = true;
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
   } else if (cancel_in_rr_) {
     request->Cancel();
   }
@@ -207,8 +210,8 @@
   received_before_network_start_count_++;
   if (quit_on_before_network_start_) {
     *defer = true;
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
   }
 }
 
@@ -216,8 +219,8 @@
                                   AuthChallengeInfo* auth_info) {
   auth_required_ = true;
   if (quit_on_auth_required_) {
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
     return;
   }
   if (!credentials_.Empty()) {
@@ -306,8 +309,8 @@
 
 void TestDelegate::OnResponseCompleted(URLRequest* request) {
   if (quit_on_complete_)
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
 }
 
 TestNetworkDelegate::TestNetworkDelegate()
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h
index 585aca9..48c3b7d 100644
--- a/net/url_request/url_request_test_util.h
+++ b/net/url_request/url_request_test_util.h
@@ -14,8 +14,8 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 158618fd..fdcf719 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -20,12 +20,13 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/format_macros.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
@@ -33,6 +34,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/histogram_tester.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/chunked_upload_data_stream.h"
 #include "net/base/elements_upload_data_stream.h"
 #include "net/base/load_flags.h"
@@ -550,7 +552,7 @@
       return auth_retval_;
 
     case AUTO_CALLBACK:
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::Bind(&BlockingNetworkDelegate::RunAuthCallback,
                      weak_factory_.GetWeakPtr(), auth_retval_, callback));
@@ -559,8 +561,8 @@
     case USER_CALLBACK:
       auth_callback_ = callback;
       stage_blocked_for_callback_ = ON_AUTH_REQUIRED;
-      base::MessageLoop::current()->PostTask(FROM_HERE,
-                                             base::MessageLoop::QuitClosure());
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::MessageLoop::QuitClosure());
       return AUTH_REQUIRED_RESPONSE_IO_PENDING;
   }
   NOTREACHED();
@@ -590,17 +592,16 @@
       return retval_;
 
     case AUTO_CALLBACK:
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&BlockingNetworkDelegate::RunCallback,
-                     weak_factory_.GetWeakPtr(), retval_, callback));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&BlockingNetworkDelegate::RunCallback,
+                                weak_factory_.GetWeakPtr(), retval_, callback));
       return ERR_IO_PENDING;
 
     case USER_CALLBACK:
       callback_ = callback;
       stage_blocked_for_callback_ = stage;
-      base::MessageLoop::current()->PostTask(FROM_HERE,
-                                             base::MessageLoop::QuitClosure());
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::MessageLoop::QuitClosure());
       return ERR_IO_PENDING;
   }
   NOTREACHED();
@@ -648,7 +649,7 @@
     job_factory_impl_->SetProtocolHandler("data", new DataProtocolHandler);
 #if !defined(DISABLE_FILE_SUPPORT)
     job_factory_impl_->SetProtocolHandler(
-        "file", new FileProtocolHandler(base::MessageLoopProxy::current()));
+        "file", new FileProtocolHandler(base::ThreadTaskRunnerHandle::Get()));
 #endif
   }
 
@@ -4288,9 +4289,8 @@
     LoadStateWithParam load_state = url_request_->GetLoadState();
     EXPECT_EQ(expected_first_load_state_, load_state.state);
     EXPECT_NE(ASCIIToUTF16(kFirstDelegateInfo), load_state.param);
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&AsyncDelegateLogger::LogSecondDelegate, this));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&AsyncDelegateLogger::LogSecondDelegate, this));
   }
 
   void LogSecondDelegate() {
@@ -4302,9 +4302,8 @@
     } else {
       EXPECT_NE(ASCIIToUTF16(kSecondDelegateInfo), load_state.param);
     }
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&AsyncDelegateLogger::LogComplete, this));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&AsyncDelegateLogger::LogComplete, this));
   }
 
   void LogComplete() {
@@ -5162,11 +5161,8 @@
     path = path.Append(kTestFilePath);
     path = path.Append(FILE_PATH_LITERAL("with-headers.html"));
     element_readers.push_back(
-        new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                    path,
-                                    0,
-                                    kuint64max,
-                                    base::Time()));
+        new UploadFileElementReader(base::ThreadTaskRunnerHandle::Get().get(),
+                                    path, 0, kuint64max, base::Time()));
     r->set_upload(make_scoped_ptr<UploadDataStream>(
         new ElementsUploadDataStream(element_readers.Pass(), 0)));
 
@@ -5206,12 +5202,10 @@
     ScopedVector<UploadElementReader> element_readers;
 
     element_readers.push_back(new UploadFileElementReader(
-        base::MessageLoopProxy::current().get(),
+        base::ThreadTaskRunnerHandle::Get().get(),
         base::FilePath(FILE_PATH_LITERAL(
             "c:\\path\\to\\non\\existant\\file.randomness.12345")),
-        0,
-        kuint64max,
-        base::Time()));
+        0, kuint64max, base::Time()));
     r->set_upload(make_scoped_ptr<UploadDataStream>(
         new ElementsUploadDataStream(element_readers.Pass(), 0)));
 
@@ -5575,7 +5569,8 @@
 TEST_F(URLRequestTestHTTP, ProtocolHandlerAndFactoryRestrictFileRedirects) {
   // Test URLRequestJobFactory::ProtocolHandler::IsSafeRedirectTarget().
   GURL file_url("file:///foo.txt");
-  FileProtocolHandler file_protocol_handler(base::MessageLoopProxy::current());
+  FileProtocolHandler file_protocol_handler(
+      base::ThreadTaskRunnerHandle::Get());
   EXPECT_FALSE(file_protocol_handler.IsSafeRedirectTarget(file_url));
 
   // Test URLRequestJobFactoryImpl::IsSafeRedirectTarget().
diff --git a/net/websockets/websocket_basic_handshake_stream.cc b/net/websockets/websocket_basic_handshake_stream.cc
index 7bb34a3..1261e1c55 100644
--- a/net/websockets/websocket_basic_handshake_stream.cc
+++ b/net/websockets/websocket_basic_handshake_stream.cc
@@ -142,7 +142,7 @@
     return false;
   }
 
-  if (!LowerCaseEqualsASCII(value, websockets::kWebSocketLowercase)) {
+  if (!base::LowerCaseEqualsASCII(value, websockets::kWebSocketLowercase)) {
     *failure_message =
         "'Upgrade' header value is not 'WebSocket': " + value;
     return false;
diff --git a/net/websockets/websocket_channel.cc b/net/websockets/websocket_channel.cc
index b5656e5..254c6a41 100644
--- a/net/websockets/websocket_channel.cc
+++ b/net/websockets/websocket_channel.cc
@@ -13,13 +13,15 @@
 #include "base/big_endian.h"
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/io_buffer.h"
 #include "net/http/http_request_headers.h"
@@ -640,10 +642,9 @@
 }
 
 void WebSocketChannel::ScheduleOpeningHandshakeNotification() {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(HandshakeNotificationSender::Send,
-                 notification_sender_->AsWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(HandshakeNotificationSender::Send,
+                            notification_sender_->AsWeakPtr()));
 }
 
 ChannelState WebSocketChannel::WriteFrames() {
diff --git a/net/websockets/websocket_channel_test.cc b/net/websockets/websocket_channel_test.cc
index c659685..032123e 100644
--- a/net/websockets/websocket_channel_test.cc
+++ b/net/websockets/websocket_channel_test.cc
@@ -19,7 +19,9 @@
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_piece.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
 #include "net/http/http_response_headers.h"
@@ -484,12 +486,9 @@
       return ERR_IO_PENDING;
     if (responses_[index_]->async == ASYNC) {
       read_frames_pending_ = true;
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&ReadableFakeWebSocketStream::DoCallback,
-                     base::Unretained(this),
-                     frames,
-                     callback));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&ReadableFakeWebSocketStream::DoCallback,
+                                base::Unretained(this), frames, callback));
       return ERR_IO_PENDING;
     } else {
       frames->swap(responses_[index_]->frames);
@@ -580,10 +579,9 @@
 
  private:
   void PostCallback() {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&EchoeyFakeWebSocketStream::DoCallback,
-                   base::Unretained(this)));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&EchoeyFakeWebSocketStream::DoCallback,
+                              base::Unretained(this)));
   }
 
   void DoCallback() {
@@ -634,17 +632,15 @@
 
   int WriteFrames(ScopedVector<WebSocketFrame>* frames,
                   const CompletionCallback& callback) override {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ResetOnWriteFakeWebSocketStream::CallCallbackUnlessClosed,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   callback,
+                   weak_ptr_factory_.GetWeakPtr(), callback,
                    ERR_CONNECTION_RESET));
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ResetOnWriteFakeWebSocketStream::CallCallbackUnlessClosed,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   read_callback_,
+                   weak_ptr_factory_.GetWeakPtr(), read_callback_,
                    ERR_CONNECTION_RESET));
     return ERR_IO_PENDING;
   }
diff --git a/net/websockets/websocket_end_to_end_test.cc b/net/websockets/websocket_end_to_end_test.cc
index 9dc6c54..a5cf6b4 100644
--- a/net/websockets/websocket_end_to_end_test.cc
+++ b/net/websockets/websocket_end_to_end_test.cc
@@ -13,10 +13,12 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_piece.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/auth.h"
 #include "net/base/network_delegate.h"
 #include "net/base/test_data_directory.h"
@@ -177,7 +179,7 @@
     const GURL& url,
     const SSLInfo& ssl_info,
     bool fatal) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&SSLErrorCallbacks::CancelSSLRequest,
                             base::Owned(ssl_error_callbacks.release()),
                             ERR_SSL_PROTOCOL_ERROR, &ssl_info));
diff --git a/pdf/document_loader.cc b/pdf/document_loader.cc
index 165fffe..48d8352 100644
--- a/pdf/document_loader.cc
+++ b/pdf/document_loader.cc
@@ -27,9 +27,9 @@
 bool GetByteRange(const std::string& headers, uint32_t* start, uint32_t* end) {
   net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n");
   while (it.GetNext()) {
-    if (LowerCaseEqualsASCII(it.name(), "content-range")) {
+    if (base::LowerCaseEqualsASCII(it.name(), "content-range")) {
       std::string range = it.values().c_str();
-      if (StartsWithASCII(range, "bytes", false)) {
+      if (base::StartsWithASCII(range, "bytes", false)) {
         range = range.substr(strlen("bytes"));
         std::string::size_type pos = range.find('-');
         std::string range_end;
@@ -51,9 +51,9 @@
 std::string GetMultiPartBoundary(const std::string& headers) {
   net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n");
   while (it.GetNext()) {
-    if (LowerCaseEqualsASCII(it.name(), "content-type")) {
+    if (base::LowerCaseEqualsASCII(it.name(), "content-type")) {
       std::string type = base::StringToLowerASCII(it.values());
-      if (StartsWithASCII(type, "multipart/", true)) {
+      if (base::StartsWithASCII(type, "multipart/", true)) {
         const char* boundary = strstr(type.c_str(), "boundary=");
         if (!boundary) {
           NOTREACHED();
@@ -118,8 +118,8 @@
 
   // This happens for PDFs not loaded from http(s) sources.
   if (response_headers == "Content-Type: text/plain") {
-    if (!StartsWithASCII(url, "http://", false) &&
-        !StartsWithASCII(url, "https://", false)) {
+    if (!base::StartsWithASCII(url, "http://", false) &&
+        !base::StartsWithASCII(url, "https://", false)) {
       type = "application/pdf";
     }
   }
@@ -127,27 +127,27 @@
     net::HttpUtil::HeadersIterator it(response_headers.begin(),
                                       response_headers.end(), "\n");
     while (it.GetNext()) {
-      if (LowerCaseEqualsASCII(it.name(), "content-length")) {
+      if (base::LowerCaseEqualsASCII(it.name(), "content-length")) {
         content_length = atoi(it.values().c_str());
-      } else if (LowerCaseEqualsASCII(it.name(), "accept-ranges")) {
-        accept_ranges_bytes = LowerCaseEqualsASCII(it.values(), "bytes");
-      } else if (LowerCaseEqualsASCII(it.name(), "content-encoding")) {
+      } else if (base::LowerCaseEqualsASCII(it.name(), "accept-ranges")) {
+        accept_ranges_bytes = base::LowerCaseEqualsASCII(it.values(), "bytes");
+      } else if (base::LowerCaseEqualsASCII(it.name(), "content-encoding")) {
         content_encoded = true;
-      } else if (LowerCaseEqualsASCII(it.name(), "content-type")) {
+      } else if (base::LowerCaseEqualsASCII(it.name(), "content-type")) {
         type = it.values();
         size_t semi_colon_pos = type.find(';');
         if (semi_colon_pos != std::string::npos) {
           type = type.substr(0, semi_colon_pos);
         }
         TrimWhitespace(type, base::TRIM_ALL, &type);
-      } else if (LowerCaseEqualsASCII(it.name(), "content-disposition")) {
+      } else if (base::LowerCaseEqualsASCII(it.name(), "content-disposition")) {
         disposition = it.values();
       }
     }
   }
   if (!type.empty() && !IsValidContentType(type))
     return false;
-  if (StartsWithASCII(disposition, "attachment", false))
+  if (base::StartsWithASCII(disposition, "attachment", false))
     return false;
 
   if (content_length > 0)
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 4b279462..1672ec4 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -592,6 +592,7 @@
       last_page_to_search_(-1),
       last_character_index_to_search_(-1),
       permissions_(0),
+      permissions_handler_revision_(-1),
       fpdf_availability_(NULL),
       next_timer_id_(0),
       last_page_mouse_down_(-1),
@@ -2324,16 +2325,32 @@
 }
 
 bool PDFiumEngine::HasPermission(DocumentPermission permission) const {
+  // PDF 1.7 spec, section 3.5.2 says: "If the revision number is 2 or greater,
+  // the operations to which user access can be controlled are as follows: ..."
+  //
+  // Thus for revision numbers less than 2, permissions are ignored and this
+  // always returns true.
+  if (permissions_handler_revision_ < 2)
+    return true;
+
+  // Handle high quality printing permission separately for security handler
+  // revision 3+. See table 3.20 in the PDF 1.7 spec.
+  if (permission == PERMISSION_PRINT_HIGH_QUALITY &&
+      permissions_handler_revision_ >= 3) {
+    return (permissions_ & kPDFPermissionPrintLowQualityMask) != 0 &&
+           (permissions_ & kPDFPermissionPrintHighQualityMask) != 0;
+  }
+
   switch (permission) {
     case PERMISSION_COPY:
       return (permissions_ & kPDFPermissionCopyMask) != 0;
     case PERMISSION_COPY_ACCESSIBLE:
       return (permissions_ & kPDFPermissionCopyAccessibleMask) != 0;
     case PERMISSION_PRINT_LOW_QUALITY:
-      return (permissions_ & kPDFPermissionPrintLowQualityMask) != 0;
     case PERMISSION_PRINT_HIGH_QUALITY:
-      return (permissions_ & kPDFPermissionPrintLowQualityMask) != 0 &&
-             (permissions_ & kPDFPermissionPrintHighQualityMask) != 0;
+      // With security handler revision 2 rules, check the same bit for high
+      // and low quality. See table 3.20 in the PDF 1.7 spec.
+      return (permissions_ & kPDFPermissionPrintLowQualityMask) != 0;
     default:
       return true;
   }
@@ -2622,6 +2639,7 @@
     client_->DocumentHasUnsupportedFeature("Bookmarks");
 
   permissions_ = FPDF_GetDocPermissions(doc_);
+  permissions_handler_revision_ = FPDF_GetSecurityHandlerRevision(doc_);
 
   if (!form_) {
     // Only returns 0 when data isn't available.  If form data is downloaded, or
@@ -3899,7 +3917,7 @@
         doc, "Creator", WriteInto(&creator, buffer_bytes + 1), buffer_bytes);
   }
   bool use_bitmap = false;
-  if (StartsWith(creator, L"cairo", false))
+  if (base::StartsWith(creator, L"cairo", false))
     use_bitmap = true;
 
   // Another temporary hack. Some PDFs seems to render very slowly if
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 480a6e8..ff45f45 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -647,6 +647,9 @@
   // Permissions bitfield.
   unsigned long permissions_;
 
+  // Permissions security handler revision number. -1 for unknown.
+  int permissions_handler_revision_;
+
   // Interface structure to provide access to document stream.
   FPDF_FILEACCESS file_access_;
   // Interface structure to check data availability in the document stream.
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.cc b/ppapi/proxy/ppapi_command_buffer_proxy.cc
index 73f6dfce..384df02a 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.cc
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.cc
@@ -162,6 +162,11 @@
   NOTIMPLEMENTED();
 }
 
+bool PpapiCommandBufferProxy::IsGpuChannelLost() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
 uint32 PpapiCommandBufferProxy::InsertSyncPoint() {
   uint32 sync_point = 0;
   if (last_state_.error == gpu::error::kNoError) {
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.h b/ppapi/proxy/ppapi_command_buffer_proxy.h
index 62f77a4..24ed177 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.h
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.h
@@ -66,6 +66,7 @@
   void SetSurfaceVisible(bool visible) override;
   uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
+  bool IsGpuChannelLost() override;
 
  private:
   bool Send(IPC::Message* msg);
diff --git a/ppapi/proxy/raw_var_data_unittest.cc b/ppapi/proxy/raw_var_data_unittest.cc
index ac353b9..8f783c2 100644
--- a/ppapi/proxy/raw_var_data_unittest.cc
+++ b/ppapi/proxy/raw_var_data_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
 #include "base/values.h"
 #include "ppapi/c/pp_bool.h"
 #include "ppapi/c/pp_var.h"
@@ -46,6 +47,7 @@
   }
 
  private:
+  base::MessageLoop message_loop_;  // Required to receive callbacks.
   TestGlobals globals_;
 };
 
diff --git a/ppapi/shared_impl/proxy_lock_unittest.cc b/ppapi/shared_impl/proxy_lock_unittest.cc
index c533b5b..425a00d 100644
--- a/ppapi/shared_impl/proxy_lock_unittest.cc
+++ b/ppapi/shared_impl/proxy_lock_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
 #include "ppapi/shared_impl/proxy_lock.h"
 #include "ppapi/shared_impl/test_globals.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -65,7 +66,11 @@
 
 }  // namespace
 
-TEST(PpapiProxyLockTest, Locking) {
+class PpapiProxyLockTest : public testing::Test {
+  base::MessageLoop message_loop_;  // Required to receive callbacks.
+};
+
+TEST_F(PpapiProxyLockTest, Locking) {
   TestGlobals globals;
   expect_to_be_locked = true;
 
@@ -143,7 +148,7 @@
   called_num = 0;
 }
 
-TEST(PpapiProxyLockTest, Unlocking) {
+TEST_F(PpapiProxyLockTest, Unlocking) {
   TestGlobals globals;
   expect_to_be_locked = false;
   // These calls should all try to _unlock_, so we must be locked before
diff --git a/ppapi/shared_impl/resource_tracker_unittest.cc b/ppapi/shared_impl/resource_tracker_unittest.cc
index a8fac3b..c57b32d2 100644
--- a/ppapi/shared_impl/resource_tracker_unittest.cc
+++ b/ppapi/shared_impl/resource_tracker_unittest.cc
@@ -5,6 +5,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
 #include "ppapi/shared_impl/proxy_lock.h"
 #include "ppapi/shared_impl/resource.h"
 #include "ppapi/shared_impl/resource_tracker.h"
@@ -48,6 +49,7 @@
   ResourceTracker& resource_tracker() { return *globals_.GetResourceTracker(); }
 
  private:
+  base::MessageLoop message_loop_;  // Required to receive callbacks.
   TestGlobals globals_;
 };
 
diff --git a/ppapi/shared_impl/var_tracker_unittest.cc b/ppapi/shared_impl/var_tracker_unittest.cc
index 9dd03b3..f0408e7 100644
--- a/ppapi/shared_impl/var_tracker_unittest.cc
+++ b/ppapi/shared_impl/var_tracker_unittest.cc
@@ -5,6 +5,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
 #include "ppapi/shared_impl/proxy_lock.h"
 #include "ppapi/shared_impl/var.h"
 #include "ppapi/shared_impl/var_tracker.h"
@@ -48,6 +49,7 @@
   VarTracker& var_tracker() { return *globals_.GetVarTracker(); }
 
  private:
+  base::MessageLoop message_loop_;  // Required to receive callbacks.
   TestGlobals globals_;
 };
 
diff --git a/remoting/android/java/src/org/chromium/chromoting/Desktop.java b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
index ac61f249..c4f3695 100644
--- a/remoting/android/java/src/org/chromium/chromoting/Desktop.java
+++ b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
@@ -138,8 +138,9 @@
     }
 
     public void showActionBar() {
-        showActionBarWithoutSystemUi();
-
+        // Request exit from any fullscreen mode. The action-bar controls will be shown in response
+        // to the SystemUiVisibility notification. The visibility of the action-bar should be tied
+        // to the fullscreen state of the system, so there's no need to explicitly show it here.
         View decorView = getWindow().getDecorView();
         decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
     }
@@ -151,8 +152,12 @@
 
     @SuppressLint("InlinedApi")
     public void hideActionBar() {
-        hideActionBarWithoutSystemUi();
-
+        // Request the device to enter fullscreen mode. Don't hide the controls yet, because the
+        // system might not honor the fullscreen request immediately (for example, if the
+        // keyboard is visible, the system might delay fullscreen until the keyboard is hidden).
+        // The controls will be hidden in response to the SystemUiVisibility notification.
+        // This helps ensure that the visibility of the controls is synchronized with the
+        // fullscreen state.
         View decorView = getWindow().getDecorView();
 
         // LOW_PROFILE gives the status and navigation bars a "lights-out" appearance.
diff --git a/remoting/app_remoting_test.gyp b/remoting/app_remoting_test.gyp
deleted file mode 100644
index 8c33043..0000000
--- a/remoting/app_remoting_test.gyp
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'includes': [
-    'remoting_version.gypi',
-  ],
-
-  'target_defaults': {
-    'type': 'none',
-  },  # target_defaults
-
-  'targets': [
-    {
-      'target_name': 'ar_test_driver_common',
-      'type': 'static_library',
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../base/base.gyp:test_support_base',
-        '../google_apis/google_apis.gyp:google_apis',
-        '../net/net.gyp:net',
-        '../remoting/remoting.gyp:remoting_base',
-        '../remoting/remoting.gyp:remoting_client',
-        '../remoting/remoting.gyp:remoting_protocol',
-        '../remoting/proto/chromotocol.gyp:chromotocol_proto_lib',
-        '../testing/gtest.gyp:gtest',
-      ],
-      'defines': [
-        'VERSION=<(version_full)',
-      ],
-      'sources': [
-        'test/access_token_fetcher.cc',
-        'test/access_token_fetcher.h',
-        'test/app_remoting_connected_client_fixture.cc',
-        'test/app_remoting_connected_client_fixture.h',
-        'test/app_remoting_test_driver_environment.cc',
-        'test/app_remoting_test_driver_environment.h',
-        'test/refresh_token_store.cc',
-        'test/refresh_token_store.h',
-        'test/remote_application_details.h',
-        'test/remote_connection_observer.h',
-        'test/remote_host_info.cc',
-        'test/remote_host_info.h',
-        'test/remote_host_info_fetcher.cc',
-        'test/remote_host_info_fetcher.h',
-        'test/test_chromoting_client.cc',
-        'test/test_chromoting_client.h',
-        'test/test_video_renderer.cc',
-        'test/test_video_renderer.h',
-      ],
-    },  # end of target 'ar_test_driver_common'
-    {
-      # An external version of the test driver tool which includes minimal tests
-      'target_name': 'ar_sample_test_driver',
-      'type': '<(gtest_target_type)',
-      'dependencies': [
-        'ar_test_driver_common',
-      ],
-      'defines': [
-        'VERSION=<(version_full)',
-      ],
-      'sources': [
-        'test/app_remoting_test_driver.cc',
-        'test/app_remoting_test_driver_environment_app_details.cc',
-      ],
-      'include_dirs': [
-        '../testing/gtest/include',
-      ],
-    },  # end of target 'ar_sample_test_driver'
-  ],  # end of targets
-}
diff --git a/remoting/app_remoting_webapp_files.gypi b/remoting/app_remoting_webapp_files.gypi
index 560bf83..fc5686d 100644
--- a/remoting/app_remoting_webapp_files.gypi
+++ b/remoting/app_remoting_webapp_files.gypi
@@ -62,8 +62,10 @@
       'webapp/app_remoting/js/context_menu_chrome.js',
       'webapp/app_remoting/js/context_menu_dom.js',
       'webapp/app_remoting/js/drag_and_drop.js',
+      'webapp/app_remoting/js/gaia_license_manager.js',
       'webapp/app_remoting/js/idle_detector.js',
       'webapp/app_remoting/js/keyboard_layouts_menu.js',
+      'webapp/app_remoting/js/license_manager.js',
       'webapp/app_remoting/js/loading_window.js',
       'webapp/app_remoting/js/submenu_manager.js',
       'webapp/app_remoting/js/window_activation_menu.js',
diff --git a/remoting/base/run_all_unittests.cc b/remoting/base/run_all_unittests.cc
index 5f52f7e..a9c5b64 100644
--- a/remoting/base/run_all_unittests.cc
+++ b/remoting/base/run_all_unittests.cc
@@ -14,8 +14,8 @@
   // single-threaded.
   net::EnableSSLServerSockets();
 
-  // Ensures runtime specific CPU features are initialized.
-  media::InitializeCPUSpecificMediaFeatures();
+  // Ensures that media library and specific CPU features are initialized.
+  media::InitializeMediaLibrary();
 
   return base::LaunchUnitTests(
       argc, argv, base::Bind(&base::TestSuite::Run,
diff --git a/remoting/codec/codec_test.cc b/remoting/codec/codec_test.cc
index 8b9511c..51b52f03e 100644
--- a/remoting/codec/codec_test.cc
+++ b/remoting/codec/codec_test.cc
@@ -247,7 +247,7 @@
 
 static void TestEncodingRects(VideoEncoder* encoder,
                               VideoEncoderTester* tester,
-                              webrtc::DesktopFrame* frame,
+                              DesktopFrame* frame,
                               const DesktopRect* rects,
                               int count) {
   frame->mutable_updated_region()->Clear();
@@ -267,7 +267,7 @@
   for (size_t xi = 0; xi < arraysize(kSizes); ++xi) {
     for (size_t yi = 0; yi < arraysize(kSizes); ++yi) {
       DesktopSize size = DesktopSize(kSizes[xi], kSizes[yi]);
-      scoped_ptr<webrtc::DesktopFrame> frame = PrepareFrame(size);
+      scoped_ptr<DesktopFrame> frame = PrepareFrame(size);
       std::vector<std::vector<DesktopRect> > test_rect_lists =
           MakeTestRectLists(size);
       for (size_t i = 0; i < test_rect_lists.size(); ++i) {
@@ -275,10 +275,31 @@
         TestEncodingRects(encoder, &tester, frame.get(),
                           &test_rects[0], test_rects.size());
       }
+
+      // Pass some empty frames through the encoder.
+      for (int i = 0; i < 10; ++i) {
+        TestEncodingRects(encoder, &tester, frame.get(), nullptr, 0);
+      }
     }
   }
 }
 
+void TestVideoEncoderEmptyFrames(VideoEncoder* encoder, int topoff_frames) {
+  const DesktopSize kSize(640, 480);
+  scoped_ptr<DesktopFrame> frame(PrepareFrame(kSize));
+
+  frame->mutable_updated_region()->SetRect(
+      webrtc::DesktopRect::MakeSize(kSize));
+  EXPECT_TRUE(encoder->Encode(*frame));
+
+  frame->mutable_updated_region()->Clear();
+  for (int i=0; i < topoff_frames; ++i) {
+    EXPECT_TRUE(encoder->Encode(*frame));
+  }
+
+  EXPECT_FALSE(encoder->Encode(*frame));
+}
+
 static void TestEncodeDecodeRects(VideoEncoder* encoder,
                                   VideoEncoderTester* encoder_tester,
                                   VideoDecoderTester* decoder_tester,
diff --git a/remoting/codec/codec_test.h b/remoting/codec/codec_test.h
index 9c9ec7b..0c143b779 100644
--- a/remoting/codec/codec_test.h
+++ b/remoting/codec/codec_test.h
@@ -26,6 +26,12 @@
 // rects match dirty rects.
 void TestVideoEncoder(VideoEncoder* encoder, bool strict);
 
+// Generate test data and test the encoder for a sequence of one "changed"
+// frame followed by one or more "unchanged" frames, and verify that the
+// encoder sends exactly |topoff_frames| of non-empty data for unchanged
+// frames, after which it returns null frames.
+void TestVideoEncoderEmptyFrames(VideoEncoder* encoder, int topoff_frames);
+
 // Generate test data and test the encoder and decoder pair.
 //
 // If |strict| is set to true, this routine will make sure the updated rects
diff --git a/remoting/codec/video_encoder.h b/remoting/codec/video_encoder.h
index f497eb3..9da447c 100644
--- a/remoting/codec/video_encoder.h
+++ b/remoting/codec/video_encoder.h
@@ -25,7 +25,10 @@
   virtual void SetLosslessEncode(bool want_lossless) {}
   virtual void SetLosslessColor(bool want_lossless) {}
 
-  // Encode an image stored in |frame|.
+  // Encode an image stored in |frame|. If |frame.updated_region()| is empty
+  // then the encoder may return a packet (e.g. to top-off previously-encoded
+  // portions of the frame to higher quality) or return nullptr to indicate that
+  // there is no work to do.
   virtual scoped_ptr<VideoPacket> Encode(const webrtc::DesktopFrame& frame) = 0;
 };
 
diff --git a/remoting/codec/video_encoder_verbatim.cc b/remoting/codec/video_encoder_verbatim.cc
index c7550e17..2948e3e 100644
--- a/remoting/codec/video_encoder_verbatim.cc
+++ b/remoting/codec/video_encoder_verbatim.cc
@@ -25,7 +25,12 @@
 
 scoped_ptr<VideoPacket> VideoEncoderVerbatim::Encode(
     const webrtc::DesktopFrame& frame) {
-  CHECK(frame.data());
+  DCHECK(frame.data());
+
+  // If nothing has changed in the frame then return NULL to indicate that
+  // we don't need to actually send anything (e.g. nothing to top-off).
+  if (frame.updated_region().is_empty())
+    return nullptr;
 
   base::Time encode_start_time = base::Time::Now();
 
diff --git a/remoting/codec/video_encoder_verbatim_unittest.cc b/remoting/codec/video_encoder_verbatim_unittest.cc
index b9e72ac..a294d7bd 100644
--- a/remoting/codec/video_encoder_verbatim_unittest.cc
+++ b/remoting/codec/video_encoder_verbatim_unittest.cc
@@ -21,4 +21,9 @@
   TestVideoEncoderDecoder(encoder.get(), decoder.get(), true);
 }
 
+TEST(VideoEncoderVerbatimTest, EncodeUnchangedFrame) {
+  scoped_ptr<VideoEncoderVerbatim> encoder(new VideoEncoderVerbatim());
+  TestVideoEncoderEmptyFrames(encoder.get(), 0);
+}
+
 }  // namespace remoting
diff --git a/remoting/codec/video_encoder_vpx.cc b/remoting/codec/video_encoder_vpx.cc
index c74f0d8..adc6bf9 100644
--- a/remoting/codec/video_encoder_vpx.cc
+++ b/remoting/codec/video_encoder_vpx.cc
@@ -5,7 +5,6 @@
 #include "remoting/codec/video_encoder_vpx.h"
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/sys_info.h"
 #include "remoting/base/util.h"
@@ -25,9 +24,6 @@
 
 namespace {
 
-// Name of command-line flag to enable VP9 to use I444 by default.
-const char kEnableI444SwitchName[] = "enable-i444";
-
 // Number of bytes in an RGBx pixel.
 const int kBytesPerRgbPixel = 4;
 
@@ -103,7 +99,9 @@
     config->rc_max_quantizer = 0;
     config->rc_end_usage = VPX_VBR;
   } else {
-    config->rc_min_quantizer = 4;
+    // TODO(wez): Set quantization range to 4-40, once the libvpx encoder is
+    // updated not to output any bits if nothing needs topping-off.
+    config->rc_min_quantizer = 20;
     config->rc_max_quantizer = 30;
     config->rc_end_usage = VPX_CBR;
     // In the absence of a good bandwidth estimator set the target bitrate to a
@@ -268,6 +266,22 @@
   DCHECK_LE(32, frame.size().width());
   DCHECK_LE(32, frame.size().height());
 
+  if (!use_vp9_ || lossless_encode_) {
+    // Neither VP8 nor VP9-lossless support top-off, so ignore unchanged frames.
+    if (frame.updated_region().is_empty())
+      return nullptr;
+  } else {
+    // Let VP9-lossy mode top-off, by continuing to pass it unchanged frames
+    // for a short while.
+    if (frame.updated_region().is_empty()) {
+      if (topoff_frame_count_ == 0)
+        return nullptr;
+      topoff_frame_count_--;
+    } else {
+      topoff_frame_count_ = 2;
+    }
+  }
+
   base::TimeTicks encode_start_time = base::TimeTicks::Now();
 
   // Create or reconfigure the codec to match the size of |frame|.
@@ -343,19 +357,7 @@
   return packet.Pass();
 }
 
-VideoEncoderVpx::VideoEncoderVpx(bool use_vp9)
-    : use_vp9_(use_vp9),
-      lossless_encode_(false),
-      lossless_color_(false),
-      active_map_width_(0),
-      active_map_height_(0) {
-  if (use_vp9_) {
-    // Use I444 colour space, by default, if specified on the command-line.
-    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-            kEnableI444SwitchName)) {
-      SetLosslessColor(true);
-    }
-  }
+VideoEncoderVpx::VideoEncoderVpx(bool use_vp9) : use_vp9_(use_vp9) {
 }
 
 void VideoEncoderVpx::Configure(const webrtc::DesktopSize& size) {
diff --git a/remoting/codec/video_encoder_vpx.h b/remoting/codec/video_encoder_vpx.h
index d8d39eb..dbfefeb1 100644
--- a/remoting/codec/video_encoder_vpx.h
+++ b/remoting/codec/video_encoder_vpx.h
@@ -58,8 +58,8 @@
 
   // Options controlling VP9 encode quantization and color space.
   // These are always off (false) for VP8.
-  bool lossless_encode_;
-  bool lossless_color_;
+  bool lossless_encode_ = false;
+  bool lossless_color_ = false;
 
   // Holds the initialized & configured codec.
   ScopedVpxCodec codec_;
@@ -73,8 +73,12 @@
 
   // Active map used to optimize out processing of un-changed macroblocks.
   scoped_ptr<uint8[]> active_map_;
-  int active_map_width_;
-  int active_map_height_;
+  int active_map_width_ = 0;
+  int active_map_height_ = 0;
+
+  // Number of "top-off" frames we've encoded since we were last passed a
+  // frame containing an actual change. Used only when encoding with top-off.
+  int topoff_frame_count_ = 0;
 
   // Used to help initialize VideoPackets from DesktopFrames.
   VideoEncoderHelper helper_;
diff --git a/remoting/codec/video_encoder_vpx_unittest.cc b/remoting/codec/video_encoder_vpx_unittest.cc
index 98b3991..efe07d2b 100644
--- a/remoting/codec/video_encoder_vpx_unittest.cc
+++ b/remoting/codec/video_encoder_vpx_unittest.cc
@@ -39,19 +39,19 @@
   return frame.Pass();
 }
 
-TEST(VideoEncoderVpxTest, TestVp8VideoEncoder) {
+TEST(VideoEncoderVpxTest, Vp8) {
   scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
   TestVideoEncoder(encoder.get(), false);
 }
 
-TEST(VideoEncoderVpxTest, TestVp9VideoEncoder) {
+TEST(VideoEncoderVpxTest, Vp9) {
   scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
   // VP9 encoder defaults to lossless encode and lossy (I420) color.
   TestVideoEncoder(encoder.get(), false);
 }
 
 // Test that the VP9 encoder can switch between lossy & lossless encode.
-TEST(VideoEncoderVpxTest, TestVp9VideoEncoderLossyEncode) {
+TEST(VideoEncoderVpxTest, Vp9LossyEncodeSwitching) {
   scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
 
   webrtc::DesktopSize frame_size(1024, 768);
@@ -77,7 +77,7 @@
 }
 
 // Test that the VP9 encoder can switch between lossy & lossless color.
-TEST(VideoEncoderVpxTest, TestVp9VideoEncoderLossyColor) {
+TEST(VideoEncoderVpxTest, Vp9LossyColorSwitching) {
   scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
 
   webrtc::DesktopSize frame_size(1024, 768);
@@ -97,7 +97,7 @@
 }
 
 // Test that the VP8 encoder ignores lossless modes without crashing.
-TEST(VideoEncoderVpxTest, TestVp8VideoEncoderIgnoreLossy) {
+TEST(VideoEncoderVpxTest, Vp8IgnoreLossy) {
   scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
 
   webrtc::DesktopSize frame_size(1024, 768);
@@ -112,7 +112,7 @@
 
 // Test that calling Encode with a larger frame size than the initial one
 // does not cause VP8 to crash.
-TEST(VideoEncoderVpxTest, TestVp8SizeChangeNoCrash) {
+TEST(VideoEncoderVpxTest, Vp8SizeChangeNoCrash) {
   webrtc::DesktopSize frame_size(1000, 1000);
 
   scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
@@ -131,7 +131,7 @@
 
 // Test that calling Encode with a larger frame size than the initial one
 // does not cause VP9 to crash.
-TEST(VideoEncoderVpxTest, TestVp9SizeChangeNoCrash) {
+TEST(VideoEncoderVpxTest, Vp9SizeChangeNoCrash) {
   webrtc::DesktopSize frame_size(1000, 1000);
 
   scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
@@ -150,7 +150,7 @@
 
 // Test that the DPI information is correctly propagated from the
 // media::ScreenCaptureData to the VideoPacket.
-TEST(VideoEncoderVpxTest, TestDpiPropagation) {
+TEST(VideoEncoderVpxTest, DpiPropagation) {
   webrtc::DesktopSize frame_size(32, 32);
 
   scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
@@ -162,4 +162,21 @@
   EXPECT_EQ(packet->format().y_dpi(), 97);
 }
 
+TEST(VideoEncoderVerbatimTest, Vp8EncodeUnchangedFrame) {
+  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
+  TestVideoEncoderEmptyFrames(encoder.get(), 0);
+}
+
+TEST(VideoEncoderVerbatimTest, Vp9LosslessUnchangedFrame) {
+  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
+  encoder->SetLosslessEncode(true);
+  TestVideoEncoderEmptyFrames(encoder.get(), 0);
+}
+
+TEST(VideoEncoderVerbatimTest, Vp9LossyUnchangedFrame) {
+  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
+  encoder->SetLosslessEncode(false);
+  TestVideoEncoderEmptyFrames(encoder.get(), 2);
+}
+
 }  // namespace remoting
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index d6a02fa6..2b72eca8 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/command_line.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "remoting/base/capabilities.h"
@@ -41,6 +42,9 @@
 
 namespace {
 
+// Name of command-line flag to enable VP9 to use I444 by default.
+const char kEnableI444SwitchName[] = "enable-i444";
+
 scoped_ptr<VideoEncoder> CreateVideoEncoder(
     const protocol::SessionConfig& config) {
   const protocol::ChannelConfig& video_config = config.video_config();
@@ -107,7 +111,8 @@
       is_authenticated_(false),
       pause_video_(false),
       lossless_video_encode_(false),
-      lossless_video_color_(false),
+      lossless_video_color_(base::CommandLine::ForCurrentProcess()->HasSwitch(
+          kEnableI444SwitchName)),
       weak_factory_(this) {
   connection_->SetEventHandler(this);
 
diff --git a/remoting/host/fake_desktop_capturer.cc b/remoting/host/fake_desktop_capturer.cc
index 56a39cf..520d396 100644
--- a/remoting/host/fake_desktop_capturer.cc
+++ b/remoting/host/fake_desktop_capturer.cc
@@ -143,8 +143,10 @@
 void FakeDesktopCapturer::Capture(const webrtc::DesktopRegion& region) {
   base::Time capture_start_time = base::Time::Now();
   scoped_ptr<webrtc::DesktopFrame> frame = frame_generator_.Run(callback_);
-  frame->set_capture_time_ms(
-      (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
+  if (frame) {
+    frame->set_capture_time_ms(
+        (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
+  }
   callback_->OnCaptureCompleted(frame.release());
 }
 
diff --git a/remoting/host/gcd_state_updater.cc b/remoting/host/gcd_state_updater.cc
index f4921844..5acfacd 100644
--- a/remoting/host/gcd_state_updater.cc
+++ b/remoting/host/gcd_state_updater.cc
@@ -24,11 +24,11 @@
     const base::Closure& on_update_successful_callback,
     const base::Closure& on_unknown_host_id_error,
     SignalStrategy* signal_strategy,
-    GcdRestClient* gcd_rest_client)
+    scoped_ptr<GcdRestClient> gcd_rest_client)
     : on_update_successful_callback_(on_update_successful_callback),
       on_unknown_host_id_error_(on_unknown_host_id_error),
       signal_strategy_(signal_strategy),
-      gcd_rest_client_(gcd_rest_client) {
+      gcd_rest_client_(gcd_rest_client.Pass()) {
   DCHECK(signal_strategy_);
   DCHECK(thread_checker_.CalledOnValidThread());
 
diff --git a/remoting/host/gcd_state_updater.h b/remoting/host/gcd_state_updater.h
index 84dccea..7962275 100644
--- a/remoting/host/gcd_state_updater.h
+++ b/remoting/host/gcd_state_updater.h
@@ -36,7 +36,7 @@
   GcdStateUpdater(const base::Closure& on_update_successful_callback,
                   const base::Closure& on_unknown_host_id_error,
                   SignalStrategy* signal_strategy,
-                  GcdRestClient* gcd_client);
+                  scoped_ptr<GcdRestClient> gcd_client);
   ~GcdStateUpdater() override;
 
   // See HeartbeatSender::SetHostOfflineReason.
@@ -56,7 +56,7 @@
   base::Closure on_update_successful_callback_;
   base::Closure on_unknown_host_id_error_;
   SignalStrategy* signal_strategy_;
-  GcdRestClient* gcd_rest_client_;
+  scoped_ptr<GcdRestClient> gcd_rest_client_;
   BackoffTimer timer_;
   base::ThreadChecker thread_checker_;
   bool has_pending_state_request_ = false;
diff --git a/remoting/host/gcd_state_updater_unittest.cc b/remoting/host/gcd_state_updater_unittest.cc
index 9d5baff..9ac287d 100644
--- a/remoting/host/gcd_state_updater_unittest.cc
+++ b/remoting/host/gcd_state_updater_unittest.cc
@@ -33,12 +33,13 @@
         token_getter_(OAuthTokenGetter::SUCCESS,
                       "<fake_user_email>",
                       "<fake_access_token>"),
-        rest_client_("http://gcd_base_url",
-                     "<gcd_device_id>",
-                     nullptr,
-                     &token_getter_),
+        rest_client_(new GcdRestClient(
+            "http://gcd_base_url",
+            "<gcd_device_id>",
+            nullptr,
+            &token_getter_)),
         signal_strategy_("local_jid") {
-    rest_client_.SetClockForTest(make_scoped_ptr(new base::SimpleTestClock));
+    rest_client_->SetClockForTest(make_scoped_ptr(new base::SimpleTestClock));
   }
 
   void OnSuccess() { on_success_count_++; }
@@ -51,7 +52,7 @@
   scoped_ptr<base::Clock> clock_;
   net::TestURLFetcherFactory url_fetcher_factory_;
   FakeOAuthTokenGetter token_getter_;
-  GcdRestClient rest_client_;
+  scoped_ptr<GcdRestClient> rest_client_;
   FakeSignalStrategy signal_strategy_;
   int on_success_count_ = 0;
   int on_host_id_error_count_ = 0;
@@ -61,7 +62,7 @@
   scoped_ptr<GcdStateUpdater> updater(new GcdStateUpdater(
       base::Bind(&GcdStateUpdaterTest::OnSuccess, base::Unretained(this)),
       base::Bind(&GcdStateUpdaterTest::OnHostIdError, base::Unretained(this)),
-      &signal_strategy_, &rest_client_));
+      &signal_strategy_, rest_client_.Pass()));
 
   signal_strategy_.Connect();
   task_runner_->RunUntilIdle();
@@ -85,7 +86,7 @@
   scoped_ptr<GcdStateUpdater> updater(new GcdStateUpdater(
       base::Bind(&GcdStateUpdaterTest::OnSuccess, base::Unretained(this)),
       base::Bind(&GcdStateUpdaterTest::OnHostIdError, base::Unretained(this)),
-      &signal_strategy_, &rest_client_));
+      &signal_strategy_, rest_client_.Pass()));
 
   // Connect, then re-connect with a different JID while the status
   // update for the first connection is pending.
@@ -129,7 +130,7 @@
   scoped_ptr<GcdStateUpdater> updater(new GcdStateUpdater(
       base::Bind(&GcdStateUpdaterTest::OnSuccess, base::Unretained(this)),
       base::Bind(&GcdStateUpdaterTest::OnHostIdError, base::Unretained(this)),
-      &signal_strategy_, &rest_client_));
+      &signal_strategy_, rest_client_.Pass()));
 
   signal_strategy_.Connect();
   task_runner_->RunUntilIdle();
@@ -154,7 +155,7 @@
   scoped_ptr<GcdStateUpdater> updater(new GcdStateUpdater(
       base::Bind(&GcdStateUpdaterTest::OnSuccess, base::Unretained(this)),
       base::Bind(&GcdStateUpdaterTest::OnHostIdError, base::Unretained(this)),
-      &signal_strategy_, &rest_client_));
+      &signal_strategy_, rest_client_.Pass()));
 
   signal_strategy_.Connect();
   task_runner_->RunUntilIdle();
diff --git a/remoting/host/host_mock_objects.cc b/remoting/host/host_mock_objects.cc
index c48517f5..8fdc11e 100644
--- a/remoting/host/host_mock_objects.cc
+++ b/remoting/host/host_mock_objects.cc
@@ -13,8 +13,10 @@
 #include "remoting/host/audio_capturer.h"
 #include "remoting/host/input_injector.h"
 #include "remoting/proto/event.pb.h"
+#include "remoting/proto/video.pb.h"
 #include "remoting/protocol/transport.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
 
 namespace remoting {
 
@@ -88,4 +90,15 @@
 
 MockMouseCursorMonitor::~MockMouseCursorMonitor() {}
 
+MockVideoEncoder::MockVideoEncoder() {
+}
+
+MockVideoEncoder::~MockVideoEncoder() {
+}
+
+scoped_ptr<VideoPacket> MockVideoEncoder::Encode(
+    const webrtc::DesktopFrame& frame) {
+  return make_scoped_ptr(EncodePtr(frame));
+}
+
 }  // namespace remoting
diff --git a/remoting/host/host_mock_objects.h b/remoting/host/host_mock_objects.h
index 52d0170..d4462c8 100644
--- a/remoting/host/host_mock_objects.h
+++ b/remoting/host/host_mock_objects.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "net/base/ip_endpoint.h"
+#include "remoting/codec/video_encoder.h"
 #include "remoting/host/chromoting_host_context.h"
 #include "remoting/host/client_session.h"
 #include "remoting/host/client_session_control.h"
@@ -19,6 +20,7 @@
 #include "remoting/host/screen_resolution.h"
 #include "remoting/proto/control.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
 
 namespace base {
@@ -164,6 +166,18 @@
   DISALLOW_COPY_AND_ASSIGN(MockMouseCursorMonitor);
 };
 
+class MockVideoEncoder : public VideoEncoder {
+ public:
+  MockVideoEncoder();
+  ~MockVideoEncoder() override;
+
+  MOCK_METHOD1(SetLosslessEncode, void(bool));
+  MOCK_METHOD1(SetLosslessColor, void(bool));
+  MOCK_METHOD1(EncodePtr, VideoPacket*(const webrtc::DesktopFrame&));
+
+  scoped_ptr<VideoPacket> Encode(const webrtc::DesktopFrame& frame) override;
+};
+
 }  // namespace remoting
 
 #endif  // REMOTING_HOST_HOST_MOCK_OBJECTS_H_
diff --git a/remoting/host/input_injector_chromeos.cc b/remoting/host/input_injector_chromeos.cc
index 58afde0..8fa2ea2e 100644
--- a/remoting/host/input_injector_chromeos.cc
+++ b/remoting/host/input_injector_chromeos.cc
@@ -84,8 +84,8 @@
 
   // Ignore events which can't be mapped.
   if (dom_code != ui::DomCode::NONE) {
-    delegate_->InjectKeyPress(dom_code, event.pressed(),
-                              false /* enable_repeat */);
+    delegate_->InjectKeyEvent(dom_code, event.pressed(),
+                              true /* suppress_auto_repeat */);
   }
 }
 
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index 415681c..c1841f0 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -50,8 +50,8 @@
       weak_factory_(this) {
   weak_ptr_ = weak_factory_.GetWeakPtr();
 
-  // Ensures runtime specific CPU features are initialized.
-  media::InitializeCPUSpecificMediaFeatures();
+  // Ensures that media library and specific CPU features are initialized.
+  media::InitializeMediaLibrary();
 
   const ServiceUrls* service_urls = ServiceUrls::GetInstance();
   const bool xmpp_server_valid =
@@ -168,7 +168,8 @@
   // the authServiceWithToken field. But auth service part is always expected to
   // be set to oauth2.
   const char kOAuth2ServicePrefix[] = "oauth2:";
-  if (!StartsWithASCII(auth_service_with_token, kOAuth2ServicePrefix, true)) {
+  if (!base::StartsWithASCII(auth_service_with_token, kOAuth2ServicePrefix,
+                             true)) {
     SendErrorAndExit(response.Pass(), "Invalid 'authServiceWithToken': " +
                                           auth_service_with_token);
     return;
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 3b52799..eeb65be 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -45,6 +45,8 @@
 #include "remoting/host/desktop_environment.h"
 #include "remoting/host/desktop_session_connector.h"
 #include "remoting/host/dns_blackhole_checker.h"
+#include "remoting/host/gcd_rest_client.h"
+#include "remoting/host/gcd_state_updater.h"
 #include "remoting/host/heartbeat_sender.h"
 #include "remoting/host/host_change_notification_listener.h"
 #include "remoting/host/host_config.h"
@@ -75,6 +77,7 @@
 #include "remoting/protocol/pairing_registry.h"
 #include "remoting/protocol/port_range.h"
 #include "remoting/protocol/token_validator.h"
+#include "remoting/signaling/push_notification_subscriber.h"
 #include "remoting/signaling/xmpp_signal_strategy.h"
 
 #if defined(OS_POSIX)
@@ -307,6 +310,8 @@
                const std::string& file_name,
                const int& line_number);
 
+  bool using_gcd() { return !gcd_device_id_.empty(); }
+
   scoped_ptr<ChromotingHostContext> context_;
 
   // Accessed on the UI thread.
@@ -359,12 +364,17 @@
   // Used to specify which window to stream, if enabled.
   webrtc::WindowId window_id_;
 
-  // |heartbeat_sender_| and |signaling_connector_| have to be destroyed before
-  // |signal_strategy_| because their destructors need to call
-  // signal_strategy_->RemoveListener(this)
+  // Must outlive |gcd_state_updater_| and |signaling_connector_|.
+  scoped_ptr<OAuthTokenGetter> oauth_token_getter_;
+
+  // Must outlive |signaling_connector_|, |gcd_subscriber_|, and
+  // |heartbeat_sender_|.
   scoped_ptr<SignalStrategy> signal_strategy_;
+
   scoped_ptr<SignalingConnector> signaling_connector_;
   scoped_ptr<HeartbeatSender> heartbeat_sender_;
+  scoped_ptr<GcdStateUpdater> gcd_state_updater_;
+  scoped_ptr<PushNotificationSubscriber> gcd_subscriber_;
 
   scoped_ptr<HostChangeNotificationListener> host_change_notification_listener_;
   scoped_ptr<HostStatusLogger> host_status_logger_;
@@ -1109,9 +1119,9 @@
     }
 
     std::string username = GetUsername();
-    bool shutdown = username.empty() ||
-        !StartsWithASCII(host_owner_, username + std::string("@"),
-                         false);
+    bool shutdown =
+        username.empty() ||
+        !base::StartsWithASCII(host_owner_, username + std::string("@"), false);
 
 #if defined(OS_MACOSX)
     // On Mac, we run as root at the login screen, so the username won't match.
@@ -1309,8 +1319,13 @@
 }
 
 void HostProcess::InitializeSignaling() {
-  DCHECK(!host_id_.empty());  // |ApplyConfig| should already have been run.
+  DCHECK(!host_id_.empty());  // ApplyConfig() should already have been run.
   DCHECK(!signal_strategy_);
+  DCHECK(!oauth_token_getter_);
+  DCHECK(!signaling_connector_);
+  DCHECK(!gcd_state_updater_);
+  DCHECK(!gcd_subscriber_);
+  DCHECK(!heartbeat_sender_);
 
   // Create SignalStrategy.
   XmppSignalStrategy* xmpp_signal_strategy = new XmppSignalStrategy(
@@ -1325,19 +1340,40 @@
       new OAuthTokenGetter::OAuthCredentials(xmpp_server_config_.username,
                                              oauth_refresh_token_,
                                              use_service_account_));
-  scoped_ptr<OAuthTokenGetter> oauth_token_getter(new OAuthTokenGetterImpl(
+  oauth_token_getter_.reset(new OAuthTokenGetterImpl(
       oauth_credentials.Pass(), context_->url_request_context_getter(), false,
-      gcd_device_id_.empty()));
+      !using_gcd()));
   signaling_connector_.reset(new SignalingConnector(
       xmpp_signal_strategy, dns_blackhole_checker.Pass(),
-      oauth_token_getter.Pass(),
+      oauth_token_getter_.get(),
       base::Bind(&HostProcess::OnAuthFailed, base::Unretained(this))));
 
-  // Create HeartbeatSender.
-  heartbeat_sender_.reset(new HeartbeatSender(
-      base::Bind(&HostProcess::OnHeartbeatSuccessful, base::Unretained(this)),
-      base::Bind(&HostProcess::OnUnknownHostIdError, base::Unretained(this)),
-      host_id_, xmpp_signal_strategy, key_pair_, directory_bot_jid_));
+  if (using_gcd()) {
+    // Create objects to manage GCD state.
+    ServiceUrls* service_urls = ServiceUrls::GetInstance();
+    scoped_ptr<GcdRestClient> gcd_rest_client(new GcdRestClient(
+        service_urls->gcd_base_url(), gcd_device_id_,
+        context_->url_request_context_getter(), oauth_token_getter_.get()));
+    gcd_state_updater_.reset(
+        new GcdStateUpdater(base::Bind(&HostProcess::OnHeartbeatSuccessful,
+                                       base::Unretained(this)),
+                            base::Bind(&HostProcess::OnUnknownHostIdError,
+                                       base::Unretained(this)),
+                            signal_strategy_.get(), gcd_rest_client.Pass()));
+
+    PushNotificationSubscriber::Subscription sub;
+    sub.channel = "cloud_devices";
+    PushNotificationSubscriber::SubscriptionList subs;
+    subs.push_back(sub);
+    gcd_subscriber_.reset(
+        new PushNotificationSubscriber(signal_strategy_.get(), subs));
+  } else {
+    // Create HeartbeatSender.
+    heartbeat_sender_.reset(new HeartbeatSender(
+        base::Bind(&HostProcess::OnHeartbeatSuccessful, base::Unretained(this)),
+        base::Bind(&HostProcess::OnUnknownHostIdError, base::Unretained(this)),
+        host_id_, signal_strategy_.get(), key_pair_, directory_bot_jid_));
+  }
 }
 
 void HostProcess::StartHostIfReady() {
@@ -1413,9 +1449,14 @@
   host_change_notification_listener_.reset(new HostChangeNotificationListener(
       this, host_id_, signal_strategy_.get(), directory_bot_jid_));
 
-  host_status_logger_.reset(
-      new HostStatusLogger(host_->AsWeakPtr(), ServerLogEntry::ME2ME,
-                           signal_strategy_.get(), directory_bot_jid_));
+  if (using_gcd()) {
+    // TODO(jrw): Implement logging for GCD hosts.
+    HOST_LOG << "Logging not implemented for GCD hosts.";
+  } else {
+    host_status_logger_.reset(new HostStatusLogger(
+        host_->AsWeakPtr(), ServerLogEntry::ME2ME,
+        signal_strategy_.get(), directory_bot_jid_));
+  }
 
   // Set up reporting the host status notifications.
 #if defined(REMOTING_MULTI_PROCESS)
@@ -1489,10 +1530,18 @@
       InitializeSignaling();
 
     HOST_LOG << "SendHostOfflineReason: sending " << host_offline_reason << ".";
-    heartbeat_sender_->SetHostOfflineReason(
-        host_offline_reason,
-        base::TimeDelta::FromSeconds(kHostOfflineReasonTimeoutSeconds),
-        base::Bind(&HostProcess::OnHostOfflineReasonAck, this));
+    if (heartbeat_sender_) {
+      heartbeat_sender_->SetHostOfflineReason(
+          host_offline_reason,
+          base::TimeDelta::FromSeconds(kHostOfflineReasonTimeoutSeconds),
+          base::Bind(&HostProcess::OnHostOfflineReasonAck, this));
+    }
+    if (gcd_state_updater_) {
+      gcd_state_updater_->SetHostOfflineReason(
+          host_offline_reason,
+          base::TimeDelta::FromSeconds(kHostOfflineReasonTimeoutSeconds),
+          base::Bind(&HostProcess::OnHostOfflineReasonAck, this));
+    }
     return;  // Shutdown will resume after OnHostOfflineReasonAck.
   }
 
@@ -1508,8 +1557,11 @@
 
   HOST_LOG << "SendHostOfflineReason " << (success ? "succeeded." : "failed.");
   heartbeat_sender_.reset();
+  oauth_token_getter_.reset();
   signaling_connector_.reset();
   signal_strategy_.reset();
+  gcd_state_updater_.reset();
+  gcd_subscriber_.reset();
 
   if (state_ == HOST_GOING_OFFLINE_TO_RESTART) {
     SetState(HOST_STARTING);
@@ -1558,8 +1610,8 @@
   // single-threaded.
   net::EnableSSLServerSockets();
 
-  // Ensures runtime specific CPU features are initialized.
-  media::InitializeCPUSpecificMediaFeatures();
+  // Ensures that media library and specific CPU features are initialized.
+  media::InitializeMediaLibrary();
 
   // Create the main message loop and start helper threads.
   base::MessageLoopForUI message_loop;
diff --git a/remoting/host/signaling_connector.cc b/remoting/host/signaling_connector.cc
index 7359e154..5e07c22 100644
--- a/remoting/host/signaling_connector.cc
+++ b/remoting/host/signaling_connector.cc
@@ -26,12 +26,12 @@
 SignalingConnector::SignalingConnector(
     XmppSignalStrategy* signal_strategy,
     scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker,
-    scoped_ptr<OAuthTokenGetter> oauth_token_getter,
+    OAuthTokenGetter* oauth_token_getter,
     const base::Closure& auth_failed_callback)
     : signal_strategy_(signal_strategy),
       auth_failed_callback_(auth_failed_callback),
       dns_blackhole_checker_(dns_blackhole_checker.Pass()),
-      oauth_token_getter_(oauth_token_getter.Pass()),
+      oauth_token_getter_(oauth_token_getter),
       reconnect_attempts_(0) {
   DCHECK(!auth_failed_callback_.is_null());
   DCHECK(dns_blackhole_checker_.get());
diff --git a/remoting/host/signaling_connector.h b/remoting/host/signaling_connector.h
index 8a59e903..b8186b7 100644
--- a/remoting/host/signaling_connector.h
+++ b/remoting/host/signaling_connector.h
@@ -31,11 +31,10 @@
       public net::NetworkChangeNotifier::IPAddressObserver {
  public:
   // The |auth_failed_callback| is called when authentication fails.
-  SignalingConnector(
-      XmppSignalStrategy* signal_strategy,
-      scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker,
-      scoped_ptr<OAuthTokenGetter> oauth_token_getter,
-      const base::Closure& auth_failed_callback);
+  SignalingConnector(XmppSignalStrategy* signal_strategy,
+                     scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker,
+                     OAuthTokenGetter* oauth_token_getter,
+                     const base::Closure& auth_failed_callback);
   ~SignalingConnector() override;
 
   // OAuthTokenGetter callback.
@@ -65,7 +64,7 @@
   base::Closure auth_failed_callback_;
   scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker_;
 
-  scoped_ptr<OAuthTokenGetter> oauth_token_getter_;
+  OAuthTokenGetter* oauth_token_getter_;
 
   // Number of times we tried to connect without success.
   int reconnect_attempts_;
diff --git a/remoting/host/video_frame_pump.cc b/remoting/host/video_frame_pump.cc
index 526615c9..37d9da7 100644
--- a/remoting/host/video_frame_pump.cc
+++ b/remoting/host/video_frame_pump.cc
@@ -22,18 +22,22 @@
 
 namespace {
 
-// Helper used to encode frames on the encode thread.
-//
-// TODO(sergeyu): This functions doesn't do much beside calling
-// VideoEncoder::Encode(). It's only needed to handle empty frames properly and
-// that logic can be moved to VideoEncoder implementations.
 scoped_ptr<VideoPacket> EncodeFrame(VideoEncoder* encoder,
                                     scoped_ptr<webrtc::DesktopFrame> frame) {
-  // If there is nothing to encode then send an empty packet.
-  if (!frame || frame->updated_region().is_empty())
-    return make_scoped_ptr(new VideoPacket());
+  scoped_ptr<VideoPacket> packet;
 
-  return encoder->Encode(*frame);
+  // If |frame| is non-NULL then let the encoder process it.
+  if (frame) {
+    packet = encoder->Encode(*frame);
+  }
+
+  // If |frame| is NULL, or the encoder returned nothing, return an empty
+  // packet.
+  if (!packet) {
+    packet.reset(new VideoPacket());
+  }
+
+  return packet.Pass();
 }
 
 }  // namespace
diff --git a/remoting/host/video_frame_pump_unittest.cc b/remoting/host/video_frame_pump_unittest.cc
index cd5cd01..f72644b 100644
--- a/remoting/host/video_frame_pump_unittest.cc
+++ b/remoting/host/video_frame_pump_unittest.cc
@@ -26,9 +26,11 @@
 using ::remoting::protocol::MockVideoStub;
 
 using ::testing::_;
+using ::testing::AtLeast;
 using ::testing::DoAll;
 using ::testing::Expectation;
 using ::testing::InvokeWithoutArgs;
+using ::testing::Return;
 
 namespace remoting {
 
@@ -38,6 +40,18 @@
   arg1.Run();
 }
 
+scoped_ptr<webrtc::DesktopFrame> CreateNullFrame(
+    webrtc::DesktopCapturer::Callback*) {
+  return nullptr;
+}
+
+scoped_ptr<webrtc::DesktopFrame> CreateUnchangedFrame(
+    webrtc::DesktopCapturer::Callback*) {
+  const webrtc::DesktopSize kSize(800, 640);
+  // updated_region() is already empty by default in new BasicDesktopFrames.
+  return make_scoped_ptr(new webrtc::BasicDesktopFrame(kSize));
+}
+
 }  // namespace
 
 static const int kWidth = 640;
@@ -159,6 +173,65 @@
                                      capture_task_runner_, capturer.Pass())),
                                  encoder.Pass(), &video_stub_));
 
+  // Run MessageLoop until the first frame is received.
+  run_loop.Run();
+}
+
+// Tests that the pump handles null frames returned by the capturer.
+TEST_F(VideoFramePumpTest, NullFrame) {
+  scoped_ptr<FakeDesktopCapturer> capturer(new FakeDesktopCapturer);
+  scoped_ptr<MockVideoEncoder> encoder(new MockVideoEncoder);
+
+  base::RunLoop run_loop;
+
+  // Set up the capturer to return null frames.
+  capturer->set_frame_generator(base::Bind(&CreateNullFrame));
+
+  // Expect that the VideoEncoder::Encode() method is never called.
+  EXPECT_CALL(*encoder, EncodePtr(_)).Times(0);
+
+  // When the first ProcessVideoPacket is received we stop the VideoFramePump.
+  EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
+      .WillOnce(DoAll(FinishSend(),
+                      InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)))
+      .RetiresOnSaturation();
+
+  // Start video frame capture.
+  pump_.reset(new VideoFramePump(encode_task_runner_,
+                                 make_scoped_ptr(new DesktopCapturerProxy(
+                                     capture_task_runner_, capturer.Pass())),
+                                 encoder.Pass(), &video_stub_));
+
+  // Run MessageLoop until the first frame is received..
+  run_loop.Run();
+}
+
+// Tests how the pump handles unchanged frames returned by the capturer.
+TEST_F(VideoFramePumpTest, UnchangedFrame) {
+  scoped_ptr<FakeDesktopCapturer> capturer(new FakeDesktopCapturer);
+  scoped_ptr<MockVideoEncoder> encoder(new MockVideoEncoder);
+
+  base::RunLoop run_loop;
+
+  // Set up the capturer to return unchanged frames.
+  capturer->set_frame_generator(base::Bind(&CreateUnchangedFrame));
+
+  // Expect that the VideoEncoder::Encode() method is called.
+  EXPECT_CALL(*encoder, EncodePtr(_)).WillRepeatedly(Return(nullptr));
+
+  // When the first ProcessVideoPacket is received we stop the VideoFramePump.
+  // TODO(wez): Verify that the generated packet has no content here.
+  EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
+      .WillOnce(DoAll(FinishSend(),
+                      InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)))
+      .RetiresOnSaturation();
+
+  // Start video frame capture.
+  pump_.reset(new VideoFramePump(encode_task_runner_,
+                                 make_scoped_ptr(new DesktopCapturerProxy(
+                                     capture_task_runner_, capturer.Pass())),
+                                 encoder.Pass(), &video_stub_));
+
   // Run MessageLoop until the first frame is received..
   run_loop.Run();
 }
diff --git a/remoting/host/video_frame_recorder_unittest.cc b/remoting/host/video_frame_recorder_unittest.cc
index ac00e45..3192012 100644
--- a/remoting/host/video_frame_recorder_unittest.cc
+++ b/remoting/host/video_frame_recorder_unittest.cc
@@ -132,11 +132,11 @@
 
   // Fill content, DPI and updated-region based on |frame_count_| so that each
   // generated frame is different.
+  ++frame_count_;
   memset(frame->data(), frame_count_, frame->stride() * kFrameHeight);
   frame->set_dpi(webrtc::DesktopVector(frame_count_, frame_count_));
   frame->mutable_updated_region()->SetRect(
       webrtc::DesktopRect::MakeWH(frame_count_, frame_count_));
-  ++frame_count_;
 
   return frame.Pass();
 }
@@ -160,6 +160,8 @@
 void VideoFrameRecorderTest::EncodeDummyFrame() {
   webrtc::BasicDesktopFrame dummy_frame(
       webrtc::DesktopSize(kFrameWidth, kFrameHeight));
+  dummy_frame.mutable_updated_region()->SetRect(
+      webrtc::DesktopRect::MakeWH(kFrameWidth, kFrameHeight));
   ASSERT_TRUE(encoder_->Encode(dummy_frame));
   base::RunLoop().RunUntilIdle();
 }
diff --git a/remoting/protocol/me2me_host_authenticator_factory.cc b/remoting/protocol/me2me_host_authenticator_factory.cc
index d69930b..abf8541 100644
--- a/remoting/protocol/me2me_host_authenticator_factory.cc
+++ b/remoting/protocol/me2me_host_authenticator_factory.cc
@@ -129,7 +129,7 @@
   // Verify that the client's jid is an ASCII string, and then check that the
   // client JID has the expected prefix. Comparison is case insensitive.
   if (!base::IsStringASCII(remote_jid) ||
-      !StartsWithASCII(remote_jid, remote_jid_prefix + '/', false)) {
+      !base::StartsWithASCII(remote_jid, remote_jid_prefix + '/', false)) {
     LOG(ERROR) << "Rejecting incoming connection from " << remote_jid;
     return make_scoped_ptr(new RejectingAuthenticator());
   }
diff --git a/remoting/remoting_all.gyp b/remoting/remoting_all.gyp
index 7e89cb6..2451f15 100644
--- a/remoting/remoting_all.gyp
+++ b/remoting/remoting_all.gyp
@@ -12,6 +12,9 @@
       'target_name': 'remoting_all',
       'type': 'none',
       'dependencies': [
+        '../remoting/app_remoting_webapp.gyp:ar_sample_app',
+        '../remoting/remoting.gyp:ar_sample_test_driver',
+        '../remoting/remoting.gyp:chromoting_test_driver',
         '../remoting/remoting.gyp:remoting_base',
         '../remoting/remoting.gyp:remoting_breakpad',
         '../remoting/remoting.gyp:remoting_browser_test_resources',
@@ -24,8 +27,6 @@
         '../remoting/remoting.gyp:remoting_webapp',
         '../remoting/remoting.gyp:remoting_webapp_html',
         '../remoting/remoting.gyp:remoting_webapp_unittests',
-        '../remoting/app_remoting_test.gyp:ar_sample_test_driver',
-        '../remoting/app_remoting_webapp.gyp:ar_sample_app',
       ],
 
       'conditions' : [
diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi
index cc87e5f4..807e86e 100644
--- a/remoting/remoting_test.gypi
+++ b/remoting/remoting_test.gypi
@@ -91,6 +91,94 @@
         }],
       ],
     },
+    {
+      'target_name': 'remoting_test_driver_common',
+      'type': 'static_library',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../base/base.gyp:test_support_base',
+        '../google_apis/google_apis.gyp:google_apis',
+        '../net/net.gyp:net',
+        '../remoting/remoting.gyp:remoting_base',
+        '../remoting/remoting.gyp:remoting_client',
+        '../remoting/remoting.gyp:remoting_protocol',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'defines': [
+        'VERSION=<(version_full)',
+      ],
+      'sources': [
+        'test/access_token_fetcher.cc',
+        'test/access_token_fetcher.h',
+        'test/refresh_token_store.cc',
+        'test/refresh_token_store.h',
+        'test/remote_connection_observer.h',
+        'test/test_chromoting_client.cc',
+        'test/test_chromoting_client.h',
+        'test/test_video_renderer.cc',
+        'test/test_video_renderer.h',
+      ],
+    }, # end of target 'remoting_test_driver_common'
+    {
+      # A chromoting version of remoting_test_driver_common
+      'target_name': 'chromoting_test_driver',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        'remoting_test_driver_common',
+      ],
+      'defines': [
+        'VERSION=<(version_full)',
+      ],
+      'sources': [
+        'test/chromoting_test_driver.cc',
+      ],
+      'include_dirs': [
+        '../testing/gtest/include',
+      ],
+    }, # end of target 'chromoting_test_driver'
+    {
+      'target_name': 'ar_test_driver_common',
+      'type': 'static_library',
+      'dependencies': [
+        '../remoting/proto/chromotocol.gyp:chromotocol_proto_lib',
+        'remoting_test_driver_common',
+      ],
+      'defines': [
+        'VERSION=<(version_full)',
+      ],
+      'sources': [
+        'test/app_remoting_connected_client_fixture.cc',
+        'test/app_remoting_connected_client_fixture.h',
+        'test/app_remoting_test_driver_environment.cc',
+        'test/app_remoting_test_driver_environment.h',
+        'test/remote_application_details.h',
+        'test/remote_host_info.cc',
+        'test/remote_host_info.h',
+        'test/remote_host_info_fetcher.cc',
+        'test/remote_host_info_fetcher.h',
+      ],
+      'include_dirs': [
+        '../testing/gtest/include',
+      ],
+    },  # end of target 'ar_test_driver_common'
+    {
+      # An external version of the test driver tool which includes minimal tests
+      'target_name': 'ar_sample_test_driver',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        'ar_test_driver_common',
+      ],
+      'defines': [
+        'VERSION=<(version_full)',
+      ],
+      'sources': [
+        'test/app_remoting_test_driver.cc',
+        'test/app_remoting_test_driver_environment_app_details.cc',
+      ],
+      'include_dirs': [
+        '../testing/gtest/include',
+      ],
+    },  # end of target 'ar_sample_test_driver'
 
     # Remoting unit tests
     {
diff --git a/remoting/remoting_webapp_files.gypi b/remoting/remoting_webapp_files.gypi
index 7474e679..3657d33 100644
--- a/remoting/remoting_webapp_files.gypi
+++ b/remoting/remoting_webapp_files.gypi
@@ -103,8 +103,8 @@
       'webapp/crd/js/gcd_client_with_mock_xhr_unittest.js',
       'webapp/crd/js/host_controller_unittest.js',
       'webapp/crd/js/host_daemon_facade_unittest.js',
-      'webapp/crd/js/host_list_api_impl_unittest.js',
       'webapp/crd/js/host_table_entry_unittest.js',
+      'webapp/crd/js/legacy_host_list_api_unittest.js',
       'webapp/crd/js/menu_button_unittest.js',
       'webapp/crd/js/mock_xhr_unittest.js',
     ],
@@ -251,6 +251,7 @@
     # Files for controlling the local machine as a host.
     # Includes both it2me and me2me files.
     'remoting_webapp_js_host_control_files': [
+      'webapp/crd/js/buffered_signal_strategy.js',
       'webapp/crd/js/host_controller.js',
       'webapp/crd/js/host_daemon_facade.js',
       'webapp/crd/js/host_screen.js',
@@ -265,10 +266,15 @@
     'remoting_webapp_js_host_display_files': [
       'webapp/crd/js/host_list.js',
       'webapp/crd/js/host_list_api.js',
-      'webapp/crd/js/host_list_api_gcd_impl.js',
-      'webapp/crd/js/host_list_api_impl.js',
       'webapp/crd/js/host_table_entry.js',
       'webapp/crd/js/local_host_section.js',
+
+      # Must come after host_list_api.js because of an issue with
+      # JSCompiler.  If an implementation of an interface occurs in a
+      # file processed before the interface itself, the @override tag
+      # doesn't always work correctly.
+      'webapp/crd/js/gcd_host_list_api.js',
+      'webapp/crd/js/legacy_host_list_api.js',
     ],
     # The CRD-specific JavaScript files required by main.html.
     'remoting_webapp_crd_js_ui_files': [
diff --git a/remoting/signaling/xmpp_login_handler.cc b/remoting/signaling/xmpp_login_handler.cc
index cc3ae94..448ecbe 100644
--- a/remoting/signaling/xmpp_login_handler.cc
+++ b/remoting/signaling/xmpp_login_handler.cc
@@ -221,14 +221,14 @@
 }
 
 void XmppLoginHandler::StartStream(const std::string& first_message) {
-  delegate_->SendMessage("<stream:stream to=\"" + server_ +
-                         "\" version=\"1.0\" xmlns=\"jabber:client\" "
-                         "xmlns:stream=\"http://etherx.jabber.org/streams\">" +
-                         first_message);
   stream_parser_.reset(new XmppStreamParser());
   stream_parser_->SetCallbacks(
       base::Bind(&XmppLoginHandler::OnStanza, base::Unretained(this)),
       base::Bind(&XmppLoginHandler::OnParserError, base::Unretained(this)));
+  delegate_->SendMessage("<stream:stream to=\"" + server_ +
+                         "\" version=\"1.0\" xmlns=\"jabber:client\" "
+                         "xmlns:stream=\"http://etherx.jabber.org/streams\">" +
+                         first_message);
 }
 
 void XmppLoginHandler::OnError(SignalStrategy::Error error) {
diff --git a/remoting/signaling/xmpp_login_handler.h b/remoting/signaling/xmpp_login_handler.h
index 10af045e..61f978a 100644
--- a/remoting/signaling/xmpp_login_handler.h
+++ b/remoting/signaling/xmpp_login_handler.h
@@ -35,6 +35,7 @@
    public:
     Delegate() {}
 
+    // All Delegate methods are allowed to destroy XmppLoginHandler.
     virtual void SendMessage(const std::string& message) = 0;
     virtual void StartTls() = 0;
     virtual void OnHandshakeDone(const std::string& jid,
diff --git a/remoting/signaling/xmpp_login_handler_unittest.cc b/remoting/signaling/xmpp_login_handler_unittest.cc
index 59afdb8..ab9abe04 100644
--- a/remoting/signaling/xmpp_login_handler_unittest.cc
+++ b/remoting/signaling/xmpp_login_handler_unittest.cc
@@ -38,21 +38,29 @@
 
   void SendMessage(const std::string& message) override {
     sent_data_ += message;
+    if (delete_login_handler_from_delegate_)
+      login_handler_.reset();
   }
 
   void StartTls() override {
     start_tls_called_ = true;
+    if (delete_login_handler_from_delegate_)
+      login_handler_.reset();
   }
 
   void OnHandshakeDone(const std::string& jid,
                        scoped_ptr<XmppStreamParser> parser) override {
     jid_ = jid;
     parser_ = parser.Pass();
+    if (delete_login_handler_from_delegate_)
+      login_handler_.reset();
   }
 
   void OnLoginHandlerError(SignalStrategy::Error error) override {
     EXPECT_NE(error, SignalStrategy::OK);
     error_ = error;
+    if (delete_login_handler_from_delegate_)
+      login_handler_.reset();
   }
 
  protected:
@@ -66,6 +74,7 @@
   std::string jid_;
   scoped_ptr<XmppStreamParser> parser_;
   SignalStrategy::Error error_;
+  bool delete_login_handler_from_delegate_ = false;
 };
 
 void XmppLoginHandlerTest::HandshakeBase() {
@@ -127,6 +136,10 @@
         "</iq>");
   sent_data_.clear();
 
+  // |login_handler_| will call OnHandshakeDone() which will delete
+  // |login_handler_|.
+  delete_login_handler_from_delegate_ = true;
+
   login_handler_->OnDataReceived(
       "<stream:stream from=\"google.com\" id=\"104FA10576E2AA80\" "
           "version=\"1.0\" "
@@ -145,6 +158,7 @@
 
   EXPECT_EQ(jid_, std::string(kTestUsername) + "/chromoting52B4920E");
   EXPECT_TRUE(parser_);
+  EXPECT_FALSE(login_handler_);
 }
 
 TEST_F(XmppLoginHandlerTest, StartTlsHandshake) {
@@ -216,8 +230,35 @@
 
 TEST_F(XmppLoginHandlerTest, StreamParseError) {
   HandshakeBase();
+  delete_login_handler_from_delegate_ = true;
   login_handler_->OnDataReceived("BAD DATA");
   EXPECT_EQ(error_, SignalStrategy::PROTOCOL_ERROR);
 }
 
+// Verify that LoginHandler doesn't crash when destroyed from
+// Delegate::SendMessage().
+TEST_F(XmppLoginHandlerTest, DeleteInSendMessage) {
+  login_handler_.reset(
+      new XmppLoginHandler("google.com", kTestUsername, kTestToken,
+                           XmppLoginHandler::TlsMode::WITHOUT_HANDSHAKE, this));
+  login_handler_->Start();
+  EXPECT_TRUE(start_tls_called_);
+
+  delete_login_handler_from_delegate_ = true;
+  login_handler_->OnTlsStarted();
+  EXPECT_FALSE(login_handler_);
+}
+
+// Verify that LoginHandler doesn't crash when destroyed from
+// Delegate::StartTls().
+TEST_F(XmppLoginHandlerTest, DeleteInStartTls) {
+  login_handler_.reset(
+      new XmppLoginHandler("google.com", kTestUsername, kTestToken,
+                           XmppLoginHandler::TlsMode::WITHOUT_HANDSHAKE, this));
+  delete_login_handler_from_delegate_ = true;
+  login_handler_->Start();
+  EXPECT_TRUE(start_tls_called_);
+  EXPECT_FALSE(login_handler_);
+}
+
 }  // namespace remoting
diff --git a/remoting/test/app_remoting_connected_client_fixture.cc b/remoting/test/app_remoting_connected_client_fixture.cc
index 806d441..6beff604 100644
--- a/remoting/test/app_remoting_connected_client_fixture.cc
+++ b/remoting/test/app_remoting_connected_client_fixture.cc
@@ -56,7 +56,7 @@
   StartConnection();
 
   if (!connection_is_ready_for_tests_) {
-    FAIL() << "Remote host connection could not be established.";
+    ADD_FAILURE() << "Remote host connection could not be established.";
     client_->EndConnection();
   }
 }
diff --git a/remoting/test/app_remoting_test_driver.cc b/remoting/test/app_remoting_test_driver.cc
index 0d8af2b..ca69735 100644
--- a/remoting/test/app_remoting_test_driver.cc
+++ b/remoting/test/app_remoting_test_driver.cc
@@ -4,6 +4,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/launcher/unit_test_launcher.h"
@@ -18,6 +19,7 @@
 const char kAuthCodeSwitchName[] = "authcode";
 const char kHelpSwitchName[] = "help";
 const char kLoggingLevelSwitchName[] = "verbosity";
+const char kRefreshTokenFileSwitchName[] = "refresh-token-file";
 const char kServiceEnvironmentSwitchName[] = "environment";
 const char kShowHostAvailabilitySwitchName[] = "show-host-availability";
 const char kSingleProcessTestsSwitchName[] = "single-process-tests";
@@ -66,6 +68,8 @@
   printf("\nOptional Parameters:\n");
   printf("  %s: Exchanged for a refresh and access token for authentication\n",
          switches::kAuthCodeSwitchName);
+  printf("  %s: Path to a JSON file containing username/refresh_token KVPs\n",
+         switches::kRefreshTokenFileSwitchName);
   printf("  %s: Displays additional usage information\n",
          switches::kHelpSwitchName);
   printf("  %s: Specifies the service api to use (dev|test) [default: dev]\n",
@@ -116,6 +120,25 @@
          switches::kUserNameSwitchName, switches::kAuthCodeSwitchName);
 }
 
+void PrintJsonFileInfo() {
+  printf("\n*****************************************\n");
+  printf("*** Refresh Token File Example Usage ***\n");
+  printf("****************************************\n\n");
+
+  printf("In order to use this option, a valid JSON file must exist, be\n");
+  printf("properly formatted, and contain a username/token KVP.\n");
+  printf("Contents of example_file.json\n");
+  printf("{\n");
+  printf("  \"username1@fauxdomain.com\": \"1/3798Gsdf898shksdvfyi8sshad\",\n");
+  printf("  \"username2@fauxdomain.com\": \"1/8974sdf87asdgadfgaerhfRsAa\",\n");
+  printf("}\n\n");
+
+  printf("\nTool usage example:\n");
+  printf("ar_test_driver --%s=%s --%s=./example_file.json\n\n",
+         switches::kUserNameSwitchName, "username1@fauxdomain.com",
+         switches::kRefreshTokenFileSwitchName);
+}
+
 }  // namespace
 
 int main(int argc, char** argv) {
@@ -144,6 +167,7 @@
   //       help is written in parallel with our text and can appear interleaved.
   if (command_line->HasSwitch(switches::kHelpSwitchName)) {
     PrintUsage();
+    PrintJsonFileInfo();
     PrintAuthCodeInfo();
     return base::LaunchUnitTestsSerially(
         argc, argv,
@@ -157,20 +181,23 @@
     return -1;
   }
 
-  std::string user_name;
-  user_name = command_line->GetSwitchValueASCII(switches::kUserNameSwitchName);
+  std::string user_name(
+      command_line->GetSwitchValueASCII(switches::kUserNameSwitchName));
   DVLOG(1) << "Running tests as: " << user_name;
 
-  std::string auth_code;
   // Check to see if the user passed in a one time use auth_code for
   // refreshing their credentials.
-  auth_code = command_line->GetSwitchValueASCII(switches::kAuthCodeSwitchName);
+  std::string auth_code(
+      command_line->GetSwitchValueASCII(switches::kAuthCodeSwitchName));
+
+  base::FilePath refresh_token_file_path(
+      command_line->GetSwitchValuePath(switches::kRefreshTokenFileSwitchName));
 
   // If the user passed in a service environment, use it, otherwise set a
   // default value.
   remoting::test::ServiceEnvironment service_environment;
-  std::string service_environment_switch = command_line->GetSwitchValueASCII(
-      switches::kServiceEnvironmentSwitchName);
+  std::string service_environment_switch(command_line->GetSwitchValueASCII(
+      switches::kServiceEnvironmentSwitchName));
   if (service_environment_switch.empty() ||
       service_environment_switch == "dev") {
     service_environment =
@@ -186,9 +213,8 @@
   }
 
   // Update the logging verbosity level is user specified one.
-  std::string verbosity_level;
-  verbosity_level =
-      command_line->GetSwitchValueASCII(switches::kLoggingLevelSwitchName);
+  std::string verbosity_level(
+      command_line->GetSwitchValueASCII(switches::kLoggingLevelSwitchName));
   if (!verbosity_level.empty()) {
     // Turn on logging for the test_driver and remoting components.
     // This switch is parsed during logging::InitLogging.
@@ -202,10 +228,9 @@
   // retrieving an access token for the user and spinning up VMs.
   // The GTest framework will own the lifetime of this object once
   // it is registered below.
-  scoped_ptr<remoting::test::AppRemotingTestDriverEnvironment> shared_data;
-
-  shared_data.reset(new remoting::test::AppRemotingTestDriverEnvironment(
-      user_name, service_environment));
+  scoped_ptr<remoting::test::AppRemotingTestDriverEnvironment> shared_data(
+      new remoting::test::AppRemotingTestDriverEnvironment(
+          user_name, refresh_token_file_path, service_environment));
 
   if (!shared_data->Initialize(auth_code)) {
     // If we failed to initialize our shared data object, then bail.
diff --git a/remoting/test/app_remoting_test_driver_environment.cc b/remoting/test/app_remoting_test_driver_environment.cc
index 9bb04bd6..73dfda72 100644
--- a/remoting/test/app_remoting_test_driver_environment.cc
+++ b/remoting/test/app_remoting_test_driver_environment.cc
@@ -25,15 +25,17 @@
 
 AppRemotingTestDriverEnvironment::AppRemotingTestDriverEnvironment(
     const std::string& user_name,
+    const base::FilePath& refresh_token_file_path,
     ServiceEnvironment service_environment)
     : user_name_(user_name),
       service_environment_(service_environment),
+      refresh_token_file_path_(refresh_token_file_path),
       test_access_token_fetcher_(nullptr),
       test_refresh_token_store_(nullptr),
       test_remote_host_info_fetcher_(nullptr),
       message_loop_(new base::MessageLoopForIO()) {
   DCHECK(!user_name_.empty());
-  DCHECK(service_environment < kUnknownEnvironment);
+  DCHECK(service_environment_ < kUnknownEnvironment);
 
   PopulateApplicationNames();
   PopulateApplicationDetailsMap();
@@ -53,7 +55,8 @@
   scoped_ptr<RefreshTokenStore> temporary_refresh_token_store;
   RefreshTokenStore* refresh_token_store = test_refresh_token_store_;
   if (!refresh_token_store) {
-    temporary_refresh_token_store = RefreshTokenStore::OnDisk(user_name_);
+    temporary_refresh_token_store =
+        RefreshTokenStore::OnDisk(user_name_, refresh_token_file_path_);
     refresh_token_store = temporary_refresh_token_store.get();
   }
 
@@ -240,7 +243,8 @@
       scoped_ptr<RefreshTokenStore> temporary_refresh_token_store;
       RefreshTokenStore* refresh_token_store = test_refresh_token_store_;
       if (!refresh_token_store) {
-        temporary_refresh_token_store = RefreshTokenStore::OnDisk(user_name_);
+        temporary_refresh_token_store =
+            RefreshTokenStore::OnDisk(user_name_, refresh_token_file_path_);
         refresh_token_store = temporary_refresh_token_store.get();
       }
 
diff --git a/remoting/test/app_remoting_test_driver_environment.h b/remoting/test/app_remoting_test_driver_environment.h
index d2053da..2ff90c77 100644
--- a/remoting/test/app_remoting_test_driver_environment.h
+++ b/remoting/test/app_remoting_test_driver_environment.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "remoting/test/remote_application_details.h"
 #include "remoting/test/remote_host_info_fetcher.h"
@@ -31,6 +32,7 @@
 class AppRemotingTestDriverEnvironment : public testing::Environment {
  public:
   AppRemotingTestDriverEnvironment(const std::string& user_name,
+                                   const base::FilePath& refresh_token_file,
                                    ServiceEnvironment service_environment);
   ~AppRemotingTestDriverEnvironment() override;
 
@@ -109,6 +111,9 @@
   // Service API to target when retrieving remote host connection information.
   ServiceEnvironment service_environment_;
 
+  // Path to a JSON file containing refresh tokens.
+  base::FilePath refresh_token_file_path_;
+
   // Access token fetcher used by TestDriverEnvironment tests.
   remoting::test::AccessTokenFetcher* test_access_token_fetcher_;
 
diff --git a/remoting/test/app_remoting_test_driver_environment_unittest.cc b/remoting/test/app_remoting_test_driver_environment_unittest.cc
index cd6c51b..484267fe 100644
--- a/remoting/test/app_remoting_test_driver_environment_unittest.cc
+++ b/remoting/test/app_remoting_test_driver_environment_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "remoting/test/app_remoting_test_driver_environment.h"
 
+#include "base/files/file_path.h"
 #include "remoting/test/fake_access_token_fetcher.h"
 #include "remoting/test/fake_remote_host_info_fetcher.h"
 #include "remoting/test/mock_access_token_fetcher.h"
@@ -75,7 +76,9 @@
  public:
   AppRemotingTestDriverEnvironmentTest()
       : fake_access_token_fetcher_(nullptr),
-        environment_object_(kUserNameValue, kDeveloperEnvironment) {}
+        environment_object_(kUserNameValue,
+                            base::FilePath(),  // refresh_token_file_path
+                            kDeveloperEnvironment) {}
   ~AppRemotingTestDriverEnvironmentTest() override {}
 
   FakeAccessTokenFetcher* fake_access_token_fetcher() const {
@@ -86,7 +89,7 @@
   // testing::Test interface.
   void SetUp() override {
     scoped_ptr<FakeAccessTokenFetcher> fake_access_token_fetcher(
-      new FakeAccessTokenFetcher());
+        new FakeAccessTokenFetcher());
     fake_access_token_fetcher_ = fake_access_token_fetcher.get();
     mock_access_token_fetcher_.SetAccessTokenFetcher(
         fake_access_token_fetcher.Pass());
diff --git a/remoting/test/chromoting_test_driver.cc b/remoting/test/chromoting_test_driver.cc
new file mode 100644
index 0000000..42a7abdcf
--- /dev/null
+++ b/remoting/test/chromoting_test_driver.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/test/test_suite.h"
+#include "base/test/test_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace switches {
+const char kSingleProcessTestsSwitchName[] = "single-process-tests";
+const char kUserNameSwitchName[] = "username";
+}
+
+int main(int argc, char* argv[]) {
+  testing::InitGoogleTest(&argc, argv);
+  base::TestSuite test_suite(argc, argv);
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  DCHECK(command_line);
+
+  // Do not retry if tests fails.
+  command_line->AppendSwitchASCII(switches::kTestLauncherRetryLimit, "0");
+
+  // Different tests may require access to the same host if run in parallel.
+  // To avoid shared resource contention, tests will be run one at a time.
+  command_line->AppendSwitch(switches::kSingleProcessTestsSwitchName);
+
+  std::string username =
+    command_line->GetSwitchValueASCII(switches::kUserNameSwitchName);
+
+  // Verify that the username is passed in as an argument.
+  if (username.empty()) {
+    LOG(ERROR) << "No username passed in, can't authenticate without that!";
+    return -1;
+  }
+  DVLOG(1) << "Running chromoting tests as: " << username;
+
+  return 0;
+}
+
diff --git a/remoting/test/refresh_token_store.cc b/remoting/test/refresh_token_store.cc
index e191f5b..ce5a5b8 100644
--- a/remoting/test/refresh_token_store.cc
+++ b/remoting/test/refresh_token_store.cc
@@ -5,36 +5,19 @@
 #include "remoting/test/refresh_token_store.h"
 
 #include "base/files/file_util.h"
+#include "base/files/important_file_writer.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
 #include "base/logging.h"
+#include "base/values.h"
 
 namespace {
 const base::FilePath::CharType kTokenFileName[] =
-    FILE_PATH_LITERAL("refresh_token.txt");
+    FILE_PATH_LITERAL("refresh_tokens.json");
 const base::FilePath::CharType kRemotingFolder[] =
     FILE_PATH_LITERAL("remoting");
 const base::FilePath::CharType kRefreshTokenStoreFolder[] =
-    FILE_PATH_LITERAL("refresh_token_store");
-
-// Returns the FilePath of the token store file for |user_name|.
-base::FilePath GetRefreshTokenDirPath(const std::string& user_name) {
-  base::FilePath refresh_token_dir_path;
-  if (!GetTempDir(&refresh_token_dir_path)) {
-    LOG(WARNING) << "Failed to retrieve temporary directory path.";
-    return base::FilePath();
-  }
-
-  refresh_token_dir_path = refresh_token_dir_path.Append(kRemotingFolder);
-  refresh_token_dir_path =
-      refresh_token_dir_path.Append(kRefreshTokenStoreFolder);
-
-  // We call AppendASCII here our user_name is a std::string but wide strings
-  // are used on WIN platforms.  ApendASCII will convert our std::string into
-  // the correct type for windows platforms.
-  refresh_token_dir_path = refresh_token_dir_path.AppendASCII(user_name);
-
-  return refresh_token_dir_path;
-}
-
+    FILE_PATH_LITERAL("token_store");
 }  // namespace
 
 namespace remoting {
@@ -44,7 +27,8 @@
 // read it back during subsequent tool runs.
 class RefreshTokenStoreOnDisk : public RefreshTokenStore {
  public:
-  explicit RefreshTokenStoreOnDisk(const std::string user_name);
+  RefreshTokenStoreOnDisk(const std::string& user_name,
+                          const base::FilePath& refresh_token_file_path);
   ~RefreshTokenStoreOnDisk() override;
 
   // RefreshTokenStore interface.
@@ -52,29 +36,52 @@
   bool StoreRefreshToken(const std::string& refresh_token) override;
 
  private:
+  // Returns the path for the file used to read from or store a refresh token
+  // for the user.
+  base::FilePath GetPathForRefreshTokenFile();
+
   // Used to access the user specific token file.
   std::string user_name_;
 
+  // Path used to retrieve the refresh token file.
+  base::FilePath refresh_token_file_path_;
+
   DISALLOW_COPY_AND_ASSIGN(RefreshTokenStoreOnDisk);
 };
 
-RefreshTokenStoreOnDisk::RefreshTokenStoreOnDisk(const std::string user_name)
-    : user_name_(user_name) {
+RefreshTokenStoreOnDisk::RefreshTokenStoreOnDisk(
+    const std::string& user_name,
+    const base::FilePath& refresh_token_file_path)
+    : user_name_(user_name), refresh_token_file_path_(refresh_token_file_path) {
 }
 
 RefreshTokenStoreOnDisk::~RefreshTokenStoreOnDisk() {
 }
 
 std::string RefreshTokenStoreOnDisk::FetchRefreshToken() {
-  base::FilePath token_dir_path(GetRefreshTokenDirPath(user_name_));
-  DCHECK(!token_dir_path.empty());
+  base::FilePath refresh_token_file_path(GetPathForRefreshTokenFile());
+  DCHECK(!refresh_token_file_path.empty());
+  DVLOG(2) << "Reading token from: " << refresh_token_file_path.value();
 
-  DVLOG(2) << "Reading token from path: " << token_dir_path.value();
-  base::FilePath token_file_path(token_dir_path.Append(kTokenFileName));
+  std::string file_contents;
+  if (!base::ReadFileToString(refresh_token_file_path, &file_contents)) {
+    DVLOG(1) << "Couldn't read token file: " << refresh_token_file_path.value();
+    return std::string();
+  }
+
+  scoped_ptr<base::Value> token_data(base::JSONReader::Read(file_contents));
+  base::DictionaryValue* tokens = nullptr;
+  if (!token_data || !token_data->GetAsDictionary(&tokens)) {
+    LOG(ERROR) << "Refresh token file contents were not valid JSON, "
+               << "could not retrieve token.";
+    return std::string();
+  }
 
   std::string refresh_token;
-  if (!base::ReadFileToString(token_file_path, &refresh_token)) {
-    DVLOG(1) << "Failed to read token file from: " << token_dir_path.value();
+  if (!tokens->GetStringWithoutPathExpansion(user_name_, &refresh_token)) {
+    // This may not be an error as the file could exist but contain refresh
+    // tokens for other users.
+    DVLOG(1) << "Could not find token for: " << user_name_;
     return std::string();
   }
 
@@ -85,56 +92,75 @@
     const std::string& refresh_token) {
   DCHECK(!refresh_token.empty());
 
-  base::FilePath token_dir_path(GetRefreshTokenDirPath(user_name_));
-  if (token_dir_path.empty()) {
-    return false;
-  }
+  base::FilePath file_path(GetPathForRefreshTokenFile());
+  DCHECK(!file_path.empty());
+  DVLOG(2) << "Storing token to: " << file_path.value();
 
-  base::FilePath token_file_path(token_dir_path.Append(kTokenFileName));
-  if (!base::DirectoryExists(token_dir_path) &&
-      !base::CreateDirectory(token_dir_path)) {
+  base::FilePath refresh_token_file_dir(file_path.DirName());
+  if (!base::DirectoryExists(refresh_token_file_dir) &&
+      !base::CreateDirectory(refresh_token_file_dir)) {
     LOG(ERROR) << "Failed to create directory, refresh token not stored.";
     return false;
   }
 
-#if defined(OS_POSIX)
-  // For POSIX we can set permissions on the token file so we do so here.
-  // The test code should not run on other platforms since the code to safely
-  // store the token has not been implemented yet.
+  std::string file_contents("{}");
+  if (base::PathExists(file_path)) {
+    if (!base::ReadFileToString(file_path, &file_contents)) {
+      LOG(ERROR) << "Invalid token file: " << file_path.value();
+      return false;
+    }
+  }
 
-  // Create an empty stub file if one does not exist.
-  if (!base::PathExists(token_file_path) &&
-      base::WriteFile(token_file_path, "", 0) < 0) {
-    LOG(ERROR) << "Failed to create stub file, refresh token not stored.";
+  scoped_ptr<base::Value> token_data(base::JSONReader::Read(file_contents));
+  base::DictionaryValue* tokens = nullptr;
+  if (!token_data || !token_data->GetAsDictionary(&tokens)) {
+    LOG(ERROR) << "Invalid refresh token file format, could not store token.";
     return false;
   }
 
-  // Set permissions on the stub file.
-  int mode =
-      base::FILE_PERMISSION_READ_BY_USER | base::FILE_PERMISSION_WRITE_BY_USER;
-  if (!SetPosixFilePermissions(token_file_path, mode)) {
-    LOG(ERROR) << "Failed to set file permissions, refresh token not stored.";
+  std::string json_string;
+  tokens->SetStringWithoutPathExpansion(user_name_, refresh_token);
+  if (!base::JSONWriter::Write(*token_data, &json_string)) {
+    LOG(ERROR) << "Couldn't convert JSON data to string";
     return false;
   }
 
-  // Write the refresh token to our newly created file.
-  if (base::WriteFile(token_file_path, refresh_token.c_str(),
-                      refresh_token.size()) < 0) {
+  if (!base::ImportantFileWriter::WriteFileAtomically(file_path, json_string)) {
     LOG(ERROR) << "Failed to save refresh token to the file on disk.";
     return false;
   }
 
   return true;
-#else
-  NOTIMPLEMENTED();
-  return false;
-#endif  // OS_POSIX
+}
+
+base::FilePath RefreshTokenStoreOnDisk::GetPathForRefreshTokenFile() {
+  base::FilePath refresh_token_file_path(refresh_token_file_path_);
+
+  // If we weren't given a specific file path, then use the default path.
+  if (refresh_token_file_path.empty()) {
+    if (!GetTempDir(&refresh_token_file_path)) {
+      LOG(WARNING) << "Failed to retrieve temporary directory path.";
+      return base::FilePath();
+    }
+
+    refresh_token_file_path = refresh_token_file_path.Append(kRemotingFolder);
+    refresh_token_file_path =
+        refresh_token_file_path.Append(kRefreshTokenStoreFolder);
+  }
+
+  // If no file has been specified, then we will use a default file name.
+  if (refresh_token_file_path.Extension().empty()) {
+    refresh_token_file_path = refresh_token_file_path.Append(kTokenFileName);
+  }
+
+  return refresh_token_file_path;
 }
 
 scoped_ptr<RefreshTokenStore> RefreshTokenStore::OnDisk(
-    const std::string& user_name) {
+    const std::string& user_name,
+    const base::FilePath& refresh_token_file_path) {
   return make_scoped_ptr<RefreshTokenStore>(
-      new RefreshTokenStoreOnDisk(user_name));
+      new RefreshTokenStoreOnDisk(user_name, refresh_token_file_path));
 }
 
 }  // namespace test
diff --git a/remoting/test/refresh_token_store.h b/remoting/test/refresh_token_store.h
index 6e287a0..1ee2f50 100644
--- a/remoting/test/refresh_token_store.h
+++ b/remoting/test/refresh_token_store.h
@@ -9,6 +9,10 @@
 
 #include "base/memory/scoped_ptr.h"
 
+namespace base {
+class FilePath;
+}
+
 namespace remoting {
 namespace test {
 
@@ -24,7 +28,9 @@
 
   // Returns a RefreshTokenStore which reads/writes to a user specific token
   // file on the local disk.
-  static scoped_ptr<RefreshTokenStore> OnDisk(const std::string& user_name);
+  static scoped_ptr<RefreshTokenStore> OnDisk(
+      const std::string& user_name,
+      const base::FilePath& refresh_token_file_path);
 };
 
 }  // namespace test
diff --git a/remoting/test/remote_host_info_fetcher.cc b/remoting/test/remote_host_info_fetcher.cc
index d1a651a..f65310a 100644
--- a/remoting/test/remote_host_info_fetcher.cc
+++ b/remoting/test/remote_host_info_fetcher.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/stringprintf.h"
@@ -101,7 +100,7 @@
   }
 
   scoped_ptr<base::Value> response_value(
-      base::JSONReader::DeprecatedRead(response_string));
+      base::JSONReader::Read(response_string));
   if (!response_value ||
       !response_value->IsType(base::Value::TYPE_DICTIONARY)) {
     LOG(ERROR) << "Failed to parse response string to JSON";
diff --git a/remoting/webapp/app_remoting/js/app_remoting.js b/remoting/webapp/app_remoting/js/app_remoting.js
index 25a1f8d..87b91346 100644
--- a/remoting/webapp/app_remoting/js/app_remoting.js
+++ b/remoting/webapp/app_remoting/js/app_remoting.js
@@ -15,17 +15,23 @@
 
 /**
  * @param {Array<string>} appCapabilities Array of application capabilities.
+ * @param {remoting.LicenseManager=} opt_licenseManager
  * @constructor
  * @implements {remoting.ApplicationInterface}
  * @extends {remoting.Application}
  */
-remoting.AppRemoting = function(appCapabilities) {
+remoting.AppRemoting = function(appCapabilities, opt_licenseManager) {
   base.inherits(this, remoting.Application);
 
   /** @private {remoting.Activity} */
   this.activity_ = null;
 
   /** @private */
+  this.licenseManager_ = (opt_licenseManager) ?
+                             opt_licenseManager :
+                             new remoting.GaiaLicenseManager();
+
+  /** @private */
   this.appCapabilities_ = appCapabilities;
 };
 
@@ -55,20 +61,23 @@
 /**
  * @override {remoting.ApplicationInterface}
  */
-remoting.AppRemoting.prototype.initApplication_ = function() {
-  var windowShape = new remoting.WindowShape();
-  windowShape.updateClientWindowShape();
-
-  this.activity_ = new remoting.AppRemotingActivity(this.appCapabilities_, this,
-                                                    windowShape);
-};
+remoting.AppRemoting.prototype.initApplication_ = function() {};
 
 /**
  * @param {string} token An OAuth access token.
  * @override {remoting.ApplicationInterface}
  */
 remoting.AppRemoting.prototype.startApplication_ = function(token) {
-  this.activity_.start();
+  var windowShape = new remoting.WindowShape();
+  windowShape.updateClientWindowShape();
+  var that = this;
+
+  this.licenseManager_.getSubscriptionToken(token).then(
+      function(/** string*/ subscriptionToken) {
+    that.activity_ = new remoting.AppRemotingActivity(
+        that.appCapabilities_, that, windowShape, subscriptionToken);
+    that.activity_.start();
+  });
 };
 
 /**
diff --git a/remoting/webapp/app_remoting/js/app_remoting_activity.js b/remoting/webapp/app_remoting/js/app_remoting_activity.js
index 427470b..4ad682a 100644
--- a/remoting/webapp/app_remoting/js/app_remoting_activity.js
+++ b/remoting/webapp/app_remoting/js/app_remoting_activity.js
@@ -28,11 +28,13 @@
  * @param {Array<string>} appCapabilities Array of application capabilities.
  * @param {remoting.Application} app
  * @param {remoting.WindowShape} windowShape
+ * @param {string} subscriptionToken
  *
  * @constructor
  * @implements {remoting.Activity}
  */
-remoting.AppRemotingActivity = function(appCapabilities, app, windowShape) {
+remoting.AppRemotingActivity = function(appCapabilities, app, windowShape,
+                                        subscriptionToken) {
   /** @private */
   this.sessionFactory_ = new remoting.ClientSessionFactory(
       document.querySelector('#client-container .client-plugin-container'),
@@ -49,6 +51,9 @@
 
   /** @private */
   this.windowShape_ = windowShape;
+
+  /** @private */
+  this.subscriptionToken_ = subscriptionToken;
 };
 
 remoting.AppRemotingActivity.prototype.dispose = function() {
@@ -90,6 +95,7 @@
 remoting.AppRemotingActivity.prototype.getAppHostInfo_ = function(token) {
   var url = remoting.settings.APP_REMOTING_API_BASE_URL + '/applications/' +
             remoting.settings.getAppRemotingApplicationId() + '/run';
+  // TODO(kelvinp): Passes |this.subscriptionToken_| to the XHR.
   return new remoting.AutoRetryXhr({
     method: 'POST',
     url: url,
diff --git a/remoting/webapp/app_remoting/js/gaia_license_manager.js b/remoting/webapp/app_remoting/js/gaia_license_manager.js
new file mode 100644
index 0000000..af8b48a
--- /dev/null
+++ b/remoting/webapp/app_remoting/js/gaia_license_manager.js
@@ -0,0 +1,38 @@
+// 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.
+
+/** @suppress {duplicate} */
+var remoting = remoting || {};
+
+(function() {
+
+"use strict";
+
+/**
+ * A simple implementation of AppRemotingAuth using the user's GAIA token.
+ *
+ * @implements{remoting.LicenseManager}
+ * @constructor
+ */
+remoting.GaiaLicenseManager = function() {};
+
+/**
+ * @param {string} oauthToken
+ * @return {Promise<!string>}
+ */
+remoting.GaiaLicenseManager.prototype.getSubscriptionToken =
+    function(oauthToken) {
+  return Promise.resolve(oauthToken);
+};
+
+/**
+ * @param {string} oauthToken
+ * @return {Promise<!string>}
+ */
+remoting.GaiaLicenseManager.prototype.getAccessToken = function(oauthToken) {
+  return Promise.resolve("");
+};
+
+})();
+
diff --git a/remoting/webapp/app_remoting/js/license_manager.js b/remoting/webapp/app_remoting/js/license_manager.js
new file mode 100644
index 0000000..d29f9d1
--- /dev/null
+++ b/remoting/webapp/app_remoting/js/license_manager.js
@@ -0,0 +1,47 @@
+// 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.
+
+/** @suppress {duplicate} */
+var remoting = remoting || {};
+
+(function() {
+
+'use strict';
+
+/**
+ * @interface
+ */
+remoting.LicenseManager = function() {};
+
+/**
+ * Called by App Streaming to obtain a fresh Subscription Token to pass to the
+ * Orchestrator to authorize access to the Vendor’s application.
+ * The returned Promise should emit the token serialized into a string, suitable
+ * for the App Streaming client to deliver to the VM.
+ *
+ * @param {string} oauthToken Identity Token identifying the user for which a
+ *     Subscription token is being requested.
+ * @return {Promise<!string>}
+ */
+remoting.LicenseManager.prototype.getSubscriptionToken = function(oauthToken){};
+
+/**
+ * Called by App Streaming to obtain a fresh Access Token to pass to the
+ * application VM for use by the application to access services provided by the
+ * Vendor.
+ * The returned Promise should emit the token serialized into a string, suitable
+ * for the App Streaming client to deliver to the VM.
+ * NOTE: This interface may be revised to allow for supporting e.g. client-bound
+ * Access Tokens in future.
+ *
+ * @param {string} oauthToken Identity Token identifying the user for which an
+ *     Access Token is being requested.
+ * @return {Promise<!string>}
+ */
+remoting.LicenseManager.prototype.getAccessToken = function(oauthToken) {};
+
+})();
+
+
+
diff --git a/remoting/webapp/base/js/client_session.js b/remoting/webapp/base/js/client_session.js
index 294fe53..d8fd810 100644
--- a/remoting/webapp/base/js/client_session.js
+++ b/remoting/webapp/base/js/client_session.js
@@ -527,6 +527,10 @@
   if (newState == remoting.ClientSession.State.CONNECTED) {
     this.connectedDisposables_.add(
         new base.RepeatingTimer(this.reportStatistics.bind(this), 1000));
+    if (this.plugin_.hasCapability(
+          remoting.ClientSession.Capability.TOUCH_EVENTS)) {
+      this.plugin_.enableTouchEvents(true);
+    }
   } else if (this.isFinished()) {
     base.dispose(this.connectedDisposables_);
     this.connectedDisposables_ = null;
@@ -534,10 +538,6 @@
 
   this.notifyStateChanges_(oldState, this.state_);
   this.logToServer_.logClientSessionStateChange(this.state_, this.error_);
-  if (this.plugin_.hasCapability(
-          remoting.ClientSession.Capability.TOUCH_EVENTS)) {
-    this.plugin_.enableTouchEvents(true);
-  }
 };
 
 /**
diff --git a/remoting/webapp/base/js/log_to_server.js b/remoting/webapp/base/js/log_to_server.js
index 42b1ddb7..7cb0043d 100644
--- a/remoting/webapp/base/js/log_to_server.js
+++ b/remoting/webapp/base/js/log_to_server.js
@@ -14,9 +14,11 @@
 
 /**
  * @param {remoting.SignalStrategy} signalStrategy Signal strategy.
+ * @param {boolean=} opt_isHost True if this instance should log role=host
+ *     events rather than role=client.
  * @constructor
  */
-remoting.LogToServer = function(signalStrategy) {
+remoting.LogToServer = function(signalStrategy, opt_isHost) {
   /** @private */
   this.statsAccumulator_ = new remoting.StatsAccumulator();
   /** @private */
@@ -35,8 +37,10 @@
   this.hostVersion_ = '';
   /** @private */
   this.logEntryMode_ = remoting.ServerLogEntry.VALUE_MODE_UNKNOWN;
+  /** @private */
+  this.role_ = opt_isHost ? 'host' : 'client';
 
-  this.setSessionId_();
+  this.setSessionId();
   signalStrategy.sendConnectionSetupResults(this);
 };
 
@@ -65,7 +69,7 @@
   this.maybeExpireSessionId_();
   // Log the session state change.
   var entry = remoting.ServerLogEntry.makeClientSessionStateChange(
-      state, connectionError, this.logEntryMode_);
+      state, connectionError, this.logEntryMode_, this.role_);
   entry.addClientOSFields();
   entry.addChromeVersionField();
   entry.addWebappVersionField();
@@ -204,10 +208,8 @@
 
 /**
  * Sets the session ID to a random string.
- *
- * @private
  */
-remoting.LogToServer.prototype.setSessionId_ = function() {
+remoting.LogToServer.prototype.setSessionId = function() {
   this.sessionId_ = remoting.LogToServer.generateSessionId_();
   this.sessionIdGenerationTime_ = new Date().getTime();
 };
@@ -239,7 +241,7 @@
                                                          this.logEntryMode_);
     this.log_(entry);
     // Generate a new session ID.
-    this.setSessionId_();
+    this.setSessionId();
     // Log the new session ID.
     entry = remoting.ServerLogEntry.makeSessionIdNew(this.sessionId_,
                                                      this.logEntryMode_);
diff --git a/remoting/webapp/base/js/server_log_entry.js b/remoting/webapp/base/js/server_log_entry.js
index 0af065f..c38f9aed 100644
--- a/remoting/webapp/base/js/server_log_entry.js
+++ b/remoting/webapp/base/js/server_log_entry.js
@@ -216,13 +216,14 @@
  * @param {remoting.ClientSession.State} state
  * @param {!remoting.Error} connectionError
  * @param {string} mode The current app mode (It2Me, Me2Me, AppRemoting).
+ * @param {string} role 'client' if the app is acting as a Chromoting client
+ *     or 'host' if it is acting as a host (IT2Me)
  * @return {remoting.ServerLogEntry}
  */
 remoting.ServerLogEntry.makeClientSessionStateChange = function(state,
-    connectionError, mode) {
+    connectionError, mode, role) {
   var entry = new remoting.ServerLogEntry();
-  entry.set_(remoting.ServerLogEntry.KEY_ROLE_,
-             remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
+  entry.set_(remoting.ServerLogEntry.KEY_ROLE_, role);
   entry.set_(remoting.ServerLogEntry.KEY_EVENT_NAME_,
              remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_STATE_);
   entry.set_(remoting.ServerLogEntry.KEY_SESSION_STATE_,
@@ -439,4 +440,3 @@
 remoting.ServerLogEntry.prototype.addApplicationId = function() {
   this.set_(remoting.ServerLogEntry.KEY_APP_ID_, chrome.runtime.id);
 };
-
diff --git a/remoting/webapp/crd/js/buffered_signal_strategy.js b/remoting/webapp/crd/js/buffered_signal_strategy.js
new file mode 100644
index 0000000..0dba7b53
--- /dev/null
+++ b/remoting/webapp/crd/js/buffered_signal_strategy.js
@@ -0,0 +1,107 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+/** @suppress {duplicate} */
+var remoting = remoting || {};
+
+/**
+ * Simplified SignalStrategy implementation that wraps an underlying signal
+ * strategy and forwards messages when it is CONNECTED. It is used only to
+ * log status messages during IT2Me connection setup, and only those methods
+ * required for that are implemented.
+ *
+ * TODO(jamiewalch): Remove this class once a signal strategy is no longer
+ *     required for logging (crbug.com/497269).
+ *
+ * @constructor
+ * @param {remoting.SignalStrategy} underlying The underlying implementation.
+ * @implements {remoting.SignalStrategy}
+ */
+remoting.BufferedSignalStrategy = function(underlying) {
+  /** @private */
+  this.underlying_ = underlying;
+  /** @private {Array<string>} */
+  this.pendingMessages_ = [];
+
+  this.underlying_.setStateChangedCallback(this.flush_.bind(this));
+};
+
+remoting.BufferedSignalStrategy.prototype.dispose = function() {
+  this.underlying_.dispose();
+};
+
+/**
+ * Sends a message. Can be called only in CONNECTED state.
+ * @param {string} message
+ */
+remoting.BufferedSignalStrategy.prototype.sendMessage = function(message) {
+  this.pendingMessages_.push(message);
+  this.flush_();
+};
+
+/**
+ * Send any messages accumulated during connection set-up.
+ *
+ * @param {remoting.LogToServer} logToServer The LogToServer instance for the
+ *     connection.
+ */
+remoting.BufferedSignalStrategy.prototype.sendConnectionSetupResults =
+    function(logToServer) {
+  this.underlying_.sendConnectionSetupResults(logToServer);
+};
+
+/**
+ * If the underlying implementation is connected, flush all pending messages.
+ * @private
+ */
+remoting.BufferedSignalStrategy.prototype.flush_ = function() {
+  if (this.underlying_.getState() !== remoting.SignalStrategy.State.CONNECTED) {
+    return;
+  }
+  for (var i = 0; i < this.pendingMessages_.length; ++i) {
+    this.underlying_.sendMessage(this.pendingMessages_[i]);
+  }
+  this.pendingMessages_ = [];
+};
+
+
+// The following methods are not used by LogToServer and are not implemented.
+
+remoting.BufferedSignalStrategy.prototype.setStateChangedCallback =
+    function(onStateChangedCallback) {
+  base.debug.assert(false);
+};
+
+remoting.BufferedSignalStrategy.prototype.setIncomingStanzaCallback =
+    function(onIncomingStanzaCallback) {
+  base.debug.assert(false);
+};
+
+remoting.BufferedSignalStrategy.prototype.connect =
+    function(server, username, authToken) {
+  base.debug.assert(false);
+};
+
+remoting.BufferedSignalStrategy.prototype.sendConnectionSetupResults =
+    function(logToServer) {
+  base.debug.assert(false);
+};
+
+remoting.BufferedSignalStrategy.prototype.getState = function() {
+  base.debug.assert(false);
+};
+
+remoting.BufferedSignalStrategy.prototype.getError = function() {
+  base.debug.assert(false);
+};
+
+remoting.BufferedSignalStrategy.prototype.getJid = function() {
+  base.debug.assert(false);
+};
+
+remoting.BufferedSignalStrategy.prototype.getType = function() {
+  base.debug.assert(false);
+};
diff --git a/remoting/webapp/crd/js/gcd_client.js b/remoting/webapp/crd/js/gcd_client.js
index a2cac57..5bfab9f 100644
--- a/remoting/webapp/crd/js/gcd_client.js
+++ b/remoting/webapp/crd/js/gcd_client.js
@@ -32,7 +32,9 @@
  * TODO: Flesh out with typical fields.
  * @typedef {{
  *   id:string,
- *   name:string
+ *   name:string,
+ *   state:(!Object|undefined),
+ *   tags:(!Array<string>|undefined)
  * }}
  */
 remoting.gcd.Device;
@@ -206,18 +208,12 @@
 /**
  * Lists devices user has access to.
  * TODO: Add link to GCD docs.
- * @param {string=} opt_nameSubstring If present, the list of devices
- *     is filtered by GCD such that every device returned contains
- *     this string as as a substring of its |name| or |displayName|.
  * @return {!Promise<!Array<remoting.gcd.Device>>}
  */
-remoting.gcd.Client.prototype.listDevices = function(opt_nameSubstring) {
+remoting.gcd.Client.prototype.listDevices = function() {
   return new remoting.Xhr({
     method: 'GET',
     url: this.apiBaseUrl_ + '/devices',
-    urlParams: {
-      nameSubstring: opt_nameSubstring || null
-    },
     useIdentity: true,
     acceptJson: true
   }).start().then(function(response) {
diff --git a/remoting/webapp/crd/js/gcd_host_list_api.js b/remoting/webapp/crd/js/gcd_host_list_api.js
new file mode 100644
index 0000000..a904c9d
--- /dev/null
+++ b/remoting/webapp/crd/js/gcd_host_list_api.js
@@ -0,0 +1,180 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * REST API for host-list management.
+ */
+
+/** @suppress {duplicate} */
+var remoting = remoting || {};
+
+(function() {
+
+'use strict';
+
+/**
+ * @constructor
+ * @implements {remoting.HostListApi}
+ */
+remoting.GcdHostListApi = function() {
+  this.gcd_ = new remoting.gcd.Client({
+    apiKey: remoting.settings.GOOGLE_API_KEY
+  });
+};
+
+/** @override */
+remoting.GcdHostListApi.prototype.register = function(
+    hostName, publicKey, hostClientId) {
+  var self = this;
+  var deviceDraft = {
+    channel: {
+      supportedType: 'xmpp'
+    },
+    deviceKind: 'vendor',
+    name: hostName,
+    state: {
+      base: {
+        firmwareVersion: 'none',
+        localDiscoveryEnabled: false,
+        localAnonymousAccessMaxRole: 'none',
+        localPairingEnabled: false,
+        // The leading underscore is necessary for |_publicKey|
+        // because it's not a standard key defined by GCD.
+        _publicKey: publicKey
+      }
+    },
+    'tags': [CHROMOTING_DEVICE_TAG]
+  };
+
+  return /** @type {!Promise<remoting.HostListApi.RegisterResult>} */ (
+      this.gcd_.insertRegistrationTicket().
+      then(function(ticket) {
+        return self.gcd_.patchRegistrationTicket(
+            ticket.id, deviceDraft, hostClientId);
+      }).
+      then(function(/**remoting.gcd.RegistrationTicket*/ ticket) {
+        return self.gcd_.finalizeRegistrationTicket(ticket.id);
+      }).
+      then(function(/**remoting.gcd.RegistrationTicket*/ ticket) {
+        return {
+          authCode: ticket.robotAccountAuthorizationCode,
+          email: ticket.robotAccountEmail,
+          hostId: ticket.deviceId,
+          isLegacy: false
+        };
+      }).
+      catch(function(error) {
+        console.error('Error registering device with GCD: ' + error);
+        throw new remoting.Error(remoting.Error.Tag.REGISTRATION_FAILED);
+      }));
+};
+
+/** @override */
+remoting.GcdHostListApi.prototype.get = function() {
+  return this.gcd_.listDevices().
+      then(function(devices) {
+        var hosts = [];
+        devices.forEach(function(device) {
+          try {
+            if (isChromotingHost(device)) {
+              hosts.push(deviceToHost(device));
+            }
+          } catch (/** @type {*} */ error) {
+            console.warn('Invalid device spec:', error);
+          }
+        });
+        return hosts;
+      });
+};
+
+/** @override */
+remoting.GcdHostListApi.prototype.put =
+    function(hostId, hostName, hostPublicKey) {
+  return this.gcd_.patchDevice(hostId, {
+    'name': hostName
+  }).then(function(device) {
+    if (device.name != hostName) {
+      console.error('error updating host name');
+      throw remoting.Error.unexpected();
+    }
+    if (!device.state || device.state['_publicKey'] != hostPublicKey) {
+      // TODO(jrw): Is there any reason to believe this would ever be
+      // happen?
+      console.error('unexpected host public key');
+      throw remoting.Error.unexpected();
+    }
+    // Don't return anything.
+  });
+};
+
+/** @override */
+remoting.GcdHostListApi.prototype.remove = function(hostId) {
+  return this.gcd_.deleteDevice(hostId).then(function(deleted) {
+    if (!deleted) {
+      console.error('error deleting host from GCD');
+      throw remoting.Error.unexpected();
+    }
+    // Don't return anything.
+  });
+};
+
+/** @override */
+remoting.GcdHostListApi.prototype.getSupportHost = function(supportId) {
+  console.error('getSupportHost not supported by HostListApiGclImpl');
+  return Promise.reject(remoting.Error.unexpected());
+};
+
+/**
+ * Tag for distinguishing Chromoting hosts from other devices stored
+ * in GCD.
+ *
+ * @const
+ */
+var CHROMOTING_DEVICE_TAG = '1ce4542c-dd87-4320-ba19-ac173f98c04e';
+
+/**
+ * Check whether a GCD device entry is a Chromoting host.
+ *
+ * @param {remoting.gcd.Device} device
+ * @return {boolean}
+ */
+function isChromotingHost(device) {
+  return device.tags != null &&
+      device.tags.indexOf(CHROMOTING_DEVICE_TAG) != -1;
+}
+
+/**
+ * Converts a GCD device description to a Host object.
+ *
+ * @param {!Object} device
+ * @return {!remoting.Host}
+ */
+function deviceToHost(device) {
+  var statusMap = {
+    'online': 'ONLINE',
+    'offline': 'OFFLINE'
+  };
+  var hostId = base.getStringAttr(device, 'id');
+  var host = new remoting.Host(hostId);
+  host.hostName = base.getStringAttr(device, 'name');
+  host.status = base.getStringAttr(
+      statusMap, base.getStringAttr(device, 'connectionStatus'));
+  var state = base.getObjectAttr(device, 'state', {});
+  var baseState = base.getObjectAttr(state, 'base', {});
+  host.publicKey = base.getStringAttr(baseState, '_publicKey');
+  host.jabberId = base.getStringAttr(baseState, '_jabberId', '');
+  host.hostVersion = base.getStringAttr(baseState, '_hostVersion', '');
+  var creationTimeMs = base.getNumberAttr(device, 'creationTimeMs', 0);
+  if (creationTimeMs) {
+    host.createdTime = new Date(creationTimeMs).toISOString();
+  }
+  var lastUpdateTimeMs = base.getNumberAttr(device, 'lastUpdateTimeMs', 0);
+  if (lastUpdateTimeMs) {
+    host.updatedTime = new Date(lastUpdateTimeMs).toISOString();
+  }
+  return host;
+};
+
+})();
diff --git a/remoting/webapp/crd/js/host_controller.js b/remoting/webapp/crd/js/host_controller.js
index a3ae6e66..730b8822 100644
--- a/remoting/webapp/crd/js/host_controller.js
+++ b/remoting/webapp/crd/js/host_controller.js
@@ -9,7 +9,23 @@
 
 /** @constructor */
 remoting.HostController = function() {
-  this.hostDaemonFacade_ = this.createDaemonFacade_();
+  /** @type {remoting.HostDaemonFacade} @private */
+  this.hostDaemonFacade_ = new remoting.HostDaemonFacade();
+
+  /** @param {string} version */
+  var printVersion = function(version) {
+    if (version == '') {
+      console.log('Host not installed.');
+    } else {
+      console.log('Host version: ' + version);
+    }
+  };
+
+  this.getLocalHostVersion()
+      .then(printVersion)
+      .catch(function() {
+        console.log('Host version not available.');
+      });
 };
 
 // The values in the enums below are duplicated in daemon_controller.h except
@@ -56,30 +72,6 @@
 }
 
 /**
- * @return {remoting.HostDaemonFacade}
- * @private
- */
-remoting.HostController.prototype.createDaemonFacade_ = function() {
-  /** @type {remoting.HostDaemonFacade} @private */
-  var hostDaemonFacade = new remoting.HostDaemonFacade();
-
-  /** @param {string} version */
-  var printVersion = function(version) {
-    if (version == '') {
-      console.log('Host not installed.');
-    } else {
-      console.log('Host version: ' + version);
-    }
-  };
-
-  hostDaemonFacade.getDaemonVersion().then(printVersion, function() {
-    console.log('Host version not available.');
-  });
-
-  return hostDaemonFacade;
-};
-
-/**
  * Set of features for which hasFeature() can be used to test.
  *
  * @enum {string}
@@ -163,13 +155,8 @@
       return null;
     }
   });
-  var newHostId = base.generateUuid();
-  var pinHashPromise = this.hostDaemonFacade_.getPinHash(newHostId, hostPin);
   var hostOwnerPromise = this.getClientBaseJid_();
 
-  /** @type {boolean} */
-  var hostRegistered = false;
-
   // Register the host and extract an auth code from the host response
   // and, optionally an email address for the robot account.
   /** @type {!Promise<remoting.HostListApi.RegisterResult>} */
@@ -183,10 +170,19 @@
     var keyPair = /** @type {remoting.KeyPair} */ (a[2]);
 
     return remoting.HostListApi.getInstance().register(
-        newHostId, hostName, keyPair.publicKey, hostClientId);
-  }).then(function(/** remoting.HostListApi.RegisterResult */ result) {
-    hostRegistered = true;
-    return result;
+        hostName, keyPair.publicKey, hostClientId);
+  });
+
+  // For convenience, make the host ID available as a separate promise.
+  /** @type {!Promise<string>} */
+  var hostIdPromise = registerResultPromise.then(function(registerResult) {
+    return registerResult.hostId;
+  });
+
+  // Get the PIN hash based on the host ID.
+  /** @type {!Promise<string>} */
+  var pinHashPromise = hostIdPromise.then(function(hostId) {
+    return that.hostDaemonFacade_.getPinHash(hostId, hostPin);
   });
 
   // Get XMPP creditials.
@@ -230,7 +226,6 @@
     var hostConfig = {
       xmpp_login: xmppCreds.userEmail,
       oauth_refresh_token: xmppCreds.refreshToken,
-      host_id: newHostId,
       host_name: hostName,
       host_secret_hash: hostSecretHash,
       private_key: keyPair.privateKey,
@@ -239,8 +234,11 @@
     if (hostOwnerEmail != hostOwner) {
       hostConfig['host_owner_email'] = hostOwnerEmail;
     }
-    if (registerResult.gcdId) {
-      hostConfig['gcd_device_id'] = registerResult.gcdId;
+    if (registerResult.isLegacy) {
+      hostConfig['host_id'] = registerResult.hostId;
+    }
+    else {
+      hostConfig['gcd_device_id'] = registerResult.hostId;
     }
     return hostConfig;
   });
@@ -253,24 +251,24 @@
       });
 
   // Update the UI or report an error.
-  return startDaemonResultPromise.then(function(result) {
-    if (result == remoting.HostController.AsyncResult.OK) {
-      return hostNamePromise.then(function(hostName) {
-        return keyPairPromise.then(function(keyPair) {
-          remoting.hostList.onLocalHostStarted(
-              hostName, newHostId, keyPair.publicKey);
+  return hostIdPromise.then(function(hostId) {
+    return startDaemonResultPromise.then(function(result) {
+      if (result == remoting.HostController.AsyncResult.OK) {
+        return hostNamePromise.then(function(hostName) {
+          return keyPairPromise.then(function(keyPair) {
+            remoting.hostList.onLocalHostStarted(
+                hostName, hostId, keyPair.publicKey);
+          });
         });
-      });
-    } else if (result == remoting.HostController.AsyncResult.CANCELLED) {
-      throw new remoting.Error(remoting.Error.Tag.CANCELLED);
-    } else {
-      throw remoting.Error.unexpected();
-    }
-  }).catch(function(error) {
-    if (hostRegistered) {
-      remoting.hostList.unregisterHostById(newHostId);
-    }
-    throw error;
+      } else if (result == remoting.HostController.AsyncResult.CANCELLED) {
+        throw new remoting.Error(remoting.Error.Tag.CANCELLED);
+      } else {
+        throw remoting.Error.unexpected();
+      }
+    }).catch(function(error) {
+      remoting.hostList.unregisterHostById(hostId);
+      throw error;
+    });
   });
 };
 
@@ -335,7 +333,7 @@
   /** @param {remoting.HostController.AsyncResult} result */
   function onConfigUpdated(result) {
     if (result == remoting.HostController.AsyncResult.OK) {
-      onDone();
+      that.clearPairedClients(onDone, onError);
     } else if (result == remoting.HostController.AsyncResult.CANCELLED) {
       onError(new remoting.Error(remoting.Error.Tag.CANCELLED));
     } else {
@@ -399,7 +397,10 @@
   function onConfig(config) {
     var hostId = null;
     if (isHostConfigValid_(config)) {
-      hostId = /** @type {string} */ (config['host_id']);
+      // Use the |gcd_device_id| field if it exists, or the |host_id|
+      // field otherwise.
+      hostId = base.getStringAttr(
+          config, 'gcd_device_id', base.getStringAttr(config, 'host_id'));
     }
     onDone(hostId);
   };
@@ -410,6 +411,14 @@
 };
 
 /**
+ * @return {Promise<string>} Promise that resolves with the host version, if
+ *     installed, or rejects otherwise.
+ */
+remoting.HostController.prototype.getLocalHostVersion = function() {
+  return this.hostDaemonFacade_.getDaemonVersion();
+};
+
+/**
  * Fetch the list of paired clients for this host.
  *
  * @param {function(Array<remoting.PairedClient>):void} onDone
diff --git a/remoting/webapp/crd/js/host_controller_unittest.js b/remoting/webapp/crd/js/host_controller_unittest.js
index 9b4aa77..5f32c4d 100644
--- a/remoting/webapp/crd/js/host_controller_unittest.js
+++ b/remoting/webapp/crd/js/host_controller_unittest.js
@@ -65,6 +65,9 @@
 /** @type {sinon.Spy|Function} */
 var updateDaemonConfigSpy;
 
+/** @type {sinon.Spy|Function} */
+var clearPairedClientsSpy;
+
 /** @type {sinon.Spy} */
 var unregisterHostByIdSpy;
 
@@ -82,6 +85,7 @@
     mockHostListApi = new remoting.MockHostListApi;
     mockHostListApi.authCodeFromRegister = FAKE_AUTH_CODE;
     mockHostListApi.emailFromRegister = '';
+    mockHostListApi.hostIdFromRegister = FAKE_HOST_ID;
     remoting.HostListApi.setInstance(mockHostListApi);
     base.debug.assert(remoting.oauth2 === null);
     remoting.oauth2 = new remoting.OAuth2();
@@ -130,6 +134,8 @@
     startDaemonSpy = sinon.spy(mockHostDaemonFacade, 'startDaemon');
     updateDaemonConfigSpy =
         sinon.spy(mockHostDaemonFacade, 'updateDaemonConfig');
+    clearPairedClientsSpy =
+        sinon.spy(mockHostDaemonFacade, 'clearPairedClients');
 
     // Set up successful responses from mockHostDaemonFacade.
     // Individual tests override these values to create errors.
@@ -265,7 +271,7 @@
 QUnit.test('start with getCredentialsFromAuthCode failure', function(assert) {
   mockHostDaemonFacade.useEmail = null;
   mockHostDaemonFacade.refreshToken = null;
-  return controller.start(FAKE_HOST_PIN, true).then(function() {
+  return controller.start(FAKE_HOST_PIN, true).then(function(result) {
     throw 'test failed';
   }, function(/** remoting.Error */ e) {
     assert.equal(e.getDetail(), 'getCredentialsFromAuthCode');
@@ -355,18 +361,23 @@
       assert.equal(unregisterHostByIdSpy.callCount, 0);
       assert.equal(onLocalHostStartedSpy.callCount, 1);
       assert.equal(startDaemonSpy.callCount, 1);
+      var expectedConfig = {
+        xmpp_login: FAKE_XMPP_LOGIN,
+        oauth_refresh_token: FAKE_REFRESH_TOKEN,
+        host_owner: FAKE_CLIENT_JID.toLowerCase(),
+        host_owner_email: FAKE_USER_EMAIL,
+        host_name: FAKE_HOST_NAME,
+        host_secret_hash: fakePinHash,
+        private_key: FAKE_PRIVATE_KEY
+      };
+      if (remoting.settings.USE_GCD) {
+        expectedConfig['gcd_device_id'] = FAKE_HOST_ID;
+      } else {
+        expectedConfig['host_id'] = FAKE_HOST_ID;
+      }
       assert.deepEqual(
           startDaemonSpy.args[0].slice(0, 2),
-          [{
-            xmpp_login: FAKE_XMPP_LOGIN,
-            oauth_refresh_token: FAKE_REFRESH_TOKEN,
-            host_owner: FAKE_CLIENT_JID.toLowerCase(),
-            host_owner_email: FAKE_USER_EMAIL,
-            host_id: FAKE_HOST_ID,
-            host_name: FAKE_HOST_NAME,
-            host_secret_hash: fakePinHash,
-            private_key: FAKE_PRIVATE_KEY
-          }, consent]);
+          [expectedConfig, consent]);
     });
   });
 });
@@ -438,6 +449,7 @@
       reject('test failed');
     }, function(/** remoting.Error */ e) {
       assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED);
+      assert.equal(clearPairedClientsSpy.callCount, 0);
       resolve(null);
     });
   });
@@ -452,6 +464,7 @@
     }, function(/** remoting.Error */ e) {
       assert.equal(e.getDetail(), 'getDaemonConfig');
       assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED);
+      assert.equal(clearPairedClientsSpy.callCount, 0);
       resolve(null);
     });
   });
@@ -468,6 +481,7 @@
     }, function(/** remoting.Error */ e) {
       assert.equal(e.getDetail(), 'updateDaemonConfig');
       assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED);
+      assert.equal(clearPairedClientsSpy.callCount, 0);
       resolve(null);
     });
   });
@@ -483,6 +497,7 @@
       reject('test failed');
     }, function(/** remoting.Error */ e) {
       assert.equal(e.getTag(), remoting.Error.Tag.CANCELLED);
+      assert.equal(clearPairedClientsSpy.callCount, 0);
       resolve(null);
     });
   });
@@ -498,6 +513,7 @@
       reject('test failed');
     }, function(/** remoting.Error */ e) {
       assert.equal(e.getTag(), remoting.Error.Tag.UNEXPECTED);
+      assert.equal(clearPairedClientsSpy.callCount, 0);
       resolve(null);
     });
   });
@@ -505,6 +521,7 @@
 
 // Check what happens when updatePin succeeds.
 QUnit.test('updatePin succeeds', function(assert) {
+  mockHostDaemonFacade.pairedClients = [];
   /** @const */
   var fakePinHash = fakePinHashFunc(FAKE_HOST_ID, FAKE_NEW_HOST_PIN);
   return new Promise(function(resolve, reject) {
@@ -517,6 +534,7 @@
           updateDaemonConfigSpy.args[0][0], {
             host_secret_hash: fakePinHash
           });
+      assert.equal(clearPairedClientsSpy.callCount, 1);
       resolve(null);
     }, reject);
   });
diff --git a/remoting/webapp/crd/js/host_list_api.js b/remoting/webapp/crd/js/host_list_api.js
index ffc167a..421314e 100644
--- a/remoting/webapp/crd/js/host_list_api.js
+++ b/remoting/webapp/crd/js/host_list_api.js
@@ -22,14 +22,13 @@
  * Registers a new host with the host registry service (either the
  * Chromoting registry or GCD).
  *
- * @param {string} newHostId The ID of the new host to register.
  * @param {string} hostName The user-visible name of the new host.
  * @param {string} publicKey The public half of the host's key pair.
  * @param {string} hostClientId The OAuth2 client ID of the host.
  * @return {!Promise<remoting.HostListApi.RegisterResult>}
  */
 remoting.HostListApi.prototype.register = function(
-    newHostId, hostName, publicKey, hostClientId) {
+    hostName, publicKey, hostClientId) {
 };
 
 /**
@@ -82,8 +81,8 @@
 remoting.HostListApi.getInstance = function() {
   if (instance == null) {
     instance = remoting.settings.USE_GCD ?
-        new remoting.HostListApiGcdImpl() :
-        new remoting.HostListApiImpl();
+        new remoting.GcdHostListApi() :
+        new remoting.LegacyHostListApi();
   }
   return instance;
 };
@@ -100,23 +99,27 @@
 
 /**
  * Information returned from the registry/GCD server when registering
- * a device.  GCD will fill in all three fields; the Chromoting
- * registry will only return an auth code; other fields will be empty.
+ * a device.
  *
  * The fields are:
  *
  * authCode: An OAuth2 authorization code that can be exchanged for a
  *     refresh token.
  *
- * email: The email/XMPP address of the robot account associated
- *     with this device.
+ * email: The email/XMPP address of the robot account associated with
+ *     this device.  The Chromoting directory sets this field to the
+ *     empty string; GCD returns a real email address.
  *
- * gcmId: The ID string assigned to this device by GCD.
+ * hostId: The ID of the newly registered host.
+ *
+ * isLegacy: True for registrations in the legacy directory, false for
+ *     registrations in GCD.
  *
  * @typedef {{
  *   authCode: string,
  *   email: string,
- *   gcdId: string
+ *   hostId: string,
+ *   isLegacy: boolean
  * }}
  */
-remoting.HostListApi.RegisterResult;
\ No newline at end of file
+remoting.HostListApi.RegisterResult;
diff --git a/remoting/webapp/crd/js/host_list_api_gcd_impl.js b/remoting/webapp/crd/js/host_list_api_gcd_impl.js
deleted file mode 100644
index 2e6e508..0000000
--- a/remoting/webapp/crd/js/host_list_api_gcd_impl.js
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview
- * REST API for host-list management.
- */
-
-/** @suppress {duplicate} */
-var remoting = remoting || {};
-
-(function() {
-
-'use strict';
-
-/**
- * @constructor
- * @implements {remoting.HostListApi}
- */
-remoting.HostListApiGcdImpl = function() {
-  this.gcd_ = new remoting.gcd.Client({
-    apiKey: remoting.settings.GOOGLE_API_KEY
-  });
-};
-
-/** @override */
-remoting.HostListApiGcdImpl.prototype.register = function(
-    newHostId, hostName, publicKey, hostClientId) {
-  var self = this;
-  var deviceDraft = {
-    channel: {
-      supportedType: 'xmpp'
-    },
-    deviceKind: 'vendor',
-    name: newHostId,
-    displayName: hostName,
-    state: {
-      'publicKey': publicKey
-    }
-  };
-
-  return /** @type {!Promise<remoting.HostListApi.RegisterResult>} */ (
-      this.gcd_.insertRegistrationTicket().
-      then(function(ticket) {
-        return self.gcd_.patchRegistrationTicket(
-            ticket.id, deviceDraft, hostClientId);
-      }).
-      then(function(/**remoting.gcd.RegistrationTicket*/ ticket) {
-        return self.gcd_.finalizeRegistrationTicket(ticket.id);
-      }).
-      then(function(/**remoting.gcd.RegistrationTicket*/ ticket) {
-        return {
-          authCode: ticket.robotAccountAuthorizationCode,
-          email: ticket.robotAccountEmail,
-          gcdId: ticket.deviceId
-        };
-      }).
-      catch(function(error) {
-        console.error('Error registering device with GCD: ' + error);
-        throw new remoting.Error(remoting.Error.Tag.REGISTRATION_FAILED);
-      }));
-};
-
-/** @override */
-remoting.HostListApiGcdImpl.prototype.get = function() {
-  return this.gcd_.listDevices().
-      then(function(devices) {
-        var hosts = [];
-        devices.forEach(function(device) {
-          try {
-            hosts.push(deviceToHost(device));
-          } catch (/** @type {*} */ error) {
-            console.warn('Invalid device spec:', error);
-          }
-        });
-        return hosts;
-      });
-};
-
-/** @override */
-remoting.HostListApiGcdImpl.prototype.put =
-    function(hostId, hostName, hostPublicKey) {
-  // TODO(jrw)
-  throw new Error('Not implemented');
-};
-
-/** @override */
-remoting.HostListApiGcdImpl.prototype.remove = function(hostId) {
-  var that = this;
-  return this.gcd_.listDevices(hostId).then(function(devices) {
-    var gcdId = null;
-    for (var i = 0; i < devices.length; i++) {
-      var device = devices[i];
-      // The "name" field in GCD holds what Chromoting considers to be
-      // the host ID.
-      if (device.name == hostId) {
-        gcdId = device.id;
-      }
-    }
-    if (gcdId == null) {
-      return false;
-    } else {
-      return that.gcd_.deleteDevice(gcdId);
-    }
-  });
-};
-
-/** @override */
-remoting.HostListApiGcdImpl.prototype.getSupportHost = function(supportId) {
-  console.error('getSupportHost not supported by HostListApiGclImpl');
-  return Promise.reject(remoting.Error.unexpected());
-};
-
-/**
- * Converts a GCD device description to a Host object.
- * @param {!Object} device
- * @return {!remoting.Host}
- */
-function deviceToHost(device) {
-  var statusMap = {
-    'online': 'ONLINE',
-    'offline': 'OFFLINE'
-  };
-  var hostId = base.getStringAttr(device, 'name');
-  var host = new remoting.Host(hostId);
-  host.hostName = base.getStringAttr(device, 'displayName');
-  host.status = base.getStringAttr(
-      statusMap, base.getStringAttr(device, 'connectionStatus'));
-  var state = base.getObjectAttr(device, 'state', {});
-  host.publicKey = base.getStringAttr(state, 'publicKey');
-  host.jabberId = base.getStringAttr(state, 'jabberId', '');
-  host.hostVersion = base.getStringAttr(state, 'hostVersion', '');
-  var creationTimeMs = base.getNumberAttr(device, 'creationTimeMs', 0);
-  if (creationTimeMs) {
-    host.createdTime = new Date(creationTimeMs).toISOString();
-  }
-  var lastUpdateTimeMs = base.getNumberAttr(device, 'lastUpdateTimeMs', 0);
-  if (lastUpdateTimeMs) {
-    host.updatedTime = new Date(lastUpdateTimeMs).toISOString();
-  }
-  return host;
-};
-
-})();
diff --git a/remoting/webapp/crd/js/host_screen.js b/remoting/webapp/crd/js/host_screen.js
index 78458632..e959043 100644
--- a/remoting/webapp/crd/js/host_screen.js
+++ b/remoting/webapp/crd/js/host_screen.js
@@ -24,12 +24,27 @@
 var lastShareWasCancelled_ = false;
 
 /**
+ * @type {remoting.LogToServer} Logging instance for IT2Me host connection
+ *     status.
+ */
+var it2meLogger = null;
+
+/**
  * Start a host session. This is the main entry point for the host screen,
  * called directly from the onclick action of a button on the home screen.
  * It first verifies that the native host components are installed and asks
  * to install them if necessary.
  */
 remoting.tryShare = function() {
+  ensureIT2MeLogger_().then(tryShareWithLogger_);
+};
+
+function tryShareWithLogger_() {
+  it2meLogger.setSessionId();
+  it2meLogger.logClientSessionStateChange(
+      remoting.ClientSession.State.INITIALIZING,
+      remoting.Error.none());
+
   /** @type {remoting.It2MeHostFacade} */
   var hostFacade = new remoting.It2MeHostFacade();
 
@@ -51,21 +66,12 @@
     var hasHostDialog = (hostInstallDialog !== null);  /** jscompile hack */
     if (!hasHostDialog) {
       hostInstallDialog = new remoting.HostInstallDialog();
-      hostInstallDialog.show(tryInitializeFacade, onInstallError);
+      hostInstallDialog.show(tryInitializeFacade, showShareError_);
     } else {
       hostInstallDialog.tryAgain();
     }
   };
 
-  /** @param {!remoting.Error} error */
-  var onInstallError = function(error) {
-    if (error.hasTag(remoting.Error.Tag.CANCELLED)) {
-      remoting.setMode(remoting.AppMode.HOME);
-    } else {
-      showShareError_(error);
-    }
-  };
-
   tryInitializeFacade();
 };
 
@@ -74,9 +80,10 @@
  */
 remoting.startHostUsingFacade_ = function(hostFacade) {
   console.log('Attempting to share...');
-  remoting.identity.getToken().then(
-      remoting.tryShareWithToken_.bind(null, hostFacade),
-      remoting.Error.handler(remoting.showErrorMessage));
+  setHostVersion_()
+      .then(remoting.identity.getToken.bind(remoting.identity))
+      .then(remoting.tryShareWithToken_.bind(null, hostFacade),
+            remoting.Error.handler(showShareError_));
 }
 
 /**
@@ -89,6 +96,9 @@
   lastShareWasCancelled_ = false;
   onNatTraversalPolicyChanged_(true);  // Hide warning by default.
   remoting.setMode(remoting.AppMode.HOST_WAITING_FOR_CODE);
+  it2meLogger.logClientSessionStateChange(
+      remoting.ClientSession.State.CONNECTING,
+      remoting.Error.none());
   document.getElementById('cancel-share-button').disabled = false;
   disableTimeoutCountdown_();
 
@@ -194,10 +204,21 @@
  * @return {void} Nothing.
  */
 function showShareError_(error) {
-  var errorDiv = document.getElementById('host-plugin-error');
-  l10n.localizeElementFromTag(errorDiv, error.getTag());
-  console.error('Sharing error: ' + error.toString());
-  remoting.setMode(remoting.AppMode.HOST_SHARE_FAILED);
+  if (error.hasTag(remoting.Error.Tag.CANCELLED)) {
+    remoting.setMode(remoting.AppMode.HOME);
+    it2meLogger.logClientSessionStateChange(
+        remoting.ClientSession.State.CONNECTION_CANCELED,
+        remoting.Error.none());
+  } else {
+    var errorDiv = document.getElementById('host-plugin-error');
+    l10n.localizeElementFromTag(errorDiv, error.getTag());
+    console.error('Sharing error: ' + error.toString());
+    remoting.setMode(remoting.AppMode.HOST_SHARE_FAILED);
+    it2meLogger.logClientSessionStateChange(
+        remoting.ClientSession.State.FAILED,
+        error);
+  }
+
   cleanUp();
 }
 
@@ -230,6 +251,9 @@
   remoting.lastShareWasCancelled = true;
   try {
     hostSession_.disconnect();
+    it2meLogger.logClientSessionStateChange(
+        remoting.ClientSession.State.CONNECTION_CANCELED,
+        remoting.Error.none());
   } catch (/** @type {*} */ error) {
     console.error('Error disconnecting: ' + error +
                   '. The host probably crashed.');
@@ -338,4 +362,45 @@
   }
 }
 
+/**
+ * Create an IT2Me LogToServer instance if one does not already exist.
+ *
+ * @return {Promise} Promise that resolves when the host version (if available),
+ *     has been set on the logger instance.
+ */
+function ensureIT2MeLogger_() {
+  if (it2meLogger) {
+    return Promise.resolve();
+  }
+
+  var xmppConnection = new remoting.XmppConnection();
+  var tokenPromise = remoting.identity.getToken();
+  var emailPromise = remoting.identity.getEmail();
+  tokenPromise.then(function(/** string */ token) {
+    emailPromise.then(function(/** string */ email) {
+      xmppConnection.connect(remoting.settings.XMPP_SERVER, email, token);
+    });
+  });
+
+  var bufferedSignalStrategy =
+      new remoting.BufferedSignalStrategy(xmppConnection);
+  it2meLogger = new remoting.LogToServer(bufferedSignalStrategy, true);
+  it2meLogger.setLogEntryMode(remoting.ServerLogEntry.VALUE_MODE_IT2ME);
+
+  return setHostVersion_();
+};
+
+/**
+ * @return {Promise} Promise that resolves when the host version (if available),
+ *     has been set on the logger instance.
+ */
+function setHostVersion_() {
+  return remoting.hostController.getLocalHostVersion().then(
+      function(/** string */ version) {
+        it2meLogger.setHostVersion(version);
+      }).catch(
+        base.doNothing
+      );
+};
+
 })();
diff --git a/remoting/webapp/crd/js/host_list_api_impl.js b/remoting/webapp/crd/js/legacy_host_list_api.js
similarity index 85%
rename from remoting/webapp/crd/js/host_list_api_impl.js
rename to remoting/webapp/crd/js/legacy_host_list_api.js
index edea3189..c99c977 100644
--- a/remoting/webapp/crd/js/host_list_api_impl.js
+++ b/remoting/webapp/crd/js/legacy_host_list_api.js
@@ -18,12 +18,13 @@
  * @constructor
  * @implements {remoting.HostListApi}
  */
-remoting.HostListApiImpl = function() {
+remoting.LegacyHostListApi = function() {
 };
 
 /** @override */
-remoting.HostListApiImpl.prototype.register = function(
-    newHostId, hostName, publicKey, hostClientId) {
+remoting.LegacyHostListApi.prototype.register = function(
+    hostName, publicKey, hostClientId) {
+  var newHostId = base.generateUuid();
   var newHostDetails = { data: {
     hostId: newHostId,
     hostName: hostName,
@@ -44,7 +45,12 @@
       var result = /** @type {!Object} */ (response.getJson());
       var data = base.getObjectAttr(result, 'data');
       var authCode = base.getStringAttr(data, 'authorizationCode');
-      return { authCode: authCode, email: '', gcdId: '' };
+      return {
+        authCode: authCode,
+        email: '',
+        hostId: newHostId,
+        isLegacy: true
+      };
     } else {
       console.log(
           'Failed to register the host. Status: ' + response.status +
@@ -55,7 +61,7 @@
 };
 
 /** @override */
-remoting.HostListApiImpl.prototype.get = function() {
+remoting.LegacyHostListApi.prototype.get = function() {
   var that = this;
   return new remoting.Xhr({
     method: 'GET',
@@ -67,7 +73,7 @@
 };
 
 /** @override */
-remoting.HostListApiImpl.prototype.put =
+remoting.LegacyHostListApi.prototype.put =
     function(hostId, hostName, hostPublicKey) {
   return new remoting.Xhr({
     method: 'PUT',
@@ -80,16 +86,16 @@
       }
     },
     useIdentity: true
-  }).start().then(remoting.HostListApiImpl.defaultResponse_());
+  }).start().then(remoting.LegacyHostListApi.defaultResponse_());
 };
 
 /** @override */
-remoting.HostListApiImpl.prototype.remove = function(hostId) {
+remoting.LegacyHostListApi.prototype.remove = function(hostId) {
   return new remoting.Xhr({
     method: 'DELETE',
     url: remoting.settings.DIRECTORY_API_BASE_URL + '/@me/hosts/' + hostId,
     useIdentity: true
-  }).start().then(remoting.HostListApiImpl.defaultResponse_(
+  }).start().then(remoting.LegacyHostListApi.defaultResponse_(
       [remoting.Error.Tag.NOT_FOUND]));
 };
 
@@ -102,7 +108,8 @@
  * @return {!Array<!remoting.Host>}
  * @private
  */
-remoting.HostListApiImpl.prototype.parseHostListResponse_ = function(response) {
+remoting.LegacyHostListApi.prototype.parseHostListResponse_ =
+    function(response) {
   if (response.status == 200) {
     var obj = /** @type {{data: {items: Array}}} */
         (base.jsonParseSafe(response.getText()));
@@ -140,7 +147,7 @@
  * @return {function(!remoting.Xhr.Response):void}
  * @private
  */
-remoting.HostListApiImpl.defaultResponse_ = function(opt_ignoreErrors) {
+remoting.LegacyHostListApi.defaultResponse_ = function(opt_ignoreErrors) {
   /** @param {!remoting.Xhr.Response} response */
   var result = function(response) {
     var error = remoting.Error.fromHttpStatus(response.status);
@@ -158,7 +165,7 @@
 };
 
 /** @override */
-remoting.HostListApiImpl.prototype.getSupportHost = function(supportId) {
+remoting.LegacyHostListApi.prototype.getSupportHost = function(supportId) {
   return new remoting.Xhr({
     method: 'GET',
     url: remoting.settings.DIRECTORY_API_BASE_URL + '/support-hosts/' +
diff --git a/remoting/webapp/crd/js/host_list_api_impl_unittest.js b/remoting/webapp/crd/js/legacy_host_list_api_unittest.js
similarity index 88%
rename from remoting/webapp/crd/js/host_list_api_impl_unittest.js
rename to remoting/webapp/crd/js/legacy_host_list_api_unittest.js
index 4e7bc3d8..ef2b598b 100644
--- a/remoting/webapp/crd/js/host_list_api_impl_unittest.js
+++ b/remoting/webapp/crd/js/legacy_host_list_api_unittest.js
@@ -17,12 +17,18 @@
 var FAKE_HOST_CLIENT_ID = '<FAKE_HOST_CLIENT_ID>';
 var FAKE_AUTH_CODE = '<FAKE_AUTH_CODE>';
 
+/** @type {sinon.TestStub} */
+var generateUuidStub;
+
 QUnit.module('host_list_api_impl', {
   beforeEach: function(/** QUnit.Assert */ assert) {
     remoting.settings = new remoting.Settings();
     remoting.MockXhr.activate();
+    generateUuidStub = sinon.stub(base, 'generateUuid');
+    generateUuidStub.returns(FAKE_HOST_ID);
   },
   afterEach: function(/** QUnit.Assert */ assert) {
+    generateUuidStub.restore();
     remoting.MockXhr.restore();
     remoting.settings = null;
   }
@@ -54,10 +60,9 @@
 }
 
 QUnit.test('register', function(assert) {
-  var impl = new remoting.HostListApiImpl();
+  var impl = new remoting.LegacyHostListApi();
   queueRegistryResponse(assert);
   return impl.register(
-      FAKE_HOST_ID,
       FAKE_HOST_NAME,
       FAKE_PUBLIC_KEY,
       FAKE_HOST_CLIENT_ID
@@ -68,11 +73,10 @@
 });
 
 QUnit.test('register failure', function(assert) {
-  var impl = new remoting.HostListApiImpl();
+  var impl = new remoting.LegacyHostListApi();
   remoting.MockXhr.setEmptyResponseFor(
       'POST', 'DIRECTORY_API_BASE_URL/@me/hosts', 500);
   return impl.register(
-      FAKE_HOST_ID,
       FAKE_HOST_NAME,
       FAKE_PUBLIC_KEY,
       FAKE_HOST_CLIENT_ID
@@ -83,4 +87,4 @@
   });
 });
 
-})();
\ No newline at end of file
+})();
diff --git a/remoting/webapp/crd/js/mock_host_list_api.js b/remoting/webapp/crd/js/mock_host_list_api.js
index e0298e4..3cead52 100644
--- a/remoting/webapp/crd/js/mock_host_list_api.js
+++ b/remoting/webapp/crd/js/mock_host_list_api.js
@@ -31,6 +31,12 @@
    */
   this.emailFromRegister = null;
 
+  /**
+   * This host ID to return from register(), or null if it should fail.
+   * @type {?string}
+   */
+  this.hostIdFromRegister = null;
+
   /** @type {Array<remoting.Host>} */
   this.hosts = [
     {
@@ -56,7 +62,7 @@
 
 /** @override */
 remoting.MockHostListApi.prototype.register = function(
-    newHostId, hostName, publicKey, hostClientId) {
+    hostName, publicKey, hostClientId) {
   if (this.authCodeFromRegister === null || this.emailFromRegister === null) {
     return Promise.reject(
         new remoting.Error(
@@ -65,7 +71,8 @@
   } else {
     return Promise.resolve({
       authCode: this.authCodeFromRegister,
-      email: this.emailFromRegister
+      email: this.emailFromRegister,
+      hostId: this.hostIdFromRegister
     });
   }
 };
diff --git a/remoting/webapp/files.gni b/remoting/webapp/files.gni
index fbd68c77..7e77289 100644
--- a/remoting/webapp/files.gni
+++ b/remoting/webapp/files.gni
@@ -251,6 +251,7 @@
 # Files for controlling the local machine as a host.
 # Includes both it2me and me2me files.
 remoting_webapp_js_host_control_files = [
+  "crd/js/buffered_signal_strategy.js",
   "crd/js/host_controller.js",
   "crd/js/host_daemon_facade.js",
   "crd/js/host_screen.js",
@@ -266,10 +267,15 @@
 remoting_webapp_js_host_display_files = [
   "crd/js/host_list.js",
   "crd/js/host_list_api.js",
-  "crd/js/host_list_api_gcd_impl.js",
-  "crd/js/host_list_api_impl.js",
   "crd/js/host_table_entry.js",
   "crd/js/local_host_section.js",
+
+  # Must come after host_list_api.js because of an issue with
+  # JSCompiler.  If an implementation of an interface occurs in a
+  # file processed before the interface itself, the @override tag
+  # doesn't always work correctly.
+  "crd/js/gcd_host_list_api.js",
+  "crd/js/legacy_host_list_api.js",
 ]
 
 # The CRD-specific JavaScript files required by main.html.
@@ -538,8 +544,10 @@
                      "app_remoting/js/context_menu_chrome.js",
                      "app_remoting/js/context_menu_dom.js",
                      "app_remoting/js/drag_and_drop.js",
+                     "app_remoting/js/gaia_license_manager.js",
                      "app_remoting/js/idle_detector.js",
                      "app_remoting/js/keyboard_layouts_menu.js",
+                     "app_remoting/js/license_manager.js",
                      "app_remoting/js/loading_window.js",
                      "app_remoting/js/submenu_manager.js",
                      "app_remoting/js/window_activation_menu.js",
diff --git a/rlz/lib/rlz_lib.cc b/rlz/lib/rlz_lib.cc
index 39bec27a..14a4fae 100644
--- a/rlz/lib/rlz_lib.cc
+++ b/rlz/lib/rlz_lib.cc
@@ -422,7 +422,7 @@
       return false;
   } else {
     checksum_param = "crc32: ";  // Empty response case.
-    if (!StartsWithASCII(response_string, checksum_param, true))
+    if (!base::StartsWithASCII(response_string, checksum_param, true))
       return false;
 
     checksum_index = 0;
@@ -534,7 +534,8 @@
     std::string response_line;
     response_line = response_string.substr(line_begin, line_end - line_begin);
 
-    if (StartsWithASCII(response_line, kRlzCgiVariable, true)) {  // An RLZ.
+    if (base::StartsWithASCII(response_line, kRlzCgiVariable,
+                              true)) {  // An RLZ.
       int separator_index = -1;
       if ((separator_index = response_line.find(": ")) < 0)
         continue;  // Not a valid key-value pair.
@@ -560,7 +561,7 @@
 
       if (IsAccessPointSupported(point))
         SetAccessPointRlz(point, rlz_value.substr(0, rlz_length).c_str());
-    } else if (StartsWithASCII(response_line, events_variable, true)) {
+    } else if (base::StartsWithASCII(response_line, events_variable, true)) {
       // Clear events which server parsed.
       std::vector<ReturnedEvent> event_array;
       GetEventsFromResponseString(response_line, events_variable, &event_array);
@@ -568,7 +569,8 @@
         ClearProductEvent(product, event_array[i].access_point,
                           event_array[i].event_type);
       }
-    } else if (StartsWithASCII(response_line, stateful_events_variable, true)) {
+    } else if (base::StartsWithASCII(response_line, stateful_events_variable,
+                                     true)) {
       // Record any stateful events the server send over.
       std::vector<ReturnedEvent> event_array;
       GetEventsFromResponseString(response_line, stateful_events_variable,
diff --git a/rlz/win/lib/machine_deal.cc b/rlz/win/lib/machine_deal.cc
index 9c83a4c..aeab4f4f 100644
--- a/rlz/win/lib/machine_deal.cc
+++ b/rlz/win/lib/machine_deal.cc
@@ -103,7 +103,7 @@
 
   value->clear();
 
-  if (!StartsWithASCII(response_line, response_key, true))
+  if (!base::StartsWithASCII(response_line, response_key, true))
     return false;
 
   std::vector<std::string> tokens;
diff --git a/sandbox/linux/services/yama_unittests.cc b/sandbox/linux/services/yama_unittests.cc
index a4100a6..204cfd6 100644
--- a/sandbox/linux/services/yama_unittests.cc
+++ b/sandbox/linux/services/yama_unittests.cc
@@ -30,7 +30,7 @@
   bool is_kernel_64bit =
       base::SysInfo::OperatingSystemArchitecture() == "x86_64";
   bool is_linux = base::SysInfo::OperatingSystemName() == "Linux";
-  bool is_3_dot_2 = StartsWithASCII(
+  bool is_3_dot_2 = base::StartsWithASCII(
       base::SysInfo::OperatingSystemVersion(), "3.2", /*case_sensitive=*/false);
   if (is_kernel_64bit && is_linux && is_3_dot_2)
     return true;
diff --git a/sandbox/win/OWNERS b/sandbox/win/OWNERS
index 9ccaeb39..fd5dcfda 100644
--- a/sandbox/win/OWNERS
+++ b/sandbox/win/OWNERS
@@ -1,3 +1,4 @@
 cpu@chromium.org
 jschuh@chromium.org
 rvargas@chromium.org
+wfh@chromium.org
diff --git a/sandbox/win/sandbox_poc/main_ui_window.cc b/sandbox/win/sandbox_poc/main_ui_window.cc
index 1671424..6c5d177 100644
--- a/sandbox/win/sandbox_poc/main_ui_window.cc
+++ b/sandbox/win/sandbox_poc/main_ui_window.cc
@@ -5,6 +5,7 @@
 #include <windows.h>
 #include <CommCtrl.h>
 #include <commdlg.h>
+#include <stdarg.h>
 #include <time.h>
 #include <windowsx.h>
 #include <atlbase.h>
@@ -624,7 +625,7 @@
   const int kMaxDebugBuffSize = 1024;
 
   va_list arg_list;
-  _crt_va_start(arg_list, format);
+  va_start(arg_list, format);
 
   wchar_t text[kMaxDebugBuffSize + 1];
   vswprintf_s(text, kMaxDebugBuffSize, format, arg_list);
diff --git a/skia/ext/skia_utils_mac.h b/skia/ext/skia_utils_mac.h
index b60f9e8..55bdf215 100644
--- a/skia/ext/skia_utils_mac.h
+++ b/skia/ext/skia_utils_mac.h
@@ -133,11 +133,6 @@
   SkIPoint bitmapOffset_;
   SkScalar bitmapScaleFactor_;
 
-  // True if we are drawing to |canvas_|'s SkBaseDevice's bits directly through
-  // |bitmap_|. Otherwise, the bits in |bitmap_| are our allocation and need to
-  // be copied over to |canvas_|.
-  bool useDeviceBits_;
-
   // True if |bitmap_| is a dummy 1x1 bitmap allocated for the sake of creating
   // a non-NULL CGContext (it is invalid to use a NULL CGContext), and will not
   // be copied to |canvas_|. This will happen if |canvas_|'s clip region is
diff --git a/skia/ext/skia_utils_mac.mm b/skia/ext/skia_utils_mac.mm
index 9e552eb..1cc5599 100644
--- a/skia/ext/skia_utils_mac.mm
+++ b/skia/ext/skia_utils_mac.mm
@@ -270,7 +270,6 @@
       userClipRectSpecified_(false),
       cgContext_(0),
       bitmapScaleFactor_(1),
-      useDeviceBits_(false),
       bitmapIsDummy_(false) {
 }
 
@@ -281,7 +280,6 @@
       userClipRectSpecified_(true),
       cgContext_(0),
       bitmapScaleFactor_(bitmapScaleFactor),
-      useDeviceBits_(false),
       bitmapIsDummy_(false) {
   canvas_->save();
   canvas_->clipRect(SkRect::MakeFromIRect(userClipRect));
@@ -367,9 +365,7 @@
 void SkiaBitLocker::releaseIfNeeded() {
   if (!cgContext_)
     return;
-  if (useDeviceBits_) {
-    bitmap_.unlockPixels();
-  } else if (!bitmapIsDummy_) {
+  if (!bitmapIsDummy_) {
     // Find the bits that were drawn to.
     SkIRect bounds = computeDirtyRect();
     SkBitmap subset;
@@ -387,7 +383,6 @@
   }
   CGContextRelease(cgContext_);
   cgContext_ = 0;
-  useDeviceBits_ = false;
   bitmapIsDummy_ = false;
 }
 
@@ -401,42 +396,19 @@
     clip_bounds = SkIRect::MakeXYWH(0, 0, 1, 1);
   }
 
-  SkBaseDevice* device = canvas_->getTopDevice();
-  DCHECK(device);
-  if (!device)
-    return 0;
-
   releaseIfNeeded(); // This flushes any prior bitmap use
 
   // remember the top/left, in case we need to compose this later
   bitmapOffset_.set(clip_bounds.x(), clip_bounds.y());
 
-  // Now make clip_bounds be relative to the current layer/device
-  clip_bounds.offset(-device->getOrigin());
-
-  const SkBitmap& deviceBits = device->accessBitmap(true);
-
-  // Only draw directly if we have pixels, and we're only rect-clipped.
-  // If not, we allocate an offscreen and draw into that, relying on the
-  // compositing step to apply skia's clip.
-  useDeviceBits_ = deviceBits.getPixels() &&
-                   canvas_->isClipRect() &&
-                   !bitmapIsDummy_;
-  if (useDeviceBits_) {
-    bool result = deviceBits.extractSubset(&bitmap_, clip_bounds);
-    DCHECK(result);
-    if (!result)
-      return 0;
-    bitmap_.lockPixels();
-  } else {
-    bool result = bitmap_.tryAllocN32Pixels(
+  bool result = bitmap_.tryAllocN32Pixels(
         SkScalarCeilToInt(bitmapScaleFactor_ * clip_bounds.width()),
         SkScalarCeilToInt(bitmapScaleFactor_ * clip_bounds.height()));
-    DCHECK(result);
-    if (!result)
-      return 0;
-    bitmap_.eraseColor(0);
-  }
+  DCHECK(result);
+  if (!result)
+    return 0;
+  bitmap_.eraseColor(0);
+
   base::ScopedCFTypeRef<CGColorSpaceRef> colorSpace(
       CGColorSpaceCreateDeviceRGB());
   cgContext_ = CGBitmapContextCreate(bitmap_.getPixels(), bitmap_.width(),
diff --git a/storage/browser/blob/blob_url_request_job_factory.cc b/storage/browser/blob/blob_url_request_job_factory.cc
index e09efe5a..7efe280 100644
--- a/storage/browser/blob/blob_url_request_job_factory.cc
+++ b/storage/browser/blob/blob_url_request_job_factory.cc
@@ -78,7 +78,7 @@
   // TODO(michaeln): Replace this use case and others like it with a BlobReader
   // impl that does not depend on urlfetching to perform this function.
   const std::string kPrefix("blob:uuid/");
-  if (!StartsWithASCII(request->url().spec(), kPrefix, true))
+  if (!base::StartsWithASCII(request->url().spec(), kPrefix, true))
     return NULL;
   std::string uuid = request->url().spec().substr(kPrefix.length());
   scoped_ptr<BlobDataHandle> handle = context_->GetBlobDataFromUUID(uuid);
diff --git a/storage/browser/fileapi/obfuscated_file_util.cc b/storage/browser/fileapi/obfuscated_file_util.cc
index 67421c1..34c0718f 100644
--- a/storage/browser/fileapi/obfuscated_file_util.cc
+++ b/storage/browser/fileapi/obfuscated_file_util.cc
@@ -901,7 +901,7 @@
   const std::string key_prefix = GetDirectoryDatabaseKey(origin, type_string);
   for (DirectoryMap::iterator iter = directories_.lower_bound(key_prefix);
        iter != directories_.end();) {
-    if (!StartsWithASCII(iter->first, key_prefix, true))
+    if (!base::StartsWithASCII(iter->first, key_prefix, true))
       break;
     DCHECK(type_string.empty() || iter->first == key_prefix);
     scoped_ptr<SandboxDirectoryDatabase> database(iter->second);
@@ -925,7 +925,7 @@
   const std::string key_prefix = GetDirectoryDatabaseKey(origin, type_string);
   for (DirectoryMap::iterator iter = directories_.lower_bound(key_prefix);
        iter != directories_.end();) {
-    if (!StartsWithASCII(iter->first, key_prefix, true))
+    if (!base::StartsWithASCII(iter->first, key_prefix, true))
       break;
     DCHECK(type_string.empty() || iter->first == key_prefix);
     scoped_ptr<SandboxDirectoryDatabase> database(iter->second);
diff --git a/storage/browser/fileapi/sandbox_directory_database.cc b/storage/browser/fileapi/sandbox_directory_database.cc
index 4543863..ed900ec 100644
--- a/storage/browser/fileapi/sandbox_directory_database.cc
+++ b/storage/browser/fileapi/sandbox_directory_database.cc
@@ -200,7 +200,7 @@
   scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
   for (itr->SeekToFirst(); itr->Valid(); itr->Next()) {
     std::string key = itr->key().ToString();
-    if (StartsWithASCII(key, kChildLookupPrefix, true)) {
+    if (base::StartsWithASCII(key, kChildLookupPrefix, true)) {
       // key: "CHILD_OF:<parent_id>:<name>"
       // value: "<child_id>"
       ++num_hierarchy_links_in_db_;
@@ -475,8 +475,8 @@
   scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions()));
   iter->Seek(child_key_prefix);
   children->clear();
-  while (iter->Valid() &&
-      StartsWithASCII(iter->key().ToString(), child_key_prefix, true)) {
+  while (iter->Valid() && base::StartsWithASCII(iter->key().ToString(),
+                                                child_key_prefix, true)) {
     std::string child_id_string = iter->value().ToString();
     FileId child_id;
     if (!base::StringToInt64(child_id_string, &child_id)) {
diff --git a/storage/browser/fileapi/sandbox_origin_database.cc b/storage/browser/fileapi/sandbox_origin_database.cc
index 1f149e3..1a91b10 100644
--- a/storage/browser/fileapi/sandbox_origin_database.cc
+++ b/storage/browser/fileapi/sandbox_origin_database.cc
@@ -291,8 +291,8 @@
   std::string origin_key_prefix = OriginToOriginKey(std::string());
   iter->Seek(origin_key_prefix);
   origins->clear();
-  while (iter->Valid() &&
-      StartsWithASCII(iter->key().ToString(), origin_key_prefix, true)) {
+  while (iter->Valid() && base::StartsWithASCII(iter->key().ToString(),
+                                                origin_key_prefix, true)) {
     std::string origin =
       iter->key().ToString().substr(origin_key_prefix.length());
     base::FilePath path = StringToFilePath(iter->value().ToString());
diff --git a/storage/common/fileapi/file_system_util.cc b/storage/common/fileapi/file_system_util.cc
index ed84b90..f67c864 100644
--- a/storage/common/fileapi/file_system_util.cc
+++ b/storage/common/fileapi/file_system_util.cc
@@ -420,8 +420,8 @@
   // names, so we do a case insensitive compare by converting both strings
   // to uppercase.
   // TODO(benwells): Remove this when WebKit uses the same constant.
-  start_token = StringToUpperASCII(start_token);
-  std::string filesystem_name_upper = StringToUpperASCII(filesystem_name);
+  start_token = base::StringToUpperASCII(start_token);
+  std::string filesystem_name_upper = base::StringToUpperASCII(filesystem_name);
   size_t pos = filesystem_name_upper.find(start_token);
   if (pos == std::string::npos)
     return false;
diff --git a/sync/BUILD.gn b/sync/BUILD.gn
index e262686..3a5438c 100644
--- a/sync/BUILD.gn
+++ b/sync/BUILD.gn
@@ -250,7 +250,6 @@
     "internal_api/public/user_share.h",
     "internal_api/public/util/experiments.h",
     "internal_api/public/util/immutable.h",
-    "internal_api/public/util/report_unrecoverable_error_function.h",
     "internal_api/public/util/sync_db_util.h",
     "internal_api/public/util/sync_string_conversions.cc",
     "internal_api/public/util/sync_string_conversions.h",
diff --git a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
index 6f49d1f..856a5a0d 100644
--- a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
+++ b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
@@ -5,6 +5,7 @@
 package org.chromium.sync.signin;
 
 
+import android.Manifest;
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerFuture;
@@ -13,8 +14,10 @@
 import android.accounts.OperationCanceledException;
 import android.app.Activity;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.Process;
 import android.util.Log;
 
 import org.chromium.base.ThreadUtils;
@@ -236,6 +239,11 @@
         }
     }
 
+    private boolean hasUseCredentialsPermission() {
+        return mApplicationContext.checkPermission(Manifest.permission.USE_CREDENTIALS,
+                Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED;
+    }
+
     // Gets the auth token synchronously
     private String getAuthTokenInner(AccountManagerFuture<Bundle> future,
             AtomicBoolean errorEncountered) {
@@ -261,6 +269,11 @@
             final String authTokenType, final GetAuthTokenCallback callback,
             final AtomicInteger numTries, final AtomicBoolean errorEncountered,
             final ConnectionRetry retry) {
+        // Return null token for no USE_CREDENTIALS permission.
+        if (!hasUseCredentialsPermission()) {
+            callback.tokenAvailable(null);
+            return;
+        }
         final AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(
                 account, authTokenType, true, null, null);
         errorEncountered.set(false);
@@ -349,6 +362,10 @@
      * Removes an auth token from the AccountManager's cache.
      */
     public void invalidateAuthToken(String authToken) {
+        // Cancel operation for no USE_CREDENTIALS permission.
+        if (!hasUseCredentialsPermission()) {
+            return;
+        }
         if (authToken != null && !authToken.isEmpty()) {
             mAccountManager.invalidateAuthToken(GOOGLE_ACCOUNT_TYPE, authToken);
         }
diff --git a/sync/api/sync_data.h b/sync/api/sync_data.h
index e3885291..6815896 100644
--- a/sync/api/sync_data.h
+++ b/sync/api/sync_data.h
@@ -193,7 +193,7 @@
 };
 
 // gmock printer helper.
-void SYNC_EXPORT PrintTo(const SyncData& sync_data, std::ostream* os);
+void PrintTo(const SyncData& sync_data, std::ostream* os);
 
 typedef std::vector<SyncData> SyncDataList;
 
diff --git a/sync/engine/all_status.cc b/sync/engine/all_status.cc
index 5a2f616..36fb23ef 100644
--- a/sync/engine/all_status.cc
+++ b/sync/engine/all_status.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 
 #include "base/logging.h"
-#include "base/port.h"
 #include "sync/engine/net/server_connection_manager.h"
 #include "sync/engine/sync_cycle_event.h"
 #include "sync/internal_api/public/base/model_type.h"
diff --git a/sync/engine/get_updates_processor.cc b/sync/engine/get_updates_processor.cc
index a33c70d..4fcd058b 100644
--- a/sync/engine/get_updates_processor.cc
+++ b/sync/engine/get_updates_processor.cc
@@ -240,7 +240,14 @@
         base::Time::Now(), update_response, result);
     session->SendProtocolEvent(response_event);
 
-    LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates";
+    // Sync authorization expires every 60 mintues, so SYNC_AUTH_ERROR will
+    // appear every 60 minutes, and then sync services will refresh the
+    // authorization. Therefore SYNC_AUTH_ERROR is excluded here to reduce the
+    // ERROR messages in the log.
+    if (result != SYNC_AUTH_ERROR) {
+      LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates";
+    }
+
     return result;
   }
 
diff --git a/sync/engine/net/url_translator.cc b/sync/engine/net/url_translator.cc
index e9cae5a..285053a 100644
--- a/sync/engine/net/url_translator.cc
+++ b/sync/engine/net/url_translator.cc
@@ -8,7 +8,6 @@
 #include "sync/engine/net/url_translator.h"
 
 #include "base/basictypes.h"
-#include "base/port.h"
 #include "net/base/escape.h"
 
 using std::string;
diff --git a/sync/engine/process_updates_util.cc b/sync/engine/process_updates_util.cc
index 8978fb8..9b428ef9 100644
--- a/sync/engine/process_updates_util.cc
+++ b/sync/engine/process_updates_util.cc
@@ -323,10 +323,11 @@
       continue;
     }
 
+    // Mark entry as unapplied update first to ensure journaling the deletion.
+    entry.PutIsUnappliedUpdate(true);
     // Mark entry as deleted by server.
     entry.PutServerIsDel(true);
     entry.PutServerVersion(version_watermark);
-    entry.PutIsUnappliedUpdate(true);
   }
 }
 
diff --git a/sync/engine/syncer_util.cc b/sync/engine/syncer_util.cc
index a2dc605..3a88700 100644
--- a/sync/engine/syncer_util.cc
+++ b/sync/engine/syncer_util.cc
@@ -387,6 +387,8 @@
       // the version number check has a similar effect.
       return;
     }
+    // Mark entry as unapplied update first to ensure journaling the deletion.
+    target->PutIsUnappliedUpdate(true);
     // The server returns very lightweight replies for deletions, so we don't
     // clobber a bunch of fields on delete.
     target->PutServerIsDel(true);
@@ -399,7 +401,6 @@
       target->PutServerVersion(
           std::max(target->GetServerVersion(), target->GetBaseVersion()) + 1);
     }
-    target->PutIsUnappliedUpdate(true);
     return;
   }
 
@@ -438,13 +439,14 @@
     UpdateBookmarkPositioning(update, target);
   }
 
-  target->PutServerIsDel(update.deleted());
   // We only mark the entry as unapplied if its version is greater than the
   // local data. If we're processing the update that corresponds to one of our
   // commit we don't apply it as time differences may occur.
   if (update.version() > target->GetBaseVersion()) {
     target->PutIsUnappliedUpdate(true);
   }
+  DCHECK(!update.deleted());
+  target->PutServerIsDel(false);
 }
 
 // Creates a new Entry iff no Entry exists with the given id.
diff --git a/sync/engine/update_applicator.h b/sync/engine/update_applicator.h
index ff8fa15..55534ad1 100644
--- a/sync/engine/update_applicator.h
+++ b/sync/engine/update_applicator.h
@@ -14,7 +14,6 @@
 #include <vector>
 
 #include "base/basictypes.h"
-#include "base/port.h"
 #include "sync/internal_api/public/engine/model_safe_worker.h"
 #include "sync/syncable/syncable_id.h"
 #include "sync/sessions/status_controller.h"
diff --git a/sync/internal_api/base_node.cc b/sync/internal_api/base_node.cc
index 4d6d56f..9ecbf19 100644
--- a/sync/internal_api/base_node.cc
+++ b/sync/internal_api/base_node.cc
@@ -21,6 +21,7 @@
 #include "sync/protocol/typed_url_specifics.pb.h"
 #include "sync/syncable/directory.h"
 #include "sync/syncable/entry.h"
+#include "sync/syncable/syncable_base_transaction.h"
 #include "sync/syncable/syncable_id.h"
 #include "sync/util/time.h"
 
@@ -56,7 +57,9 @@
     scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics(
         specifics, GetTransaction()->GetCryptographer()));
     if (!data) {
-      LOG(ERROR) << "Failed to decrypt password specifics.";
+      GetTransaction()->GetWrappedTrans()->OnUnrecoverableError(
+          FROM_HERE, std::string("Failed to decrypt encrypted node of type ") +
+                         ModelTypeToString(GetModelType()));
       return false;
     }
     password_data_.swap(data);
@@ -89,17 +92,14 @@
   std::string plaintext_data = GetTransaction()->GetCryptographer()->
       DecryptToString(encrypted);
   if (plaintext_data.length() == 0) {
-    LOG(ERROR) << "Failed to decrypt encrypted node of type "
-               << ModelTypeToString(GetModelType()) << ".";
-    // Debugging for crbug.com/123223. We failed to decrypt the data, which
-    // means we applied an update without having the key or lost the key at a
-    // later point.
-    CHECK(false);
+    GetTransaction()->GetWrappedTrans()->OnUnrecoverableError(
+        FROM_HERE, std::string("Failed to decrypt encrypted node of type ") +
+                       ModelTypeToString(GetModelType()));
     return false;
   } else if (!unencrypted_data_.ParseFromString(plaintext_data)) {
-    // Debugging for crbug.com/123223. We should never succeed in decrypting
-    // but fail to parse into a protobuf.
-    CHECK(false);
+    GetTransaction()->GetWrappedTrans()->OnUnrecoverableError(
+        FROM_HERE, std::string("Failed to parse encrypted node of type ") +
+                       ModelTypeToString(GetModelType()));
     return false;
   }
   DVLOG(2) << "Decrypted specifics of type "
@@ -218,21 +218,6 @@
   return GetEntry()->GetLocalExternalId();
 }
 
-const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const {
-  DCHECK_EQ(GetModelType(), APPS);
-  return GetEntitySpecifics().app();
-}
-
-const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const {
-  DCHECK_EQ(GetModelType(), AUTOFILL);
-  return GetEntitySpecifics().autofill();
-}
-
-const AutofillProfileSpecifics& BaseNode::GetAutofillProfileSpecifics() const {
-  DCHECK_EQ(GetModelType(), AUTOFILL_PROFILE);
-  return GetEntitySpecifics().autofill_profile();
-}
-
 const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const {
   DCHECK_EQ(GetModelType(), BOOKMARKS);
   return GetEntitySpecifics().bookmark();
@@ -248,42 +233,16 @@
   return *password_data_;
 }
 
-const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const {
-  DCHECK_EQ(GetModelType(), THEMES);
-  return GetEntitySpecifics().theme();
-}
-
 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const {
   DCHECK_EQ(GetModelType(), TYPED_URLS);
   return GetEntitySpecifics().typed_url();
 }
 
-const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const {
-  DCHECK_EQ(GetModelType(), EXTENSIONS);
-  return GetEntitySpecifics().extension();
-}
-
-const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const {
-  DCHECK_EQ(GetModelType(), SESSIONS);
-  return GetEntitySpecifics().session();
-}
-
-const sync_pb::DeviceInfoSpecifics& BaseNode::GetDeviceInfoSpecifics() const {
-  DCHECK_EQ(GetModelType(), DEVICE_INFO);
-  return GetEntitySpecifics().device_info();
-}
-
 const sync_pb::ExperimentsSpecifics& BaseNode::GetExperimentsSpecifics() const {
   DCHECK_EQ(GetModelType(), EXPERIMENTS);
   return GetEntitySpecifics().experiments();
 }
 
-const sync_pb::PriorityPreferenceSpecifics&
-    BaseNode::GetPriorityPreferenceSpecifics() const {
-  DCHECK_EQ(GetModelType(), PRIORITY_PREFERENCES);
-  return GetEntitySpecifics().priority_preference();
-}
-
 const sync_pb::EntitySpecifics& BaseNode::GetEntitySpecifics() const {
   return GetUnencryptedSpecifics(GetEntry());
 }
diff --git a/sync/internal_api/public/base_node.h b/sync/internal_api/public/base_node.h
index 93d2baf..93ede5b8 100644
--- a/sync/internal_api/public/base_node.h
+++ b/sync/internal_api/public/base_node.h
@@ -115,17 +115,6 @@
   // data.  Can only be called if GetModelType() == BOOKMARK.
   const sync_pb::BookmarkSpecifics& GetBookmarkSpecifics() const;
 
-  // Getter specific to the APPS datatype.  Returns protobuf
-  // data.  Can only be called if GetModelType() == APPS.
-  const sync_pb::AppSpecifics& GetAppSpecifics() const;
-
-  // Getter specific to the AUTOFILL datatype.  Returns protobuf
-  // data.  Can only be called if GetModelType() == AUTOFILL.
-  const sync_pb::AutofillSpecifics& GetAutofillSpecifics() const;
-
-  virtual const sync_pb::AutofillProfileSpecifics&
-      GetAutofillProfileSpecifics() const;
-
   // Getter specific to the NIGORI datatype.  Returns protobuf
   // data.  Can only be called if GetModelType() == NIGORI.
   const sync_pb::NigoriSpecifics& GetNigoriSpecifics() const;
@@ -134,39 +123,14 @@
   // data.  Can only be called if GetModelType() == PASSWORD.
   const sync_pb::PasswordSpecificsData& GetPasswordSpecifics() const;
 
-  // Getter specific to the PREFERENCE datatype.  Returns protobuf
-  // data.  Can only be called if GetModelType() == PREFERENCE.
-  const sync_pb::PreferenceSpecifics& GetPreferenceSpecifics() const;
-
-  // Getter specific to the THEME datatype.  Returns protobuf
-  // data.  Can only be called if GetModelType() == THEME.
-  const sync_pb::ThemeSpecifics& GetThemeSpecifics() const;
-
   // Getter specific to the TYPED_URLS datatype.  Returns protobuf
   // data.  Can only be called if GetModelType() == TYPED_URLS.
   const sync_pb::TypedUrlSpecifics& GetTypedUrlSpecifics() const;
 
-  // Getter specific to the EXTENSIONS datatype.  Returns protobuf
-  // data.  Can only be called if GetModelType() == EXTENSIONS.
-  const sync_pb::ExtensionSpecifics& GetExtensionSpecifics() const;
-
-  // Getter specific to the SESSIONS datatype.  Returns protobuf
-  // data.  Can only be called if GetModelType() == SESSIONS.
-  const sync_pb::SessionSpecifics& GetSessionSpecifics() const;
-
-  // Getter specific to the DEVICE_INFO datatype.  Returns protobuf
-  // data.  Can only be called if GetModelType() == DEVICE_INFO.
-  const sync_pb::DeviceInfoSpecifics& GetDeviceInfoSpecifics() const;
-
   // Getter specific to the EXPERIMENTS datatype.  Returns protobuf
   // data.  Can only be called if GetModelType() == EXPERIMENTS.
   const sync_pb::ExperimentsSpecifics& GetExperimentsSpecifics() const;
 
-  // Getter specific to the PRIORITY_PREFERENCE datatype. Returns protobuf
-  // data.  Can only be called if GetModelType() == PRIORITY_PREFERENCE.
-  const sync_pb::PriorityPreferenceSpecifics&
-      GetPriorityPreferenceSpecifics() const;
-
   const sync_pb::EntitySpecifics& GetEntitySpecifics() const;
 
   // Returns the local external ID associated with the node.
diff --git a/sync/internal_api/public/sync_manager.h b/sync/internal_api/public/sync_manager.h
index 41d9cae..7899162 100644
--- a/sync/internal_api/public/sync_manager.h
+++ b/sync/internal_api/public/sync_manager.h
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/basictypes.h"
-#include "base/callback_forward.h"
+#include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
@@ -30,7 +30,6 @@
 #include "sync/internal_api/public/shutdown_reason.h"
 #include "sync/internal_api/public/sync_context_proxy.h"
 #include "sync/internal_api/public/sync_encryption_handler.h"
-#include "sync/internal_api/public/util/report_unrecoverable_error_function.h"
 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
 #include "sync/internal_api/public/util/weak_handle.h"
 #include "sync/protocol/sync_protocol_error.h"
@@ -263,7 +262,7 @@
     Encryptor* encryptor;
 
     scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler;
-    ReportUnrecoverableErrorFunction report_unrecoverable_error_function;
+    base::Closure report_unrecoverable_error_function;
 
     // Carries shutdown requests across threads and will be used to cut short
     // any network I/O and tell the syncer to exit early.
diff --git a/sync/internal_api/public/util/report_unrecoverable_error_function.h b/sync/internal_api/public/util/report_unrecoverable_error_function.h
deleted file mode 100644
index c0686ca..0000000
--- a/sync/internal_api/public/util/report_unrecoverable_error_function.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SYNC_UTIL_REPORT_UNRECOVERABLE_ERROR_FUNCTION_H_
-#define SYNC_UTIL_REPORT_UNRECOVERABLE_ERROR_FUNCTION_H_
-
-namespace syncer {
-
-// A ReportUnrecoverableErrorFunction is a function that is called
-// immediately when an unrecoverable error is encountered.  Unlike
-// UnrecoverableErrorHandler, it should just log the error and any
-// context surrounding it.
-typedef void (*ReportUnrecoverableErrorFunction)(void);
-
-}  // namespace syncer
-
-#endif  // SYNC_UTIL_REPORT_UNRECOVERABLE_ERROR_FUNCTION_H_
diff --git a/sync/internal_api/public/write_node.h b/sync/internal_api/public/write_node.h
index 2d84aaef..b79ae30 100644
--- a/sync/internal_api/public/write_node.h
+++ b/sync/internal_api/public/write_node.h
@@ -15,16 +15,10 @@
 #include "sync/internal_api/public/base_node.h"
 
 namespace sync_pb {
-class AppSpecifics;
-class AutofillSpecifics;
-class AutofillProfileSpecifics;
 class BookmarkSpecifics;
 class EntitySpecifics;
-class ExtensionSpecifics;
-class SessionSpecifics;
 class NigoriSpecifics;
 class PasswordSpecificsData;
-class ThemeSpecifics;
 class TypedUrlSpecifics;
 }
 
@@ -47,8 +41,6 @@
     INIT_SUCCESS,
     // The tag passed into this method was empty.
     INIT_FAILED_EMPTY_TAG,
-    // An entry with this tag already exists.
-    INIT_FAILED_ENTRY_ALREADY_EXISTS,
     // The constructor for a new MutableEntry with the specified data failed.
     INIT_FAILED_COULD_NOT_CREATE_ENTRY,
     // Setting the predecessor failed
@@ -77,8 +69,8 @@
   // Create nodes using this function if they're unique items that
   // you want to fetch using client_tag. Note that the behavior of these
   // items is slightly different than that of normal items.
-  // Most importantly, if it exists locally, this function will
-  // actually undelete it
+  // Most importantly, if it exists locally but is deleted, this function will
+  // actually undelete it. Otherwise it will reuse the existing node.
   // Client unique tagged nodes must NOT be folders.
   InitUniqueByCreationResult InitUniqueByCreation(
       ModelType model_type,
@@ -131,17 +123,6 @@
   // TODO(sync): Remove the setters below when the corresponding data
   // types are ported to the new sync service API.
 
-  // Set the app specifics (id, update url, enabled state, etc).
-  // Should only be called if GetModelType() == APPS.
-  void SetAppSpecifics(const sync_pb::AppSpecifics& specifics);
-
-  // Set the autofill specifics (name and value).
-  // Should only be called if GetModelType() == AUTOFILL.
-  void SetAutofillSpecifics(const sync_pb::AutofillSpecifics& specifics);
-
-  void SetAutofillProfileSpecifics(
-      const sync_pb::AutofillProfileSpecifics& specifics);
-
   // Set the nigori specifics.
   // Should only be called if GetModelType() == NIGORI.
   void SetNigoriSpecifics(const sync_pb::NigoriSpecifics& specifics);
@@ -150,35 +131,10 @@
   // Should only be called if GetModelType() == PASSWORD.
   void SetPasswordSpecifics(const sync_pb::PasswordSpecificsData& specifics);
 
-  // Set the theme specifics (name and value).
-  // Should only be called if GetModelType() == THEME.
-  void SetThemeSpecifics(const sync_pb::ThemeSpecifics& specifics);
-
   // Set the typed_url specifics (url, title, typed_count, etc).
   // Should only be called if GetModelType() == TYPED_URLS.
   void SetTypedUrlSpecifics(const sync_pb::TypedUrlSpecifics& specifics);
 
-  // Set the extension specifics (id, update url, enabled state, etc).
-  // Should only be called if GetModelType() == EXTENSIONS.
-  void SetExtensionSpecifics(const sync_pb::ExtensionSpecifics& specifics);
-
-  // Set the session specifics (windows, tabs, navigations etc.).
-  // Should only be called if GetModelType() == SESSIONS.
-  void SetSessionSpecifics(const sync_pb::SessionSpecifics& specifics);
-
-  // Set the device info specifics.
-  // Should only be called if GetModelType() == DEVICE_INFO.
-  void SetDeviceInfoSpecifics(const sync_pb::DeviceInfoSpecifics& specifics);
-
-  // Set the experiments specifics.
-  // Should only be called if GetModelType() == EXPERIMENTS.
-  void SetExperimentsSpecifics(const sync_pb::ExperimentsSpecifics& specifics);
-
-  // Set the priority preference specifics.
-  // Should only be called if GetModelType() == PRIORITY_PREFERENCE.
-  void SetPriorityPreferenceSpecifics(
-      const sync_pb::PriorityPreferenceSpecifics& specifics);
-
   // Set the attachment metadata.
   void SetAttachmentMetadata(
       const sync_pb::AttachmentMetadata& attachment_metadata);
diff --git a/sync/internal_api/sync_encryption_handler_impl.cc b/sync/internal_api/sync_encryption_handler_impl.cc
index 4bf559fd..1e73b4a 100644
--- a/sync/internal_api/sync_encryption_handler_impl.cc
+++ b/sync/internal_api/sync_encryption_handler_impl.cc
@@ -833,10 +833,8 @@
     int64 child_id = passwords_root.GetFirstChildId();
     while (child_id != kInvalidId) {
       WriteNode child(trans);
-      if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) {
-        NOTREACHED();
-        return;
-      }
+      if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK)
+        break;  // Possible if we failed to decrypt the data for some reason.
       child.SetPasswordSpecifics(child.GetPasswordSpecifics());
       child_id = child.GetSuccessorId();
     }
diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc
index fe0bb0f..42de79e 100644
--- a/sync/internal_api/sync_manager_impl.cc
+++ b/sync/internal_api/sync_manager_impl.cc
@@ -88,7 +88,6 @@
       change_delegate_(NULL),
       initialized_(false),
       observing_network_connectivity_changes_(false),
-      report_unrecoverable_error_function_(NULL),
       weak_ptr_factory_(this) {
   // Pre-fill |notification_info_map_|.
   for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
diff --git a/sync/internal_api/sync_manager_impl.h b/sync/internal_api/sync_manager_impl.h
index f07cbfb..283d3f1 100644
--- a/sync/internal_api/sync_manager_impl.h
+++ b/sync/internal_api/sync_manager_impl.h
@@ -330,7 +330,7 @@
   ProtocolEventBuffer protocol_event_buffer_;
 
   scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler_;
-  ReportUnrecoverableErrorFunction report_unrecoverable_error_function_;
+  base::Closure report_unrecoverable_error_function_;
 
   // Sync's encryption handler. It tracks the set of encrypted types, manages
   // changing passphrases, and in general handles sync-specific interactions
diff --git a/sync/internal_api/sync_manager_impl_unittest.cc b/sync/internal_api/sync_manager_impl_unittest.cc
index 41b2e2df4..8bab47a 100644
--- a/sync/internal_api/sync_manager_impl_unittest.cc
+++ b/sync/internal_api/sync_manager_impl_unittest.cc
@@ -69,7 +69,7 @@
 #include "sync/test/fake_encryptor.h"
 #include "sync/util/cryptographer.h"
 #include "sync/util/extensions_activity.h"
-#include "sync/util/test_unrecoverable_error_handler.h"
+#include "sync/util/mock_unrecoverable_error_handler.h"
 #include "sync/util/time.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -836,7 +836,8 @@
   };
 
   SyncManagerTest()
-      : sync_manager_("Test sync manager") {
+      : sync_manager_("Test sync manager"),
+        mock_unrecoverable_error_handler_(NULL) {
     switches_.encryption_method =
         InternalComponentsFactory::ENCRYPTION_KEYSTORE;
   }
@@ -886,7 +887,8 @@
     args.invalidator_client_id = "fake_invalidator_client_id";
     args.internal_components_factory.reset(GetFactory());
     args.encryptor = &encryptor_;
-    args.unrecoverable_error_handler.reset(new TestUnrecoverableErrorHandler);
+    mock_unrecoverable_error_handler_ = new MockUnrecoverableErrorHandler();
+    args.unrecoverable_error_handler.reset(mock_unrecoverable_error_handler_);
     args.cancelation_signal = &cancelation_signal_;
     sync_manager_.Init(&args);
 
@@ -1080,6 +1082,12 @@
               sync_manager_.GetEncryptionHandler()->GetPassphraseType());
   }
 
+  bool HasUnrecoverableError() {
+    if (mock_unrecoverable_error_handler_)
+      return mock_unrecoverable_error_handler_->invocation_count() > 0;
+    return false;
+  }
+
  private:
   // Needed by |sync_manager_|.
   base::MessageLoop message_loop_;
@@ -1099,6 +1107,9 @@
   StrictMock<SyncEncryptionHandlerObserverMock> encryption_observer_;
   InternalComponentsFactory::Switches switches_;
   InternalComponentsFactory::StorageOption storage_used_;
+
+  // Not owned (ownership is passed to the SyncManager).
+  MockUnrecoverableErrorHandler* mock_unrecoverable_error_handler_;
 };
 
 TEST_F(SyncManagerTest, GetAllNodesForTypeTest) {
@@ -2058,6 +2069,93 @@
   EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, client_tag));
 }
 
+// Test that attempting to start up with corrupted password data triggers
+// an unrecoverable error (rather than crashing).
+TEST_F(SyncManagerTest, ReencryptEverythingWithUnrecoverableErrorPasswords) {
+  const char kClientTag[] = "client_tag";
+
+  EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION));
+  sync_pb::EntitySpecifics entity_specifics;
+  {
+    // Create a synced bookmark with undecryptable data.
+    ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
+
+    Cryptographer other_cryptographer(&encryptor_);
+    KeyParams fake_params = {"localhost", "dummy", "fake_key"};
+    other_cryptographer.AddKey(fake_params);
+    sync_pb::PasswordSpecificsData data;
+    data.set_password_value("secret");
+    other_cryptographer.Encrypt(
+        data,
+        entity_specifics.mutable_password()->mutable_encrypted());
+
+    // Set up the real cryptographer with a different key.
+    KeyParams real_params = {"localhost", "username", "real_key"};
+    trans.GetCryptographer()->AddKey(real_params);
+  }
+  MakeServerNode(sync_manager_.GetUserShare(), PASSWORDS, kClientTag,
+                 syncable::GenerateSyncableHash(PASSWORDS,
+                                                kClientTag),
+                 entity_specifics);
+  EXPECT_FALSE(ResetUnsyncedEntry(PASSWORDS, kClientTag));
+
+  // Force a re-encrypt everything. Should trigger an unrecoverable error due
+  // to being unable to decrypt the data that was previously applied.
+  testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
+  EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
+  EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
+  EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false));
+  EXPECT_FALSE(HasUnrecoverableError());
+  sync_manager_.GetEncryptionHandler()->Init();
+  PumpLoop();
+  EXPECT_TRUE(HasUnrecoverableError());
+}
+
+// Test that attempting to start up with corrupted bookmark data triggers
+// an unrecoverable error (rather than crashing).
+TEST_F(SyncManagerTest, ReencryptEverythingWithUnrecoverableErrorBookmarks) {
+  const char kClientTag[] = "client_tag";
+  EXPECT_CALL(encryption_observer_,
+              OnEncryptedTypesChanged(
+                  HasModelTypes(EncryptableUserTypes()), true));
+  EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, FULL_ENCRYPTION));
+  sync_pb::EntitySpecifics entity_specifics;
+  {
+    // Create a synced bookmark with undecryptable data.
+    ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare());
+
+    Cryptographer other_cryptographer(&encryptor_);
+    KeyParams fake_params = {"localhost", "dummy", "fake_key"};
+    other_cryptographer.AddKey(fake_params);
+    sync_pb::EntitySpecifics bm_specifics;
+    bm_specifics.mutable_bookmark()->set_title("title");
+    bm_specifics.mutable_bookmark()->set_url("url");
+    sync_pb::EncryptedData encrypted;
+    other_cryptographer.Encrypt(bm_specifics, &encrypted);
+    entity_specifics.mutable_encrypted()->CopyFrom(encrypted);
+
+    // Set up the real cryptographer with a different key.
+    KeyParams real_params = {"localhost", "username", "real_key"};
+    trans.GetCryptographer()->AddKey(real_params);
+  }
+  MakeServerNode(sync_manager_.GetUserShare(), BOOKMARKS, kClientTag,
+                 syncable::GenerateSyncableHash(BOOKMARKS,
+                                                kClientTag),
+                 entity_specifics);
+  EXPECT_FALSE(ResetUnsyncedEntry(BOOKMARKS, kClientTag));
+
+  // Force a re-encrypt everything. Should trigger an unrecoverable error due
+  // to being unable to decrypt the data that was previously applied.
+  testing::Mock::VerifyAndClearExpectations(&encryption_observer_);
+  EXPECT_CALL(encryption_observer_, OnEncryptionComplete());
+  EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_));
+  EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, true));
+  EXPECT_FALSE(HasUnrecoverableError());
+  sync_manager_.GetEncryptionHandler()->Init();
+  PumpLoop();
+  EXPECT_TRUE(HasUnrecoverableError());
+}
+
 // Verify SetTitle(..) doesn't unnecessarily set IS_UNSYNCED for bookmarks
 // when we write the same data, but does set it when we write new data.
 TEST_F(SyncManagerTest, SetBookmarkTitle) {
diff --git a/sync/internal_api/sync_rollback_manager_base.cc b/sync/internal_api/sync_rollback_manager_base.cc
index a5501b78..3e748fc 100644
--- a/sync/internal_api/sync_rollback_manager_base.cc
+++ b/sync/internal_api/sync_rollback_manager_base.cc
@@ -37,8 +37,7 @@
 namespace syncer {
 
 SyncRollbackManagerBase::SyncRollbackManagerBase()
-    : report_unrecoverable_error_function_(NULL),
-      dummy_handler_(new DummyEntryptionHandler),
+    : dummy_handler_(new DummyEntryptionHandler),
       initialized_(false),
       weak_ptr_factory_(this) {
 }
@@ -51,7 +50,7 @@
     InternalComponentsFactory* internal_components_factory,
     InternalComponentsFactory::StorageOption storage,
     scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
-    ReportUnrecoverableErrorFunction report_unrecoverable_error_function) {
+    const base::Closure& report_unrecoverable_error_function) {
   unrecoverable_error_handler_ = unrecoverable_error_handler.Pass();
   report_unrecoverable_error_function_ = report_unrecoverable_error_function;
 
diff --git a/sync/internal_api/sync_rollback_manager_base.h b/sync/internal_api/sync_rollback_manager_base.h
index a284f1f..aa415a26 100644
--- a/sync/internal_api/sync_rollback_manager_base.h
+++ b/sync/internal_api/sync_rollback_manager_base.h
@@ -100,7 +100,7 @@
       InternalComponentsFactory* internal_components_factory,
       InternalComponentsFactory::StorageOption storage,
       scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
-      ReportUnrecoverableErrorFunction report_unrecoverable_error_function);
+      const base::Closure& report_unrecoverable_error_function);
 
   void RegisterDirectoryTypeDebugInfoObserver(
       syncer::TypeDebugInfoObserver* observer) override;
@@ -129,7 +129,7 @@
   base::ObserverList<SyncManager::Observer> observers_;
 
   scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler_;
-  ReportUnrecoverableErrorFunction report_unrecoverable_error_function_;
+  base::Closure report_unrecoverable_error_function_;
 
   scoped_ptr<SyncEncryptionHandler> dummy_handler_;
 
diff --git a/sync/internal_api/syncapi_internal.cc b/sync/internal_api/syncapi_internal.cc
index 91a6d79..d3ac5231 100644
--- a/sync/internal_api/syncapi_internal.cc
+++ b/sync/internal_api/syncapi_internal.cc
@@ -30,6 +30,8 @@
   const sync_pb::EncryptedData& encrypted = password_specifics.encrypted();
   scoped_ptr<sync_pb::PasswordSpecificsData> data(
       new sync_pb::PasswordSpecificsData);
+  if (!crypto->CanDecrypt(encrypted))
+    return NULL;
   if (!crypto->Decrypt(encrypted, data.get()))
     return NULL;
   return data.release();
diff --git a/sync/internal_api/write_node.cc b/sync/internal_api/write_node.cc
index cefe854..f3852b0 100644
--- a/sync/internal_api/write_node.cc
+++ b/sync/internal_api/write_node.cc
@@ -10,13 +10,7 @@
 #include "sync/internal_api/public/base_transaction.h"
 #include "sync/internal_api/public/write_transaction.h"
 #include "sync/internal_api/syncapi_internal.h"
-#include "sync/protocol/app_specifics.pb.h"
-#include "sync/protocol/autofill_specifics.pb.h"
 #include "sync/protocol/bookmark_specifics.pb.h"
-#include "sync/protocol/extension_specifics.pb.h"
-#include "sync/protocol/password_specifics.pb.h"
-#include "sync/protocol/session_specifics.pb.h"
-#include "sync/protocol/theme_specifics.pb.h"
 #include "sync/protocol/typed_url_specifics.pb.h"
 #include "sync/syncable/mutable_entry.h"
 #include "sync/syncable/nigori_util.h"
@@ -110,28 +104,6 @@
   MarkForSyncing();
 }
 
-void WriteNode::SetAppSpecifics(
-    const sync_pb::AppSpecifics& new_value) {
-  sync_pb::EntitySpecifics entity_specifics;
-  entity_specifics.mutable_app()->CopyFrom(new_value);
-  SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetAutofillSpecifics(
-    const sync_pb::AutofillSpecifics& new_value) {
-  sync_pb::EntitySpecifics entity_specifics;
-  entity_specifics.mutable_autofill()->CopyFrom(new_value);
-  SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetAutofillProfileSpecifics(
-    const sync_pb::AutofillProfileSpecifics& new_value) {
-  sync_pb::EntitySpecifics entity_specifics;
-  entity_specifics.mutable_autofill_profile()->
-      CopyFrom(new_value);
-  SetEntitySpecifics(entity_specifics);
-}
-
 void WriteNode::SetBookmarkSpecifics(
     const sync_pb::BookmarkSpecifics& new_value) {
   sync_pb::EntitySpecifics entity_specifics;
@@ -168,48 +140,13 @@
   // This will only update password_specifics if the underlying unencrypted blob
   // was different from |data| or was not encrypted with the proper passphrase.
   if (!cryptographer->Encrypt(data, password_specifics->mutable_encrypted())) {
-    NOTREACHED() << "Failed to encrypt password, possibly due to sync node "
-                 << "corruption";
+    LOG(ERROR) << "Failed to encrypt password, possibly due to sync node "
+               << "corruption";
     return;
   }
   SetEntitySpecifics(entity_specifics);
 }
 
-void WriteNode::SetThemeSpecifics(
-    const sync_pb::ThemeSpecifics& new_value) {
-  sync_pb::EntitySpecifics entity_specifics;
-  entity_specifics.mutable_theme()->CopyFrom(new_value);
-  SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetSessionSpecifics(
-    const sync_pb::SessionSpecifics& new_value) {
-  sync_pb::EntitySpecifics entity_specifics;
-  entity_specifics.mutable_session()->CopyFrom(new_value);
-  SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetDeviceInfoSpecifics(
-    const sync_pb::DeviceInfoSpecifics& new_value) {
-  sync_pb::EntitySpecifics entity_specifics;
-  entity_specifics.mutable_device_info()->CopyFrom(new_value);
-  SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetExperimentsSpecifics(
-    const sync_pb::ExperimentsSpecifics& new_value) {
-  sync_pb::EntitySpecifics entity_specifics;
-  entity_specifics.mutable_experiments()->CopyFrom(new_value);
-  SetEntitySpecifics(entity_specifics);
-}
-
-void WriteNode::SetPriorityPreferenceSpecifics(
-    const sync_pb::PriorityPreferenceSpecifics& new_value) {
-  sync_pb::EntitySpecifics entity_specifics;
-  entity_specifics.mutable_priority_preference()->CopyFrom(new_value);
-  SetEntitySpecifics(entity_specifics);
-}
-
 void WriteNode::SetEntitySpecifics(
     const sync_pb::EntitySpecifics& new_value) {
   ModelType new_specifics_type =
@@ -256,13 +193,6 @@
   SetEntitySpecifics(entity_specifics);
 }
 
-void WriteNode::SetExtensionSpecifics(
-    const sync_pb::ExtensionSpecifics& new_value) {
-  sync_pb::EntitySpecifics entity_specifics;
-  entity_specifics.mutable_extension()->CopyFrom(new_value);
-  SetEntitySpecifics(entity_specifics);
-}
-
 void WriteNode::SetExternalId(int64 id) {
   if (GetExternalId() != id)
     entry_->PutLocalExternalId(id);
@@ -381,8 +311,6 @@
 // and bind this WriteNode to it.
 // Return true on success. If the tag exists in the database, then
 // we will attempt to undelete the node.
-// TODO(chron): Code datatype into hash tag.
-// TODO(chron): Is model type ever lost?
 WriteNode::InitUniqueByCreationResult WriteNode::InitUniqueByCreationImpl(
     ModelType model_type,
     const syncable::Id& parent_id,
@@ -440,22 +368,20 @@
       sync_pb::EntitySpecifics specifics;
       AddDefaultFieldValue(model_type, &specifics);
       existing_entry->PutSpecifics(specifics);
-
-      entry_ = existing_entry.release();
-    } else {
-      return INIT_FAILED_ENTRY_ALREADY_EXISTS;
-    }
+    }  // Else just reuse the existing entry.
+    entry_ = existing_entry.release();
   } else {
     entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
                                         syncable::CREATE,
                                         model_type, parent_id, dummy);
-    if (!entry_->good())
-      return INIT_FAILED_COULD_NOT_CREATE_ENTRY;
-
-    // Only set IS_DIR for new entries. Don't bitflip undeleted ones.
-    entry_->PutUniqueClientTag(hash);
   }
 
+  if (!entry_->good())
+    return INIT_FAILED_COULD_NOT_CREATE_ENTRY;
+
+  // Has no impact if the client tag is already set.
+  entry_->PutUniqueClientTag(hash);
+
   // We don't support directory and tag combinations.
   entry_->PutIsDir(false);
 
diff --git a/sync/sync.gyp b/sync/sync.gyp
index 6e47201..07d1c2e 100644
--- a/sync/sync.gyp
+++ b/sync/sync.gyp
@@ -303,7 +303,6 @@
         'internal_api/public/user_share.h',
         'internal_api/public/util/experiments.h',
         'internal_api/public/util/immutable.h',
-        'internal_api/public/util/report_unrecoverable_error_function.h',
         'internal_api/public/util/sync_db_util.h',
         'internal_api/public/util/sync_string_conversions.cc',
         'internal_api/public/util/sync_string_conversions.h',
diff --git a/sync/syncable/directory.cc b/sync/syncable/directory.cc
index 2fbceec3..e23065b15 100644
--- a/sync/syncable/directory.cc
+++ b/sync/syncable/directory.cc
@@ -103,12 +103,11 @@
                                        metahandles_map.end());
 }
 
-Directory::Directory(
-    DirectoryBackingStore* store,
-    UnrecoverableErrorHandler* unrecoverable_error_handler,
-    ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
-    NigoriHandler* nigori_handler,
-    Cryptographer* cryptographer)
+Directory::Directory(DirectoryBackingStore* store,
+                     UnrecoverableErrorHandler* unrecoverable_error_handler,
+                     const base::Closure& report_unrecoverable_error_function,
+                     NigoriHandler* nigori_handler,
+                     Cryptographer* cryptographer)
     : kernel_(NULL),
       store_(store),
       unrecoverable_error_handler_(unrecoverable_error_handler),
@@ -1031,6 +1030,12 @@
   return cryptographer_;
 }
 
+void Directory::ReportUnrecoverableError() {
+  if (!report_unrecoverable_error_function_.is_null()) {
+    report_unrecoverable_error_function_.Run();
+  }
+}
+
 void Directory::GetAllMetaHandles(BaseTransaction* trans,
                                   MetahandleSet* result) {
   result->clear();
diff --git a/sync/syncable/directory.h b/sync/syncable/directory.h
index d8a02d9..7358f17 100644
--- a/sync/syncable/directory.h
+++ b/sync/syncable/directory.h
@@ -11,13 +11,13 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/callback.h"
 #include "base/containers/hash_tables.h"
 #include "base/files/file_util.h"
 #include "base/gtest_prod_util.h"
 #include "base/values.h"
 #include "sync/api/attachments/attachment_id.h"
 #include "sync/base/sync_export.h"
-#include "sync/internal_api/public/util/report_unrecoverable_error_function.h"
 #include "sync/internal_api/public/util/weak_handle.h"
 #include "sync/syncable/dir_open_result.h"
 #include "sync/syncable/entry.h"
@@ -248,13 +248,11 @@
   // Does not take ownership of |encryptor|.
   // |report_unrecoverable_error_function| may be NULL.
   // Takes ownership of |store|.
-  Directory(
-      DirectoryBackingStore* store,
-      UnrecoverableErrorHandler* unrecoverable_error_handler,
-      ReportUnrecoverableErrorFunction
-          report_unrecoverable_error_function,
-      NigoriHandler* nigori_handler,
-      Cryptographer* cryptographer);
+  Directory(DirectoryBackingStore* store,
+            UnrecoverableErrorHandler* unrecoverable_error_handler,
+            const base::Closure& report_unrecoverable_error_function,
+            NigoriHandler* nigori_handler,
+            Cryptographer* cryptographer);
   virtual ~Directory();
 
   // Does not take ownership of |delegate|, which must not be NULL.
@@ -327,11 +325,7 @@
 
   // Called to immediately report an unrecoverable error (but don't
   // propagate it up).
-  void ReportUnrecoverableError() {
-    if (report_unrecoverable_error_function_) {
-      report_unrecoverable_error_function_();
-    }
-  }
+  void ReportUnrecoverableError();
 
   // Called to set the unrecoverable error on the directory and to propagate
   // the error to upper layers.
@@ -643,7 +637,7 @@
   scoped_ptr<DirectoryBackingStore> store_;
 
   UnrecoverableErrorHandler* const unrecoverable_error_handler_;
-  const ReportUnrecoverableErrorFunction report_unrecoverable_error_function_;
+  base::Closure report_unrecoverable_error_function_;
   bool unrecoverable_error_set_;
 
   // Not owned.
diff --git a/sync/syncable/directory_unittest.cc b/sync/syncable/directory_unittest.cc
index 96aaa70..735dca5 100644
--- a/sync/syncable/directory_unittest.cc
+++ b/sync/syncable/directory_unittest.cc
@@ -75,10 +75,7 @@
   // performance benefits of not writing to disk.
   dir_.reset(
       new Directory(new TestDirectoryBackingStore(kDirectoryName, &connection_),
-                    &handler_,
-                    NULL,
-                    NULL,
-                    NULL));
+                    &handler_, base::Closure(), NULL, NULL));
 
   DirOpenResult open_result =
       dir_->Open(kDirectoryName, &delegate_, NullTransactionObserver());
@@ -436,26 +433,41 @@
   AddDefaultFieldValue(BOOKMARKS, &bookmark_specifics);
   bookmark_specifics.mutable_bookmark()->set_url("url");
 
-  Id id1 = TestIdFactory::FromNumber(-1);
-  Id id2 = TestIdFactory::FromNumber(-2);
+  // The first two IDs are server IDs.
+  Id id1 = TestIdFactory::FromNumber(1);
+  Id id2 = TestIdFactory::FromNumber(2);
+  // The third one is a client ID.
+  Id id3 = TestIdFactory::FromNumber(-3);
   int64 handle1 = 0;
   int64 handle2 = 0;
+  int64 handle3 = 0;
   {
-    // Create two bookmark entries and save in database.
-    CreateEntry(BOOKMARKS, "item1", id1);
-    CreateEntry(BOOKMARKS, "item2", id2);
+    // Create 3 bookmark entries and save in database.
     {
       WriteTransaction trans(FROM_HERE, UNITTEST, dir().get());
-      MutableEntry item1(&trans, GET_BY_ID, id1);
-      ASSERT_TRUE(item1.good());
-      handle1 = item1.GetMetahandle();
+
+      MutableEntry item1(&trans, CREATE, BOOKMARKS, trans.root_id(), "item1");
+      item1.PutId(id1);
       item1.PutSpecifics(bookmark_specifics);
       item1.PutServerSpecifics(bookmark_specifics);
-      MutableEntry item2(&trans, GET_BY_ID, id2);
-      ASSERT_TRUE(item2.good());
-      handle2 = item2.GetMetahandle();
+      item1.PutIsUnappliedUpdate(true);
+      item1.PutBaseVersion(10);
+      handle1 = item1.GetMetahandle();
+
+      MutableEntry item2(&trans, CREATE, BOOKMARKS, trans.root_id(), "item2");
+      item2.PutId(id2);
       item2.PutSpecifics(bookmark_specifics);
       item2.PutServerSpecifics(bookmark_specifics);
+      item2.PutIsUnappliedUpdate(true);
+      item2.PutBaseVersion(10);
+      handle2 = item2.GetMetahandle();
+
+      MutableEntry item3(&trans, CREATE, BOOKMARKS, trans.root_id(), "item3");
+      item3.PutId(id3);
+      item3.PutSpecifics(bookmark_specifics);
+      item3.PutServerSpecifics(bookmark_specifics);
+      item3.PutIsUnsynced(true);
+      handle3 = item3.GetMetahandle();
     }
     ASSERT_EQ(OPENED, SimulateSaveAndReloadDir());
   }
@@ -469,18 +481,25 @@
       ASSERT_EQ(0u, journal_entries.size());
 
       // Set SERVER_IS_DEL of the entries to true and they should be added to
-      // delete journals.
+      // delete journals, but only if the deletion is initiated in update e.g.
+      // IS_UNAPPLIED_UPDATE is also true.
       MutableEntry item1(&trans, GET_BY_ID, id1);
       ASSERT_TRUE(item1.good());
       item1.PutServerIsDel(true);
       MutableEntry item2(&trans, GET_BY_ID, id2);
       ASSERT_TRUE(item2.good());
       item2.PutServerIsDel(true);
+      MutableEntry item3(&trans, GET_BY_ID, id3);
+      ASSERT_TRUE(item3.good());
+      item3.PutServerIsDel(true);
+      // Expect only the first two items to be in the delete journal.
       EntryKernel tmp;
       tmp.put(ID, id1);
       EXPECT_TRUE(delete_journal->delete_journals_.count(&tmp));
       tmp.put(ID, id2);
       EXPECT_TRUE(delete_journal->delete_journals_.count(&tmp));
+      tmp.put(ID, id3);
+      EXPECT_FALSE(delete_journal->delete_journals_.count(&tmp));
     }
 
     // Save delete journals in database and verify memory clearing.
@@ -505,6 +524,8 @@
       EXPECT_TRUE(journal_entries.count(&tmp));
       tmp.put(META_HANDLE, handle2);
       EXPECT_TRUE(journal_entries.count(&tmp));
+      tmp.put(META_HANDLE, handle3);
+      EXPECT_FALSE(journal_entries.count(&tmp));
 
       // Purge item2.
       MetahandleSet to_purge;
@@ -534,9 +555,10 @@
       tmp.put(META_HANDLE, handle1);
       EXPECT_TRUE(journal_entries.count(&tmp));
 
-      // Undelete item1.
+      // Undelete item1 (IS_UNAPPLIED_UPDATE shouldn't matter in this case).
       MutableEntry item1(&trans, GET_BY_ID, id1);
       ASSERT_TRUE(item1.good());
+      item1.PutIsUnappliedUpdate(false);
       item1.PutServerIsDel(false);
       EXPECT_TRUE(delete_journal->delete_journals_.empty());
       EXPECT_EQ(1u, delete_journal->delete_journals_to_purge_.size());
@@ -2006,7 +2028,8 @@
 TEST_F(SyncableDirectoryTest, CatastrophicError) {
   MockUnrecoverableErrorHandler unrecoverable_error_handler;
   Directory dir(new InMemoryDirectoryBackingStore("catastrophic_error"),
-                &unrecoverable_error_handler, nullptr, nullptr, nullptr);
+                &unrecoverable_error_handler, base::Closure(), nullptr,
+                nullptr);
   ASSERT_EQ(OPENED, dir.Open(kDirectoryName, directory_change_delegate(),
                              NullTransactionObserver()));
   ASSERT_EQ(0, unrecoverable_error_handler.invocation_count());
diff --git a/sync/syncable/model_neutral_mutable_entry.cc b/sync/syncable/model_neutral_mutable_entry.cc
index a7beadca..02cdcbb 100644
--- a/sync/syncable/model_neutral_mutable_entry.cc
+++ b/sync/syncable/model_neutral_mutable_entry.cc
@@ -237,13 +237,20 @@
     kernel_->mark_dirty(GetDirtyIndexHelper());
   }
 
-  // Update delete journal for existence status change on server side here
-  // instead of in PutIsDel() because IS_DEL may not be updated due to
-  // early returns when processing updates. And because
-  // UpdateDeleteJournalForServerDelete() checks for SERVER_IS_DEL, it has
-  // to be called on sync thread.
-  dir()->delete_journal()->UpdateDeleteJournalForServerDelete(
-      base_write_transaction(), old_value, *kernel_);
+  if (!value || kernel_->ref(IS_UNAPPLIED_UPDATE)) {
+    // Update delete journal for existence status change on server side here
+    // instead of in PutIsDel() because IS_DEL may not be updated due to
+    // early returns when processing updates. And because
+    // UpdateDeleteJournalForServerDelete() checks for SERVER_IS_DEL, it has
+    // to be called on sync thread.
+
+    // Please note that the delete journal applies only to the deletions
+    // originating on the server side (hence the IS_UNAPPLIED_UPDATE check),
+    // but it still makes sense to remove the entry from the delete journal
+    // when it gets undeleted locally.
+    dir()->delete_journal()->UpdateDeleteJournalForServerDelete(
+        base_write_transaction(), old_value, *kernel_);
+  }
 }
 
 void ModelNeutralMutableEntry::PutServerNonUniqueName(
diff --git a/sync/syncable/syncable_unittest.cc b/sync/syncable/syncable_unittest.cc
index f7d85cc..1cbd457 100644
--- a/sync/syncable/syncable_unittest.cc
+++ b/sync/syncable/syncable_unittest.cc
@@ -116,7 +116,7 @@
 TestDirectory::TestDirectory(Encryptor* encryptor,
                              UnrecoverableErrorHandler* handler,
                              TestBackingStore* backing_store)
-    : Directory(backing_store, handler, NULL, NULL, NULL),
+    : Directory(backing_store, handler, base::Closure(), NULL, NULL),
       backing_store_(backing_store) {
 }
 
@@ -344,12 +344,9 @@
   }
 
   dir()->SaveChanges();
-  dir().reset(
-      new Directory(new OnDiskDirectoryBackingStore(kDirectoryName, file_path_),
-                    unrecoverable_error_handler(),
-                    NULL,
-                    NULL,
-                    NULL));
+  dir().reset(new Directory(
+      new OnDiskDirectoryBackingStore(kDirectoryName, file_path_),
+      unrecoverable_error_handler(), base::Closure(), NULL, NULL));
 
   ASSERT_TRUE(dir().get());
   ASSERT_EQ(OPENED,
@@ -563,7 +560,7 @@
 
   {
     Directory dir(new OnDiskDirectoryBackingStore("ScopeTest", path), &handler_,
-                  NULL, NULL, NULL);
+                  base::Closure(), NULL, NULL);
     DirOpenResult result =
         dir.Open("ScopeTest", &delegate_, NullTransactionObserver());
     ASSERT_EQ(result, OPENED);
diff --git a/sync/test/engine/test_directory_setter_upper.cc b/sync/test/engine/test_directory_setter_upper.cc
index 847a7bb0..85e8aa39 100644
--- a/sync/test/engine/test_directory_setter_upper.cc
+++ b/sync/test/engine/test_directory_setter_upper.cc
@@ -27,13 +27,10 @@
   WeakHandle<syncable::TransactionObserver> transaction_observer =
       MakeWeakHandle(test_transaction_observer_->AsWeakPtr());
 
-  directory_.reset(
-      new syncable::Directory(
-          new syncable::InMemoryDirectoryBackingStore(name_),
-          &handler_,
-          NULL,
-          &encryption_handler_,
-          encryption_handler_.cryptographer()));
+  directory_.reset(new syncable::Directory(
+      new syncable::InMemoryDirectoryBackingStore(name_), &handler_,
+      base::Closure(), &encryption_handler_,
+      encryption_handler_.cryptographer()));
   ASSERT_EQ(syncable::OPENED, directory_->Open(
           name_, &delegate_, transaction_observer));
 }
@@ -45,12 +42,9 @@
   WeakHandle<syncable::TransactionObserver> transaction_observer =
       MakeWeakHandle(test_transaction_observer_->AsWeakPtr());
 
-  directory_.reset(
-      new syncable::Directory(directory_store,
-                              &handler_,
-                              NULL,
-                              &encryption_handler_,
-                              encryption_handler_.cryptographer()));
+  directory_.reset(new syncable::Directory(
+      directory_store, &handler_, base::Closure(), &encryption_handler_,
+      encryption_handler_.cryptographer()));
     ASSERT_EQ(syncable::OPENED, directory_->Open(
           name_, &delegate_, transaction_observer));
 }
diff --git a/sync/tools/sync_client.cc b/sync/tools/sync_client.cc
index 99a2a48..a433fa9 100644
--- a/sync/tools/sync_client.cc
+++ b/sync/tools/sync_client.cc
@@ -38,7 +38,6 @@
 #include "sync/internal_api/public/read_node.h"
 #include "sync/internal_api/public/sync_manager.h"
 #include "sync/internal_api/public/sync_manager_factory.h"
-#include "sync/internal_api/public/util/report_unrecoverable_error_function.h"
 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
 #include "sync/internal_api/public/util/weak_handle.h"
 #include "sync/js/js_event_details.h"
@@ -437,7 +436,8 @@
       new InternalComponentsFactoryImpl(factory_switches));
   args.encryptor = &null_encryptor;
   args.unrecoverable_error_handler.reset(new LoggingUnrecoverableErrorHandler);
-  args.report_unrecoverable_error_function = &LogUnrecoverableErrorContext;
+  args.report_unrecoverable_error_function =
+      base::Bind(LogUnrecoverableErrorContext);
   args.cancelation_signal = &scm_cancelation_signal;
   sync_manager->Init(&args);
   // TODO(akalin): Avoid passing in model parameters multiple times by
diff --git a/sync/util/cryptographer.cc b/sync/util/cryptographer.cc
index c22f0a32..bccf9a2 100644
--- a/sync/util/cryptographer.cc
+++ b/sync/util/cryptographer.cc
@@ -127,8 +127,10 @@
     const sync_pb::EncryptedData& encrypted) const {
   NigoriMap::const_iterator it = nigoris_.find(encrypted.key_name());
   if (nigoris_.end() == it) {
-    NOTREACHED() << "Cannot decrypt message";
-    return std::string();  // Caller should have called CanDecrypt(encrypt).
+    // The key used to encrypt the blob is not part of the set of installed
+    // nigoris.
+    LOG(ERROR) << "Cannot decrypt message";
+    return std::string();
   }
 
   std::string plaintext;
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 177b686..daa9b22 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -220,6 +220,9 @@
         "test": "midi_unittests"
       },
       {
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -408,6 +411,9 @@
         "test": "midi_unittests"
       },
       {
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -592,6 +598,9 @@
         "test": "midi_unittests"
       },
       {
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 8509c57f..f3ce760 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4,7 +4,7 @@
       {
         "args": [
           "--enable-browser-side-navigation",
-          "--gtest_filter=-CrossSiteRedirectorBrowserTest.VerifyCrossSiteRedirectURL:CrossSiteTransferTest.NoLeakOnCrossSiteCancel:CrossSiteTransferTest.ReplaceEntryCrossProcessThenTransfer:CrossSiteTransferTest.ReplaceEntryCrossProcessTwice:CrossSiteTransferTest.ReplaceEntryInProcessThenTranfers:DatabaseTest.ReloadPage:NavigationControllerBrowserTest.CorrectLengthWithCurrentItemReplacement:NavigationControllerBrowserTest.FrameNavigationEntry_BlankAutoSubframe:NavigationControllerBrowserTest.NavigationTypeClassification_ClientSideRedirect:NavigationControllerBrowserTest.NavigationTypeClassification_ExistingPage:NavigationControllerBrowserTest.NavigationTypeClassification_InPage:NavigationControllerBrowserTest.NavigationTypeClassification_NewAndAutoSubframe:NavigationControllerBrowserTest.NavigationTypeClassification_NewPage:NavigationControllerBrowserTest.PreventSpoofFromSubframeAndReplace:NavigationControllerBrowserTest.StopCausesFailureDespiteJavaScriptURL:NavigationControllerBrowserTest.SubframeBackFromReplaceState:RFHMProcessPerTabTest.BackFromWebUI:RenderFrameHostManagerTest.BackForwardNotStale:RenderFrameHostManagerTest.DisownOpener:RenderFrameHostManagerTest.RestoreFileAccessForHistoryNavigation:RenderFrameHostManagerTest.RestoreSubframeFileAccessForHistoryNavigation:RenderFrameHostManagerTest.SwappedOutViewHasCorrectVisibilityState:RenderViewImplTest.DecideNavigationPolicy:RenderViewImplTest.NavigationStartOverride:RenderViewImplTest.OnNavigationHttpPost:RenderViewImplTest.ReloadWhileSwappedOut:RenderViewImplTest.StaleNavigationsIgnored:RenderViewImplTest.TestBackForward:SecurityExploitBrowserTest.AttemptDuplicateRenderViewHost:SecurityExploitBrowserTest.AttemptDuplicateRenderWidgetHost:SecurityExploitBrowserTest.InterstitialCommandFromUnderlyingContent:ServiceWorkerBrowserTest.CrossSiteTransfer:ServiceWorkerBrowserTest.ImportsBustMemcache:ServiceWorkerBrowserTest.Reload:ServiceWorkerBrowserTest.ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure:ServiceWorkerBrowserTest.ResponseFromHTTPSServiceWorkerIsMarkedAsSecure:SessionHistoryTest.BasicBackForward:SessionHistoryTest.CrossFrameFormBackForward:SessionHistoryTest.FragmentBackForward:SessionHistoryTest.FrameBackForward:SessionHistoryTest.FrameFormBackForward:SessionHistoryTest.HistoryLength:SessionHistoryTest.JavascriptHistory:SessionHistoryTest.LocationChangeInSubframe:SitePerProcessBrowserTest.CrossSiteDidStopLoading:WebContentsImplBrowserTest.ClearNonVisiblePendingOnFail:WebContentsViewAuraTest.OverscrollScreenshot:WebContentsViewAuraTest.ReplaceStateReloadPushState:WebRtcBrowserTest.CallInsideIframe:WebUIMojoTest.EndToEndPing"
+          "--gtest_filter=-CrossSiteRedirectorBrowserTest.VerifyCrossSiteRedirectURL:CrossSiteTransferTest.NoLeakOnCrossSiteCancel:CrossSiteTransferTest.ReplaceEntryCrossProcessThenTransfer:CrossSiteTransferTest.ReplaceEntryCrossProcessTwice:CrossSiteTransferTest.ReplaceEntryInProcessThenTranfers:DevToolsProtocolTest.NavigationPreservesMessages:NavigationControllerBrowserTest.CorrectLengthWithCurrentItemReplacement:NavigationControllerBrowserTest.FrameNavigationEntry_BlankAutoSubframe:NavigationControllerBrowserTest.NavigationTypeClassification_ClientSideRedirect:NavigationControllerBrowserTest.NavigationTypeClassification_ExistingPage:NavigationControllerBrowserTest.NavigationTypeClassification_InPage:NavigationControllerBrowserTest.NavigationTypeClassification_NewAndAutoSubframe:NavigationControllerBrowserTest.NavigationTypeClassification_NewPage:NavigationControllerBrowserTest.PreventSpoofFromSubframeAndReplace:NavigationControllerBrowserTest.StopCausesFailureDespiteJavaScriptURL:RenderViewImplTest.DecideNavigationPolicy:RenderViewImplTest.NavigationStartOverride:RenderViewImplTest.OnNavigationHttpPost:RenderViewImplTest.ReloadWhileSwappedOut:RenderViewImplTest.TestBackForward:SecurityExploitBrowserTest.AttemptDuplicateRenderViewHost:SecurityExploitBrowserTest.AttemptDuplicateRenderWidgetHost:SecurityExploitBrowserTest.InterstitialCommandFromUnderlyingContent:ServiceWorkerBrowserTest.CrossSiteTransfer:ServiceWorkerBrowserTest.ImportsBustMemcache:ServiceWorkerBrowserTest.Reload:ServiceWorkerBrowserTest.ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure:ServiceWorkerBrowserTest.ResponseFromHTTPSServiceWorkerIsMarkedAsSecure:SessionHistoryTest.CrossFrameFormBackForward:SessionHistoryTest.FrameBackForward:SessionHistoryTest.FrameFormBackForward:SessionHistoryTest.LocationChangeInSubframe:SitePerProcessBrowserTest.CrossSiteDidStopLoading:WebContentsImplBrowserTest.ClearNonVisiblePendingOnFail:WebContentsViewAuraTest.ReplaceStateReloadPushState:WebRtcBrowserTest.CallInsideIframe:WebUIMojoTest.EndToEndPing"
         ],
         "test": "content_browsertests"
       },
@@ -284,6 +284,9 @@
         "test": "mojo_system_unittests"
       },
       {
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -2366,16 +2369,9 @@
         "test": "angle_unittests"
       },
       {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "base_unittests"
       },
       {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 10
-        },
         "test": "browser_tests"
       },
       {
@@ -2388,27 +2384,15 @@
         "test": "components_unittests"
       },
       {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "content_browsertests"
       },
       {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "content_unittests"
       },
       {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "courgette_unittests"
       },
       {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "crypto_unittests"
       },
       {
@@ -2442,9 +2426,6 @@
         "test": "midi_unittests"
       },
       {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "net_unittests"
       },
       {
@@ -2478,9 +2459,6 @@
         "test": "ui_base_unittests"
       },
       {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "unit_tests"
       },
       {
@@ -2880,6 +2858,9 @@
         "test": "mojo_system_unittests"
       },
       {
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -3051,6 +3032,9 @@
         "test": "mojo_system_unittests"
       },
       {
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -3228,6 +3212,9 @@
         "test": "mojo_system_unittests"
       },
       {
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -3399,6 +3386,9 @@
         "test": "mojo_system_unittests"
       },
       {
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -3464,7 +3454,7 @@
       {
         "args": [
           "--site-per-process",
-          "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:*PDFExtensionTest.Load*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewCommonTest.*:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs"
+          "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:*PDFExtensionTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewCommonTest.*:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs"
         ],
         "test": "browser_tests"
       },
@@ -3494,7 +3484,7 @@
       {
         "args": [
           "--site-per-process",
-          "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:*PDFExtensionTest.Load*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewCommonTest.*:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs"
+          "--gtest_filter=-AppApiTest.*:BlockedAppApiTest.*:BrowserTest.ClearPendingOnFailUnlessNTP:BrowserTest.OtherRedirectsDontForkProcess:BrowserTest.WindowOpenClose:ChromeAppAPITest.*:ChromeRenderProcessHostTest.*:ChromeRenderProcessHostTestWithCommandLine.*:DevToolsExperimentalExtensionTest.*:DevToolsExtensionTest.*:DnsProbeBrowserTest.*:ErrorPageTest.*:ExecuteScriptApiTest.ExecuteScriptPermissions:ExtensionApiTest.ActiveTab:ExtensionApiTest.ChromeRuntimeOpenOptionsPage:ExtensionApiTest.ContentScriptExtensionIframe:ExtensionApiTest.ContentScriptOtherExtensions:ExtensionApiTest.ContentScriptExtensionProcess:ExtensionApiTest.Tabs2:ExtensionApiTest.TabsOnUpdated:ExtensionApiTest.WindowOpenPopupIframe:ExtensionBrowserTest.LoadChromeExtensionsWithOptionsParamWhenEmbedded:ExtensionCrxInstallerTest.InstallDelayedUntilNextUpdate:ExtensionOptionsApiTest.ExtensionCanEmbedOwnOptions:ExtensionWebUITest.CanEmbedExtensionOptions:ExtensionWebUITest.ReceivesExtensionOptionsOnClose:InlineLoginUISafeIframeBrowserTest.*:IsolatedAppTest.*:LaunchWebAuthFlowFunctionTest.*:MimeHandlerViewTest.*:*.NewAvatarMenuEnabledInGuestMode:OptionsUIBrowserTest.*:*PDFExtensionTest.*:PhishingClassifierTest.*:PhishingDOMFeatureExtractorTest.*:PlatformAppUrlRedirectorBrowserTest.*:PopupBlockerBrowserTest.*:PrerenderBrowserTest.*:ProcessManagementTest.*:RedirectTest.*:ReferrerPolicyTest.*:SSLUITest.*:WebNavigationApiTest.CrossProcessFragment:WebNavigationApiTest.ServerRedirectSingleProcess:WebNavigationApiTest.CrossProcessHistory:WebViewCommonTest.*:WebViewDPITest.*:WebViewPluginTest.*:WebViewTest.*:ZoomControllerBrowserTest.*:*.NavigateFromNTPToOptionsInSameTab:*.ProfilesWithoutPagesNotLaunched:*.TabMove:*.WhitelistedExtension:*.NewTabPageURL:*.HomepageLocation:RestoreOnStartupPolicyTest*:PhishingClassifierDelegateTest.*:WebUIWebViewBrowserTest*:WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabs"
         ],
         "test": "browser_tests"
       },
diff --git a/testing/buildbot/chromium.webkit.json b/testing/buildbot/chromium.webkit.json
index 12cd7e8c..80221c9 100644
--- a/testing/buildbot/chromium.webkit.json
+++ b/testing/buildbot/chromium.webkit.json
@@ -126,6 +126,9 @@
         "test": "midi_unittests"
       },
       {
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
@@ -304,6 +307,9 @@
         "test": "midi_unittests"
       },
       {
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
         "test": "nacl_loader_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 55a95d0..f1fb8790 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -1080,17 +1080,56 @@
     ]
   },
   "Win8 Aura": {
+    "additional_compile_targets": [
+      "accessibility_unittests",
+      "app_list_unittests",
+      "app_shell_unittests",
+      "ash_unittests",
+      "aura_unittests",
+      "cacheinvalidation_unittests",
+      "cast_unittests",
+      "cc_unittests",
+      "chrome",
+      "chrome_elf_unittests",
+      "chromedriver_unittests",
+      "components_browsertests",
+      "components_unittests",
+      "compositor_unittests",
+      "content_unittests",
+      "courgette_unittests",
+      "crypto_unittests",
+      "device_unittests",
+      "extensions_browsertests",
+      "extensions_unittests",
+      "gcm_unit_tests",
+      "gfx_unittests",
+      "gl_unittests",
+      "google_apis_unittests",
+      "gpu_unittests",
+      "interactive_ui_tests",
+      "ipc_mojo_unittests",
+      "ipc_tests",
+      "jingle_unittests",
+      "keyboard_unittests",
+      "mandoline:all",
+      "media_unittests",
+      "message_center_unittests",
+      "ppapi_unittests",
+      "printing_unittests",
+      "sbox_integration_tests",
+      "sbox_unittests",
+      "sbox_validation_tests",
+      "skia_unittests",
+      "sql_unittests",
+      "sync_integration_tests",
+      "sync_unit_tests",
+      "ui_base_unittests",
+      "url_unittests",
+      "views_unittests",
+      "wm_unittests"
+    ],
     "gtest_tests": [
       {
-        "test": "ash_unittests"
-      },
-      {
-        "test": "aura_unittests"
-      },
-      {
-        "test": "compositor_unittests"
-      },
-      {
         "test": "content_browsertests"
       },
       {
@@ -1098,12 +1137,6 @@
       },
       {
         "test": "ui_touch_selection_unittests"
-      },
-      {
-        "test": "views_unittests"
-      },
-      {
-        "test": "wm_unittests"
       }
     ]
   },
diff --git a/testing/buildbot/chromium_arm.json b/testing/buildbot/chromium_arm.json
index a2d4329f..c3d306d 100644
--- a/testing/buildbot/chromium_arm.json
+++ b/testing/buildbot/chromium_arm.json
@@ -1,11 +1,13 @@
 {
   "compile_targets": [
     "browser_tests_run",
+    "nacl_helper_nonsfi_unittests_run",
     "nacl_loader_unittests_run",
     "sandbox_linux_unittests_run"
   ],
   "gtest_tests": [
     "browser_tests",
+    "nacl_helper_nonsfi_unittests",
     "nacl_loader_unittests",
     "sandbox_linux_unittests"
   ]
diff --git a/testing/buildbot/chromium_trybot.json b/testing/buildbot/chromium_trybot.json
index 7290eacc..59c8c6f 100644
--- a/testing/buildbot/chromium_trybot.json
+++ b/testing/buildbot/chromium_trybot.json
@@ -219,6 +219,12 @@
     "mojo_public_system_unittests",
     "mojo_public_utility_unittests",
     "mojo_system_unittests",
+    {
+      "platforms": [
+        "linux"
+      ],
+      "test": "nacl_helper_nonsfi_unittests"
+    },
     "nacl_loader_unittests",
     {
       "swarming": {
diff --git a/testing/buildbot/manage.py b/testing/buildbot/manage.py
index 98de7ef4..723153c 100755
--- a/testing/buildbot/manage.py
+++ b/testing/buildbot/manage.py
@@ -10,6 +10,7 @@
 """
 
 import argparse
+import ast
 import collections
 import glob
 import json
@@ -51,6 +52,15 @@
 }
 
 
+# TODO(GYP): These targets have not been ported to GN yet.
+SKIP_NINJA_TO_GN_TARGETS = {
+  'cast_media_unittests',
+  'cast_shell_browser_test',
+  'chromevox_tests',
+  'nacl_helper_nonsfi_unittests',
+}
+
+
 class Error(Exception):
   """Processing error."""
 
@@ -90,7 +100,8 @@
           filename, []).append(builder)
 
 
-def process_file(mode, test_name, tests_location, filepath):
+def process_file(mode, test_name, tests_location, filepath, ninja_targets,
+                 ninja_targets_seen):
   """Processes a file.
 
   The action depends on mode. Updates tests_location.
@@ -120,6 +131,14 @@
       raise Error(
           '%s: %s is broken: %s' % (filename, builder, data['gtest_tests']))
 
+    for d in data['gtest_tests']:
+      if (d['test'] not in ninja_targets and
+          d['test'] not in SKIP_NINJA_TO_GN_TARGETS):
+        raise Error('%s: %s / %s is not listed in ninja_to_gn.pyl.' %
+                    (filename, builder, d['test']))
+      elif d['test'] in ninja_targets:
+        ninja_targets_seen.add(d['test'])
+
     config[builder]['gtest_tests'] = sorted(
         data['gtest_tests'], key=lambda x: x['test'])
     if mode == 'remaining':
@@ -222,12 +241,26 @@
         'count_run_local': 0, 'count_run_on_swarming': 0, 'local_configs': {}
       })
 
+  with open(os.path.join(THIS_DIR, "ninja_to_gn.pyl")) as fp:
+    ninja_targets = ast.literal_eval(fp.read())
+
   try:
     result = 0
+    ninja_targets_seen = set()
     for filepath in glob.glob(os.path.join(THIS_DIR, '*.json')):
-      if not process_file(args.mode, args.test_name, tests_location, filepath):
+      if not process_file(args.mode, args.test_name, tests_location, filepath,
+                          ninja_targets, ninja_targets_seen):
         result = 1
 
+    extra_targets = set(ninja_targets) - ninja_targets_seen
+    if extra_targets:
+      if len(extra_targets) > 1:
+        extra_targets_str = ', '.join(extra_targets) + ' are'
+      else:
+        extra_targets_str = list(extra_targets)[0] + ' is'
+      raise Error('%s listed in ninja_to_gn.pyl but not in any .json files' %
+                  extra_targets_str)
+
     if args.mode == 'remaining':
       print_remaining(args.test_name, tests_location)
     return result
diff --git a/testing/buildbot/ninja_to_gn.pyl b/testing/buildbot/ninja_to_gn.pyl
new file mode 100644
index 0000000..97f50fe
--- /dev/null
+++ b/testing/buildbot/ninja_to_gn.pyl
@@ -0,0 +1,91 @@
+# 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.
+
+# ninja_to_gn - A mapping of Ninja build target names to GN labels for
+# the tests run on the bots.
+#
+# This mapping is used by MB so that we can uniformly refer to test binaries
+# by their Ninja target names in the recipes and not need to worry about how
+# they are referred to in GN or GYP specifically (the GYP target name is pretty
+# much always the same as the Ninja target name, since GYP target names are not
+# hierarchical).
+
+{
+  "base_unittests":                    "//base:base_unittests",
+  "accessibility_unittests":           "//ui/accessibility:accessibility_unittests",
+  "angle_unittests":                   "//gpu:angle_unittests",
+  "app_list_unittests":                "//ui/app_list:app_list_unittests",
+  "app_shell_unittests":               "//extensions/shell:app_shell_unittests",
+  "ash_unittests":                     "//ash:ash_unittests",
+  "aura_unittests":                    "//ui/aura:aura_unittests",
+  "blink_heap_unittests":              "//third_party/WebKit/public:blink_heap_unittests",
+  "blink_platform_unittests":          "//third_party/WebKit/public:blink_platform_unittests",
+  "browser_tests":                     "//chrome/test:browser_tests",
+  "cacheinvalidation_unittests":       "//third_party/cacheinvalidation:cacheinvalidation_unittests",
+  "cast_base_unittests":               "//cast:cast_base_unittests",
+  "cast_unittests":                    "//cast:cast_unittests",
+  "cc_unittests":                      "//cc:cc_unittests",
+  "chromedriver_unittests":            "//chrome/test/chromedriver:chromedriver_unittests",
+  "chrome_elf_unittests":              "//chrome_elf:chrome_elf_unittests",
+  "chromeos_unittests":                "//chromeos:chromeos_unittests",
+  "components_browsertests":           "//components:components_browsertests",
+  "components_unittests":              "//components:components_unittests",
+  "compositor_unittests":              "//ui/compositor:compositor_unittests",
+  "content_browsertests":              "//content/test:content_browsertests",
+  "content_unittests":                 "//content/test:content_unittests",
+  "courgette_unittests":               "//courgette:courgette_unittests",
+  "crypto_unittests":                  "//crypto:crypto_unittests",
+  "dbus_unittests":                    "//dbus:dbus_unittests",
+  "device_unittests":                  "//device:device_unittests",
+  "display_unittests":                 "//ui/display:display_unittests",
+  "events_unittests":                  "//ui/events:events_unittests",
+  "extensions_browsertests":           "//extensions:extensions_browsertests",
+  "extensions_unittests":              "//extensions:extensions_unittests",
+  "gcm_unit_tests":                    "//google_apis/gcm:gcm_unit_tests",
+  "gfx_unittests":                     "//ui/gfx:gfx_unittests",
+  "gl_unittests":                      "//ui/gl:gl_unittests",
+  "gn_unittests":                      "//tools/gn:gn_unittests",
+  "google_apis_unittests":             "//google_apis:google_apis_unittests",
+  "gpu_unittests":                     "//gpu:gpu_unittests",
+  "installer_util_unittests":          "//chrome/installer/util:installer_util_unittests",
+  "interactive_ui_tests":              "//chrome/test:interactive_ui_tests",
+  "ipc_mojo_unittests":                "//ipc/mojo:ipc_mojo_unittests",
+  "ipc_tests":                         "//ipc:ipc_tests",
+  "jingle_unittests":                  "//jingle:jingle_unittests",
+  "keyboard_unittests":                "//ui/keyboard:keyboard_unittests",
+  "media_unittests":                   "//media:media_unittests",
+  "midi_unittests":                    "//media:midi_unittests",
+  "mojo_common_unittests":             "//mojo/common:mojo_common_unittests",
+  "mojo_public_application_unittests": "//third_party/mojo/src/mojo/edk/test:mojo_public_applicaiton_unittests",
+  "mojo_public_bindings_unittests":    "//third_party/mojo/src/mojo/edk/test:mojo_public_bindings_unittests",
+  "mojo_public_environment_unittests": "//third_party/mojo/src/mojo/edk/test:mojo_public_environment_unittests",
+  "mojo_public_system_unittests":      "//third_party/mojo/src/mojo/edk/test:mojo_public_system_unittests",
+  "mojo_public_utility_unittests":     "//third_party/mojo/src/mojo/edk/test:mojo_public_utility_unittests",
+  "mojo_system_unittests":             "//third_party/mojo/src/mojo/edk/system:mojo_system_unittests",
+  "message_center_unittests":          "//ui/message_center:message_center_unittests",
+  "nacl_loader_unittests":             "//components/nacl:nacl_loader_unittests",
+  "net_unittests":                     "//net:net_unittests",
+  "ozone_unittests":                   "//ui/ozone:ozone_unittests",
+  "ppapi_unittests":                   "//ppapi:ppapi_unittests",
+  "printing_unittests":                "//printing:printing_unittests",
+  "remoting_unittests":                "//remoting:remoting_unittests",
+  "sandbox_linux_unittests":           "//sandbox/linux:sandbox_linux_unittests",
+  "sandbox_mac_unittests":             "//sandbox/mac:sandbox_mac_unittests",
+  "sbox_integration_tests":            "//sandbox/win:sbox_integration_tests",
+  "sbox_unittests":                    "//sandbox/win:sbox_unittests",
+  "sbox_validation_tests":             "//sandbox/win:sbox_validation_tests",
+  "skia_unittests":                    "//skia:skia_unittests",
+  "sql_unittests":                     "//sql:sql_unittests",
+  "sync_integration_tests":            "//sync:sync_integration_tests",
+  "sync_unit_tests":                   "//sync:sync_unit_tests",
+  "ui_base_unittests":                 "//ui/base:ui_base_unittests",
+  "ui_chromeos_unittests":             "//ui/chromeos:ui_chromeos_unittests",
+  "ui_touch_selection_unittests":      "//ui/touch_selection:ui_touch_selection_unittests",
+  "unit_tests":                        "//chrome/test:unit_tests",
+  "url_unittests":                     "//url:url_unittests",
+  "views_unittests":                   "//ui/views:views_unittests",
+  "webkit_unit_tests":                 "//third_party/WebKit/public:webkit_unit_tests",
+  "wm_unittests":                      "//ui/wm:wm_unittests",
+  "wtf_unittests":                     "//third_party/WebKit/public:wtf_unittests",
+}
diff --git a/testing/chromoting/browser_test_commands_linux.txt b/testing/chromoting/browser_test_commands_linux.txt
index c4c69da..dbc386c 100644
--- a/testing/chromoting/browser_test_commands_linux.txt
+++ b/testing/chromoting/browser_test_commands_linux.txt
@@ -1,17 +1,17 @@
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch:RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gafyd --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch:RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_RetryOnHostOffline --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_v2_Alive_OnLostFocus --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_Connect --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_InvalidAccessCode --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_CancelShare --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_VerifyAccessCodeNonReusable --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Cancel_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Update_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Invalid_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123457 --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=FullscreenBrowserTest.MANUAL_Me2Me_Bump_Scroll --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile --v=2
-cd ../../remoting/internal/config && /usr/bin/python ./is_valid_json.py
\ No newline at end of file
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch:RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gafyd
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch:RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_RetryOnHostOffline --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_v2_Alive_OnLostFocus --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_Connect --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_InvalidAccessCode --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_CancelShare --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_VerifyAccessCodeNonReusable --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Cancel_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Update_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Invalid_PIN --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123457 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=FullscreenBrowserTest.MANUAL_Me2Me_Bump_Scroll --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+cd ../../remoting/internal/config && /usr/bin/python ./is_valid_json.py
diff --git a/testing/chromoting/browser_tests_launcher.py b/testing/chromoting/browser_tests_launcher.py
index 1c9652f..d39d291 100644
--- a/testing/chromoting/browser_tests_launcher.py
+++ b/testing/chromoting/browser_tests_launcher.py
@@ -25,11 +25,45 @@
 TEST_FAILURE = False
 FAILING_TESTS = ''
 HOST_READY_INDICATOR = 'Host ready to receive connections.'
+BROWSER_NOT_STARTED_ERROR = (
+    'Still waiting for the following processes to finish')
+TIME_OUT_INDICATOR = '(TIMED OUT)'
+MAX_RETRIES = 1
 
 
-def LaunchBTCommand(command):
+def LaunchBTCommand(args, command):
+  """Launches the specified browser-test command.
+
+      If the execution failed because a browser-instance was not launched, retry
+      once.
+  Args:
+    args: Command line args, used for test-case startup tasks.
+    command: Browser-test command line.
+  """
   global TEST_FAILURE, FAILING_TESTS
-  results = RunCommandInSubProcess(command)
+
+  retries = 0
+  while retries <= MAX_RETRIES:
+    TestCaseSetup(args)
+    results = RunCommandInSubProcess(command)
+
+    if SUCCESS_INDICATOR in results:
+      # Test passed.
+      break
+
+    # Sometimes, during execution of browser-tests, a browser instance is
+    # not started and the test times out. See http://crbug/480025.
+    # To work around it, check if this execution failed owing to that
+    # problem and retry.
+    # There are 2 things to look for in the results:
+    # A line saying "Still waiting for the following processes to finish",
+    # and, because sometimes that line gets logged even if the test
+    # eventually passes, we'll also look for "(TIMED OUT)", before retrying.
+    if not (
+        BROWSER_NOT_STARTED_ERROR in results and TIME_OUT_INDICATOR in results):
+      # Test failed for some other reason. Let's not retry.
+      break
+    retries += 1
 
   # Check that the test passed.
   if SUCCESS_INDICATOR not in results:
@@ -173,28 +207,28 @@
     print process.name
 
 
+def TestCaseSetup(args):
+  # Stop+start me2me host process.
+  if not RestartMe2MeHost():
+    # Host restart failed. Don't run any more tests.
+    raise Exception('Host restart failed.')
+
+  # Reset the user profile directory to start each test with a clean slate.
+  SetupUserProfileDir(args.me2me_manifest_file, args.it2me_manifest_file,
+                      args.user_profile_dir)
+
+
 def main(args):
 
   InitialiseTestMachineForLinux(args.cfg_file)
 
   with open(args.commands_file) as f:
     for line in f:
-      # Reset the user profile directory to start each test with a clean slate.
-      SetupUserProfileDir(args.me2me_manifest_file, args.it2me_manifest_file,
-                          args.user_profile_dir)
-
       # Replace the PROD_DIR value in the command-line with
       # the passed in value.
       line = line.replace(PROD_DIR_ID, args.prod_dir)
       # Launch specified command line for test.
-      LaunchBTCommand(line)
-      # After each test, stop+start me2me host process.
-      if not RestartMe2MeHost():
-        # Host restart failed. Don't run any more tests.
-        raise Exception('Host restart failed.')
-
-      # Print list of currently running processes.
-      PrintRunningProcesses()
+      LaunchBTCommand(args, line)
 
   # All tests completed. Include host-logs in the test results.
   host_log_contents = ''
diff --git a/testing/chromoting/chromoting_integration_tests.isolate b/testing/chromoting/chromoting_integration_tests.isolate
index 6062cb2b..eb7fec0 100644
--- a/testing/chromoting/chromoting_integration_tests.isolate
+++ b/testing/chromoting/chromoting_integration_tests.isolate
@@ -24,7 +24,6 @@
           '../xvfb.py',
           './browser_tests_launcher.py',
           './browser_test_commands_linux.txt',
-          '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
           '<(PRODUCT_DIR)/nacl_irt_x86_64.nexe',
           '../../remoting/tools/internal/test-account-host-config.json',
@@ -71,7 +70,6 @@
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/chrome_elf.dll',
-          '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/libglesv2.dll',
         ],
       },
@@ -81,7 +79,6 @@
         'files': [
           '<(PRODUCT_DIR)/<(mac_product_name).app/',
           '<(PRODUCT_DIR)/exif.so',
-          '<(PRODUCT_DIR)/ffmpegsumo.so',
         ],
       },
     }],
diff --git a/testing/generate_gmock_mutant.py b/testing/generate_gmock_mutant.py
index 9c5678c..45ac4ed 100755
--- a/testing/generate_gmock_mutant.py
+++ b/testing/generate_gmock_mutant.py
@@ -66,7 +66,7 @@
 // // Will invoke mock.HandleFlowers("orchids", n, request)
 // // "orchids" is a pre-bound argument, and <n> and <request> are call-time
 // // arguments - they are not known until the OnRequest mock is invoked.
-// EXPECT_CALL(mock, OnRequest(Ge(5), StartsWith("flower"))
+// EXPECT_CALL(mock, OnRequest(Ge(5), base::StartsWith("flower"))
 //   .Times(1)
 //   .WillOnce(Invoke(CreateFunctor(&mock, &Mock::HandleFlowers,
 //       string("orchids"))));
diff --git a/testing/gmock_mutant.h b/testing/gmock_mutant.h
index acc1ae9..6049d1d 100644
--- a/testing/gmock_mutant.h
+++ b/testing/gmock_mutant.h
@@ -57,7 +57,7 @@
 // // Will invoke mock.HandleFlowers("orchids", n, request)
 // // "orchids" is a pre-bound argument, and <n> and <request> are call-time
 // // arguments - they are not known until the OnRequest mock is invoked.
-// EXPECT_CALL(mock, OnRequest(Ge(5), StartsWith("flower"))
+// EXPECT_CALL(mock, OnRequest(Ge(5), base::StartsWith("flower"))
 //   .Times(1)
 //   .WillOnce(Invoke(CreateFunctor(&mock, &Mock::HandleFlowers,
 //       string("orchids"))));
diff --git a/testing/iossim/iossim.mm b/testing/iossim/iossim.mm
index 3910ba5d..933a183c 100644
--- a/testing/iossim/iossim.mm
+++ b/testing/iossim/iossim.mm
@@ -32,6 +32,7 @@
 // (crbug.com/385030).
 #if defined(IOSSIM_USE_XCODE_6)
 @protocol SimBridge;
+@class DVTSimulatorApplication;
 @class SimDeviceSet;
 @class SimDeviceType;
 @class SimRuntime;
diff --git a/testing/variations/field_trial_config_android.json b/testing/variations/field_trial_config_android.json
new file mode 100644
index 0000000..22cb5a7
--- /dev/null
+++ b/testing/variations/field_trial_config_android.json
@@ -0,0 +1,24 @@
+{
+    "EnhancedBookmarks": [
+        {
+            "group_name": "EnableEnhancedBookmarks",
+            "params": {
+                "id": "Fake_id_to_trigger_experiment_code"
+            }
+        },
+        {
+            "group_name": "EnableEnhancedBookmarksGrid",
+            "params": {
+                "DefaultViewMode": "Grid",
+                "id": "Fake_id_to_trigger_experiment_code"
+            }
+        },
+        {
+            "group_name": "EnableEnhancedBookmarksList",
+            "params": {
+                "DefaultViewMode": "List",
+                "id": "Fake_id_to_trigger_experiment_code"
+            }
+        }
+    ]
+}
diff --git a/third_party/android_data_chart/README.chromium b/third_party/android_data_chart/README.chromium
index c65a057..9624d86 100644
--- a/third_party/android_data_chart/README.chromium
+++ b/third_party/android_data_chart/README.chromium
@@ -1,4 +1,4 @@
-Name: Android Open Source Project
+Name: Android Open Source Project - Settings App
 URL: https://android.googlesource.com/platform/packages/apps/Settings/
 Version: unknown
 License: Apache 2.0
diff --git a/third_party/android_platform/README.chromium b/third_party/android_platform/README.chromium
index 192b9d6..854a36b 100644
--- a/third_party/android_platform/README.chromium
+++ b/third_party/android_platform/README.chromium
@@ -26,7 +26,8 @@
 Added memoization of addr2line and objdump.
 Added option to change the amount of symbolization done.
 Updated output directories to use environment variable.
-When calling addr2line, check the symbol is a file (and not a directory).
+When calling addr2line, check the symbol is a file that looks like it contains
+    symbols.
 Added support for parsing LOG(FATAL) and DCHECK errors and their
     stack traces, as emitted by src/base/debug/stack_trace_android.cc
 Added support for finding symbols when library is loaded directly from the APK.
diff --git a/third_party/android_platform/development/scripts/symbol.py b/third_party/android_platform/development/scripts/symbol.py
index dcb0e77..4cde7d96 100755
--- a/third_party/android_platform/development/scripts/symbol.py
+++ b/third_party/android_platform/development/scripts/symbol.py
@@ -452,6 +452,9 @@
 
 
   symbols = SYMBOLS_DIR + lib
+  if not os.path.splitext(symbols)[1] in ['', '.so', '.apk']:
+    return None
+
   if not os.path.isfile(symbols):
     return None
 
diff --git a/third_party/android_protobuf/BUILD.gn b/third_party/android_protobuf/BUILD.gn
index 7863b079..2a07fc2 100644
--- a/third_party/android_protobuf/BUILD.gn
+++ b/third_party/android_protobuf/BUILD.gn
@@ -28,17 +28,24 @@
       "src/src/google/protobuf/compiler/cpp/cpp_service.cc",
       "src/src/google/protobuf/compiler/cpp/cpp_string_field.cc",
       "src/src/google/protobuf/compiler/importer.cc",
+      "src/src/google/protobuf/compiler/java/java_context.cc",
+      "src/src/google/protobuf/compiler/java/java_doc_comment.cc",
       "src/src/google/protobuf/compiler/java/java_enum.cc",
       "src/src/google/protobuf/compiler/java/java_enum_field.cc",
       "src/src/google/protobuf/compiler/java/java_extension.cc",
       "src/src/google/protobuf/compiler/java/java_field.cc",
       "src/src/google/protobuf/compiler/java/java_file.cc",
       "src/src/google/protobuf/compiler/java/java_generator.cc",
+      "src/src/google/protobuf/compiler/java/java_generator_factory.cc",
       "src/src/google/protobuf/compiler/java/java_helpers.cc",
+      "src/src/google/protobuf/compiler/java/java_lazy_message_field.cc",
       "src/src/google/protobuf/compiler/java/java_message.cc",
       "src/src/google/protobuf/compiler/java/java_message_field.cc",
+      "src/src/google/protobuf/compiler/java/java_name_resolver.cc",
       "src/src/google/protobuf/compiler/java/java_primitive_field.cc",
       "src/src/google/protobuf/compiler/java/java_service.cc",
+      "src/src/google/protobuf/compiler/java/java_shared_code_generator.cc",
+      "src/src/google/protobuf/compiler/java/java_string_field.cc",
       "src/src/google/protobuf/compiler/javamicro/javamicro_enum.cc",
       "src/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc",
       "src/src/google/protobuf/compiler/javamicro/javamicro_field.cc",
@@ -76,6 +83,7 @@
       "src/src/google/protobuf/io/coded_stream.cc",
       "src/src/google/protobuf/io/gzip_stream.cc",
       "src/src/google/protobuf/io/printer.cc",
+      "src/src/google/protobuf/io/strtod.cc",
       "src/src/google/protobuf/io/tokenizer.cc",
       "src/src/google/protobuf/io/zero_copy_stream.cc",
       "src/src/google/protobuf/io/zero_copy_stream_impl.cc",
@@ -85,9 +93,12 @@
       "src/src/google/protobuf/reflection_ops.cc",
       "src/src/google/protobuf/repeated_field.cc",
       "src/src/google/protobuf/service.cc",
+      "src/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc",
+      "src/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc",
       "src/src/google/protobuf/stubs/common.cc",
       "src/src/google/protobuf/stubs/hash.cc",
       "src/src/google/protobuf/stubs/once.cc",
+      "src/src/google/protobuf/stubs/stringprintf.cc",
       "src/src/google/protobuf/stubs/structurally_valid.cc",
       "src/src/google/protobuf/stubs/strutil.cc",
       "src/src/google/protobuf/stubs/substitute.cc",
@@ -127,6 +138,8 @@
       "src/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java",
       "src/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java",
       "src/java/src/main/java/com/google/protobuf/nano/Extension.java",
+      "src/java/src/main/java/com/google/protobuf/nano/FieldArray.java",
+      "src/java/src/main/java/com/google/protobuf/nano/FieldData.java",
       "src/java/src/main/java/com/google/protobuf/nano/InternalNano.java",
       "src/java/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java",
       "src/java/src/main/java/com/google/protobuf/nano/MessageNano.java",
diff --git a/third_party/android_protobuf/README.chromium b/third_party/android_protobuf/README.chromium
index 26e64366..358088c5 100644
--- a/third_party/android_protobuf/README.chromium
+++ b/third_party/android_protobuf/README.chromium
@@ -2,9 +2,9 @@
 Short Name: protobuf
 URL: https://android.googlesource.com/platform/external/protobuf.git
 Version: 2.2.0a
-Revision: L-preview
+Revision: M-preview
 License: BSD
-License File: src/COPYING.txt
+License File: src/LICENSE
 Security Critical: no
 
 Description:
diff --git a/third_party/android_protobuf/android_protobuf.gyp b/third_party/android_protobuf/android_protobuf.gyp
index 5d1f1015..9d7061bc 100644
--- a/third_party/android_protobuf/android_protobuf.gyp
+++ b/third_party/android_protobuf/android_protobuf.gyp
@@ -14,6 +14,7 @@
             # does not have a src/ subfolder.
             'java_in_dir': '../../build/android/empty',
             'additional_src_dirs': [ 'src/java/src/main/java/com/google/protobuf/nano' ],
+            'run_findbugs': 0,
           },
           'includes': [ '../../build/java.gypi' ],
         },
@@ -64,17 +65,24 @@
             'src/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc',
             'src/src/google/protobuf/compiler/cpp/cpp_service.cc',
             'src/src/google/protobuf/compiler/cpp/cpp_string_field.cc',
+            'src/src/google/protobuf/compiler/java/java_context.cc',
+            'src/src/google/protobuf/compiler/java/java_doc_comment.cc',
             'src/src/google/protobuf/compiler/java/java_enum.cc',
             'src/src/google/protobuf/compiler/java/java_enum_field.cc',
             'src/src/google/protobuf/compiler/java/java_extension.cc',
             'src/src/google/protobuf/compiler/java/java_field.cc',
             'src/src/google/protobuf/compiler/java/java_file.cc',
             'src/src/google/protobuf/compiler/java/java_generator.cc',
+            'src/src/google/protobuf/compiler/java/java_generator_factory.cc',
             'src/src/google/protobuf/compiler/java/java_helpers.cc',
+            'src/src/google/protobuf/compiler/java/java_lazy_message_field.cc',
             'src/src/google/protobuf/compiler/java/java_message.cc',
             'src/src/google/protobuf/compiler/java/java_message_field.cc',
+            'src/src/google/protobuf/compiler/java/java_name_resolver.cc',
             'src/src/google/protobuf/compiler/java/java_primitive_field.cc',
             'src/src/google/protobuf/compiler/java/java_service.cc',
+            'src/src/google/protobuf/compiler/java/java_shared_code_generator.cc',
+            'src/src/google/protobuf/compiler/java/java_string_field.cc',
             'src/src/google/protobuf/compiler/javamicro/javamicro_enum.cc',
             'src/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc',
             'src/src/google/protobuf/compiler/javamicro/javamicro_field.cc',
@@ -98,13 +106,17 @@
             'src/src/google/protobuf/io/coded_stream.cc',
             'src/src/google/protobuf/io/gzip_stream.cc',
             'src/src/google/protobuf/io/printer.cc',
+            'src/src/google/protobuf/io/strtod.cc',
             'src/src/google/protobuf/io/tokenizer.cc',
             'src/src/google/protobuf/io/zero_copy_stream.cc',
             'src/src/google/protobuf/io/zero_copy_stream_impl.cc',
             'src/src/google/protobuf/io/zero_copy_stream_impl_lite.cc',
+            'src/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc',
+            'src/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc',
             'src/src/google/protobuf/stubs/common.cc',
             'src/src/google/protobuf/stubs/hash.cc',
             'src/src/google/protobuf/stubs/once.cc',
+            'src/src/google/protobuf/stubs/stringprintf.cc',
             'src/src/google/protobuf/stubs/structurally_valid.cc',
             'src/src/google/protobuf/stubs/strutil.cc',
             'src/src/google/protobuf/stubs/substitute.cc',
diff --git a/third_party/android_swipe_refresh/README.chromium b/third_party/android_swipe_refresh/README.chromium
index 3fde9b2..9f016b2 100644
--- a/third_party/android_swipe_refresh/README.chromium
+++ b/third_party/android_swipe_refresh/README.chromium
@@ -1,4 +1,4 @@
-Name: Android Open Source Project
+Name: Android Open Source Project - App Compat Library
 URL: https://android.googlesource.com/platform/frameworks/support
 Version: unknown
 License: Apache 2.0
diff --git a/third_party/cacheinvalidation/src/proto/android_channel.proto b/third_party/cacheinvalidation/src/proto/android_channel.proto
index e4a92f5..8f45997 100644
--- a/third_party/cacheinvalidation/src/proto/android_channel.proto
+++ b/third_party/cacheinvalidation/src/proto/android_channel.proto
@@ -35,6 +35,7 @@
 // channel version controls the expected envelope syntax and semantics of
 // http and c2dm messages sent between the client and server.
 enum MajorVersion {
+  option allow_alias = true;
 
   // The initial version of the android channel protocol.  Inbound and
   // outbound channel packets contained a single binary protocol message only.
diff --git a/third_party/class-dump/class-dump.gyp b/third_party/class-dump/class-dump.gyp
index 68dec19..60d06789 100644
--- a/third_party/class-dump/class-dump.gyp
+++ b/third_party/class-dump/class-dump.gyp
@@ -171,10 +171,16 @@
         'src/Source/NSString-CDExtensions.m',
         'src/Source/cd_objc2.h',
       ],
-      'libraries': [
-        '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
-        '$(SDKROOT)/usr/lib/libcrypto.dylib',
-      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+        ],
+        'xcode_settings': {
+          'OTHER_LDFLAGS': [
+            '-lcrypto',
+          ],
+        },
+      },
       'include_dirs': [
         'src/Source',
       ],
diff --git a/third_party/closure_compiler/compiler_test.py b/third_party/closure_compiler/compiler_test.py
index a39776a..d1ff08e 100755
--- a/third_party/closure_compiler/compiler_test.py
+++ b/third_party/closure_compiler/compiler_test.py
@@ -20,6 +20,8 @@
 _POLYMER_EXTERNS = os.path.join(_SRC_DIR, "third_party", "polymer", "v1_0",
                                 "components-chromium", "polymer-externs",
                                 "polymer.externs.js")
+_CHROME_SEND_EXTERNS = os.path.join(_SRC_DIR, "third_party", "closure_compiler",
+                                    "externs", "chrome_send_externs.js")
 
 
 class CompilerTest(unittest.TestCase):
@@ -41,8 +43,9 @@
     FileCache._cache[file_path] = source_code
     out_file, out_map = self._createOutFiles()
 
+    externs = [_POLYMER_EXTERNS, _CHROME_SEND_EXTERNS]
     found_errors, stderr = self._checker.check(file_path,
-                                               externs=[_POLYMER_EXTERNS],
+                                               externs=externs,
                                                out_file=out_file,
                                                output_wrapper=output_wrapper)
     return found_errors, stderr, out_file, out_map
diff --git a/third_party/closure_compiler/externs/settings_private.js b/third_party/closure_compiler/externs/settings_private.js
index 3de196a..8cc4619e 100644
--- a/third_party/closure_compiler/externs/settings_private.js
+++ b/third_party/closure_compiler/externs/settings_private.js
@@ -1,11 +1,4 @@
-// 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.
-
-/**
- * @fileoverview Externs generated from namespace: settingsPrivate
- * @externs
- */
+/** @fileoverview Externs generated from namespace: settingsPrivate */
 
 /**
  * @const
@@ -13,53 +6,77 @@
 chrome.settingsPrivate = {};
 
 /**
+ * @enum {string}
+ * @see https://developer.chrome.com/extensions/settingsPrivate#type-PrefType
+ */
+chrome.settingsPrivate.PrefType = {
+  BOOLEAN: 'BOOLEAN',
+  NUMBER: 'NUMBER',
+  STRING: 'STRING',
+  URL: 'URL',
+  LIST: 'LIST',
+};
+
+/**
+ * @enum {string}
+ * @see https://developer.chrome.com/extensions/settingsPrivate#type-PolicySource
+ */
+chrome.settingsPrivate.PolicySource = {
+  DEVICE: 'DEVICE',
+  USER: 'USER',
+};
+
+/**
+ * @enum {string}
+ * @see https://developer.chrome.com/extensions/settingsPrivate#type-PolicyEnforcement
+ */
+chrome.settingsPrivate.PolicyEnforcement = {
+  ENFORCED: 'ENFORCED',
+  RECOMMENDED: 'RECOMMENDED',
+};
+
+/**
  * @typedef {{
  *   key: string,
- *   type: chrome.settingsPrivate.PrefType,
+ *   type: !chrome.settingsPrivate.PrefType,
  *   value: *,
- *   policySource: (chrome.settingsPrivate.PolicySource|undefined),
- *   policyEnforcement: (chrome.settingsPrivate.PolicyEnforcement|undefined),
+ *   policySource: (!chrome.settingsPrivate.PolicySource|undefined),
+ *   policyEnforcement: (!chrome.settingsPrivate.PolicyEnforcement|undefined)
  * }}
+ * @see https://developer.chrome.com/extensions/settingsPrivate#type-PrefObject
  */
-chrome.settingsPrivate.PrefObject;
-
-/**
- * @typedef {function(success)}
- */
-chrome.settingsPrivate.OnPrefSetCallback;
-
-/**
- * @typedef {function(!Array<chrome.settingsPrivate.PrefObject>)}
- */
-chrome.settingsPrivate.GetAllPrefsCallback;
-
-/**
- * @typedef {function(chrome.settingsPrivate.PrefObject)}
- */
-chrome.settingsPrivate.GetPrefCallback;
+var PrefObject;
 
 /**
  * Sets a settings value.
- * @param {string} name
- * @param {*} value
- * @param {string} pageId
- * @param {chrome.settingsPrivate.OnPrefSetCallback} callback
+ * @param {string} name The name of the pref.
+ * @param {*} value The new value of the pref.
+ * @param {string} pageId The user metrics identifier or null.
+ * @param {function(boolean):void} callback The callback for whether the pref
+ *     was set or not.
+ * @see https://developer.chrome.com/extensions/settingsPrivate#method-setPref
  */
-chrome.settingsPrivate.setPref =
-    function(name, value, pageId, callback) {};
+chrome.settingsPrivate.setPref = function(name, value, pageId, callback) {};
 
 /**
- * Gets all the prefs.
- * @param {chrome.settingsPrivate.GetAllPrefsCallback} callback
+ * Gets an array of all the prefs.
+ * @param {function(!Array<PrefObject>):void} callback
+ * @see https://developer.chrome.com/extensions/settingsPrivate#method-getAllPrefs
  */
 chrome.settingsPrivate.getAllPrefs = function(callback) {};
 
 /**
  * Gets the value of a specific pref.
  * @param {string} name
- * @param {chrome.settingsPrivate.GetPrefCallback} callback
+ * @param {function(PrefObject):void} callback
+ * @see https://developer.chrome.com/extensions/settingsPrivate#method-getPref
  */
 chrome.settingsPrivate.getPref = function(name, callback) {};
 
-/** @type {!ChromeEvent} */
+/**
+ * <p>Fired when a set of prefs has changed.</p><p>|prefs| The prefs that
+ * changed.</p>
+ * @type {!ChromeEvent}
+ * @see https://developer.chrome.com/extensions/settingsPrivate#event-onPrefsChanged
+ */
 chrome.settingsPrivate.onPrefsChanged;
diff --git a/third_party/dom_distiller_js/README.chromium b/third_party/dom_distiller_js/README.chromium
index ff27690..acf0f25 100644
--- a/third_party/dom_distiller_js/README.chromium
+++ b/third_party/dom_distiller_js/README.chromium
@@ -1,6 +1,6 @@
 Name: dom-distiller-js
 URL: https://github.com/chromium/dom-distiller
-Version: aa79b394e7
+Version: 6300dcfdb5
 License: BSD
 Security Critical: yes
 
diff --git a/third_party/freetype-android/BUILD.gn b/third_party/freetype-android/BUILD.gn
index 67f6fe8d..e8b3aa8 100644
--- a/third_party/freetype-android/BUILD.gn
+++ b/third_party/freetype-android/BUILD.gn
@@ -5,7 +5,10 @@
 assert(is_android, "This library is only used on Android")
 
 config("freetype_config") {
-  include_dirs = [ "src/include" ]
+  include_dirs = [
+    "include",
+    "src/include",
+  ]
 }
 
 source_set("freetype") {
@@ -14,12 +17,12 @@
     # same order as in Android.mk to ease maintenance.
     "src/src/base/ftbbox.c",
     "src/src/base/ftbitmap.c",
+    "src/src/base/ftfntfmt.c",
     "src/src/base/ftfstype.c",
     "src/src/base/ftglyph.c",
     "src/src/base/ftlcdfil.c",
     "src/src/base/ftstroke.c",
     "src/src/base/fttype1.c",
-    "src/src/base/ftxf86.c",
     "src/src/base/ftbase.c",
     "src/src/base/ftsystem.c",
     "src/src/base/ftinit.c",
@@ -39,6 +42,9 @@
   defines = [
     "FT2_BUILD_LIBRARY",
     "DARWIN_NO_CARBON",
+    # Long directory name to avoid accidentally using wrong headers.
+    "FT_CONFIG_MODULES_H=<freetype-android-config/ftmodule.h>",
+    "FT_CONFIG_OPTIONS_H=<freetype-android-config/ftoption.h>",
   ]
 
   public_configs = [ ":freetype_config" ]
diff --git a/third_party/freetype-android/README.chromium b/third_party/freetype-android/README.chromium
index 45032d2..72d405a 100644
--- a/third_party/freetype-android/README.chromium
+++ b/third_party/freetype-android/README.chromium
@@ -1,18 +1,26 @@
-Name: Freetype
-URL: https://android.googlesource.com/platform/external/freetype/
-Version: 9c745321260bb728ab1cd1c8fd5f075854b2ad49
+Name: FreeType
+URL: http://www.freetype.org/
+Version: VER-2-6
+Revision: e186230678ee8e4ea4ac4797ece8125761e3225a
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
-License File: src/NOTICE
+License File: src/docs/FTL.TXT
 Security Critical: yes
 License Android Compatible: yes
 
 Description:
-This package was copied from Android source tree and just used for Android.
-For other platforms, the freetype is normally found outside the Chromium tree;
-e.g. on Mac it's in /usr/include
+This package tracks upstream FreeType, but the build files and configuration
+are based on the Android source tree. This package is only used for Android.
+For other platforms the system FreeType library is used.
 
 How to update:
-1. Follow the directions in src/README.chromium to update the source.
-2. Update freetype.gyp and BUILD.gn to reflect any changes in src/Android.mk.
-3. Commit build changes while rolling Chromium DEPS to new commit.
+1. Find the desired commit in
+   https://chromium.googlesource.com/chromium/src/third_party/freetype2/ .
+   If such a commit does not yet exist, branch from the appropriate point with
+   a branch name like "chromium/android/VER-X-X-X-updates" depending on the
+   FreeType tag being branched and commit changes there.
+2. Update freetype.gyp and BUILD.gn to reflect any changes. These should be kept
+   in sync with the Android.mk for FreeType in Android as possible.
+3. Update this file.
+4. Commit build changes while rolling Chromium's freetype-android DEPS to the
+   new commit.
diff --git a/third_party/freetype-android/freetype.gyp b/third_party/freetype-android/freetype.gyp
index 5db04b8..169f132 100644
--- a/third_party/freetype-android/freetype.gyp
+++ b/third_party/freetype-android/freetype.gyp
@@ -3,6 +3,9 @@
 # found in the LICENSE file.
 
 {
+  'variables': {
+    'ft2_dir': 'src',
+  },
   'conditions': [
     [ 'OS == "android"', {
       'targets': [
@@ -13,43 +16,48 @@
           'sources': [
             # The following files are not sorted alphabetically, but in the
             # same order as in Android.mk to ease maintenance.
-            'src/src/base/ftbbox.c',
-            'src/src/base/ftbitmap.c',
-            'src/src/base/ftfstype.c',
-            'src/src/base/ftglyph.c',
-            'src/src/base/ftlcdfil.c',
-            'src/src/base/ftstroke.c',
-            'src/src/base/fttype1.c',
-            'src/src/base/ftxf86.c',
-            'src/src/base/ftbase.c',
-            'src/src/base/ftsystem.c',
-            'src/src/base/ftinit.c',
-            'src/src/base/ftgasp.c',
-            'src/src/base/ftmm.c',
-            'src/src/gzip/ftgzip.c',
-            'src/src/raster/raster.c',
-            'src/src/sfnt/sfnt.c',
-            'src/src/smooth/smooth.c',
-            'src/src/autofit/autofit.c',
-            'src/src/truetype/truetype.c',
-            'src/src/cff/cff.c',
-            'src/src/psnames/psnames.c',
-            'src/src/pshinter/pshinter.c',
+            '<(ft2_dir)/src/base/ftbbox.c',
+            '<(ft2_dir)/src/base/ftbitmap.c',
+            '<(ft2_dir)/src/base/ftfntfmt.c',
+            '<(ft2_dir)/src/base/ftfstype.c',
+            '<(ft2_dir)/src/base/ftglyph.c',
+            '<(ft2_dir)/src/base/ftlcdfil.c',
+            '<(ft2_dir)/src/base/ftstroke.c',
+            '<(ft2_dir)/src/base/fttype1.c',
+            '<(ft2_dir)/src/base/ftbase.c',
+            '<(ft2_dir)/src/base/ftsystem.c',
+            '<(ft2_dir)/src/base/ftinit.c',
+            '<(ft2_dir)/src/base/ftgasp.c',
+            '<(ft2_dir)/src/base/ftmm.c',
+            '<(ft2_dir)/src/gzip/ftgzip.c',
+            '<(ft2_dir)/src/raster/raster.c',
+            '<(ft2_dir)/src/sfnt/sfnt.c',
+            '<(ft2_dir)/src/smooth/smooth.c',
+            '<(ft2_dir)/src/autofit/autofit.c',
+            '<(ft2_dir)/src/truetype/truetype.c',
+            '<(ft2_dir)/src/cff/cff.c',
+            '<(ft2_dir)/src/psnames/psnames.c',
+            '<(ft2_dir)/src/pshinter/pshinter.c',
           ],
           'dependencies': [
             '../libpng/libpng.gyp:libpng',
             '../zlib/zlib.gyp:zlib',
           ],
           'include_dirs': [
-            'src/include',
+            'include',
+            '<(ft2_dir)/include',
           ],
           'defines': [
             'FT2_BUILD_LIBRARY',
             'DARWIN_NO_CARBON',
+            # Long directory name to avoid accidentally using wrong headers.
+            'FT_CONFIG_MODULES_H=<freetype-android-config/ftmodule.h>',
+            'FT_CONFIG_OPTIONS_H=<freetype-android-config/ftoption.h>',
           ],
           'direct_dependent_settings': {
             'include_dirs': [
-              '../../third_party/freetype-android/src/include',
+              'include',
+              '<(ft2_dir)/include',
             ],
           },
         },
diff --git a/third_party/freetype-android/include/freetype-android-config/ftmodule.h b/third_party/freetype-android/include/freetype-android-config/ftmodule.h
new file mode 100644
index 0000000..8ec70b80
--- /dev/null
+++ b/third_party/freetype-android/include/freetype-android-config/ftmodule.h
@@ -0,0 +1,38 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftmodule.h                                                             */
+/*                                                                         */
+/*    User-selectable module macros.                                       */
+/*                                                                         */
+/*  Copyright 1996-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+FT_USE_MODULE( FT_Module_Class, autofit_module_class )
+FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class )
+FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class )
+FT_USE_MODULE( FT_Module_Class, psnames_module_class )
+FT_USE_MODULE( FT_Module_Class, pshinter_module_class )
+FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class )
+FT_USE_MODULE( FT_Module_Class, sfnt_module_class )
+FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class )
+FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcd_renderer_class )
+FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcdv_renderer_class )
+
+/*
+FT_USE_MODULE( FT_Driver_ClassRec, t1_driver_class )
+FT_USE_MODULE( FT_Driver_ClassRec, t1cid_driver_class )
+FT_USE_MODULE( FT_Driver_ClassRec, pfr_driver_class )
+FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class )
+FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class )
+FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class )
+FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class )
+FT_USE_MODULE( FT_Module_Class, psaux_module_class )
+*/
diff --git a/third_party/freetype-android/include/freetype-android-config/ftoption.h b/third_party/freetype-android/include/freetype-android-config/ftoption.h
new file mode 100644
index 0000000..24991961
--- /dev/null
+++ b/third_party/freetype-android/include/freetype-android-config/ftoption.h
@@ -0,0 +1,886 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftoption.h                                                             */
+/*                                                                         */
+/*    User-selectable configuration macros (specification only).           */
+/*                                                                         */
+/*  Copyright 1996-2015 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __FTOPTION_H__
+#define __FTOPTION_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                 USER-SELECTABLE CONFIGURATION MACROS                  */
+  /*                                                                       */
+  /* This file contains the default configuration macro definitions for    */
+  /* a standard build of the FreeType library.  There are three ways to    */
+  /* use this file to build project-specific versions of the library:      */
+  /*                                                                       */
+  /*  - You can modify this file by hand, but this is not recommended in   */
+  /*    cases where you would like to build several versions of the        */
+  /*    library from a single source directory.                            */
+  /*                                                                       */
+  /*  - You can put a copy of this file in your build directory, more      */
+  /*    precisely in `$BUILD/config/ftoption.h', where `$BUILD' is the     */
+  /*    name of a directory that is included _before_ the FreeType include */
+  /*    path during compilation.                                           */
+  /*                                                                       */
+  /*    The default FreeType Makefiles and Jamfiles use the build          */
+  /*    directory `builds/<system>' by default, but you can easily change  */
+  /*    that for your own projects.                                        */
+  /*                                                                       */
+  /*  - Copy the file <ft2build.h> to `$BUILD/ft2build.h' and modify it    */
+  /*    slightly to pre-define the macro FT_CONFIG_OPTIONS_H used to       */
+  /*    locate this file during the build.  For example,                   */
+  /*                                                                       */
+  /*      #define FT_CONFIG_OPTIONS_H  <myftoptions.h>                     */
+  /*      #include <config/ftheader.h>                                     */
+  /*                                                                       */
+  /*    will use `$BUILD/myftoptions.h' instead of this file for macro     */
+  /*    definitions.                                                       */
+  /*                                                                       */
+  /*    Note also that you can similarly pre-define the macro              */
+  /*    FT_CONFIG_MODULES_H used to locate the file listing of the modules */
+  /*    that are statically linked to the library at compile time.  By     */
+  /*    default, this file is <config/ftmodule.h>.                         */
+  /*                                                                       */
+  /* We highly recommend using the third method whenever possible.         */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /**** G E N E R A L   F R E E T Y P E   2   C O N F I G U R A T I O N ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Uncomment the line below if you want to activate sub-pixel rendering  */
+  /* (a.k.a. LCD rendering, or ClearType) in this build of the library.    */
+  /*                                                                       */
+  /* Note that this feature is covered by several Microsoft patents        */
+  /* and should not be activated in any default build of the library.      */
+  /*                                                                       */
+  /* This macro has no impact on the FreeType API, only on its             */
+  /* _implementation_.  For example, using FT_RENDER_MODE_LCD when calling */
+  /* FT_Render_Glyph still generates a bitmap that is 3 times wider than   */
+  /* the original size in case this macro isn't defined; however, each     */
+  /* triplet of subpixels has R=G=B.                                       */
+  /*                                                                       */
+  /* This is done to allow FreeType clients to run unmodified, forcing     */
+  /* them to display normal gray-level anti-aliased glyphs.                */
+  /*                                                                       */
+/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Many compilers provide a non-ANSI 64-bit data type that can be used   */
+  /* by FreeType to speed up some computations.  However, this will create */
+  /* some problems when compiling the library in strict ANSI mode.         */
+  /*                                                                       */
+  /* For this reason, the use of 64-bit integers is normally disabled when */
+  /* the __STDC__ macro is defined.  You can however disable this by       */
+  /* defining the macro FT_CONFIG_OPTION_FORCE_INT64 here.                 */
+  /*                                                                       */
+  /* For most compilers, this will only create compilation warnings when   */
+  /* building the library.                                                 */
+  /*                                                                       */
+  /* ObNote: The compiler-specific 64-bit integers are detected in the     */
+  /*         file `ftconfig.h' either statically or through the            */
+  /*         `configure' script on supported platforms.                    */
+  /*                                                                       */
+#undef FT_CONFIG_OPTION_FORCE_INT64
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* If this macro is defined, do not try to use an assembler version of   */
+  /* performance-critical functions (e.g. FT_MulFix).  You should only do  */
+  /* that to verify that the assembler function works properly, or to      */
+  /* execute benchmark tests of the various implementations.               */
+/* #define FT_CONFIG_OPTION_NO_ASSEMBLER */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* If this macro is defined, try to use an inlined assembler version of  */
+  /* the `FT_MulFix' function, which is a `hotspot' when loading and       */
+  /* hinting glyphs, and which should be executed as fast as possible.     */
+  /*                                                                       */
+  /* Note that if your compiler or CPU is not supported, this will default */
+  /* to the standard and portable implementation found in `ftcalc.c'.      */
+  /*                                                                       */
+#define FT_CONFIG_OPTION_INLINE_MULFIX
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* LZW-compressed file support.                                          */
+  /*                                                                       */
+  /*   FreeType now handles font files that have been compressed with the  */
+  /*   `compress' program.  This is mostly used to parse many of the PCF   */
+  /*   files that come with various X11 distributions.  The implementation */
+  /*   uses NetBSD's `zopen' to partially uncompress the file on the fly   */
+  /*   (see src/lzw/ftgzip.c).                                             */
+  /*                                                                       */
+  /*   Define this macro if you want to enable this `feature'.             */
+  /*                                                                       */
+#define FT_CONFIG_OPTION_USE_LZW
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Gzip-compressed file support.                                         */
+  /*                                                                       */
+  /*   FreeType now handles font files that have been compressed with the  */
+  /*   `gzip' program.  This is mostly used to parse many of the PCF files */
+  /*   that come with XFree86.  The implementation uses `zlib' to          */
+  /*   partially uncompress the file on the fly (see src/gzip/ftgzip.c).   */
+  /*                                                                       */
+  /*   Define this macro if you want to enable this `feature'.  See also   */
+  /*   the macro FT_CONFIG_OPTION_SYSTEM_ZLIB below.                       */
+  /*                                                                       */
+#define FT_CONFIG_OPTION_USE_ZLIB
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ZLib library selection                                                */
+  /*                                                                       */
+  /*   This macro is only used when FT_CONFIG_OPTION_USE_ZLIB is defined.  */
+  /*   It allows FreeType's `ftgzip' component to link to the system's     */
+  /*   installation of the ZLib library.  This is useful on systems like   */
+  /*   Unix or VMS where it generally is already available.                */
+  /*                                                                       */
+  /*   If you let it undefined, the component will use its own copy        */
+  /*   of the zlib sources instead.  These have been modified to be        */
+  /*   included directly within the component and *not* export external    */
+  /*   function names.  This allows you to link any program with FreeType  */
+  /*   _and_ ZLib without linking conflicts.                               */
+  /*                                                                       */
+  /*   Do not #undef this macro here since the build system might define   */
+  /*   it for certain configurations only.                                 */
+  /*                                                                       */
+/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Bzip2-compressed file support.                                        */
+  /*                                                                       */
+  /*   FreeType now handles font files that have been compressed with the  */
+  /*   `bzip2' program.  This is mostly used to parse many of the PCF      */
+  /*   files that come with XFree86.  The implementation uses `libbz2' to  */
+  /*   partially uncompress the file on the fly (see src/bzip2/ftbzip2.c). */
+  /*   Contrary to gzip, bzip2 currently is not included and need to use   */
+  /*   the system available bzip2 implementation.                          */
+  /*                                                                       */
+  /*   Define this macro if you want to enable this `feature'.             */
+  /*                                                                       */
+/* #define FT_CONFIG_OPTION_USE_BZIP2 */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define to disable the use of file stream functions and types, FILE,   */
+  /* fopen() etc.  Enables the use of smaller system libraries on embedded */
+  /* systems that have multiple system libraries, some with or without     */
+  /* file stream support, in the cases where file stream support is not    */
+  /* necessary such as memory loading of font files.                       */
+  /*                                                                       */
+/* #define FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* PNG bitmap support.                                                   */
+  /*                                                                       */
+  /*   FreeType now handles loading color bitmap glyphs in the PNG format. */
+  /*   This requires help from the external libpng library.  Uncompressed  */
+  /*   color bitmaps do not need any external libraries and will be        */
+  /*   supported regardless of this configuration.                         */
+  /*                                                                       */
+  /*   Define this macro if you want to enable this `feature'.             */
+  /*                                                                       */
+#define FT_CONFIG_OPTION_USE_PNG
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* HarfBuzz support.                                                     */
+  /*                                                                       */
+  /*   FreeType uses the HarfBuzz library to improve auto-hinting of       */
+  /*   OpenType fonts.  If available, many glyphs not directly addressable */
+  /*   by a font's character map will be hinted also.                      */
+  /*                                                                       */
+  /*   Define this macro if you want to enable this `feature'.             */
+  /*                                                                       */
+/* #define FT_CONFIG_OPTION_USE_HARFBUZZ */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* DLL export compilation                                                */
+  /*                                                                       */
+  /*   When compiling FreeType as a DLL, some systems/compilers need a     */
+  /*   special keyword in front OR after the return type of function       */
+  /*   declarations.                                                       */
+  /*                                                                       */
+  /*   Two macros are used within the FreeType source code to define       */
+  /*   exported library functions: FT_EXPORT and FT_EXPORT_DEF.            */
+  /*                                                                       */
+  /*     FT_EXPORT( return_type )                                          */
+  /*                                                                       */
+  /*       is used in a function declaration, as in                        */
+  /*                                                                       */
+  /*         FT_EXPORT( FT_Error )                                         */
+  /*         FT_Init_FreeType( FT_Library*  alibrary );                    */
+  /*                                                                       */
+  /*                                                                       */
+  /*     FT_EXPORT_DEF( return_type )                                      */
+  /*                                                                       */
+  /*       is used in a function definition, as in                         */
+  /*                                                                       */
+  /*         FT_EXPORT_DEF( FT_Error )                                     */
+  /*         FT_Init_FreeType( FT_Library*  alibrary )                     */
+  /*         {                                                             */
+  /*           ... some code ...                                           */
+  /*           return FT_Err_Ok;                                           */
+  /*         }                                                             */
+  /*                                                                       */
+  /*   You can provide your own implementation of FT_EXPORT and            */
+  /*   FT_EXPORT_DEF here if you want.  If you leave them undefined, they  */
+  /*   will be later automatically defined as `extern return_type' to      */
+  /*   allow normal compilation.                                           */
+  /*                                                                       */
+  /*   Do not #undef these macros here since the build system might define */
+  /*   them for certain configurations only.                               */
+  /*                                                                       */
+/* #define FT_EXPORT(x)      extern x */
+/* #define FT_EXPORT_DEF(x)  x */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Glyph Postscript Names handling                                       */
+  /*                                                                       */
+  /*   By default, FreeType 2 is compiled with the `psnames' module.  This */
+  /*   module is in charge of converting a glyph name string into a        */
+  /*   Unicode value, or return a Macintosh standard glyph name for the    */
+  /*   use with the TrueType `post' table.                                 */
+  /*                                                                       */
+  /*   Undefine this macro if you do not want `psnames' compiled in your   */
+  /*   build of FreeType.  This has the following effects:                 */
+  /*                                                                       */
+  /*   - The TrueType driver will provide its own set of glyph names,      */
+  /*     if you build it to support postscript names in the TrueType       */
+  /*     `post' table.                                                     */
+  /*                                                                       */
+  /*   - The Type 1 driver will not be able to synthesize a Unicode        */
+  /*     charmap out of the glyphs found in the fonts.                     */
+  /*                                                                       */
+  /*   You would normally undefine this configuration macro when building  */
+  /*   a version of FreeType that doesn't contain a Type 1 or CFF driver.  */
+  /*                                                                       */
+#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Postscript Names to Unicode Values support                            */
+  /*                                                                       */
+  /*   By default, FreeType 2 is built with the `PSNames' module compiled  */
+  /*   in.  Among other things, the module is used to convert a glyph name */
+  /*   into a Unicode value.  This is especially useful in order to        */
+  /*   synthesize on the fly a Unicode charmap from the CFF/Type 1 driver  */
+  /*   through a big table named the `Adobe Glyph List' (AGL).             */
+  /*                                                                       */
+  /*   Undefine this macro if you do not want the Adobe Glyph List         */
+  /*   compiled in your `PSNames' module.  The Type 1 driver will not be   */
+  /*   able to synthesize a Unicode charmap out of the glyphs found in the */
+  /*   fonts.                                                              */
+  /*                                                                       */
+#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Support for Mac fonts                                                 */
+  /*                                                                       */
+  /*   Define this macro if you want support for outline fonts in Mac      */
+  /*   format (mac dfont, mac resource, macbinary containing a mac         */
+  /*   resource) on non-Mac platforms.                                     */
+  /*                                                                       */
+  /*   Note that the `FOND' resource isn't checked.                        */
+  /*                                                                       */
+#define FT_CONFIG_OPTION_MAC_FONTS
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Guessing methods to access embedded resource forks                    */
+  /*                                                                       */
+  /*   Enable extra Mac fonts support on non-Mac platforms (e.g.           */
+  /*   GNU/Linux).                                                         */
+  /*                                                                       */
+  /*   Resource forks which include fonts data are stored sometimes in     */
+  /*   locations which users or developers don't expected.  In some cases, */
+  /*   resource forks start with some offset from the head of a file.  In  */
+  /*   other cases, the actual resource fork is stored in file different   */
+  /*   from what the user specifies.  If this option is activated,         */
+  /*   FreeType tries to guess whether such offsets or different file      */
+  /*   names must be used.                                                 */
+  /*                                                                       */
+  /*   Note that normal, direct access of resource forks is controlled via */
+  /*   the FT_CONFIG_OPTION_MAC_FONTS option.                              */
+  /*                                                                       */
+#ifdef FT_CONFIG_OPTION_MAC_FONTS
+#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK
+#endif
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Allow the use of FT_Incremental_Interface to load typefaces that      */
+  /* contain no glyph data, but supply it via a callback function.         */
+  /* This is required by clients supporting document formats which         */
+  /* supply font data incrementally as the document is parsed, such        */
+  /* as the Ghostscript interpreter for the PostScript language.           */
+  /*                                                                       */
+/* #define FT_CONFIG_OPTION_INCREMENTAL */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The size in bytes of the render pool used by the scan-line converter  */
+  /* to do all of its work.                                                */
+  /*                                                                       */
+#define FT_RENDER_POOL_SIZE  16384L
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* FT_MAX_MODULES                                                        */
+  /*                                                                       */
+  /*   The maximum number of modules that can be registered in a single    */
+  /*   FreeType library object.  32 is the default.                        */
+  /*                                                                       */
+#define FT_MAX_MODULES  32
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Debug level                                                           */
+  /*                                                                       */
+  /*   FreeType can be compiled in debug or trace mode.  In debug mode,    */
+  /*   errors are reported through the `ftdebug' component.  In trace      */
+  /*   mode, additional messages are sent to the standard output during    */
+  /*   execution.                                                          */
+  /*                                                                       */
+  /*   Define FT_DEBUG_LEVEL_ERROR to build the library in debug mode.     */
+  /*   Define FT_DEBUG_LEVEL_TRACE to build it in trace mode.              */
+  /*                                                                       */
+  /*   Don't define any of these macros to compile in `release' mode!      */
+  /*                                                                       */
+  /*   Do not #undef these macros here since the build system might define */
+  /*   them for certain configurations only.                               */
+  /*                                                                       */
+/* #define FT_DEBUG_LEVEL_ERROR */
+/* #define FT_DEBUG_LEVEL_TRACE */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Autofitter debugging                                                  */
+  /*                                                                       */
+  /*   If FT_DEBUG_AUTOFIT is defined, FreeType provides some means to     */
+  /*   control the autofitter behaviour for debugging purposes with global */
+  /*   boolean variables (consequently, you should *never* enable this     */
+  /*   while compiling in `release' mode):                                 */
+  /*                                                                       */
+  /*     _af_debug_disable_horz_hints                                      */
+  /*     _af_debug_disable_vert_hints                                      */
+  /*     _af_debug_disable_blue_hints                                      */
+  /*                                                                       */
+  /*   Additionally, the following functions provide dumps of various      */
+  /*   internal autofit structures to stdout (using `printf'):             */
+  /*                                                                       */
+  /*     af_glyph_hints_dump_points                                        */
+  /*     af_glyph_hints_dump_segments                                      */
+  /*     af_glyph_hints_dump_edges                                         */
+  /*     af_glyph_hints_get_num_segments                                   */
+  /*     af_glyph_hints_get_segment_offset                                 */
+  /*                                                                       */
+  /*   As an argument, they use another global variable:                   */
+  /*                                                                       */
+  /*     _af_debug_hints                                                   */
+  /*                                                                       */
+  /*   Please have a look at the `ftgrid' demo program to see how those    */
+  /*   variables and macros should be used.                                */
+  /*                                                                       */
+  /*   Do not #undef these macros here since the build system might define */
+  /*   them for certain configurations only.                               */
+  /*                                                                       */
+/* #define FT_DEBUG_AUTOFIT */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Memory Debugging                                                      */
+  /*                                                                       */
+  /*   FreeType now comes with an integrated memory debugger that is       */
+  /*   capable of detecting simple errors like memory leaks or double      */
+  /*   deletes.  To compile it within your build of the library, you       */
+  /*   should define FT_DEBUG_MEMORY here.                                 */
+  /*                                                                       */
+  /*   Note that the memory debugger is only activated at runtime when     */
+  /*   when the _environment_ variable `FT2_DEBUG_MEMORY' is defined also! */
+  /*                                                                       */
+  /*   Do not #undef this macro here since the build system might define   */
+  /*   it for certain configurations only.                                 */
+  /*                                                                       */
+/* #define FT_DEBUG_MEMORY */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Module errors                                                         */
+  /*                                                                       */
+  /*   If this macro is set (which is _not_ the default), the higher byte  */
+  /*   of an error code gives the module in which the error has occurred,  */
+  /*   while the lower byte is the real error code.                        */
+  /*                                                                       */
+  /*   Setting this macro makes sense for debugging purposes only, since   */
+  /*   it would break source compatibility of certain programs that use    */
+  /*   FreeType 2.                                                         */
+  /*                                                                       */
+  /*   More details can be found in the files ftmoderr.h and fterrors.h.   */
+  /*                                                                       */
+#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Position Independent Code                                             */
+  /*                                                                       */
+  /*   If this macro is set (which is _not_ the default), FreeType2 will   */
+  /*   avoid creating constants that require address fixups.  Instead the  */
+  /*   constants will be moved into a struct and additional intialization  */
+  /*   code will be used.                                                  */
+  /*                                                                       */
+  /*   Setting this macro is needed for systems that prohibit address      */
+  /*   fixups, such as BREW.                                               */
+  /*                                                                       */
+/* #define FT_CONFIG_OPTION_PIC */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****        S F N T   D R I V E R    C O N F I G U R A T I O N       ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define TT_CONFIG_OPTION_EMBEDDED_BITMAPS if you want to support       */
+  /* embedded bitmaps in all formats using the SFNT module (namely         */
+  /* TrueType & OpenType).                                                 */
+  /*                                                                       */
+#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to    */
+  /* load and enumerate the glyph Postscript names in a TrueType or        */
+  /* OpenType file.                                                        */
+  /*                                                                       */
+  /* Note that when you do not compile the `PSNames' module by undefining  */
+  /* the above FT_CONFIG_OPTION_POSTSCRIPT_NAMES, the `sfnt' module will   */
+  /* contain additional code used to read the PS Names table from a font.  */
+  /*                                                                       */
+  /* (By default, the module uses `PSNames' to extract glyph names.)       */
+  /*                                                                       */
+#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define TT_CONFIG_OPTION_SFNT_NAMES if your applications need to       */
+  /* access the internal name table in a SFNT-based format like TrueType   */
+  /* or OpenType.  The name table contains various strings used to         */
+  /* describe the font, like family name, copyright, version, etc.  It     */
+  /* does not contain any glyph name though.                               */
+  /*                                                                       */
+  /* Accessing SFNT names is done through the functions declared in        */
+  /* `ftsnames.h'.                                                         */
+  /*                                                                       */
+#define TT_CONFIG_OPTION_SFNT_NAMES
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TrueType CMap support                                                 */
+  /*                                                                       */
+  /*   Here you can fine-tune which TrueType CMap table format shall be    */
+  /*   supported.                                                          */
+#define TT_CONFIG_CMAP_FORMAT_0
+#define TT_CONFIG_CMAP_FORMAT_2
+#define TT_CONFIG_CMAP_FORMAT_4
+#define TT_CONFIG_CMAP_FORMAT_6
+#define TT_CONFIG_CMAP_FORMAT_8
+#define TT_CONFIG_CMAP_FORMAT_10
+#define TT_CONFIG_CMAP_FORMAT_12
+#define TT_CONFIG_CMAP_FORMAT_13
+#define TT_CONFIG_CMAP_FORMAT_14
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****    T R U E T Y P E   D R I V E R    C O N F I G U R A T I O N   ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define TT_CONFIG_OPTION_BYTECODE_INTERPRETER if you want to compile   */
+  /* a bytecode interpreter in the TrueType driver.                        */
+  /*                                                                       */
+  /* By undefining this, you will only compile the code necessary to load  */
+  /* TrueType glyphs without hinting.                                      */
+  /*                                                                       */
+  /*   Do not #undef this macro here, since the build system might         */
+  /*   define it for certain configurations only.                          */
+  /*                                                                       */
+#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING if you want to compile       */
+  /* EXPERIMENTAL subpixel hinting support into the TrueType driver.  This */
+  /* replaces the native TrueType hinting mechanism when anything but      */
+  /* FT_RENDER_MODE_MONO is requested.                                     */
+  /*                                                                       */
+  /* Enabling this causes the TrueType driver to ignore instructions under */
+  /* certain conditions.  This is done in accordance with the guide here,  */
+  /* with some minor differences:                                          */
+  /*                                                                       */
+  /*  http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */
+  /*                                                                       */
+  /* By undefining this, you only compile the code necessary to hint       */
+  /* TrueType glyphs with native TT hinting.                               */
+  /*                                                                       */
+  /*   This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be    */
+  /*   defined.                                                            */
+  /*                                                                       */
+/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* If you define TT_CONFIG_OPTION_UNPATENTED_HINTING, a special version  */
+  /* of the TrueType bytecode interpreter is used that doesn't implement   */
+  /* any of the patented opcodes and algorithms.  The patents related to   */
+  /* TrueType hinting have expired worldwide since May 2010; this option   */
+  /* is now deprecated.                                                    */
+  /*                                                                       */
+  /* Note that the TT_CONFIG_OPTION_UNPATENTED_HINTING macro is *ignored*  */
+  /* if you define TT_CONFIG_OPTION_BYTECODE_INTERPRETER; in other words,  */
+  /* either define TT_CONFIG_OPTION_BYTECODE_INTERPRETER or                */
+  /* TT_CONFIG_OPTION_UNPATENTED_HINTING but not both at the same time.    */
+  /*                                                                       */
+  /* This macro is only useful for a small number of font files (mostly    */
+  /* for Asian scripts) that require bytecode interpretation to properly   */
+  /* load glyphs.  For all other fonts, this produces unpleasant results,  */
+  /* thus the unpatented interpreter is never used to load glyphs from     */
+  /* TrueType fonts unless one of the following two options is used.       */
+  /*                                                                       */
+  /*   - The unpatented interpreter is explicitly activated by the user    */
+  /*     through the FT_PARAM_TAG_UNPATENTED_HINTING parameter tag         */
+  /*     when opening the FT_Face.                                         */
+  /*                                                                       */
+  /*   - FreeType detects that the FT_Face corresponds to one of the       */
+  /*     `trick' fonts (e.g., `Mingliu') it knows about.  The font engine  */
+  /*     contains a hard-coded list of font names and other matching       */
+  /*     parameters (see function `tt_face_init' in file                   */
+  /*     `src/truetype/ttobjs.c').                                         */
+  /*                                                                       */
+  /* Here a sample code snippet for using FT_PARAM_TAG_UNPATENTED_HINTING. */
+  /*                                                                       */
+  /*   {                                                                   */
+  /*     FT_Parameter  parameter;                                          */
+  /*     FT_Open_Args  open_args;                                          */
+  /*                                                                       */
+  /*                                                                       */
+  /*     parameter.tag = FT_PARAM_TAG_UNPATENTED_HINTING;                  */
+  /*                                                                       */
+  /*     open_args.flags      = FT_OPEN_PATHNAME | FT_OPEN_PARAMS;         */
+  /*     open_args.pathname   = my_font_pathname;                          */
+  /*     open_args.num_params = 1;                                         */
+  /*     open_args.params     = &parameter;                                */
+  /*                                                                       */
+  /*     error = FT_Open_Face( library, &open_args, index, &face );        */
+  /*     ...                                                               */
+  /*   }                                                                   */
+  /*                                                                       */
+/* #define TT_CONFIG_OPTION_UNPATENTED_HINTING */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED to compile the        */
+  /* TrueType glyph loader to use Apple's definition of how to handle      */
+  /* component offsets in composite glyphs.                                */
+  /*                                                                       */
+  /* Apple and MS disagree on the default behavior of component offsets    */
+  /* in composites.  Apple says that they should be scaled by the scaling  */
+  /* factors in the transformation matrix (roughly, it's more complex)     */
+  /* while MS says they should not.  OpenType defines two bits in the      */
+  /* composite flags array which can be used to disambiguate, but old      */
+  /* fonts will not have them.                                             */
+  /*                                                                       */
+  /*   http://www.microsoft.com/typography/otspec/glyf.htm                 */
+  /*   https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html */
+  /*                                                                       */
+#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define TT_CONFIG_OPTION_GX_VAR_SUPPORT if you want to include         */
+  /* support for Apple's distortable font technology (fvar, gvar, cvar,    */
+  /* and avar tables).  This has many similarities to Type 1 Multiple      */
+  /* Masters support.                                                      */
+  /*                                                                       */
+#define TT_CONFIG_OPTION_GX_VAR_SUPPORT
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define TT_CONFIG_OPTION_BDF if you want to include support for        */
+  /* an embedded `BDF ' table within SFNT-based bitmap formats.            */
+  /*                                                                       */
+#define TT_CONFIG_OPTION_BDF
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****      T Y P E 1   D R I V E R    C O N F I G U R A T I O N       ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* T1_MAX_DICT_DEPTH is the maximum depth of nest dictionaries and       */
+  /* arrays in the Type 1 stream (see t1load.c).  A minimum of 4 is        */
+  /* required.                                                             */
+  /*                                                                       */
+#define T1_MAX_DICT_DEPTH  5
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine   */
+  /* calls during glyph loading.                                           */
+  /*                                                                       */
+#define T1_MAX_SUBRS_CALLS  16
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity.  A     */
+  /* minimum of 16 is required.                                            */
+  /*                                                                       */
+  /* The Chinese font MingTiEG-Medium (CNS 11643 character set) needs 256. */
+  /*                                                                       */
+#define T1_MAX_CHARSTRINGS_OPERANDS  256
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define this configuration macro if you want to prevent the            */
+  /* compilation of `t1afm', which is in charge of reading Type 1 AFM      */
+  /* files into an existing face.  Note that if set, the T1 driver will be */
+  /* unable to produce kerning distances.                                  */
+  /*                                                                       */
+#undef T1_CONFIG_OPTION_NO_AFM
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define this configuration macro if you want to prevent the            */
+  /* compilation of the Multiple Masters font support in the Type 1        */
+  /* driver.                                                               */
+  /*                                                                       */
+#undef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****         C F F   D R I V E R    C O N F I G U R A T I O N        ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Using CFF_CONFIG_OPTION_DARKENING_PARAMETER_{X,Y}{1,2,3,4} it is      */
+  /* possible to set up the default values of the four control points that */
+  /* define the stem darkening behaviour of the (new) CFF engine.  For     */
+  /* more details please read the documentation of the                     */
+  /* `darkening-parameters' property of the cff driver module (file        */
+  /* `ftcffdrv.h'), which allows the control at run-time.                  */
+  /*                                                                       */
+  /* Do *not* undefine these macros!                                       */
+  /*                                                                       */
+#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1   500
+#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1   400
+
+#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2  1000
+#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2   275
+
+#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3  1667
+#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3   275
+
+#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4  2333
+#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4     0
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* CFF_CONFIG_OPTION_OLD_ENGINE controls whether the pre-Adobe CFF       */
+  /* engine gets compiled into FreeType.  If defined, it is possible to    */
+  /* switch between the two engines using the `hinting-engine' property of */
+  /* the cff driver module.                                                */
+  /*                                                                       */
+/* #define CFF_CONFIG_OPTION_OLD_ENGINE */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****    A U T O F I T   M O D U L E    C O N F I G U R A T I O N     ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Compile autofit module with CJK (Chinese, Japanese, Korean) script    */
+  /* support.                                                              */
+  /*                                                                       */
+#define AF_CONFIG_OPTION_CJK
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Compile autofit module with Indic script support.                     */
+  /*                                                                       */
+#define AF_CONFIG_OPTION_INDIC
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Compile autofit module with warp hinting.  The idea of the warping    */
+  /* code is to slightly scale and shift a glyph within a single dimension */
+  /* so that as much of its segments are aligned (more or less) on the     */
+  /* grid.  To find out the optimal scaling and shifting value, various    */
+  /* parameter combinations are tried and scored.                          */
+  /*                                                                       */
+  /* This experimental option is active only if the rendering mode is      */
+  /* FT_RENDER_MODE_LIGHT; you can switch warping on and off with the      */
+  /* `warping' property of the auto-hinter (see file `ftautoh.h' for more  */
+  /* information; by default it is switched off).                          */
+  /*                                                                       */
+/*#define AF_CONFIG_OPTION_USE_WARPER*/
+
+  /* */
+
+
+  /*
+   * This macro is obsolete.  Support has been removed in FreeType
+   * version 2.5.
+   */
+/* #define FT_CONFIG_OPTION_OLD_INTERNALS */
+
+
+  /*
+   * This macro is defined if either unpatented or native TrueType
+   * hinting is requested by the definitions above.
+   */
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#define  TT_USE_BYTECODE_INTERPRETER
+#undef   TT_CONFIG_OPTION_UNPATENTED_HINTING
+#elif defined TT_CONFIG_OPTION_UNPATENTED_HINTING
+#define  TT_USE_BYTECODE_INTERPRETER
+#endif
+
+
+  /*
+   * Check CFF darkening parameters.  The checks are the same as in function
+   * `cff_property_set' in file `cffdrivr.c'.
+   */
+#if CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 < 0   || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 < 0   || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 < 0   || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 < 0   || \
+                                                      \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 < 0   || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 < 0   || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 < 0   || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 < 0   || \
+                                                      \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 >        \
+      CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2     || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 >        \
+      CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3     || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 >        \
+      CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4     || \
+                                                      \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 > 500 || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 > 500 || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 > 500 || \
+    CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 > 500
+#error "Invalid CFF darkening parameters!"
+#endif
+
+FT_END_HEADER
+
+
+#endif /* __FTOPTION_H__ */
+
+
+/* END */
diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc
index 8ca4cc47..67a3a54 100644
--- a/third_party/leveldatabase/env_chromium.cc
+++ b/third_party/leveldatabase/env_chromium.cc
@@ -320,11 +320,7 @@
 
 class IDBEnv : public ChromiumEnv {
  public:
-  IDBEnv() : ChromiumEnv() {
-    name_ = "LevelDBEnv.IDB";
-    uma_ioerror_base_name_ = name_ + ".IOError.BFE";
-    make_backup_ = true;
-  }
+  IDBEnv() : ChromiumEnv("LevelDBEnv.IDB", true /* make_backup */) {}
 };
 
 base::LazyInstance<IDBEnv>::Leaky idb_env = LAZY_INSTANCE_INITIALIZER;
@@ -517,8 +513,11 @@
 }
 
 ChromiumEnv::ChromiumEnv()
-    : name_("LevelDBEnv"),
-      make_backup_(false),
+    : ChromiumEnv("LevelDBEnv", false /* make_backup */) {}
+
+ChromiumEnv::ChromiumEnv(const std::string& name, bool make_backup)
+    : name_(name),
+      make_backup_(make_backup),
       bgsignal_(&mu_),
       started_bgthread_(false),
       kMaxRetryTimeMillis(1000) {
diff --git a/third_party/leveldatabase/env_chromium.h b/third_party/leveldatabase/env_chromium.h
index 622cae59..55a064a 100644
--- a/third_party/leveldatabase/env_chromium.h
+++ b/third_party/leveldatabase/env_chromium.h
@@ -139,9 +139,7 @@
                                     leveldb::Logger** result);
 
  protected:
-  std::string name_;
-  std::string uma_ioerror_base_name_;
-  bool make_backup_;
+  ChromiumEnv(const std::string& name, bool make_backup);
 
  private:
   static const char* FileErrorString(base::File::Error error);
@@ -193,6 +191,10 @@
 
   base::FilePath test_directory_;
 
+  std::string name_;
+  std::string uma_ioerror_base_name_;
+  bool make_backup_;
+
   base::Lock mu_;
   base::ConditionVariable bgsignal_;
   bool started_bgthread_;
diff --git a/third_party/libjingle/BUILD.gn b/third_party/libjingle/BUILD.gn
index 23663d9..ad7e954 100644
--- a/third_party/libjingle/BUILD.gn
+++ b/third_party/libjingle/BUILD.gn
@@ -417,8 +417,6 @@
       "source/talk/media/base/constants.cc",
       "source/talk/media/base/constants.h",
       "source/talk/media/base/cryptoparams.h",
-      "source/talk/media/base/filemediaengine.cc",
-      "source/talk/media/base/filemediaengine.h",
       "source/talk/media/base/hybriddataengine.h",
       "source/talk/media/base/mediachannel.h",
       "source/talk/media/base/mediaengine.cc",
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index 8998b97..1a217c8 100644
--- a/third_party/libjingle/README.chromium
+++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@
 Name: libjingle
 URL: http://code.google.com/p/webrtc/
 Version: unknown
-Revision: 9384
+Revision: 9415
 License: BSD
 License File: source/talk/COPYING
 Security Critical: yes
diff --git a/third_party/libjingle/libjingle.gyp b/third_party/libjingle/libjingle.gyp
index a415ae8..aec1019 100644
--- a/third_party/libjingle/libjingle.gyp
+++ b/third_party/libjingle/libjingle.gyp
@@ -401,8 +401,6 @@
             '<(libjingle_source)/talk/media/base/constants.cc',
             '<(libjingle_source)/talk/media/base/constants.h',
             '<(libjingle_source)/talk/media/base/cryptoparams.h',
-            '<(libjingle_source)/talk/media/base/filemediaengine.cc',
-            '<(libjingle_source)/talk/media/base/filemediaengine.h',
             '<(libjingle_source)/talk/media/base/hybriddataengine.h',
             '<(libjingle_source)/talk/media/base/mediachannel.h',
             '<(libjingle_source)/talk/media/base/mediaengine.cc',
diff --git a/third_party/libusb/README.chromium b/third_party/libusb/README.chromium
index e74344c..d548a7ebb 100644
--- a/third_party/libusb/README.chromium
+++ b/third_party/libusb/README.chromium
@@ -19,4 +19,5 @@
 - upstream-tick147.patch has been applied.
 - linux-udev.patch has been applied.
 - composite-hid-close.patch has been applied.
-- assign-endpoints-checks.patch has been applied.
\ No newline at end of file
+- assign-endpoints-checks.patch has been applied.
+- open-fd.patch has been applied.
diff --git a/third_party/libusb/open-fd.patch b/third_party/libusb/open-fd.patch
new file mode 100644
index 0000000..5c5eb12
--- /dev/null
+++ b/third_party/libusb/open-fd.patch
@@ -0,0 +1,236 @@
+diff --git a/third_party/libusb/src/libusb/core.c b/third_party/libusb/src/libusb/core.c
+index e816284..abc4f89 100644
+--- a/third_party/libusb/src/libusb/core.c
++++ b/third_party/libusb/src/libusb/core.c
+@@ -1129,6 +1129,83 @@ int API_EXPORTED libusb_open(libusb_device *dev,
+ }
+ 
+ /** \ingroup dev
++ * Open a device and obtain a device handle. A handle allows you to perform
++ * I/O on the device in question.
++ *
++ * Instead of opening the device itself this function accepts an open file
++ * descriptor that it will take ownership of.
++ *
++ * Internally, this function adds a reference to the device and makes it
++ * available to you through libusb_get_device(). This reference is removed
++ * during libusb_close().
++ *
++ * This is a non-blocking function; no requests are sent over the bus.
++ *
++ * \param dev the device to open
++ * \param fd open file handle to the device
++ * \param handle output location for the returned device handle pointer. Only
++ * populated when the return code is 0.
++ * \returns 0 on success
++ * \returns LIBUSB_ERROR_NO_MEM on memory allocation failure
++ * \returns LIBUSB_ERROR_ACCESS if the user has insufficient permissions
++ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
++ * \returns another LIBUSB_ERROR code on other failure
++ */
++int API_EXPORTED libusb_open_fd(libusb_device *dev,
++  int fd,
++  libusb_device_handle **handle)
++{
++  struct libusb_context *ctx = DEVICE_CTX(dev);
++  struct libusb_device_handle *_handle;
++  size_t priv_size = usbi_backend->device_handle_priv_size;
++  int r;
++  usbi_dbg("open %d.%d", dev->bus_number, dev->device_address);
++
++  if (!dev->attached) {
++    return LIBUSB_ERROR_NO_DEVICE;
++  }
++
++  _handle = malloc(sizeof(*_handle) + priv_size);
++  if (!_handle)
++    return LIBUSB_ERROR_NO_MEM;
++
++  r = usbi_mutex_init(&_handle->lock, NULL);
++  if (r) {
++    free(_handle);
++    return LIBUSB_ERROR_OTHER;
++  }
++
++  _handle->dev = libusb_ref_device(dev);
++  _handle->auto_detach_kernel_driver = 0;
++  _handle->claimed_interfaces = 0;
++  memset(&_handle->os_priv, 0, priv_size);
++
++  r = usbi_backend->open_fd(_handle, fd);
++  if (r < 0) {
++    usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r);
++    libusb_unref_device(dev);
++    usbi_mutex_destroy(&_handle->lock);
++    free(_handle);
++    return r;
++  }
++
++  usbi_mutex_lock(&ctx->open_devs_lock);
++  list_add(&_handle->list, &ctx->open_devs);
++  usbi_mutex_unlock(&ctx->open_devs_lock);
++  *handle = _handle;
++
++  /* At this point, we want to interrupt any existing event handlers so
++   * that they realise the addition of the new device's poll fd. One
++   * example when this is desirable is if the user is running a separate
++   * dedicated libusbx events handling thread, which is running with a long
++   * or infinite timeout. We want to interrupt that iteration of the loop,
++   * so that it picks up the new fd, and then continues. */
++  usbi_fd_notification(ctx);
++
++  return 0;
++}
++
++/** \ingroup dev
+  * Convenience function for finding a device with a particular
+  * <tt>idVendor</tt>/<tt>idProduct</tt> combination. This function is intended
+  * for those scenarios where you are using libusbx to knock up a quick test
+diff --git a/third_party/libusb/src/libusb/libusb.h b/third_party/libusb/src/libusb/libusb.h
+index d144b3e..5d60951 100644
+--- a/third_party/libusb/src/libusb/libusb.h
++++ b/third_party/libusb/src/libusb/libusb.h
+@@ -1371,6 +1371,8 @@ int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev,
+ 	unsigned char endpoint);
+ 
+ int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle);
++int LIBUSB_CALL libusb_open_fd(libusb_device *dev, int fd,
++	libusb_device_handle **handle);
+ void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle);
+ libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle);
+ 
+diff --git a/third_party/libusb/src/libusb/libusbi.h b/third_party/libusb/src/libusb/libusbi.h
+index bc608b92..eb2f0e6 100644
+--- a/third_party/libusb/src/libusb/libusbi.h
++++ b/third_party/libusb/src/libusb/libusbi.h
+@@ -615,6 +615,11 @@ struct usbi_os_backend {
+ 	 */
+ 	int (*open)(struct libusb_device_handle *handle);
+ 
++	/* Like open() above but uses the file descriptor provided instead of opening
++	 * one on its own.
++	 */
++	int (*open_fd)(struct libusb_device_handle *handle, int fd);
++
+ 	/* Close a device such that the handle cannot be used again. Your backend
+ 	 * should destroy any resources that were allocated in the open path.
+ 	 * This may also be a good place to call usbi_remove_pollfd() to inform
+diff --git a/third_party/libusb/src/libusb/os/darwin_usb.c b/third_party/libusb/src/libusb/os/darwin_usb.c
+index f95706a..f6b397e 100644
+--- a/third_party/libusb/src/libusb/os/darwin_usb.c
++++ b/third_party/libusb/src/libusb/os/darwin_usb.c
+@@ -1877,6 +1877,7 @@ const struct usbi_os_backend darwin_backend = {
+         .get_config_descriptor = darwin_get_config_descriptor,
+ 
+         .open = darwin_open,
++        .open_fd = NULL, /* not implemented */
+         .close = darwin_close,
+         .get_configuration = darwin_get_configuration,
+         .set_configuration = darwin_set_configuration,
+diff --git a/third_party/libusb/src/libusb/os/linux_usbfs.c b/third_party/libusb/src/libusb/os/linux_usbfs.c
+index 142fa2b..e965856 100644
+--- a/third_party/libusb/src/libusb/os/linux_usbfs.c
++++ b/third_party/libusb/src/libusb/os/linux_usbfs.c
+@@ -1259,26 +1259,12 @@ static int linux_default_scan_devices (struct libusb_context *ctx)
+ }
+ #endif
+ 
+-static int op_open(struct libusb_device_handle *handle)
++static int op_open_fd(struct libusb_device_handle *handle, int fd)
+ {
+ 	struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
+ 	int r;
+ 
+-	hpriv->fd = _get_usbfs_fd(handle->dev, O_RDWR, 0);
+-	if (hpriv->fd < 0) {
+-		if (hpriv->fd == LIBUSB_ERROR_NO_DEVICE) {
+-			/* device will still be marked as attached if hotplug monitor thread
+-			 * hasn't processed remove event yet */
+-			usbi_mutex_static_lock(&linux_hotplug_lock);
+-			if (handle->dev->attached) {
+-				usbi_dbg("open failed with no device, but device still attached");
+-				linux_device_disconnected(handle->dev->bus_number,
+-						handle->dev->device_address, NULL);
+-			}
+-			usbi_mutex_static_unlock(&linux_hotplug_lock);
+-		}
+-		return hpriv->fd;
+-	}
++	hpriv->fd = fd;
+ 
+ 	r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps);
+ 	if (r < 0) {
+@@ -1296,6 +1282,29 @@ static int op_open(struct libusb_device_handle *handle)
+ 	return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
+ }
+ 
++static int op_open(struct libusb_device_handle *handle)
++{
++	struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
++	int fd = _get_usbfs_fd(handle->dev, O_RDWR, 0);
++
++	if (fd < 0) {
++		if (fd == LIBUSB_ERROR_NO_DEVICE) {
++			/* device will still be marked as attached if hotplug monitor thread
++			 * hasn't processed remove event yet */
++			usbi_mutex_static_lock(&linux_hotplug_lock);
++			if (handle->dev->attached) {
++				usbi_dbg("open failed with no device, but device still attached");
++				linux_device_disconnected(handle->dev->bus_number,
++						handle->dev->device_address, NULL);
++			}
++			usbi_mutex_static_unlock(&linux_hotplug_lock);
++		}
++		return fd;
++	}
++
++	return op_open_fd(handle, fd);
++}
++
+ static void op_close(struct libusb_device_handle *dev_handle)
+ {
+ 	int fd = _device_handle_priv(dev_handle)->fd;
+@@ -2570,6 +2579,7 @@ const struct usbi_os_backend linux_usbfs_backend = {
+ 	.get_config_descriptor_by_value = op_get_config_descriptor_by_value,
+ 
+ 	.open = op_open,
++	.open_fd = op_open_fd,
+ 	.close = op_close,
+ 	.get_configuration = op_get_configuration,
+ 	.set_configuration = op_set_configuration,
+diff --git a/third_party/libusb/src/libusb/os/openbsd_usb.c b/third_party/libusb/src/libusb/os/openbsd_usb.c
+index 2997e53..2d24f2c 100644
+--- a/third_party/libusb/src/libusb/os/openbsd_usb.c
++++ b/third_party/libusb/src/libusb/os/openbsd_usb.c
+@@ -98,6 +98,7 @@ const struct usbi_os_backend openbsd_backend = {
+ 	obsd_get_device_list,
+ 	NULL,				/* hotplug_poll */
+ 	obsd_open,
++	NULL,       /* open_fd */
+ 	obsd_close,
+ 
+ 	obsd_get_device_descriptor,
+diff --git a/third_party/libusb/src/libusb/os/wince_usb.c b/third_party/libusb/src/libusb/os/wince_usb.c
+index 90c129b..c069c56 100644
+--- a/third_party/libusb/src/libusb/os/wince_usb.c
++++ b/third_party/libusb/src/libusb/os/wince_usb.c
+@@ -990,6 +990,7 @@ const struct usbi_os_backend wince_backend = {
+         wince_get_device_list,
+ 	NULL,				/* hotplug_poll */
+         wince_open,
++        NULL, /* open_fd */
+         wince_close,
+ 
+         wince_get_device_descriptor,
+diff --git a/third_party/libusb/src/libusb/os/windows_usb.c b/third_party/libusb/src/libusb/os/windows_usb.c
+index 4469992..bc4def6 100644
+--- a/third_party/libusb/src/libusb/os/windows_usb.c
++++ b/third_party/libusb/src/libusb/os/windows_usb.c
+@@ -2290,6 +2290,7 @@ const struct usbi_os_backend windows_backend = {
+ 	windows_get_device_list,
+ 	NULL,				/* hotplug_poll */
+ 	windows_open,
++	NULL,       /* open_fd */
+ 	windows_close,
+ 
+ 	windows_get_device_descriptor,
diff --git a/third_party/libusb/src/libusb/core.c b/third_party/libusb/src/libusb/core.c
index e8162846..abc4f89 100644
--- a/third_party/libusb/src/libusb/core.c
+++ b/third_party/libusb/src/libusb/core.c
@@ -1129,6 +1129,83 @@
 }
 
 /** \ingroup dev
+ * Open a device and obtain a device handle. A handle allows you to perform
+ * I/O on the device in question.
+ *
+ * Instead of opening the device itself this function accepts an open file
+ * descriptor that it will take ownership of.
+ *
+ * Internally, this function adds a reference to the device and makes it
+ * available to you through libusb_get_device(). This reference is removed
+ * during libusb_close().
+ *
+ * This is a non-blocking function; no requests are sent over the bus.
+ *
+ * \param dev the device to open
+ * \param fd open file handle to the device
+ * \param handle output location for the returned device handle pointer. Only
+ * populated when the return code is 0.
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_NO_MEM on memory allocation failure
+ * \returns LIBUSB_ERROR_ACCESS if the user has insufficient permissions
+ * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
+ * \returns another LIBUSB_ERROR code on other failure
+ */
+int API_EXPORTED libusb_open_fd(libusb_device *dev,
+  int fd,
+  libusb_device_handle **handle)
+{
+  struct libusb_context *ctx = DEVICE_CTX(dev);
+  struct libusb_device_handle *_handle;
+  size_t priv_size = usbi_backend->device_handle_priv_size;
+  int r;
+  usbi_dbg("open %d.%d", dev->bus_number, dev->device_address);
+
+  if (!dev->attached) {
+    return LIBUSB_ERROR_NO_DEVICE;
+  }
+
+  _handle = malloc(sizeof(*_handle) + priv_size);
+  if (!_handle)
+    return LIBUSB_ERROR_NO_MEM;
+
+  r = usbi_mutex_init(&_handle->lock, NULL);
+  if (r) {
+    free(_handle);
+    return LIBUSB_ERROR_OTHER;
+  }
+
+  _handle->dev = libusb_ref_device(dev);
+  _handle->auto_detach_kernel_driver = 0;
+  _handle->claimed_interfaces = 0;
+  memset(&_handle->os_priv, 0, priv_size);
+
+  r = usbi_backend->open_fd(_handle, fd);
+  if (r < 0) {
+    usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r);
+    libusb_unref_device(dev);
+    usbi_mutex_destroy(&_handle->lock);
+    free(_handle);
+    return r;
+  }
+
+  usbi_mutex_lock(&ctx->open_devs_lock);
+  list_add(&_handle->list, &ctx->open_devs);
+  usbi_mutex_unlock(&ctx->open_devs_lock);
+  *handle = _handle;
+
+  /* At this point, we want to interrupt any existing event handlers so
+   * that they realise the addition of the new device's poll fd. One
+   * example when this is desirable is if the user is running a separate
+   * dedicated libusbx events handling thread, which is running with a long
+   * or infinite timeout. We want to interrupt that iteration of the loop,
+   * so that it picks up the new fd, and then continues. */
+  usbi_fd_notification(ctx);
+
+  return 0;
+}
+
+/** \ingroup dev
  * Convenience function for finding a device with a particular
  * <tt>idVendor</tt>/<tt>idProduct</tt> combination. This function is intended
  * for those scenarios where you are using libusbx to knock up a quick test
diff --git a/third_party/libusb/src/libusb/libusb.h b/third_party/libusb/src/libusb/libusb.h
index d144b3ee..5d60951 100644
--- a/third_party/libusb/src/libusb/libusb.h
+++ b/third_party/libusb/src/libusb/libusb.h
@@ -1371,6 +1371,8 @@
 	unsigned char endpoint);
 
 int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle);
+int LIBUSB_CALL libusb_open_fd(libusb_device *dev, int fd,
+	libusb_device_handle **handle);
 void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle);
 libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle);
 
diff --git a/third_party/libusb/src/libusb/libusbi.h b/third_party/libusb/src/libusb/libusbi.h
index bc608b92..eb2f0e652 100644
--- a/third_party/libusb/src/libusb/libusbi.h
+++ b/third_party/libusb/src/libusb/libusbi.h
@@ -615,6 +615,11 @@
 	 */
 	int (*open)(struct libusb_device_handle *handle);
 
+	/* Like open() above but uses the file descriptor provided instead of opening
+	 * one on its own.
+	 */
+	int (*open_fd)(struct libusb_device_handle *handle, int fd);
+
 	/* Close a device such that the handle cannot be used again. Your backend
 	 * should destroy any resources that were allocated in the open path.
 	 * This may also be a good place to call usbi_remove_pollfd() to inform
diff --git a/third_party/libusb/src/libusb/os/darwin_usb.c b/third_party/libusb/src/libusb/os/darwin_usb.c
index f95706a..f6b397e 100644
--- a/third_party/libusb/src/libusb/os/darwin_usb.c
+++ b/third_party/libusb/src/libusb/os/darwin_usb.c
@@ -1877,6 +1877,7 @@
         .get_config_descriptor = darwin_get_config_descriptor,
 
         .open = darwin_open,
+        .open_fd = NULL, /* not implemented */
         .close = darwin_close,
         .get_configuration = darwin_get_configuration,
         .set_configuration = darwin_set_configuration,
diff --git a/third_party/libusb/src/libusb/os/linux_usbfs.c b/third_party/libusb/src/libusb/os/linux_usbfs.c
index 142fa2b..e965856b 100644
--- a/third_party/libusb/src/libusb/os/linux_usbfs.c
+++ b/third_party/libusb/src/libusb/os/linux_usbfs.c
@@ -1259,26 +1259,12 @@
 }
 #endif
 
-static int op_open(struct libusb_device_handle *handle)
+static int op_open_fd(struct libusb_device_handle *handle, int fd)
 {
 	struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
 	int r;
 
-	hpriv->fd = _get_usbfs_fd(handle->dev, O_RDWR, 0);
-	if (hpriv->fd < 0) {
-		if (hpriv->fd == LIBUSB_ERROR_NO_DEVICE) {
-			/* device will still be marked as attached if hotplug monitor thread
-			 * hasn't processed remove event yet */
-			usbi_mutex_static_lock(&linux_hotplug_lock);
-			if (handle->dev->attached) {
-				usbi_dbg("open failed with no device, but device still attached");
-				linux_device_disconnected(handle->dev->bus_number,
-						handle->dev->device_address, NULL);
-			}
-			usbi_mutex_static_unlock(&linux_hotplug_lock);
-		}
-		return hpriv->fd;
-	}
+	hpriv->fd = fd;
 
 	r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps);
 	if (r < 0) {
@@ -1296,6 +1282,29 @@
 	return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
 }
 
+static int op_open(struct libusb_device_handle *handle)
+{
+	struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
+	int fd = _get_usbfs_fd(handle->dev, O_RDWR, 0);
+
+	if (fd < 0) {
+		if (fd == LIBUSB_ERROR_NO_DEVICE) {
+			/* device will still be marked as attached if hotplug monitor thread
+			 * hasn't processed remove event yet */
+			usbi_mutex_static_lock(&linux_hotplug_lock);
+			if (handle->dev->attached) {
+				usbi_dbg("open failed with no device, but device still attached");
+				linux_device_disconnected(handle->dev->bus_number,
+						handle->dev->device_address, NULL);
+			}
+			usbi_mutex_static_unlock(&linux_hotplug_lock);
+		}
+		return fd;
+	}
+
+	return op_open_fd(handle, fd);
+}
+
 static void op_close(struct libusb_device_handle *dev_handle)
 {
 	int fd = _device_handle_priv(dev_handle)->fd;
@@ -2570,6 +2579,7 @@
 	.get_config_descriptor_by_value = op_get_config_descriptor_by_value,
 
 	.open = op_open,
+	.open_fd = op_open_fd,
 	.close = op_close,
 	.get_configuration = op_get_configuration,
 	.set_configuration = op_set_configuration,
diff --git a/third_party/libusb/src/libusb/os/openbsd_usb.c b/third_party/libusb/src/libusb/os/openbsd_usb.c
index 2997e53..2d24f2c0 100644
--- a/third_party/libusb/src/libusb/os/openbsd_usb.c
+++ b/third_party/libusb/src/libusb/os/openbsd_usb.c
@@ -98,6 +98,7 @@
 	obsd_get_device_list,
 	NULL,				/* hotplug_poll */
 	obsd_open,
+	NULL,       /* open_fd */
 	obsd_close,
 
 	obsd_get_device_descriptor,
diff --git a/third_party/libusb/src/libusb/os/wince_usb.c b/third_party/libusb/src/libusb/os/wince_usb.c
index 90c129b..c069c56 100644
--- a/third_party/libusb/src/libusb/os/wince_usb.c
+++ b/third_party/libusb/src/libusb/os/wince_usb.c
@@ -990,6 +990,7 @@
         wince_get_device_list,
 	NULL,				/* hotplug_poll */
         wince_open,
+        NULL, /* open_fd */
         wince_close,
 
         wince_get_device_descriptor,
diff --git a/third_party/libusb/src/libusb/os/windows_usb.c b/third_party/libusb/src/libusb/os/windows_usb.c
index 4469992..bc4def6073 100644
--- a/third_party/libusb/src/libusb/os/windows_usb.c
+++ b/third_party/libusb/src/libusb/os/windows_usb.c
@@ -2290,6 +2290,7 @@
 	windows_get_device_list,
 	NULL,				/* hotplug_poll */
 	windows_open,
+	NULL,       /* open_fd */
 	windows_close,
 
 	windows_get_device_descriptor,
diff --git a/third_party/libxml/BUILD.gn b/third_party/libxml/BUILD.gn
index 7fb6678..a12d13d 100644
--- a/third_party/libxml/BUILD.gn
+++ b/third_party/libxml/BUILD.gn
@@ -149,7 +149,7 @@
 
   if (is_win) {
     cflags_c = [ "/wd4101" ]  # Unreferenced local variable.
-  } else if (is_mac || is_android) {
+  } else if (is_mac || is_ios || is_android) {
     # http://www.xmlsoft.org/threads.html says that this is required when using
     # libxml from several threads, which can possibly happen in chrome. On
     # linux, this is picked up by transitivity from pkg-config output from
diff --git a/third_party/libxml/libxml.gyp b/third_party/libxml/libxml.gyp
index 51e45db..a3cfea9 100644
--- a/third_party/libxml/libxml.gyp
+++ b/third_party/libxml/libxml.gyp
@@ -68,9 +68,11 @@
                 ],
               },
               'link_settings': {
-                'libraries': [
-                  '$(SDKROOT)/usr/lib/libxml2.dylib',
-                ],
+                'xcode_settings': {
+                  'OTHER_LDFLAGS': [
+                    '-lxml2',
+                  ],
+                },
               },
             }],
           ],
diff --git a/third_party/mesa/BUILD.gn b/third_party/mesa/BUILD.gn
index acdca86..2d4ec15 100644
--- a/third_party/mesa/BUILD.gn
+++ b/third_party/mesa/BUILD.gn
@@ -78,10 +78,6 @@
     "$generated_src_dir/mesa/glapi",
   ]
 
-  if (is_clang) {
-    cflags += [ "-Wno-tautological-constant-out-of-range-compare" ]
-  }
-
   if (is_android) {
     defines += [
       "__GLIBC__",
@@ -108,7 +104,20 @@
       cflags += [ "-fPIC" ]
     }
   }
+}
 
+# mesa_internal_config is prepended to the config lists.  Flags that
+# disable warnings need to be appended instead so that they show up
+# after flags like -Wall. (gn orders flags on a target before flags from
+# configs.)
+config("mesa_internal_warnings") {
+  cflags = []
+  if (is_clang) {
+    cflags += [
+      "-Wno-tautological-constant-out-of-range-compare",
+      "-Wno-mismatched-tags",  # Fixed upstream.
+    ]
+  }
   if (is_win) {
     # TODO(scottmg): http://crbug.com/143877 These should be removed if
     # Mesa is ever rolled and the warnings are fixed.
@@ -117,7 +126,6 @@
       "/wd4065",  # Switch statement contains 'default' but no 'case' labels.
       "/wd4090",  # 'Operation' : different 'modifier' qualifiers
       "/wd4099",  # Type name struct-vs-class doesn't match.
-      "/wd4267",  # size_t to type.
       "/wd4273",  # Inconsistent DLL linkage.
       "/wd4291",  # No matching operator delete found for placement new.
       "/wd4305",  # Truncation from int to float.
@@ -235,7 +243,8 @@
   configs += [ "//build/config/compiler:no_chromium_code" ]
   previous_configs = configs
   configs = []
-  configs = [ ":mesa_internal_config" ] + previous_configs
+  configs = [ ":mesa_internal_config" ] + previous_configs +
+            [ ":mesa_internal_warnings" ]
 
   if (is_clang) {
     # Mesa triggers some of these Clang warnings.
@@ -617,7 +626,8 @@
   configs += [ "//build/config/compiler:no_chromium_code" ]
   previous_configs = configs
   configs = []
-  configs = [ ":mesa_internal_config" ] + previous_configs
+  configs = [ ":mesa_internal_config" ] + previous_configs +
+            [ ":mesa_internal_warnings" ]
 
   if (is_clang) {
     # Mesa triggers some of these Clang warnings.
@@ -655,7 +665,6 @@
       "src/src/mesa/drivers/common/meta.c",
       "src/src/mesa/drivers/common/meta.h",
       "src/src/mesa/drivers/osmesa/osmesa.c",
-      "src/src/mesa/drivers/osmesa/osmesa.def",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -665,7 +674,8 @@
     ]
     previous_configs = configs
     configs = []
-    configs = [ ":mesa_internal_config" ] + previous_configs
+    configs = [ ":mesa_internal_config" ] + previous_configs +
+              [ ":mesa_internal_warnings" ]
 
     include_dirs = [ "src/src/mesa/drivers" ]
 
@@ -674,6 +684,12 @@
       configs -= [ "//build/config/clang:extra_warnings" ]
     }
 
+    if (is_win) {
+      ldflags =
+          [ "/DEF:" + rebase_path("src/src/mesa/drivers/osmesa/osmesa.def",
+                                  root_build_dir) ]
+    }
+
     deps = [
       ":mesa_headers",
       ":mesa",
diff --git a/third_party/polymer/v1_0/bower.json b/third_party/polymer/v1_0/bower.json
index df034032..5236c81 100644
--- a/third_party/polymer/v1_0/bower.json
+++ b/third_party/polymer/v1_0/bower.json
@@ -7,6 +7,7 @@
 
     "iron-elements": "PolymerElements/iron-elements#~1.0.0",
     "paper-elements": "PolymerElements/paper-elements#~1.0.0",
-    "more-routing": "PolymerLabs/more-routing#^1.0.0"
+    "more-routing": "PolymerLabs/more-routing#^1.0.0",
+    "web-animations-js": "web-animations/web-animations-js#^2.0.0"
   }
 }
diff --git a/third_party/protobuf/src/google/protobuf/wire_format_unittest.cc b/third_party/protobuf/src/google/protobuf/wire_format_unittest.cc
index 9822828b1..9422f9a 100644
--- a/third_party/protobuf/src/google/protobuf/wire_format_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/wire_format_unittest.cc
@@ -848,7 +848,7 @@
   return message->ParseFromArray(wire_buffer.data(), wire_buffer.size());
 }
 
-bool StartsWith(const string& s, const string& prefix) {
+bool base::StartsWith(const string& s, const string& prefix) {
   return s.substr(0, prefix.length()) == prefix;
 }
 
@@ -863,10 +863,11 @@
   }
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
   ASSERT_EQ(1, errors.size());
-  EXPECT_TRUE(StartsWith(errors[0],
-                         "String field contains invalid UTF-8 data when "
-                         "serializing a protocol buffer. Use the "
-                         "'bytes' type if you intend to send raw bytes."));
+  EXPECT_TRUE(
+      base::StartsWith(errors[0],
+                       "String field contains invalid UTF-8 data when "
+                       "serializing a protocol buffer. Use the "
+                       "'bytes' type if you intend to send raw bytes."));
 #else
   ASSERT_EQ(0, errors.size());
 #endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
@@ -885,10 +886,11 @@
   }
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
   ASSERT_EQ(1, errors.size());
-  EXPECT_TRUE(StartsWith(errors[0],
-                         "String field contains invalid UTF-8 data when "
-                         "parsing a protocol buffer. Use the "
-                         "'bytes' type if you intend to send raw bytes."));
+  EXPECT_TRUE(
+      base::StartsWith(errors[0],
+                       "String field contains invalid UTF-8 data when "
+                       "parsing a protocol buffer. Use the "
+                       "'bytes' type if you intend to send raw bytes."));
 
 #else
   ASSERT_EQ(0, errors.size());
diff --git a/third_party/qcms/README.chromium b/third_party/qcms/README.chromium
index 7546ec7a..36bb39b 100644
--- a/third_party/qcms/README.chromium
+++ b/third_party/qcms/README.chromium
@@ -73,6 +73,8 @@
    - https://code.google.com/p/chromium/issues/detail?id=491784
  - Add matrix transform flag and matrix extraction api
    - https://code.google.com/p/chromium/issues/detail?id=491826
+ - Add tone reproduction curve (TRC) extraction api
+   - https://code.google.com/p/chromium/issues/detail?id=491826
 
 For the Chromium changes, since the import, in a patch format run:
   git diff b8456f38 src
diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h
index fb69bc9..6b8a361 100644
--- a/third_party/qcms/src/qcms.h
+++ b/third_party/qcms/src/qcms.h
@@ -114,6 +114,14 @@
 	QCMS_OUTPUT_BGRX
 } qcms_output_type;
 
+/* Data output format for qcms_transform_get_input|output_trc_rgba() */
+typedef enum {
+	QCMS_TRC_PARAMETRIC,
+	QCMS_TRC_FLOAT,
+	QCMS_TRC_HALF_FLOAT, // XXX: only type implemented.
+	QCMS_TRC_USHORT,
+} qcms_trc_type;
+
 /* the names for the following two types are sort of ugly */
 typedef struct
 {
@@ -161,6 +169,11 @@
 		qcms_profile *out, qcms_data_type out_type,
 		qcms_intent intent);
 
+size_t qcms_transform_get_input_trc_rgba(
+		qcms_transform *transform, qcms_profile *in, qcms_trc_type type, unsigned short *data);
+size_t qcms_transform_get_output_trc_rgba(
+		qcms_transform *transform, qcms_profile *out, qcms_trc_type type, unsigned short *data);
+
 qcms_bool qcms_transform_is_matrix(qcms_transform *transform);
 float qcms_transform_get_matrix(qcms_transform *transform, unsigned i, unsigned j);
 
diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c
index bafd26a9e..3ebfe1c 100644
--- a/third_party/qcms/src/transform.c
+++ b/third_party/qcms/src/transform.c
@@ -1460,3 +1460,93 @@
 
 	return t->matrix[j][i];
 }
+
+static inline qcms_bool supported_trc_type(qcms_trc_type type)
+{
+	return type == QCMS_TRC_HALF_FLOAT;
+}
+
+const uint16_t half_float_one = 0x3c00;
+
+size_t qcms_transform_get_input_trc_rgba(qcms_transform *t, qcms_profile *in, qcms_trc_type type, unsigned short *data)
+{
+	const size_t size = 256; // The input gamma tables always have 256 entries.
+
+	size_t i;
+
+	if (in->color_space != RGB_SIGNATURE || !supported_trc_type(type))
+		return 0;
+
+	// qcms_profile *in is assumed to be the profile on the input-side of the color transform t.
+	// When a transform is created, the input gamma curve data is stored in the transform ...
+
+	if (!t->input_gamma_table_r || !t->input_gamma_table_g || !t->input_gamma_table_b)
+		return 0;
+
+	// Report the size if no output data is requested. This allows callers to first work out the
+	// the curve size, then provide allocated memory sufficient to store the curve rgba data.
+
+	if (!data)
+		return size;
+
+	for (i = 0; i < size; ++i) {
+		*data++ = float_to_half_float(t->input_gamma_table_r[i]); // r
+		*data++ = float_to_half_float(t->input_gamma_table_g[i]); // g
+		*data++ = float_to_half_float(t->input_gamma_table_b[i]); // b
+		*data++ = half_float_one;                                 // a
+	}
+
+	return size;
+}
+
+const float inverse65535 = (float) (1.0 / 65535.0);
+
+size_t qcms_transform_get_output_trc_rgba(qcms_transform *t, qcms_profile *out, qcms_trc_type type, unsigned short *data)
+{
+	size_t size, i;
+
+	if (out->color_space != RGB_SIGNATURE || !supported_trc_type(type))
+		return 0;
+
+	// qcms_profile *out is assumed to be the profile on the output-side of the transform t.
+	// If the transform output gamma curves need building, do that. They're usually built when
+	// the transform was created, but sometimes not due to the output gamma precache ...
+
+	if (!out->redTRC || !out->greenTRC || !out->blueTRC)
+		return 0;
+	if (!t->output_gamma_lut_r)
+		build_output_lut(out->redTRC, &t->output_gamma_lut_r, &t->output_gamma_lut_r_length);
+	if (!t->output_gamma_lut_g)
+		build_output_lut(out->greenTRC, &t->output_gamma_lut_g, &t->output_gamma_lut_g_length);
+	if (!t->output_gamma_lut_b)
+		build_output_lut(out->blueTRC, &t->output_gamma_lut_b, &t->output_gamma_lut_b_length);
+
+	if (!t->output_gamma_lut_r || !t->output_gamma_lut_g || !t->output_gamma_lut_b)
+		return 0;
+
+	// Output gamma tables should have the same size and should have 4096 entries at most (the
+	// minimum is 256). Larger tables are rare and ignored here: fail by returning 0.
+
+	size = t->output_gamma_lut_r_length;
+	if (size != t->output_gamma_lut_g_length)
+		return 0;
+	if (size != t->output_gamma_lut_b_length)
+		return 0;
+	if (size < 256 || size > 4096)
+		return 0;
+
+	// Report the size if no output data is requested. This allows callers to first work out the
+	// the curve size, then provide allocated memory sufficient to store the curve rgba data.
+
+	if (!data)
+		return size;
+
+	for (i = 0; i < size; ++i) {
+		*data++ = float_to_half_float(t->output_gamma_lut_r[i] * inverse65535); // r
+		*data++ = float_to_half_float(t->output_gamma_lut_g[i] * inverse65535); // g
+		*data++ = float_to_half_float(t->output_gamma_lut_b[i] * inverse65535); // b
+		*data++ = half_float_one;                                               // a
+	}
+
+	return size;
+}
diff --git a/third_party/sqlite/sqlite.gyp b/third_party/sqlite/sqlite.gyp
index 21245db..afd3f2b 100644
--- a/third_party/sqlite/sqlite.gyp
+++ b/third_party/sqlite/sqlite.gyp
@@ -18,7 +18,7 @@
       'SQLITE_ENABLE_MEMORY_MANAGEMENT',
       'SQLITE_SECURE_DELETE',
       # Custom flag to tweak pcache pools.
-      # TODO(shess): This shouldn't use faux-SQLite naming.      
+      # TODO(shess): This shouldn't use faux-SQLite naming.
       'SQLITE_SEPARATE_CACHE_POOLS',
       # TODO(shess): SQLite adds mutexes to protect structures which cross
       # threads.  In theory Chromium should be able to turn this off for a
@@ -81,9 +81,11 @@
                 'sqlite_regexp',
               ],
               'link_settings': {
-                'libraries': [
-                  '$(SDKROOT)/usr/lib/libsqlite3.dylib',
-                ],
+                'xcode_settings': {
+                  'OTHER_LDFLAGS': [
+                    '-lsqlite3',
+                  ],
+                },
               },
             }],
             ['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
diff --git a/third_party/zlib/google/zip_reader.cc b/third_party/zlib/google/zip_reader.cc
index 59d96da1..3acbb418 100644
--- a/third_party/zlib/google/zip_reader.cc
+++ b/third_party/zlib/google/zip_reader.cc
@@ -10,6 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "third_party/zlib/google/zip_internal.h"
 
 #if defined(USE_SYSTEM_MINIZIP)
@@ -144,7 +145,8 @@
 
   // We also consider that the file name is unsafe, if it's absolute.
   // On Windows, IsAbsolute() returns false for paths starting with "/".
-  if (file_path_.IsAbsolute() || StartsWithASCII(file_name_in_zip, "/", false))
+  if (file_path_.IsAbsolute() ||
+      base::StartsWithASCII(file_name_in_zip, "/", false))
     is_unsafe_ = true;
 
   // Construct the last modified time. The timezone info is not present in
@@ -355,24 +357,24 @@
   // If this is a directory, just create it and return.
   if (current_entry_info()->is_directory()) {
     if (base::CreateDirectory(output_file_path)) {
-      base::MessageLoopProxy::current()->PostTask(FROM_HERE, success_callback);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, success_callback);
     } else {
       DVLOG(1) << "Unzip failed: unable to create directory.";
-      base::MessageLoopProxy::current()->PostTask(FROM_HERE, failure_callback);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, failure_callback);
     }
     return;
   }
 
   if (unzOpenCurrentFile(zip_file_) != UNZ_OK) {
     DVLOG(1) << "Unzip failed: unable to open current zip entry.";
-    base::MessageLoopProxy::current()->PostTask(FROM_HERE, failure_callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, failure_callback);
     return;
   }
 
   base::FilePath output_dir_path = output_file_path.DirName();
   if (!base::CreateDirectory(output_dir_path)) {
     DVLOG(1) << "Unzip failed: unable to create containing directory.";
-    base::MessageLoopProxy::current()->PostTask(FROM_HERE, failure_callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, failure_callback);
     return;
   }
 
@@ -382,7 +384,7 @@
   if (!output_file.IsValid()) {
     DVLOG(1) << "Unzip failed: unable to create platform file at "
              << output_file_path.value();
-    base::MessageLoopProxy::current()->PostTask(FROM_HERE, failure_callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, failure_callback);
     return;
   }
 
diff --git a/tools/android/forwarder2/command.cc b/tools/android/forwarder2/command.cc
index 9b0aa24c..9aeee03 100644
--- a/tools/android/forwarder2/command.cc
+++ b/tools/android/forwarder2/command.cc
@@ -10,7 +10,7 @@
 #include <string.h>
 
 #include "base/logging.h"
-#include "base/safe_strerror_posix.h"
+#include "base/posix/safe_strerror.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "tools/android/forwarder2/socket.h"
@@ -50,7 +50,7 @@
   int bytes_read = socket->ReadNumBytes(command_buffer, kCommandStringSize);
   if (bytes_read != kCommandStringSize) {
     if (bytes_read < 0)
-      LOG(ERROR) << "Read() error: " << safe_strerror(errno);
+      LOG(ERROR) << "Read() error: " << base::safe_strerror(errno);
     else if (!bytes_read)
       LOG(ERROR) << "Read() error, endpoint was unexpectedly closed.";
     else
diff --git a/tools/android/forwarder2/common.cc b/tools/android/forwarder2/common.cc
index 3b7387d..ddd8c52 100644
--- a/tools/android/forwarder2/common.cc
+++ b/tools/android/forwarder2/common.cc
@@ -9,12 +9,12 @@
 
 #include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
-#include "base/safe_strerror_posix.h"
+#include "base/posix/safe_strerror.h"
 
 namespace forwarder2 {
 
 void PError(const char* msg) {
-  LOG(ERROR) << msg << ": " << safe_strerror(errno);
+  LOG(ERROR) << msg << ": " << base::safe_strerror(errno);
 }
 
 void CloseFD(int fd) {
diff --git a/tools/android/forwarder2/daemon.cc b/tools/android/forwarder2/daemon.cc
index 75de3ba3..b8217afd 100644
--- a/tools/android/forwarder2/daemon.cc
+++ b/tools/android/forwarder2/daemon.cc
@@ -23,7 +23,6 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/posix/eintr_wrapper.h"
-#include "base/safe_strerror_posix.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "tools/android/forwarder2/common.h"
diff --git a/tools/android/forwarder2/host_forwarder_main.cc b/tools/android/forwarder2/host_forwarder_main.cc
index 9aed23a..16a7b51 100644
--- a/tools/android/forwarder2/host_forwarder_main.cc
+++ b/tools/android/forwarder2/host_forwarder_main.cc
@@ -28,7 +28,6 @@
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/pickle.h"
-#include "base/safe_strerror_posix.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
diff --git a/tools/android/forwarder2/pipe_notifier.cc b/tools/android/forwarder2/pipe_notifier.cc
index 02842bd..ff944fbc3 100644
--- a/tools/android/forwarder2/pipe_notifier.cc
+++ b/tools/android/forwarder2/pipe_notifier.cc
@@ -11,7 +11,6 @@
 
 #include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
-#include "base/safe_strerror_posix.h"
 
 namespace forwarder2 {
 
diff --git a/tools/android/forwarder2/socket.cc b/tools/android/forwarder2/socket.cc
index 05dfcbd..23ff886 100644
--- a/tools/android/forwarder2/socket.cc
+++ b/tools/android/forwarder2/socket.cc
@@ -16,7 +16,7 @@
 
 #include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
-#include "base/safe_strerror_posix.h"
+#include "base/posix/safe_strerror.h"
 #include "tools/android/common/net.h"
 #include "tools/android/forwarder2/common.h"
 
@@ -243,7 +243,8 @@
     return false;
   }
   if (socket_errno != 0) {
-    LOG(ERROR) << "Could not connect to host: " << safe_strerror(socket_errno);
+    LOG(ERROR) << "Could not connect to host: "
+               << base::safe_strerror(socket_errno);
     SetSocketError();
     return false;
   }
diff --git a/tools/auto_bisect/bisect_perf_regression.py b/tools/auto_bisect/bisect_perf_regression.py
index 164e5b442..67530ea 100755
--- a/tools/auto_bisect/bisect_perf_regression.py
+++ b/tools/auto_bisect/bisect_perf_regression.py
@@ -2706,9 +2706,10 @@
     group.add_argument('--output_buildbot_annotations', action='store_true',
                        help='Add extra annotation output for buildbot.')
     group.add_argument('--target_arch', default='ia32',
-                       dest='target_arch', choices=['ia32', 'x64', 'arm'],
+                       dest='target_arch',
+                       choices=['ia32', 'x64', 'arm', 'arm64'],
                        help='The target build architecture. Choices are "ia32" '
-                            '(default), "x64" or "arm".')
+                            '(default), "x64", "arm" or "arm64".')
     group.add_argument('--target_build_type', default='Release',
                        choices=['Release', 'Debug', 'Release_x64'],
                        help='The target build type. Choices are "Release" '
diff --git a/tools/auto_bisect/fetch_build.py b/tools/auto_bisect/fetch_build.py
index b066646..2be7c973 100644
--- a/tools/auto_bisect/fetch_build.py
+++ b/tools/auto_bisect/fetch_build.py
@@ -23,7 +23,7 @@
 import zipfile
 
 # Telemetry (src/tools/telemetry) is expected to be in the PYTHONPATH.
-from telemetry.util import cloud_storage
+from catapult_base import cloud_storage
 
 import bisect_utils
 
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py b/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py
index 69d88d0..da2cee46 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py
@@ -272,7 +272,7 @@
     options.AppendExtraBrowserArgs('--data-reduction-proxy-experiment=test')
 
   def AddResults(self, tab, results):
-    self._metrics.AddResultsForBypass(tab, results, url_pattern='/exptest/')
+    self._metrics.AddResultsForBypass(tab, results, url_pattern='/exp/')
 
 class ChromeProxyPassThrough(ChromeProxyValidation):
   """Correctness measurement for Chrome-Proxy pass-through directives.
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/block_once.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/block_once.py
index 73fc062..ce3fd0d 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/block_once.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/block_once.py
@@ -40,7 +40,7 @@
 
     # Test block-once for a GET request.
     urls_list = [
-      'http://check.googlezip.net/blocksingle',
+      'http://check.googlezip.net/blocksingle/',
     ]
 
     for url in urls_list:
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/bypass.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/bypass.py
index 243c346f..7a682a1 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/bypass.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/bypass.py
@@ -20,7 +20,7 @@
     super(BypassPageSet, self).__init__()
 
     urls_list = [
-      'http://check.googlezip.net/block',
+      'http://check.googlezip.net/block/',
     ]
 
     for url in urls_list:
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/corsbypass.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/corsbypass.py
index c59ededc..c03d624 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/corsbypass.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/corsbypass.py
@@ -20,7 +20,7 @@
     super(CorsBypassPageSet, self).__init__()
 
     urls_list = [
-      'http://aws1.mdw.la/test/cors/',
+      'http://www.gstatic.com/chrome/googlezip/cors/',
     ]
 
     for url in urls_list:
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/exp_directive.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/exp_directive.py
index 49a274c..701f21dc 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/exp_directive.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/exp_directive.py
@@ -20,7 +20,7 @@
     super(ExpDirectivePageSet, self).__init__()
 
     urls_list = [
-      'http://aws1.mdw.la/exptest/',
+      'http://check.googlezip.net/exp/',
     ]
 
     for url in urls_list:
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_to_direct_fallback.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_to_direct_fallback.py
index 8a105eb..239b2a0c 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_to_direct_fallback.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_to_direct_fallback.py
@@ -18,8 +18,8 @@
     super(HTTPToDirectFallbackPageSet, self).__init__()
 
     urls_list = [
-      'http://check.googlezip.net/fallback',
-      'http://check.googlezip.net/block',
+      'http://check.googlezip.net/fallback/',
+      'http://check.googlezip.net/block/',
     ]
 
     for url in urls_list:
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/smoke.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/smoke.py
index 2e675919..a169a96 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/smoke.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/smoke.py
@@ -33,7 +33,7 @@
 
   def __init__(self, page_set):
     super(Page2, self).__init__(
-      url='http://aws1.mdw.la/static/',
+      url='http://check.googlezip.net/static/',
       page_set=page_set,
       name='compression: image')
 
@@ -46,7 +46,7 @@
 
   def __init__(self, page_set):
     super(Page3, self).__init__(
-      url='http://check.googlezip.net/block',
+      url='http://check.googlezip.net/block/',
       page_set=page_set,
       name='bypass')
 
@@ -59,7 +59,7 @@
 
   def __init__(self, page_set):
     super(Page4, self).__init__(
-      url='http://aws1.mdw.la/static/',
+      url='http://check.googlezip.net/static/',
       page_set=page_set,
       name='compression: javascript')
 
@@ -72,7 +72,7 @@
 
   def __init__(self, page_set):
     super(Page5, self).__init__(
-      url='http://aws1.mdw.la/static/',
+      url='http://check.googlezip.net/static/',
       page_set=page_set,
       name='compression: css')
 
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/synthetic.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/synthetic.py
index 0b169094..3fef221 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/synthetic.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/synthetic.py
@@ -21,7 +21,7 @@
 
     urls_list = [
       'http://check.googlezip.net/test.html',
-      'http://aws1.mdw.la/static'
+      'http://check.googlezip.net/static/'
     ]
 
     for url in urls_list:
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
index 90f326d0..19a8ab9 100755
--- a/tools/clang/scripts/package.py
+++ b/tools/clang/scripts/package.py
@@ -183,6 +183,7 @@
   # Set up symlinks.
   if sys.platform != 'win32':
     os.symlink('clang', os.path.join(pdir, 'bin', 'clang++'))
+    os.symlink('clang', os.path.join(pdir, 'bin', 'clang-cl'))
   if sys.platform == 'darwin':
     os.symlink('libc++.1.dylib', os.path.join(pdir, 'bin', 'libc++.dylib'))
     # Also copy libc++ headers.
diff --git a/tools/crx_id/PRESUBMIT.py b/tools/crx_id/PRESUBMIT.py
deleted file mode 100644
index 5aa84ad..0000000
--- a/tools/crx_id/PRESUBMIT.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Presubmit script for crx_id.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details on the presubmit API built into depot_tools.
-"""
-
-UNIT_TESTS = [
-  'crx_id_unittest',
-]
-
-def CheckChangeOnUpload(input_api, output_api):
-  return input_api.canned_checks.RunPythonUnitTests(input_api,
-                                                    output_api,
-                                                    UNIT_TESTS)
-
-def CheckChangeOnCommit(input_api, output_api):
-  output = []
-  output.extend(input_api.canned_checks.RunPythonUnitTests(input_api,
-                                                           output_api,
-                                                           UNIT_TESTS))
-  output.extend(input_api.canned_checks.CheckDoNotSubmit(input_api,
-                                                         output_api))
-  return output
diff --git a/tools/crx_id/__init__.py b/tools/crx_id/__init__.py
deleted file mode 100644
index b2e61d3..0000000
--- a/tools/crx_id/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-'''Module crx_id
-'''
-
-pass
diff --git a/tools/crx_id/crx_id.py b/tools/crx_id/crx_id.py
deleted file mode 100755
index dc30b73..0000000
--- a/tools/crx_id/crx_id.py
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-""" Read a CRX file and write out the App ID and the Full Hash of the ID.
-See: http://code.google.com/chrome/extensions/crx.html
-and 'http://stackoverflow.com/questions/'
-  + '1882981/google-chrome-alphanumeric-hashes-to-identify-extensions'
-for docs on the format.
-"""
-
-import base64
-import os
-import sys
-import hashlib
-
-try:
-  import json
-except Exception:
-  import simplejson as json
-
-EXPECTED_CRX_MAGIC_NUM = 'Cr24'
-EXPECTED_CRX_VERSION = 2
-
-def usage(argv):
-  print "%s: crx_file" % argv[0]
-
-def HexToInt(hex_chars):
-  """ Convert bytes like \xab -> 171 """
-  val = 0
-  for i in xrange(len(hex_chars)):
-    val += pow(256, i) * ord(hex_chars[i])
-  return val
-
-def HexToMPDecimal(hex_chars):
-  """ Convert bytes to an MPDecimal string. Example \x00 -> "aa"
-      This gives us the AppID for a chrome extension.
-  """
-  result = ''
-  base = ord('a')
-  for i in xrange(len(hex_chars)):
-    value = ord(hex_chars[i])
-    dig1 = value / 16
-    dig2 = value % 16
-    result += chr(dig1 + base)
-    result += chr(dig2 + base)
-  return result
-
-def HexTo256(hex_chars):
-  """ Convert bytes to pairs of hex digits. E.g., \x00\x11 -> "{0x00, 0x11}"
-      The format is taylored for copy and paste into C code:
-      const uint8 sha256_hash[] = { ... }; """
-  result = []
-  for i in xrange(len(hex_chars)):
-    value = ord(hex_chars[i])
-    dig1 = value / 16
-    dig2 = value % 16
-    result.append('0x' + hex(dig1)[2:] + hex(dig2)[2:])
-  return '{%s}' % ', '.join(result)
-
-def GetPublicKeyPacked(f):
-  magic_num = f.read(4)
-  if magic_num != EXPECTED_CRX_MAGIC_NUM:
-    raise Exception('Invalid magic number: %s (expecting %s)' %
-                    (magic_num,
-                     EXPECTED_CRX_MAGIC_NUM))
-  version = f.read(4)
-  if not version[0] != EXPECTED_CRX_VERSION:
-    raise Exception('Invalid version number: %s (expecting %s)' %
-                    (version,
-                     EXPECTED_CRX_VERSION))
-  pub_key_len_bytes = HexToInt(f.read(4))
-  sig_len_bytes = HexToInt(f.read(4))
-  pub_key = f.read(pub_key_len_bytes)
-  return pub_key
-
-def GetPublicKeyFromPath(filepath, is_win_path=False):
-  # Normalize the path for windows to have capital drive letters.
-  # We intentionally don't check if sys.platform == 'win32' and just
-  # check if this looks like drive letter so that we can test this
-  # even on posix systems.
-  if (len(filepath) >= 2 and
-      filepath[0].islower() and
-      filepath[1] == ':'):
-      filepath = filepath[0].upper() + filepath[1:]
-
-  # On Windows, filepaths are encoded using UTF-16, little endian byte order,
-  # using "wide characters" that are 16 bits in size. On POSIX systems, the
-  # encoding is generally UTF-8, which has the property of being equivalent to
-  # ASCII when only ASCII characters are in the path.
-  if is_win_path:
-    filepath = filepath.encode('utf-16le')
-
-  return filepath
-
-def GetPublicKeyUnpacked(f, filepath):
-  manifest = json.load(f)
-  if 'key' not in manifest:
-    # Use the path as the public key.
-    # See Extension::GenerateIdForPath in extension.cc
-    return GetPublicKeyFromPath(filepath)
-  else:
-    return base64.standard_b64decode(manifest['key'])
-
-def HasPublicKey(filename):
-  if os.path.isdir(filename):
-    with open(os.path.join(filename, 'manifest.json'), 'rb') as f:
-      manifest = json.load(f)
-      return 'key' in manifest
-  return False
-
-def GetPublicKey(filename, from_file_path, is_win_path=False):
-  if from_file_path:
-    return GetPublicKeyFromPath(
-        filename, is_win_path=is_win_path)
-
-  pub_key = ''
-  if os.path.isdir(filename):
-    # Assume it's an unpacked extension
-    f = open(os.path.join(filename, 'manifest.json'), 'rb')
-    pub_key = GetPublicKeyUnpacked(f, filename)
-    f.close()
-  else:
-    # Assume it's a packed extension.
-    f = open(filename, 'rb')
-    pub_key = GetPublicKeyPacked(f)
-    f.close()
-  return pub_key
-
-def GetCRXHash(filename, from_file_path=False, is_win_path=False):
-  pub_key = GetPublicKey(filename, from_file_path, is_win_path=is_win_path)
-  pub_key_hash = hashlib.sha256(pub_key).digest()
-  return HexTo256(pub_key_hash)
-
-def GetCRXAppID(filename, from_file_path=False, is_win_path=False):
-  pub_key = GetPublicKey(filename, from_file_path, is_win_path=is_win_path)
-  pub_key_hash = hashlib.sha256(pub_key).digest()
-  # AppID is the MPDecimal of only the first 128 bits of the hash.
-  return HexToMPDecimal(pub_key_hash[:128/8])
-
-def main(argv):
-  if len(argv) != 2:
-    usage(argv)
-    return 1
-  print 'Raw Bytes: %s' % GetCRXHash(sys.argv[1])
-  print 'AppID: %s' % GetCRXAppID(sys.argv[1])
-
-
-if __name__ == '__main__':
-  sys.exit(main(sys.argv))
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index 373883f..e2b35bc8 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -247,11 +247,11 @@
         'base/files/file_util_posix.cc',
         'base/message_loop/message_pump_libevent.cc',
         'base/posix/file_descriptor_shuffle.cc',
+        'base/posix/safe_strerror.cc',
         'base/process/kill_posix.cc',
         'base/process/process_handle_posix.cc',
         'base/process/process_metrics_posix.cc',
         'base/process/process_posix.cc',
-        'base/safe_strerror_posix.cc',
         'base/synchronization/condition_variable_posix.cc',
         'base/synchronization/lock_impl_posix.cc',
         'base/synchronization/waitable_event_posix.cc',
diff --git a/tools/gn/docs/cookbook.md b/tools/gn/docs/cookbook.md
index 57df03c..9e9d58b 100644
--- a/tools/gn/docs/cookbook.md
+++ b/tools/gn/docs/cookbook.md
@@ -484,8 +484,8 @@
 ```
 
 tells us that warning 4018 is already disabled globally from the
-`//build/config/compiler:default_warnings` config, and the same for
-4244. So ignore these.
+`default_warning_flags` variable in `//build/config/compiler`, and the same
+for 4244. So ignore these.
 
 Always comment what the warning is. Use your favorite search engine and
 type "vc warning 4267" to look it up. You'll end up with:
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md
index 5df04a6..c55f42e0 100644
--- a/tools/gn/docs/reference.md
+++ b/tools/gn/docs/reference.md
@@ -58,7 +58,7 @@
 
 
 ```
-## **--dotfile**: override the name of the ".gn" file.
+## **--dotfile**: Override the name of the ".gn" file.
 
 ```
   Normally GN loads the ".gn"file  from the source root for some basic
@@ -119,6 +119,41 @@
 
 
 ```
+## **--runtime-deps-list-file**: Save runtime dependencies for targets in file.
+
+```
+  --runtime-deps-list-file=<filename>
+
+  Where <filename> is a text file consisting of the labels, one per
+  line, of the targets for which runtime dependencies are desired.
+
+  See "gn help runtime_deps" for a description of how runtime
+  dependencies are computed.
+
+```
+
+### **Runtime deps output file**
+
+```
+  For each target requested, GN will write a separate runtime dependency
+  file. The runtime dependency file will be in the output directory
+  alongside the output file of the target, with a ".runtime_deps"
+  extension. For example, if the target "//foo:bar" is listed in the
+  input file, and that target produces an output file "bar.so", GN
+  will create a file "bar.so.runtime_deps" in the build directory.
+
+  If a source set, action, copy, or group is listed, the runtime deps
+  file will correspond to the .stamp file corresponding to that target.
+  This is probably not useful; the use-case for this feature is
+  generally executable targets.
+
+  The runtime dependency file will list one file per line, with no
+  escaping. The files will be relative to the root_build_dir. The first
+  line of the file will be the main output file of the target itself
+  (in the above example, "bar.so").
+
+
+```
 ## **--time**: Outputs a summary of how long everything took.
 
 ```
@@ -347,6 +382,21 @@
       Shows the given values taken from the target and all configs
       applying. See "--blame" below.
 
+  runtime_deps
+      Compute all runtime deps for the given target. This is a
+      computed list and does not correspond to any GN variable, unlike
+      most other values here.
+
+      The output is a list of file names relative to the build
+      directory. See "gn help runtime_deps" for how this is computed.
+      This also works with "--blame" to see the source of the
+      dependency.
+
+```
+
+### **Shared flags**
+
+```
   --blame
       Used with any value specified by a config, this will name
       the config that specified the value. This doesn't currently work
@@ -563,6 +613,35 @@
 
 
 ```
+## **gn path <out_dir> <target_one> <target_two>**
+
+```
+  Finds paths of dependencies between two targets. Each unique path
+  will be printed in one group, and groups will be separate by newlines.
+  The two targets can appear in either order: paths will be found going
+  in either direction.
+
+  Each dependency will be annotated with its type. By default, only the
+  first path encountered will be printed, which is not necessarily the
+  shortest path.
+
+```
+
+### **Options**
+
+```
+  --all
+     Prints all paths found rather than just the first one.
+
+```
+
+### **Example**
+
+```
+  gn path out/Default //base //tools/gn
+
+
+```
 ## **gn refs <out_dir> (<label_pattern>|<label>|<file>|@<response_file>)* [--all]**
 ```
         [--all-toolchains] [--as=...] [--testonly=...] [--type=...]
@@ -581,9 +660,9 @@
      "gn help label_pattern" for details.
 
    - File name: The result will be which targets list the given file in
-     its "inputs", "sources", "public", or "data". Any input
-     that does not contain wildcards and does not match a target or a
-     config will be treated as a file.
+     its "inputs", "sources", "public", "data", or "outputs".
+     Any input that does not contain wildcards and does not match a
+     target or a config will be treated as a file.
 
    - Response file: If the input starts with an "@", it will be
      interpreted as a path to a file containing a list of labels or
@@ -3252,17 +3331,29 @@
 ## **data**: Runtime data file dependencies.
 
 ```
-  Lists files required to run the given target. These are typically
-  data files.
+  Lists files or directories required to run the given target. These are
+  typically data files or directories of data files. The paths are
+  interpreted as being relative to the current build file. Since these
+  are runtime dependencies, they do not affect which targets are built
+  or when. To declare input files to a script, use "inputs".
 
   Appearing in the "data" section does not imply any special handling
   such as copying them to the output directory. This is just used for
-  declaring runtime dependencies. There currently isn't a good use for
-  these but it is envisioned that test data can be listed here for use
-  running automated tests.
+  declaring runtime dependencies. Runtime dependencies can be queried
+  using the "runtime_deps" category of "gn desc" or written during
+  build generation via "--runtime-deps-list-file".
 
-  See also "gn help inputs" and "gn help data_deps", both of
-  which actually affect the build in concrete ways.
+  GN doesn't require data files to exist at build-time. So actions that
+  produce files that are in turn runtime dependencies can list those
+  generated files both in the "outputs" list as well as the "data"
+  list.
+
+  By convention, directories are be listed with a trailing slash:
+    data = [ "test/data/" ]
+  However, no verification is done on these so GN doesn't enforce this.
+  The paths are just rebased and passed along when requested.
+
+  See "gn help runtime_deps" for how these are used.
 
 
 ```
@@ -4291,6 +4382,50 @@
 
 
 ```
+## **Runtime dependencies**
+
+```
+  Runtime dependencies of a target are exposed via the "runtime_deps"
+  category of "gn desc" (see "gn help desc") or they can be written
+  at build generation time via "--runtime-deps-list-file"
+  (see "gn help --runtime-deps-list-file").
+
+  To a first approximation, the runtime dependencies of a target are
+  the set of "data" files, data directories, and the shared libraries
+  from all transitive dependencies. Executables and shared libraries are
+  considered runtime dependencies of themselves.
+
+```
+
+### **Details**
+
+```
+  Executable targets and those executable targets' transitive
+  dependencies are not considered unless that executable is listed in
+  "data_deps". Otherwise, GN assumes that the executable (and
+  everything it requires) is a build-time dependency only.
+
+  Action and copy targets that are listed as "data_deps" will have all
+  of their outputs and data files considered as runtime dependencies.
+  Action and copy targets that are "deps" or "public_deps" will have
+  only their data files considered as runtime dependencies. These
+  targets can list an output file in both the "outputs" and "data"
+  lists to force an output file as a runtime dependency in all cases.
+
+  The results of static_library or source_set targets are not considered
+  runtime dependencies since these are assumed to be intermediate
+  targets only. If you need to list a static library as a runtime
+  dependency, you can manually compute the .a/.lib file name for the
+  current platform and list it in the "data" list of a target
+  (possibly on the static library target itself).
+
+  When a tool produces more than one output, only the first output
+  is considered. For example, a shared library target may produce a
+  .dll and a .lib file on Windows. Only the .dll file will be considered
+  a runtime dependency.
+
+
+```
 ## **How Source Expansion Works**
 
 ```
@@ -4416,11 +4551,12 @@
 
 **  --args**: Specifies build arguments overrides.
 **  --color**: Force colored output.
-**  --dotfile**: override the name of the ".gn" file.
+**  --dotfile**: Override the name of the ".gn" file.
 **  --markdown**: write the output in the Markdown format.
 **  --nocolor**: Force non-colored output.
 **  -q**: Quiet mode. Don't print output on success.
 **  --root**: Explicitly specify source root.
+**  --runtime-deps-list-file**: Save runtime dependencies for targets in file.
 **  --time**: Outputs a summary of how long everything took.
 **  --tracelog**: Writes a Chrome-compatible trace log to the given file.
 **  -v**: Verbose logging.
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc
index 325cfc6..67bb6e2 100644
--- a/tools/gn/filesystem_utils.cc
+++ b/tools/gn/filesystem_utils.cc
@@ -748,7 +748,7 @@
     const std::string& build_dir =
         settings->build_settings()->build_dir().value();
 
-    if (StartsWithASCII(source_dir.value(), build_dir, true)) {
+    if (base::StartsWithASCII(source_dir.value(), build_dir, true)) {
       size_t build_dir_size = build_dir.size();
       result.value().append(&source_dir.value()[build_dir_size],
                             source_dir.value().size() - build_dir_size);
diff --git a/tools/gn/header_checker.cc b/tools/gn/header_checker.cc
index 665be949..d0552438 100644
--- a/tools/gn/header_checker.cc
+++ b/tools/gn/header_checker.cc
@@ -37,7 +37,7 @@
 SourceFile RemoveRootGenDirFromFile(const Target* target,
                                     const SourceFile& file) {
   const SourceDir& gen = target->settings()->toolchain_gen_dir();
-  if (!gen.is_null() && StartsWithASCII(file.value(), gen.value(), true))
+  if (!gen.is_null() && base::StartsWithASCII(file.value(), gen.value(), true))
     return SourceFile("//" + file.value().substr(gen.value().size()));
   return file;
 }
diff --git a/tools/gn/input_conversion.cc b/tools/gn/input_conversion.cc
index 3d9d355..e4c20a0 100644
--- a/tools/gn/input_conversion.cc
+++ b/tools/gn/input_conversion.cc
@@ -116,7 +116,7 @@
     return Value();  // Empty string means discard the result.
 
   const char kTrimPrefix[] = "trim ";
-  if (StartsWithASCII(input_conversion, kTrimPrefix, true)) {
+  if (base::StartsWithASCII(input_conversion, kTrimPrefix, true)) {
     std::string trimmed;
     base::TrimWhitespaceASCII(input, base::TRIM_ALL, &trimmed);
 
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index 2ea28594..0b189e6 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -217,7 +217,7 @@
     const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this);
     const std::string& prefix = tool->output_prefix();
     // Only add the prefix if the name doesn't already have it.
-    if (!StartsWithASCII(name, prefix, true))
+    if (!base::StartsWithASCII(name, prefix, true))
       result = prefix;
   }
 
diff --git a/tools/licenses.py b/tools/licenses.py
index 8790c8db2..6b8311a2 100755
--- a/tools/licenses.py
+++ b/tools/licenses.py
@@ -444,7 +444,7 @@
     entry_template = open(os.path.join(root, 'chrome', 'browser', 'resources',
                                        'about_credits_entry.tmpl'), 'rb').read()
     entries = []
-    for path in sorted(third_party_dirs):
+    for path in third_party_dirs:
         try:
             metadata = ParseDir(path, root)
         except LicenseError:
@@ -457,13 +457,19 @@
             'url': metadata['URL'],
             'license': open(metadata['License File'], 'rb').read(),
         }
-        entries.append(EvaluateTemplate(entry_template, env))
+        entry = {
+            'name': metadata['Name'],
+            'content': EvaluateTemplate(entry_template, env),
+        }
+        entries.append(entry)
 
+    entries.sort(key=lambda entry: (entry['name'], entry['content']))
+    entries_contents = '\n'.join([entry['content'] for entry in entries])
     file_template = open(os.path.join(root, 'chrome', 'browser', 'resources',
                                       'about_credits.tmpl'), 'rb').read()
     template_contents = "<!-- Generated by licenses.py; do not edit. -->"
     template_contents += EvaluateTemplate(file_template,
-                                          {'entries': '\n'.join(entries)},
+                                          {'entries': entries_contents},
                                           escape=False)
 
     if len(sys.argv) == 3:
diff --git a/tools/luci-go/linux64/isolate.sha1 b/tools/luci-go/linux64/isolate.sha1
index 9b64657..1281abf9 100644
--- a/tools/luci-go/linux64/isolate.sha1
+++ b/tools/luci-go/linux64/isolate.sha1
@@ -1 +1 @@
-e7a0e93c9a560cee05a375f2254d17cf8c9653e6
+1c46d1f756f656ad306921109bb03f5e7c727e15
diff --git a/tools/luci-go/mac64/isolate.sha1 b/tools/luci-go/mac64/isolate.sha1
index 3dfe274..6ef0198 100644
--- a/tools/luci-go/mac64/isolate.sha1
+++ b/tools/luci-go/mac64/isolate.sha1
@@ -1 +1 @@
-6e7b095ba535219cbbb62f35e35037bb848e9ea4
+d783d7c81d915d562d75f6ad4bc3d85d91ff254d
diff --git a/tools/luci-go/win64/isolate.exe.sha1 b/tools/luci-go/win64/isolate.exe.sha1
index 84d10005..499cc1c87 100644
--- a/tools/luci-go/win64/isolate.exe.sha1
+++ b/tools/luci-go/win64/isolate.exe.sha1
@@ -1 +1 @@
-7eeb09411ce562805d5b1d4f570b124d14f21aaa
+2bddb1a8c8f61a04e734ff1fa056a61b9e2b5f86
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 0c3d4469..5b991414 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -89,6 +89,9 @@
     subp = subps.add_parser('gen',
                             help='generate a new set of build files')
     AddCommonOptions(subp)
+    subp.add_argument('--swarming-targets-file',
+                      help='save runtime dependencies for targets listed '
+                           'in file.')
     subp.add_argument('path', nargs=1,
                       help='path to generate build into')
     subp.set_defaults(func=self.CmdGen)
@@ -336,7 +339,35 @@
 
   def RunGNGen(self, path, vals):
     cmd = self.GNCmd('gen', path, vals['gn_args'])
+
+    swarming_targets = []
+    if self.args.swarming_targets_file:
+      # We need GN to generate the list of runtime dependencies for
+      # the compile targets listed (one per line) in the file so
+      # we can run them via swarming. We use ninja_to_gn.pyl to convert
+      # the compile targets to the matching GN labels.
+      contents = self.ReadFile(self.args.swarming_targets_file)
+      swarming_targets = contents.splitlines()
+      ninja_targets_to_labels = ast.literal_eval(self.ReadFile(os.path.join(
+          self.chromium_src_dir, 'testing', 'buildbot', 'ninja_to_gn.pyl')))
+      gn_labels = []
+      for target in swarming_targets:
+        if not target in ninja_targets_to_labels:
+          raise MBErr('test target "%s"  not found in %s' %
+                      (target, '//testing/buildbot/ninja_to_gn.pyl'))
+        gn_labels.append(ninja_targets_to_labels[target])
+
+      gn_runtime_deps_path = self.ToAbsPath(path, 'runtime_deps')
+      self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n')
+      cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path)
+
     ret, _, _ = self.Run(cmd)
+
+    for target in swarming_targets:
+      deps_path = self.ToAbsPath(path, target + '.runtime_deps')
+      if not self.Exists(deps_path):
+          raise MBErr('did not generate %s' % deps_path)
+
     return ret
 
   def GNCmd(self, subcommand, path, gn_args=''):
@@ -387,7 +418,7 @@
       outp = json.loads(self.ReadFile(self.args.output_path[0]))
       self.Print()
       self.Print('analyze output:')
-      self.PrintJSON(inp)
+      self.PrintJSON(outp)
       self.Print()
 
     return ret
@@ -504,10 +535,10 @@
 
     return cmdline, extra_files
 
-  def ToAbsPath(self, build_path, relpath):
+  def ToAbsPath(self, build_path, *comps):
     return os.path.join(self.chromium_src_dir,
                         self.ToSrcRelPath(build_path),
-                        relpath)
+                        *comps)
 
   def ToSrcRelPath(self, path):
     """Returns a relative path from the top of the repo."""
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index aab60a8c..8b0aee1 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -31,6 +31,9 @@
     'gn_debug_static_bot': ['gn', 'debug_static_bot'],
     'gn_debug_static_bot_x86': ['gn', 'debug_static_bot', 'x86'],
     'gyp_release_bot': ['gyp', 'release_bot'],
+    # clang/win doesn't work with goma yet, so this can't use debug_bot:
+    'win_clang_debug_bot':
+        ['gn', 'clang', 'debug', 'shared', 'minimal_symbols'],
   },
   
   # This is a list of configs that do not actually exist on any bot
@@ -69,6 +72,11 @@
       'gyp_defines': 'chromeos=1',
     },
 
+    'clang': {
+      'gn_args': 'is_clang=true',
+      'gyp_defines': 'clang=1',
+    },
+
     'dcheck_always_on': {
       'gn_args': 'dcheck_always_on=true',
       'gyp_defines': 'dcheck_always_on=1',
@@ -179,6 +187,9 @@
       'Linux GN': 'gn_release_bot',
       'Linux GN (dbg)': 'gn_debug_bot'
     },
+    'chromium.fyi': {
+      'CrWinClang64(dbg)': 'win_clang_debug_bot',
+    },
     'chromium.webrtc.fyi': {
       'Android GN': 'android_gn_release_bot',
       'Android GN (dbg)': 'android_gn_debug_bot',
@@ -216,7 +227,7 @@
     'tryserver.chromium.win': {
       'win_chromium_gn_x64_dbg': 'gn_debug_static_bot',
       'win_chromium_gn_x64_rel': 'gn_release_trybot',
-      'win8_chromium_rel': 'gn_release_trybot_x86',
+      'win8_chromium_ng': 'gn_release_trybot_x86',
       'win8_chromium_gn_dbg': 'gn_debug_static_bot_x86',
       'win8_chromium_gn_rel': 'gn_release_trybot_x86',
       'win8_chromium_gn_upload': 'gn_release_bot',
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 0990180..370f1431 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -66,6 +66,36 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="AboutFlags_data-reduction-proxy-lo-fi@1">
+  <owner>bengr@chromium.org</owner>
+  <owner>megjablon@chromium.org</owner>
+  <description>
+    User enabled flag that Forces Data Saver Lo-Fi mode to be always enabled via
+    chrome://flags. The action is emitted once per startup when the flag is
+    active.
+  </description>
+</action>
+
+<action name="AboutFlags_data-reduction-proxy-lo-fi@2">
+  <owner>bengr@chromium.org</owner>
+  <owner>megjablon@chromium.org</owner>
+  <description>
+    User enabled flag that Forces Data Saver Lo-Fi mode to be enabled only on
+    cellular connection via chrome://flags. The action is emitted once per
+    startup when the flag is active.
+  </description>
+</action>
+
+<action name="AboutFlags_data-reduction-proxy-lo-fi@3">
+  <owner>bengr@chromium.org</owner>
+  <owner>megjablon@chromium.org</owner>
+  <description>
+    User enabled flag that Forces Data Saver Lo-Fi mode to be disabled via
+    chrome://flags. The action is emitted once per startup when the flag is
+    active.
+  </description>
+</action>
+
 <action name="AboutFlags_disable-chrome-to-mobile">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
@@ -2501,6 +2531,15 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="Desktop_SwitchTask">
+  <owner>bruthig@google.com</owner>
+  <owner>tdanderson@google.com</owner>
+  <description>
+    Recorded when the user activates an existing task window by clicking or
+    tapping on it. Recorded on ChromeOS only.
+  </description>
+</action>
+
 <action name="Destination_Application_Edit">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
@@ -11343,6 +11382,23 @@
   </description>
 </action>
 
+<action name="StatusArea_Cast_Detailed_Launch_Cast">
+  <owner>jdufault@chromium.org</owner>
+  <description>
+    Counts the number of times the user has initiated a cast from the system
+    tray. This does not mean the cast has actually begun, as the user still has
+    to select what to cast (ie, the desktop or a tab) and they may cancel the
+    process.
+  </description>
+</action>
+
+<action name="StatusArea_Cast_StopCast">
+  <owner>jdufault@chromium.org</owner>
+  <description>
+    Counts the number of times the user has stopped a cast from the system tray.
+  </description>
+</action>
+
 <action name="StatusArea_Drive_CancelOperation">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index c23dc08..1dd93e8 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -62,7 +62,7 @@
 will be inserted after the first dot separator of the affected-histogram name.
 Therefore, the affected-histogram name has to have at least one dot in it.
 
-Goolgers: There are also a small number of private internal histograms found at
+Googlers: There are also a small number of private internal histograms found at
 http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
 -->
 
@@ -626,6 +626,20 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.Desktop.TimeBetweenNavigateToTaskSwitches" units="seconds">
+  <owner>bruthig@chromium.org</owner>
+  <owner>tdanderson@chromium.org</owner>
+  <summary>
+    The number of seconds between task window activations triggered by users
+    clicking or tapping on a window, as recorded by the Desktop_SwitchTask user
+    action. Recorded on ChromeOS only. Task switches from other sources are
+    ignored and do not affect this metric. In other words, if a user performs
+    the following steps (1) click on task window 'A' (2) Alt+Tab to task 'Z'(3)
+    click on task window 'B', then this will result in a sample recorded for the
+    time delta between activating task window 'A'and 'B'.
+  </summary>
+</histogram>
+
 <histogram name="Ash.Dock.Action" enum="DockedAction">
   <owner>kuscher@google.com</owner>
   <owner>varkha@chromium.org</owner>
@@ -846,6 +860,20 @@
   </summary>
 </histogram>
 
+<histogram name="Ash.TimeBetweenTaskSwitches" units="seconds">
+  <owner>bruthig@google.com</owner>
+  <owner>tdanderson@google.com</owner>
+  <summary>
+    The number of seconds between contiguous task switch user actions triggered
+    by any of the other task switch actions that are tracked. (e.g.,
+    Ash.Shelf.TimeBetweenNavigateToTaskSwitches,
+    Ash.Tab.TimeBetweenSwitchToExistingTabUserActions,
+    Ash.WindowCycleController.TimeBetweenTaskSwitches,
+    Ash.AppList.TimeBetweenTaskSwitches,
+    Ash.WindowSelector.TimeBetweenActiveWindowChanges, etc).
+  </summary>
+</histogram>
+
 <histogram name="Ash.TouchDuration" units="milliseconds">
   <obsolete>
     Deprecated 12/2013 in r239809, and replaced by Ash.TouchDuration2.
@@ -4695,6 +4723,20 @@
   </summary>
 </histogram>
 
+<histogram name="DataReductionProxy.LoFi.ImplicitOptOutAction"
+    enum="DataReductionProxyLoFiImplicitOptOutAction">
+  <owner>bengr@chromium.org</owner>
+  <owner>megjablon@chromium.org</owner>
+  <summary>
+    Counts of Lo-Fi implicit opt out actions. If the user chooses to &quot;Load
+    image&quot; for k pages in a session, LoFi is disabled for the remainder of
+    that session. If Lo-Fi is disabled for j consecutive sessions, Lo-Fi is
+    disabled for that user until the next implicit opt out epoch, which may be
+    in a later session, or never. k and j default to 3 and are assigned via the
+    DataReductionProxyLoFi field trial.
+  </summary>
+</histogram>
+
 <histogram name="DataReductionProxy.LoFi.UIAction"
     enum="DataReductionProxyLoFiUIAction">
   <owner>bengr@chromium.org</owner>
@@ -6479,6 +6521,15 @@
   </summary>
 </histogram>
 
+<histogram name="DomDistiller.Time.RunJavaScript" units="milliseconds">
+  <owner>wychen@chromium.org</owner>
+  <summary>
+    Time spent in ExecuteJavaScript() in DomDistiller. It includes JavaScript
+    code transmission through IPC, parsing, compilation, execution, and
+    returning the JSON back through IPC.
+  </summary>
+</histogram>
+
 <histogram name="DomDistiller.Time.SwipeToPaint" units="milliseconds">
   <owner>wychen@chromium.org</owner>
   <summary>
@@ -7106,6 +7157,11 @@
   <summary>The write size for calls to BaseFile::AppendDataTofile().</summary>
 </histogram>
 
+<histogram name="Drive.BatchUploadResponseCode" enum="HttpResponseCode">
+  <owner>hirono@chromium.org</owner>
+  <summary>Respose code of batch upload request.</summary>
+</histogram>
+
 <histogram name="Drive.CacheDBOpenStatus" enum="DriveCacheDBOpenStatus">
   <obsolete>
     Deprecated 8/2013.
@@ -7276,6 +7332,16 @@
   </summary>
 </histogram>
 
+<histogram name="Drive.TotalFileCountInBatchUpload">
+  <owner>hirono@chromium.org</owner>
+  <summary>Total file count contained in a drive batch upload request.</summary>
+</histogram>
+
+<histogram name="Drive.TotalFileSizeInBatchUpload" units="KB">
+  <owner>hirono@chromium.org</owner>
+  <summary>Total file size contained in a drive batch upload request.</summary>
+</histogram>
+
 <histogram name="Drive.TransferBlockedOnJobs" units="jobs">
   <owner>mtomasz@chromium.org</owner>
   <summary>
@@ -7285,6 +7351,14 @@
   </summary>
 </histogram>
 
+<histogram name="Drive.UploadProtocol" enum="DriveUploadProtocol">
+  <owner>hirono@chromium.org</owner>
+  <summary>
+    Upload protocol for each file. e.g. Batch upload including 5 files triggers
+    the metric 5 times.
+  </summary>
+</histogram>
+
 <histogram name="Drive.UploadToDriveFileSize" units="KB">
   <owner>mtomasz@chromium.org</owner>
   <summary>
@@ -10583,15 +10657,15 @@
   <owner>rpaquay@chromium.org</owner>
   <summary>
     The permissions present in an extension when it is automatically disabled
-    due to a permission increase (e.g., after an extension upgrade). To find
-    places where this histogram may be emitted, look for calls to
-    ExtensionService::RecordPermissionMessagesHistogram with the argument
-    AutoDisable.
+    due to a permission increase (e.g., after an extension upgrade).
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_AutoDisable2"
     enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by Extensions.Permissions_AutoDisable3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -10621,14 +10695,14 @@
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
-    The permissions present in an extension when it was installed. To find
-    places where this histogram may be emitted, look for calls to
-    ExtensionService::RecordPermissionMessagesHistogram with the argument
-    Install.
+    The permissions present in an extension when it was installed.
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_Install2" enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by Extensions.Permissions_Install3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -10656,15 +10730,15 @@
   <owner>rpaquay@chromium.org</owner>
   <summary>
     The permissions present in an extension when installation was aborted, not
-    including installation errors and user cancels. To find places where this
-    histogram may be emitted, look for calls to
-    ExtensionService::RecordPermissionMessagesHistogram with the argument
-    InstallAbort.
+    including installation errors and user cancels.
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_InstallAbort2"
     enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by Extensions.Permissions_InstallAbort3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -10695,15 +10769,15 @@
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
-    The permissions present in an extension when installation was canceled. To
-    find places where this histogram may be emitted, look for calls to
-    ExtensionService::RecordPermissionMessagesHistogram with the argument
-    InstallCancel.
+    The permissions present in an extension when installation was canceled.
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_InstallCancel2"
     enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by Extensions.Permissions_InstallCancel3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -10733,13 +10807,12 @@
 </histogram>
 
 <histogram name="Extensions.Permissions_Load2" enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by Extensions.Permissions_Load3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
-  <summary>
-    The permissions present in an extension when it was loaded. To find places
-    where this histogram may be emitted, look for calls to
-    ExtensionService::RecordPermissionMessagesHistogram with the argument Load.
-  </summary>
+  <summary>The permissions present in an extension when it was loaded.</summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_Load3" enum="ExtensionPermission3">
@@ -10761,13 +10834,14 @@
   <owner>rpaquay@chromium.org</owner>
   <summary>
     The permissions present in an extension when it was re-enabled from a
-    confirmation prompt. To find places where this histogram may be emitted,
-    look for calls to ExtensionService::RecordPermissionMessagesHistogram with
-    the argument ReEnable.
+    confirmation prompt.
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_ReEnable2" enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by Extensions.Permissions_ReEnable3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -10796,15 +10870,15 @@
   <owner>rpaquay@chromium.org</owner>
   <summary>
     The permissions present in an extension when the re-enable prompt was
-    aborted, not including installation errors and manual user cancels. To find
-    places where this histogram may be emitted, look for calls to
-    ExtensionService::RecordPermissionMessagesHistogram with the argument
-    ReEnableAbort.
+    aborted, not including installation errors and manual user cancels.
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_ReEnableAbort2"
     enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by Extensions.Permissions_ReEnableAbort3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -10836,14 +10910,15 @@
   <owner>rpaquay@chromium.org</owner>
   <summary>
     The permissions present in an extension when the re-enable was canceled from
-    the confirmation prompt. To find places where this histogram may be emitted,
-    look for calls to ExtensionService::RecordPermissionMessagesHistogram with
-    the argument ReEnableCancel.
+    the confirmation prompt.
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_ReEnableCancel2"
     enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by Extensions.Permissions_ReEnableCancel3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -10871,14 +10946,14 @@
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
-    The permissions present in an extension when it was uninstalled. To find
-    places where this histogram may be emitted, look for calls to
-    ExtensionService::RecordPermissionMessagesHistogram with the argument
-    Uninstall.
+    The permissions present in an extension when it was uninstalled.
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_Uninstall2" enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by Extensions.Permissions_Uninstall3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -10907,14 +10982,16 @@
   <owner>rpaquay@chromium.org</owner>
   <summary>
     The permissions present in an extension when it was installed through the
-    web store. To find places where this histogram may be emitted, look for
-    calls to ExtensionService::RecordPermissionMessagesHistogram with the
-    argument WebStoreInstall.
+    web store.
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_WebStoreInstall2"
     enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by
+    Extensions.Permissions_WebStoreInstall3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -10946,15 +11023,16 @@
   <owner>rpaquay@chromium.org</owner>
   <summary>
     The permissions present in an extension when installation from the web store
-    was aborted, not including installation errors and user cancels. To find
-    places where this histogram may be emitted, look for calls to
-    ExtensionService::RecordPermissionMessagesHistogram with the argument
-    WebStoreInstallAbort.
+    was aborted, not including installation errors and user cancels.
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_WebStoreInstallAbort2"
     enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by
+    Extensions.Permissions_WebStoreInstallAbort3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -10987,14 +11065,16 @@
   <owner>rpaquay@chromium.org</owner>
   <summary>
     The permissions present in an extension when installation from the web store
-    was canceled. To find places where this histogram may be emitted, look for
-    calls to ExtensionService::RecordPermissionMessagesHistogram with the
-    argument WebStoreInstallCancel.
+    was canceled.
   </summary>
 </histogram>
 
 <histogram name="Extensions.Permissions_WebStoreInstallCancel2"
     enum="ExtensionPermission2">
+  <obsolete>
+    Deprecated as of 6/2015, replaced by
+    Extensions.Permissions_WebStoreInstallCancel3.
+  </obsolete>
   <owner>kalman@chromium.org</owner>
   <owner>rpaquay@chromium.org</owner>
   <summary>
@@ -14681,6 +14761,79 @@
   </summary>
 </histogram>
 
+<histogram name="LevelDBEnv.ServiceWorker.IOError" enum="LevelDBIOErrorMethods">
+  <owner>nhiroki@chromium.org</owner>
+  <summary>
+    Methods where leveldb's Chromium environment has IO errors when being used
+    by ServiceWorker.
+  </summary>
+</histogram>
+
+<histogram name="LevelDBEnv.ServiceWorker.IOError." enum="PlatformFileError">
+  <owner>nhiroki@chromium.org</owner>
+  <summary>
+    PlatformFileErrors encountered by a single leveldb env method.
+  </summary>
+</histogram>
+
+<histogram name="LevelDBEnv.ServiceWorker.IOError.BFE" enum="PlatformFileError">
+  <owner>nhiroki@chromium.org</owner>
+  <summary>
+    Errors (base::File::Error) encountered by a single leveldb env method.
+  </summary>
+</histogram>
+
+<histogram name="LevelDBEnv.ServiceWorker.LockFileAncestorsNotFound"
+    units="directories">
+  <owner>nhiroki@chromium.org</owner>
+  <summary>
+    Number of directories missing when ServiceWorker LevelDBEnv tries to create
+    a Lock file.
+  </summary>
+</histogram>
+
+<histogram name="LevelDBEnv.ServiceWorker.MaxFDs" units="files">
+  <owner>nhiroki@chromium.org</owner>
+  <summary>
+    File descriptor limit recorded every time LevelDB calls NewRandomAccessFile
+    for ServiceWorker.
+  </summary>
+</histogram>
+
+<histogram name="LevelDBEnv.ServiceWorker.MissingFiles" units="files">
+  <owner>nhiroki@chromium.org</owner>
+  <summary>
+    Number of backup files found without corresponding ldb files. As measured by
+    GetChildren when used in ServiceWorker.
+  </summary>
+</histogram>
+
+<histogram name="LevelDBEnv.ServiceWorker.RetryRecoveredFromErrorIn"
+    enum="PlatformFileError">
+  <owner>nhiroki@chromium.org</owner>
+  <summary>
+    When ServiceWorker LevelDBEnv successfully retries an operation that had
+    failed, record the error from the most recent failed attempt.
+  </summary>
+</histogram>
+
+<histogram name="LevelDBEnv.ServiceWorker.Table" enum="BooleanSuccess">
+  <owner>nhiroki@chromium.org</owner>
+  <summary>
+    Success indicates a successful backup or restore operation for .ldb table
+    files when used in ServiceWorker.
+  </summary>
+</histogram>
+
+<histogram name="LevelDBEnv.ServiceWorker.TimeUntilSuccessFor"
+    units="milliseconds">
+  <owner>nhiroki@chromium.org</owner>
+  <summary>
+    Time ServiceWorker LevelDBEnv slept before successfully completing this
+    operation. 0 means success on the first try.
+  </summary>
+</histogram>
+
 <histogram name="LevelDBEnv.Table" enum="BooleanSuccess">
   <owner>dgrogan@chromium.org</owner>
   <summary>
@@ -15582,6 +15735,9 @@
 </histogram>
 
 <histogram name="Media.Initialize.Windows" units="GetLastError">
+  <obsolete>
+    Deprecated 05/2015 in Issue 1141703002. FFmpeg is now statically linked.
+  </obsolete>
   <owner>scherkus@chromium.org</owner>
   <summary>
     Errors returned by LoadLibraryEx on Windows while attempting to load
@@ -19585,7 +19741,7 @@
   </summary>
 </histogram>
 
-<histogram name="Net.DailyUserVisibleSavingsPercent_DataRedictionProxyEnabled"
+<histogram name="Net.DailyUserVisibleSavingsPercent_DataReductionProxyEnabled"
     units="Percent">
   <owner>kundaji@chromium.org</owner>
   <owner>bengr@chromium.org</owner>
@@ -19596,7 +19752,7 @@
   </summary>
 </histogram>
 
-<histogram name="Net.DailyUserVisibleSavingsSize_DataRedictionProxyEnabled"
+<histogram name="Net.DailyUserVisibleSavingsSize_DataReductionProxyEnabled"
     units="KB">
   <owner>kundaji@chromium.org</owner>
   <owner>bengr@chromium.org</owner>
@@ -41559,20 +41715,27 @@
 <histogram name="Startup.LoadTime.ExeMainToDllMain">
   <owner>jeremy@chromium.org</owner>
   <summary>
-    Time from the main() function in chrome.exe to chrome.dll's main().
+    Time from the main() function in chrome.exe to chrome.dll's main(). This
+    stat is only recorded after 7 minutes of OS uptime to try to mitigate the
+    variance resulting from Chrome being autostarted.
   </summary>
 </histogram>
 
 <histogram name="Startup.LoadTime.ProcessCreateToDllMain">
   <owner>jeremy@chromium.org</owner>
-  <summary>Time from the process creation to chrome.dll's main().</summary>
+  <summary>
+    Time from the process creation to chrome.dll's main(). This stat is only
+    recorded after 7 minutes of OS uptime to try to mitigate the variance
+    resulting from Chrome being autostarted.
+  </summary>
 </histogram>
 
 <histogram name="Startup.LoadTime.ProcessCreateToExeMain">
   <owner>jeremy@chromium.org</owner>
   <summary>
     Time from the process creation to executing the main() function in
-    chrome.exe.
+    chrome.exe. This stat is only recorded after 7 minutes of OS uptime to try
+    to mitigate the variance resulting from Chrome being autostarted.
   </summary>
 </histogram>
 
@@ -41702,6 +41865,9 @@
 </histogram>
 
 <histogram name="Startup.SlowStartupBookmarksLoad" units="milliseconds">
+  <obsolete>
+    Deprecated 06/2015.
+  </obsolete>
   <owner>jeremy@chromium.org</owner>
   <summary>
     Time it takes to load bookmarks from disk. This measurement is only sent for
@@ -41711,6 +41877,9 @@
 
 <histogram name="Startup.SlowStartupExtensionServiceInitAfterImport"
     units="milliseconds">
+  <obsolete>
+    Deprecated 06/2015.
+  </obsolete>
   <owner>jeremy@chromium.org</owner>
   <summary>
     Time it takes to finish initialization of the extension service including
@@ -41720,6 +41889,9 @@
 </histogram>
 
 <histogram name="Startup.SlowStartupFinalProfileInit" units="milliseconds">
+  <obsolete>
+    Deprecated 06/2015.
+  </obsolete>
   <owner>jeremy@chromium.org</owner>
   <summary>
     Time the final stages of profile initialization taking including
@@ -41729,6 +41901,9 @@
 </histogram>
 
 <histogram name="Startup.SlowStartupNSSInit" units="milliseconds">
+  <obsolete>
+    Deprecated 06/2015.
+  </obsolete>
   <owner>jeremy@chromium.org</owner>
   <summary>
     Time it takes to load the NSS libraries and initialize it. This measurement
@@ -41738,6 +41913,9 @@
 </histogram>
 
 <histogram name="Startup.SlowStartupPreferenceLoading" units="milliseconds">
+  <obsolete>
+    Deprecated 06/2015.
+  </obsolete>
   <owner>jeremy@chromium.org</owner>
   <summary>
     Time it takes to load preferences from disk. This measurement is only sent
@@ -41746,6 +41924,9 @@
 </histogram>
 
 <histogram name="Startup.SlowStartupProfileIODataInit" units="milliseconds">
+  <obsolete>
+    Deprecated 06/2015.
+  </obsolete>
   <owner>jeremy@chromium.org</owner>
   <summary>
     Time it takes to initialize the ProfileIOData object - this includes
@@ -41756,6 +41937,9 @@
 
 <histogram name="Startup.SlowStartupSafeBrowsingGetDatabase"
     units="milliseconds">
+  <obsolete>
+    Deprecated 06/2015.
+  </obsolete>
   <owner>jeremy@chromium.org</owner>
   <summary>
     Time it takes to load the safe browsing database from disk. This measurement
@@ -41766,6 +41950,9 @@
 
 <histogram name="Startup.SlowStartupSafeBrowsingServiceInitialize"
     units="milliseconds">
+  <obsolete>
+    Deprecated 06/2015.
+  </obsolete>
   <owner>jeremy@chromium.org</owner>
   <summary>
     Time it takes to initialize the safe browsing service. This measurement is
@@ -41776,6 +41963,9 @@
 
 <histogram name="Startup.SlowStartupSessionServiceCreateTabsAndWindows"
     units="milliseconds">
+  <obsolete>
+    Deprecated 06/2015.
+  </obsolete>
   <owner>jeremy@chromium.org</owner>
   <summary>
     Time it takes for session restore to finish initiating creation of restored
@@ -44323,6 +44513,22 @@
   <owner>pthammaiah@google.com</owner>
 </histogram>
 
+<histogram name="Tracing.Background.FinalizingTraceSizeInKB" units="KB">
+  <owner>oysteine@chromium.org</owner>
+  <summary>
+    The size, in kilobytes, of a finalized trace ready to be uploaded.
+  </summary>
+</histogram>
+
+<histogram name="Tracing.Background.ScenarioState"
+    enum="BackgroundTracingState">
+  <owner>oysteine@chromium.org</owner>
+  <summary>
+    Records state of the Background Tracing system, from when scenarios are
+    attempted to be activated until they're completed (successfully or failed)
+  </summary>
+</histogram>
+
 <histogram name="Translate.AlwaysTranslateLang">
   <owner>kenjibaheux@google.com</owner>
   <summary>
@@ -48383,6 +48589,18 @@
   </summary>
 </histogram>
 
+<histogram name="websql.Async.OpenTime.Error" units="milliseconds">
+  <owner>cmumford@chromium.org</owner>
+  <summary>
+    The time required to try (and fail) to open a Web SQL database.
+  </summary>
+</histogram>
+
+<histogram name="websql.Async.OpenTime.Success" units="milliseconds">
+  <owner>cmumford@chromium.org</owner>
+  <summary>The time required to successfully open a Web SQL database.</summary>
+</histogram>
+
 <histogram name="Webstore.ExtensionInstallResult" enum="BooleanSuccess">
   <owner>jackhou@chromium.org</owner>
   <summary>
@@ -49416,6 +49634,18 @@
   <int value="3" label="AUTO_LAUNCH_FOREGROUND_USELESS"/>
 </enum>
 
+<enum name="BackgroundTracingState" type="int">
+  <int value="0" label="Scenario activation requested"/>
+  <int value="1" label="Scenario successfully activated"/>
+  <int value="2" label="Trace recording enabled"/>
+  <int value="3" label="Running preemptive scenario triggered"/>
+  <int value="4" label="Running reactive scenario triggered"/>
+  <int value="5" label="Trace finalization allowed"/>
+  <int value="6" label="Trace finalization disallowed"/>
+  <int value="7" label="Trace finalization started"/>
+  <int value="8" label="Trace finalization complete"/>
+</enum>
+
 <enum name="BackingStoreResults" type="int">
   <int value="0" label="Unused"/>
   <int value="1" label="Success"/>
@@ -49509,6 +49739,12 @@
   <int value="75" label="FAMF_APPEND_SHARED_MEMORY_TO_STREAM"/>
   <int value="76" label="IDBDH_CAN_READ_FILE"/>
   <int value="77" label="IDBDH_GET_OR_TERMINATE"/>
+  <int value="78" label="RMF_SET_COOKIE_BAD_ORIGIN"/>
+  <int value="79" label="RMF_GET_COOKIES_BAD_ORIGIN"/>
+  <int value="80" label="SWDH_GET_REGISTRATIONS_NO_HOST"/>
+  <int value="81" label="SWDH_GET_REGISTRATIONS_INVALID_ORIGIN"/>
+  <int value="82" label="ARH_UNAUTHORIZED_URL"/>
+  <int value="83" label="BDH_INVALID_SERVICE_ID"/>
 </enum>
 
 <enum name="BadMessageReasonExtensions" type="int">
@@ -49533,6 +49769,7 @@
   <int value="1" label="Bad version"/>
   <int value="2" label="Bad update URL"/>
   <int value="3" label="No ExtensionSpecifics"/>
+  <int value="4" label="Bad disable reasons"/>
 </enum>
 
 <enum name="BaseRelocationType" type="int">
@@ -51177,6 +51414,12 @@
   <int value="10" label="Bypass due to any network error"/>
 </enum>
 
+<enum name="DataReductionProxyLoFiImplicitOptOutAction" type="int">
+  <int value="0" label="Lo-Fi disabled for the remainder of the session"/>
+  <int value="1" label="Lo-Fi disabled until next opt out epoch"/>
+  <int value="2" label="Next implict opt out epoch, Lo-Fi re-enabled"/>
+</enum>
+
 <enum name="DataReductionProxyLoFiUIAction" type="int">
   <int value="0" label="'Load images' snackbar shown"/>
   <int value="1" label="'Load images' snackbar clicked"/>
@@ -51214,6 +51457,9 @@
   <int value="3" label="Proxy pref containing a DRP was cleared"/>
   <int value="4"
       label="Proxy pref containing a *.googlezip.net proxy was cleared"/>
+  <int value="5"
+      label="Proxy pref of an embedded PAC script containing a
+             *.googlezip.net proxy was cleared"/>
 </enum>
 
 <enum name="DataReductionProxyResponseProxyServerStatus" type="int">
@@ -51921,6 +52167,12 @@
   <int value="7" label="Iterator error"/>
 </enum>
 
+<enum name="DriveUploadProtocol" type="int">
+  <int value="0" label="Resumable"/>
+  <int value="1" label="Multipart"/>
+  <int value="2" label="Batch"/>
+</enum>
+
 <enum name="DumpOutcome" type="int">
   <int value="0" label="Success"/>
   <int value="1" label="Failure"/>
@@ -54112,6 +54364,10 @@
   <int value="1048" label="USERSPRIVATE_ISCURRENTUSEROWNER"/>
   <int value="1049" label="USERSPRIVATE_ISWHITELISTMANAGED"/>
   <int value="1050" label="PRINTERPROVIDERINTERNAL_REPORTUSBPRINTERINFO"/>
+  <int value="1051" label="WEBCAMPRIVATE_OPENSERIALWEBCAM"/>
+  <int value="1052" label="WEBCAMPRIVATE_CLOSEWEBCAM"/>
+  <int value="1053" label="SERIAL_SETBREAK"/>
+  <int value="1054" label="SERIAL_CLEARBREAK"/>
 </enum>
 
 <enum name="ExtensionInstallCause" type="int">
@@ -58377,12 +58633,14 @@
   <int value="-1433719718" label="enable-webrtc-stun-origin"/>
   <int value="-1433087548" label="enable-app-install-alerts"/>
   <int value="-1419788257" label="enable-experimental-hotwording"/>
+  <int value="-1416754663" label="enable-mac-views-native-app-windows"/>
   <int value="-1411003295" label="disable-encrypted-media"/>
   <int value="-1409643943" label="enable-child-account-detection"/>
   <int value="-1408288176" label="enable-account-consistency"/>
   <int value="-1399753480" label="disable-harfbuzz-rendertext"/>
   <int value="-1399419572" label="enable-app-list"/>
   <int value="-1392562498" label="disable-origin-chip"/>
+  <int value="-1386966873" label="disable-mac-views-native-app-windows"/>
   <int value="-1375111024" label="enable-fixed-position-compositing"/>
   <int value="-1358669137" label="enable-supervised-user-blacklist"/>
   <int value="-1357655121" label="enable-iframe-based-signin"/>
@@ -58485,6 +58743,7 @@
   <int value="-385337473" label="enable-fast-unload"/>
   <int value="-384589459" label="disable-supervised-user-safesites"/>
   <int value="-378033324" label="disable-win32k-renderer-lockdown"/>
+  <int value="-360038744" label="invert-viewport-scroll-order"/>
   <int value="-349057743" label="extensions-on-chrome-urls"/>
   <int value="-344343842" label="disable-experimental-app-list"/>
   <int value="-340622848" label="disable-javascript-harmony-shipping"/>
@@ -58673,6 +58932,7 @@
   <int value="1381746642" label="enable-automatic-password-saving"/>
   <int value="1382500494" label="disable-drive-apps-in-app-list"/>
   <int value="1383591631" label="enable-gesture-typing"/>
+  <int value="1389729816" label="data-reduction-proxy-lo-fi"/>
   <int value="1405459667" label="enable-fast-text-autosizing"/>
   <int value="1407625309"
       label="disable-minimize-on-second-launcher-item-click"/>
@@ -59437,6 +59697,11 @@
   <int value="496" label="alias-webkit-shape-image-threshold"/>
   <int value="497" label="alias-webkit-shape-margin"/>
   <int value="498" label="alias-webkit-shape-outside"/>
+  <int value="499" label="scroll-snap-type"/>
+  <int value="500" label="scroll-snap-points-x"/>
+  <int value="501" label="scroll-snap-points-y"/>
+  <int value="502" label="scroll-snap-coordinate"/>
+  <int value="503" label="scroll-snap-destination"/>
 </enum>
 
 <enum name="MappedEditingCommands" type="int">
@@ -59790,10 +60055,10 @@
     chrome/browser/android/metrics/uma_bridge.cc and reference possible ways of
     completing the sign-in part of the First Run Experience.
   </summary>
-  <int value="0" label="Accept default account"/>
-  <int value="1" label="Accept another account"/>
-  <int value="2" label="Settings default account"/>
-  <int value="3" label="Settings another account"/>
+  <int value="0" label="Settings default account"/>
+  <int value="1" label="Settings another account"/>
+  <int value="2" label="Accept default account"/>
+  <int value="3" label="Accept another account"/>
   <int value="4" label="No thanks"/>
 </enum>
 
@@ -60063,6 +60328,7 @@
   <int value="6" label="javascript"/>
   <int value="7" label="about"/>
   <int value="8" label="chrome"/>
+  <int value="9" label="blob"/>
 </enum>
 
 <enum name="NetCacheState" type="int">
@@ -62314,6 +62580,7 @@
   <int value="1" label="Unthrottled by Click"/>
   <int value="2" label="Unthrottled by Retroactive Whitelist"/>
   <int value="3" label="Unthrottled by Audio Playback"/>
+  <int value="4" label="Unthrottled by Size Change"/>
 </enum>
 
 <enum name="PNaClOptionsOptLevelEnum" type="int">
@@ -64764,6 +65031,7 @@
   <int value="14" label="SERVICE_WORKER_ERROR_TIMEOUT"/>
   <int value="15" label="SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED"/>
   <int value="16" label="SERVICE_WORKER_ERROR_DISK_CACHE"/>
+  <int value="17" label="SERVICE_WORKER_ERROR_REDUNDANT"/>
 </enum>
 
 <enum name="ServiceWorkerWriteResponseResult" type="int">
@@ -65660,6 +65928,7 @@
   <int value="1" label="Accepted"/>
   <int value="2" label="Denied"/>
   <int value="3" label="Fell back to download page"/>
+  <int value="4" label="SRT download unavailable, no prompt shown."/>
 </enum>
 
 <enum name="SSLCaptivePortal" type="int">
@@ -66483,6 +66752,11 @@
   <int value="5" label="Registry exit code"/>
   <int value="6" label="Reset retries"/>
   <int value="7" label="Begin SRT download"/>
+  <int value="8" label="No browser to show prompt"/>
+  <int value="9" label="No local state"/>
+  <int value="10" label="No prompt needed"/>
+  <int value="11" label="No prompt field trial"/>
+  <int value="12" label="Already prompted"/>
 </enum>
 
 <enum name="SyncAttachmentStoreResult" type="int">
@@ -69506,6 +69780,7 @@
       label="ChromiumWritableFile::SyncParent"/>
   <affected-histogram name="LevelDBEnv.IDB.IOError.BFE"/>
   <affected-histogram name="LevelDBEnv.IOError.BFE"/>
+  <affected-histogram name="LevelDBEnv.ServiceWorker.IOError.BFE"/>
   <affected-histogram name="WebCore.IndexedDB.LevelDBOpenErrors.BFE"/>
   <affected-histogram name="WebCore.IndexedDB.LevelDBReadErrors.BFE"/>
   <affected-histogram name="WebCore.IndexedDB.LevelDBWriteErrors.BFE"/>
@@ -69515,6 +69790,7 @@
   <suffix name="Backup" label="Backing up an ldb file."/>
   <suffix name="Restore" label="Restoring an ldb file."/>
   <affected-histogram name="LevelDBEnv.IDB.Table"/>
+  <affected-histogram name="LevelDBEnv.ServiceWorker.Table"/>
   <affected-histogram name="LevelDBEnv.Table"/>
 </histogram_suffixes>
 
@@ -69529,6 +69805,7 @@
              other than exceeding the limit."/>
   <affected-histogram name="LevelDBEnv.IDB.MaxFDs"/>
   <affected-histogram name="LevelDBEnv.MaxFDs"/>
+  <affected-histogram name="LevelDBEnv.ServiceWorker.MaxFDs"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="LevelDBEnvPlatformFileErrors" separator="">
@@ -69539,6 +69816,7 @@
   <suffix name="RenameFile" label="ChromiumEnv::RenameFile"/>
   <affected-histogram name="LevelDBEnv.IDB.IOError."/>
   <affected-histogram name="LevelDBEnv.IOError."/>
+  <affected-histogram name="LevelDBEnv.ServiceWorker.IOError."/>
 </histogram_suffixes>
 
 <histogram_suffixes name="LevelDBEnvRetry" separator="">
@@ -69548,6 +69826,9 @@
   <affected-histogram name="LevelDBEnv.IDB.RetryRecoveredFromErrorIn"/>
   <affected-histogram name="LevelDBEnv.IDB.TimeUntilSuccessFor"/>
   <affected-histogram name="LevelDBEnv.RetryRecoveredFromErrorIn"/>
+  <affected-histogram
+      name="LevelDBEnv.ServiceWorker.RetryRecoveredFromErrorIn"/>
+  <affected-histogram name="LevelDBEnv.ServiceWorker.TimeUntilSuccessFor"/>
   <affected-histogram name="LevelDBEnv.TimeUntilSuccessFor"/>
 </histogram_suffixes>
 
diff --git a/tools/metrics/histograms/update_extension_permission.py b/tools/metrics/histograms/update_extension_permission.py
index 4e80249f..85073f98 100644
--- a/tools/metrics/histograms/update_extension_permission.py
+++ b/tools/metrics/histograms/update_extension_permission.py
@@ -2,9 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Updates ExtensionPermission2 and ExtensionPermission3 enums in histograms.xml
-file with values read from permission_message.h and api_permission.h,
-respectively.
+"""Updates the ExtensionPermission3 enum in the histograms.xml file with values
+read from api_permission.h.
 
 If the file was pretty-printed, the updated version is pretty-printed too.
 """
@@ -20,12 +19,6 @@
     sys.stderr.write(__doc__)
     sys.exit(1)
 
-  header_file = 'extensions/common/permissions/permission_message.h'
-  UpdateHistogramEnum(histogram_enum_name='ExtensionPermission2',
-                      source_enum_path=header_file,
-                      start_marker='^enum ID {',
-                      end_marker='^kEnumBoundary')
-
   header_file = 'extensions/common/permissions/api_permission.h'
   UpdateHistogramEnum(histogram_enum_name='ExtensionPermission3',
                       source_enum_path=header_file,
diff --git a/tools/metrics/rappor/rappor.xml b/tools/metrics/rappor/rappor.xml
index f4575571..b971378 100644
--- a/tools/metrics/rappor/rappor.xml
+++ b/tools/metrics/rappor/rappor.xml
@@ -135,6 +135,14 @@
   </summary>
 </rappor-metric>
 
+<rappor-metric name="ContentSettings.MixedScript.RanMixedScript"
+    type="ETLD_PLUS_ONE">
+  <owner>lgarron@chromium.org</owner>
+  <summary>
+    The eTLD+1 of a URL that when mixed script actually ran.
+  </summary>
+</rappor-metric>
+
 <rappor-metric name="ContentSettings.PermissionActions_Camera.Revoked.Url"
     type="ETLD_PLUS_ONE">
   <owner>jialiul@chromium.org</owner>
diff --git a/tools/perf/PRESUBMIT.py b/tools/perf/PRESUBMIT.py
index 6d01991..99ba8d5 100644
--- a/tools/perf/PRESUBMIT.py
+++ b/tools/perf/PRESUBMIT.py
@@ -31,7 +31,7 @@
 
 def _CheckWprShaFiles(input_api, output_api):
   """Check whether the wpr sha files have matching URLs."""
-  from telemetry.util import cloud_storage
+  from catapult_base import cloud_storage
   results = []
   for affected_file in input_api.AffectedFiles(include_deletes=False):
     filename = affected_file.AbsoluteLocalPath()
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 55e767be..e90bb59 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -61,7 +61,7 @@
     _AddDir(path, tuple(skipped))
   else:
     _AddPage(path)
-  ps = page_set.PageSet(file_path=os.getcwd()+os.sep,
+  ps = page_set.PageSet(base_dir=os.getcwd()+os.sep,
                         serving_dirs=serving_dirs)
   for url in page_urls:
     ps.AddUserStory(page_module.Page(
@@ -122,7 +122,8 @@
     assert 'content-shell' in options.browser_type
     options.AppendExtraBrowserArgs(['--expose-internals-for-testing'])
 
-
+# http://crbug.com/499472
+@benchmark.Disabled()
 class BlinkPerfAnimation(perf_benchmark.PerfBenchmark):
   tag = 'animation'
   test = _BlinkPerfMeasurement
diff --git a/tools/perf/benchmarks/blob_storage.py b/tools/perf/benchmarks/blob_storage.py
index 8d00be4..b448271c 100644
--- a/tools/perf/benchmarks/blob_storage.py
+++ b/tools/perf/benchmarks/blob_storage.py
@@ -18,7 +18,8 @@
 TIMELINE_REQUIRED_CATEGORY = 'blink.console'
 
 
-@benchmark.Disabled('reference')  # http://crbug.com/496155
+@benchmark.Disabled('reference',  # http://crbug.com/496155
+                    'android')    # http://crbug.com/499325
 class BlobStorage(perf_benchmark.PerfBenchmark):
   """Timeline based measurement benchmark for Blob Storage."""
 
diff --git a/tools/perf/benchmarks/chrome_signin_startup.py b/tools/perf/benchmarks/chrome_signin_startup.py
new file mode 100644
index 0000000..dc27d56
--- /dev/null
+++ b/tools/perf/benchmarks/chrome_signin_startup.py
@@ -0,0 +1,32 @@
+# 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.
+
+from core import perf_benchmark
+from measurements import startup
+import page_sets
+from telemetry import benchmark
+
+
+class _StartupWarm(perf_benchmark.PerfBenchmark):
+  """Measures warm startup time with a clean profile."""
+  options = {'pageset_repeat': 5}
+
+  @classmethod
+  def Name(cls):
+    return 'chrome_signin_starup'
+
+  def CreatePageTest(self, options):
+    return startup.Startup(cold=False)
+
+
+@benchmark.Enabled('has tabs')
+# crbug.com/499312
+@benchmark.Disabled('reference')
+class SigninStartup(_StartupWarm):
+  """Measures warm startup time of signing a profile into Chrome."""
+  page_set = page_sets.ChromeSigninPageSet
+
+  @classmethod
+  def Name(cls):
+    return 'startup.warm.chrome_signin'
diff --git a/tools/perf/benchmarks/dom_perf.py b/tools/perf/benchmarks/dom_perf.py
index 81ece8e..3c58a0b 100644
--- a/tools/perf/benchmarks/dom_perf.py
+++ b/tools/perf/benchmarks/dom_perf.py
@@ -110,7 +110,7 @@
 
   def CreatePageSet(self, options):
     dom_perf_dir = os.path.join(util.GetChromiumSrcDir(), 'data', 'dom_perf')
-    ps = page_set.PageSet(file_path=dom_perf_dir)
+    ps = page_set.PageSet(base_dir=dom_perf_dir)
     for param in self.RUN_PARAMS:
       ps.AddUserStory(page_module.Page(
           'file://run.html?reportInJS=1&run=%s' % param, ps, ps.base_dir))
diff --git a/tools/perf/benchmarks/dromaeo.py b/tools/perf/benchmarks/dromaeo.py
index d3dd3ca..9b2f4243 100644
--- a/tools/perf/benchmarks/dromaeo.py
+++ b/tools/perf/benchmarks/dromaeo.py
@@ -113,7 +113,8 @@
     archive_data_file = '../page_sets/data/dromaeo.%s.json' % self.tag
     ps = page_set.PageSet(
         archive_data_file=archive_data_file,
-        file_path=os.path.abspath(__file__), bucket=page_set.PUBLIC_BUCKET)
+        base_dir=os.path.dirname(os.path.abspath(__file__)),
+        bucket=page_set.PUBLIC_BUCKET)
     url = 'http://dromaeo.com?%s' % self.query_param
     ps.AddUserStory(page_module.Page(
         url, ps, ps.base_dir, make_javascript_deterministic=False))
diff --git a/tools/perf/benchmarks/indexeddb_perf.py b/tools/perf/benchmarks/indexeddb_perf.py
index c7f882ed2..c7dd3e7 100644
--- a/tools/perf/benchmarks/indexeddb_perf.py
+++ b/tools/perf/benchmarks/indexeddb_perf.py
@@ -93,6 +93,6 @@
   def CreatePageSet(self, options):
     indexeddb_dir = os.path.join(util.GetChromiumSrcDir(), 'chrome', 'test',
                                  'data', 'indexeddb')
-    ps = page_set.PageSet(file_path=indexeddb_dir)
+    ps = page_set.PageSet(base_dir=indexeddb_dir)
     ps.AddUserStory(page_module.Page('file://perf_test.html', ps, ps.base_dir))
     return ps
diff --git a/tools/perf/benchmarks/jetstream.py b/tools/perf/benchmarks/jetstream.py
index 90620cdb..9a73cef8 100644
--- a/tools/perf/benchmarks/jetstream.py
+++ b/tools/perf/benchmarks/jetstream.py
@@ -89,7 +89,7 @@
   def CreatePageSet(self, options):
     ps = page_set.PageSet(
         archive_data_file='../page_sets/data/jetstream.json',
-        file_path=os.path.abspath(__file__),
+        base_dir=os.path.dirname(os.path.abspath(__file__)),
         bucket=page_set.INTERNAL_BUCKET)
     ps.AddUserStory(page_module.Page(
         'http://browserbench.org/JetStream/', ps, ps.base_dir,
diff --git a/tools/perf/benchmarks/kraken.py b/tools/perf/benchmarks/kraken.py
index 0ddc0c4c..96868b8 100644
--- a/tools/perf/benchmarks/kraken.py
+++ b/tools/perf/benchmarks/kraken.py
@@ -128,7 +128,7 @@
   def CreatePageSet(self, options):
     ps = page_set.PageSet(
       archive_data_file='../page_sets/data/kraken.json',
-      file_path=os.path.abspath(__file__),
+      base_dir=os.path.dirname(os.path.abspath(__file__)),
       bucket=page_set.PARTNER_BUCKET)
     ps.AddUserStory(page_module.Page(
         'http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html',
diff --git a/tools/perf/benchmarks/maps.py b/tools/perf/benchmarks/maps.py
index f685191..0e68150 100644
--- a/tools/perf/benchmarks/maps.py
+++ b/tools/perf/benchmarks/maps.py
@@ -59,7 +59,7 @@
     page_set_path = os.path.join(
         util.GetChromiumSrcDir(), 'tools', 'perf', 'page_sets')
     ps = page_set_module.PageSet(
-        archive_data_file='data/maps.json', file_path=page_set_path,
+        archive_data_file='data/maps.json', base_dir=page_set_path,
         bucket=page_set_module.PUBLIC_BUCKET)
     ps.AddUserStory(MapsPage(ps, ps.base_dir))
     return ps
diff --git a/tools/perf/benchmarks/octane.py b/tools/perf/benchmarks/octane.py
index d9cb462..8c7c9da 100644
--- a/tools/perf/benchmarks/octane.py
+++ b/tools/perf/benchmarks/octane.py
@@ -145,7 +145,7 @@
   def CreatePageSet(self, options):
     ps = page_set.PageSet(
       archive_data_file='../page_sets/data/octane.json',
-      file_path=os.path.abspath(__file__),
+      base_dir=os.path.dirname(os.path.abspath(__file__)),
       bucket=page_set.PUBLIC_BUCKET)
     ps.AddUserStory(page_module.Page(
         'http://octane-benchmark.googlecode.com/svn/latest/index.html?auto=1',
diff --git a/tools/perf/benchmarks/oilpan_gc_times.py b/tools/perf/benchmarks/oilpan_gc_times.py
index 5c77aa9..0a79706 100644
--- a/tools/perf/benchmarks/oilpan_gc_times.py
+++ b/tools/perf/benchmarks/oilpan_gc_times.py
@@ -13,19 +13,6 @@
 import page_sets
 
 
-class OilpanGCTimesBlinkPerfAnimation(perf_benchmark.PerfBenchmark):
-  tag = 'blink_perf_animation'
-  test = oilpan_gc_times.OilpanGCTimesForBlinkPerf
-
-  @classmethod
-  def Name(cls):
-    return 'oilpan_gc_times.blink_perf_animation'
-
-  def CreatePageSet(self, options):
-    path = os.path.join(blink_perf.BLINK_PERF_BASE_DIR, 'Animation')
-    return blink_perf.CreatePageSetFromPath(path, blink_perf.SKIPPED_FILE)
-
-
 @benchmark.Enabled('content-shell')
 class OilpanGCTimesBlinkPerfStress(perf_benchmark.PerfBenchmark):
   tag = 'blink_perf_stress'
diff --git a/tools/perf/benchmarks/power.py b/tools/perf/benchmarks/power.py
index f4420bf..3ee6bfab 100644
--- a/tools/perf/benchmarks/power.py
+++ b/tools/perf/benchmarks/power.py
@@ -29,6 +29,18 @@
   def Name(cls):
     return 'power.typical_10_mobile'
 
+
+@benchmark.Enabled('android')
+@benchmark.Disabled
+class PowerTypical10MobileReload(perf_benchmark.PerfBenchmark):
+  """Android typical 10 mobile power reload test."""
+  test = power.LoadPower
+  page_set = page_sets.Typical10MobileReloadPageSet
+  @classmethod
+  def Name(cls):
+    return 'power.typical_10_mobile_reload'
+
+
 @benchmark.Enabled('android')
 class PowerGpuRasterizationTypical10Mobile(perf_benchmark.PerfBenchmark):
   """Measures power on key mobile sites with GPU rasterization."""
@@ -62,7 +74,7 @@
   def Name(cls):
     return 'power.top_25'
 
-  def CreateUserStorySet(self, _):
+  def CreateStorySet(self, _):
     # Exclude techcrunch.com. It is not suitable for this benchmark because it
     # does not consistently become quiescent within 60 seconds.
     user_stories = self.page_set()
diff --git a/tools/perf/benchmarks/repaint.py b/tools/perf/benchmarks/repaint.py
index 488a42e..913e5da 100644
--- a/tools/perf/benchmarks/repaint.py
+++ b/tools/perf/benchmarks/repaint.py
@@ -35,7 +35,9 @@
   def CreatePageTest(self, options):
     return smoothness.Repaint()
 
-@benchmark.Enabled('android')
+#crbug.com/499320
+#@benchmark.Enabled('android')
+@benchmark.Disabled()
 class RepaintKeyMobileSites(_Repaint):
   """Measures repaint performance on the key mobile sites.
 
diff --git a/tools/perf/benchmarks/robohornet_pro.py b/tools/perf/benchmarks/robohornet_pro.py
index 05ccc80..fa0e516 100644
--- a/tools/perf/benchmarks/robohornet_pro.py
+++ b/tools/perf/benchmarks/robohornet_pro.py
@@ -63,7 +63,7 @@
   def CreatePageSet(self, options):
     ps = page_set.PageSet(
         archive_data_file='../page_sets/data/robohornet_pro.json',
-        file_path=os.path.abspath(__file__),
+        base_dir=os.path.dirname(os.path.abspath(__file__)),
         bucket=page_set.PARTNER_BUCKET)
     ps.AddUserStory(page_module.Page(
         'http://ie.microsoft.com/testdrive/performance/robohornetpro/',
diff --git a/tools/perf/benchmarks/spaceport.py b/tools/perf/benchmarks/spaceport.py
index 592743f..47d6b04 100644
--- a/tools/perf/benchmarks/spaceport.py
+++ b/tools/perf/benchmarks/spaceport.py
@@ -115,6 +115,6 @@
   def CreatePageSet(self, options):
     spaceport_dir = os.path.join(util.GetChromiumSrcDir(), 'chrome', 'test',
         'data', 'third_party', 'spaceport')
-    ps = page_set.PageSet(file_path=spaceport_dir)
+    ps = page_set.PageSet(base_dir=spaceport_dir)
     ps.AddUserStory(page_module.Page('file://index.html', ps, ps.base_dir))
     return ps
diff --git a/tools/perf/benchmarks/speedometer.py b/tools/perf/benchmarks/speedometer.py
index da51419..bf97c73 100644
--- a/tools/perf/benchmarks/speedometer.py
+++ b/tools/perf/benchmarks/speedometer.py
@@ -92,7 +92,7 @@
 
   def CreatePageSet(self, options):
     ps = page_set.PageSet(
-        file_path=os.path.abspath(__file__),
+        base_dir=os.path.dirname(os.path.abspath(__file__)),
         archive_data_file='../page_sets/data/speedometer.json',
         bucket=page_set.PUBLIC_BUCKET)
     ps.AddUserStory(page_module.Page(
diff --git a/tools/perf/benchmarks/startup.py b/tools/perf/benchmarks/startup.py
index f862547..e4afb0a 100644
--- a/tools/perf/benchmarks/startup.py
+++ b/tools/perf/benchmarks/startup.py
@@ -65,12 +65,11 @@
 class StartupLargeProfileColdBlankPage(_StartupCold):
   """Measures cold startup time with a large profile."""
   tag = 'cold'
-  page_set = page_sets.BlankPageSet
+  page_set = page_sets.BlankPageSetWithLargeProfile
   options = {'pageset_repeat': 1}
 
   def __init__(self, max_failures=None):
     super(StartupLargeProfileColdBlankPage, self).__init__(max_failures)
-    self.generated_profile_archive = "large_profile.zip"
 
   def SetExtraBrowserOptions(self, options):
     options.browser_startup_timeout = 10 * 60
@@ -85,12 +84,11 @@
 class StartupLargeProfileWarmBlankPage(_StartupWarm):
   """Measures warm startup time with a large profile."""
   tag = 'warm'
-  page_set = page_sets.BlankPageSet
+  page_set = page_sets.BlankPageSetWithLargeProfile
   options = {'pageset_repeat': 1}
 
   def __init__(self, max_failures=None):
     super(StartupLargeProfileWarmBlankPage, self).__init__(max_failures)
-    self.generated_profile_archive = "large_profile.zip"
 
   def SetExtraBrowserOptions(self, options):
     options.browser_startup_timeout = 10 * 60
diff --git a/tools/perf/benchmarks/sunspider.py b/tools/perf/benchmarks/sunspider.py
index 0263ea0..10a3b0ad 100644
--- a/tools/perf/benchmarks/sunspider.py
+++ b/tools/perf/benchmarks/sunspider.py
@@ -140,7 +140,7 @@
   def CreatePageSet(self, options):
     ps = page_set.PageSet(
         archive_data_file='../page_sets/data/sunspider.json',
-        file_path=os.path.abspath(__file__),
+        base_dir=os.path.dirname(os.path.abspath(__file__)),
         bucket=page_set.PARTNER_BUCKET)
     ps.AddUserStory(page_module.Page(
         _URL, ps, ps.base_dir, make_javascript_deterministic=False))
diff --git a/tools/perf/core/perf_benchmark.py b/tools/perf/core/perf_benchmark.py
index 93b85f0..6c15175 100644
--- a/tools/perf/core/perf_benchmark.py
+++ b/tools/perf/core/perf_benchmark.py
@@ -14,6 +14,11 @@
 
 
 class PerfBenchmark(benchmark.Benchmark):
+  """ Super class for all benchmarks in src/tools/perf/benchmarks directory.
+  All the perf benchmarks must subclass from this one to to make sure that
+  the field trial configs are activated for the browser during benchmark runs.
+  For more info, see: https://goo.gl/4uvaVM
+  """
 
   def SetExtraBrowserOptions(self, options):
     """ To be overridden by perf benchmarks. """
diff --git a/tools/perf/measurements/blink_style.py b/tools/perf/measurements/blink_style.py
index b46eab1..aa7d1d1 100644
--- a/tools/perf/measurements/blink_style.py
+++ b/tools/perf/measurements/blink_style.py
@@ -40,25 +40,36 @@
         # state on every run.
         pass
 
-    tab.ExecuteJavaScript(
-        'console.time("style-update");'
-        # Occasionally documents will break the APIs we need.
-        'try {'
-        # Invalidate style for the whole document.
-        '  document && (document.documentElement.lang += "z");'
-        # Force a style update (but not layout).
-        '  getComputedStyle(document.documentElement).color;'
-        '} catch (e) {}'
-        'console.timeEnd("style-update");'
-        )
+    tab.ExecuteJavaScript('''
+        for (var i = 0; i < 11; i++) {
+          var cold = i % 2 == 0;
+          var name = "update_style";
+          if (cold) name += "_cold";
+          console.time(name);
+          // Occasionally documents will break the APIs we need
+          try {
+            // On cold runs, force a new StyleResolver
+            if (cold) {
+              var style = document.createElement("style");
+              document.head.appendChild(style);
+              style.remove();
+            }
+            // Invalidate style for the whole document
+            document.documentElement.lang += "z";
+            // Force a style update (but not layout)
+            getComputedStyle(document.documentElement).color;
+          } catch (e) {}
+          console.timeEnd(name);
+        }''')
 
     self._controller.Stop(tab, results)
     renderer = self._controller.model.GetRendererThreadFromTabId(tab.id)
     markers = [event for event in renderer.async_slices
-               if event.name == 'style-update'
+               if event.name.startswith('update_style')
                   and event.category == 'blink.console']
-    assert len(markers) == 1
-    marker = markers[0]
+    # Drop the first run.
+    markers = markers[1:]
+    assert len(markers) == 10
 
     def duration(event):
       if event.has_thread_timestamps:
@@ -66,20 +77,21 @@
       else:
         return event.duration
 
-    for event in renderer.all_slices:
-      if (event.name == 'Document::updateStyle'
-          and event.start >= marker.start
-          and event.end <= marker.end):
-        access_count = event.args.get('resolverAccessCount')
-        if access_count is None:
-          # absent in earlier versions
-          continue
-        min_access_count = 50
+    for marker in markers:
+      for event in renderer.all_slices:
+        if (event.name == 'Document::updateStyle'
+            and event.start >= marker.start
+            and event.end <= marker.end):
+          access_count = event.args.get('resolverAccessCount')
+          if access_count is None:
+            # absent in earlier versions
+            continue
+          min_access_count = 50
 
-        if access_count >= min_access_count:
-          result = 1000 * (duration(event) / access_count)
-          results.AddValue(scalar.ScalarValue(
-              page, 'update_style', 'ms/1000 elements', result))
+          if access_count >= min_access_count:
+            result = 1000 * (duration(event) / access_count)
+            results.AddValue(scalar.ScalarValue(
+                page, marker.name, 'ms/1000 elements', result))
 
     class ParserEvent(object):
       def __init__(self, summary_event, tokenize_event, parse_event):
diff --git a/tools/perf/measurements/blink_style_unittest.py b/tools/perf/measurements/blink_style_unittest.py
index f88074d..1f849a8 100644
--- a/tools/perf/measurements/blink_style_unittest.py
+++ b/tools/perf/measurements/blink_style_unittest.py
@@ -27,11 +27,12 @@
     results = self.RunMeasurement(measurement, ps, options=self._options)
     self.assertEquals(0, len(results.failures))
 
-    def getMetric(results, name):
+    def getMetric(results, name, count=1):
       metrics = results.FindAllPageSpecificValuesNamed(name)
-      self.assertEquals(1, len(metrics))
+      self.assertEquals(count, len(metrics))
       return metrics[0].value
 
     self.assertGreater(getMetric(results, 'parse_css_regular'), 0)
     self.assertGreater(getMetric(results, 'tokenize_css_regular'), 0)
-    self.assertGreater(getMetric(results, 'update_style'), 0)
+    self.assertGreater(getMetric(results, 'update_style', 5), 0)
+    self.assertGreater(getMetric(results, 'update_style_cold', 5), 0)
diff --git a/tools/perf/measurements/measurement_smoke_test.py b/tools/perf/measurements/measurement_smoke_test.py
index ef45aa9..333e1fa 100644
--- a/tools/perf/measurements/measurement_smoke_test.py
+++ b/tools/perf/measurements/measurement_smoke_test.py
@@ -12,7 +12,6 @@
 from telemetry.core import discover
 from telemetry.page import page_test
 from telemetry.unittest_util import options_for_unittests
-from telemetry.util import classes
 from telemetry.web_perf import timeline_based_measurement
 
 
@@ -26,10 +25,9 @@
   # constructable
   all_measurement_classes = discover.DiscoverClasses(
       measurements_dir, top_level_dir, page_test.PageTest,
-      index_by_class_name=True).values()
+      index_by_class_name=True, directly_constructable=True).values()
   for measurement_class in all_measurement_classes:
-    if classes.IsDirectlyConstructable(measurement_class):
-      page_test_instances.append(measurement_class())
+    page_test_instances.append(measurement_class())
 
   all_benchmarks_classes = discover.DiscoverClasses(
       benchmarks_dir, top_level_dir, benchmark_module.Benchmark).values()
diff --git a/tools/perf/measurements/oilpan_gc_times_unittest.py b/tools/perf/measurements/oilpan_gc_times_unittest.py
index 87e1bcd..dc32f62 100644
--- a/tools/perf/measurements/oilpan_gc_times_unittest.py
+++ b/tools/perf/measurements/oilpan_gc_times_unittest.py
@@ -5,12 +5,12 @@
 from measurements import oilpan_gc_times
 
 from telemetry.core import util
-from telemetry.results import page_test_results
+from telemetry.internal.results import page_test_results
+from telemetry.page import page as page_module
 from telemetry.timeline import model
 from telemetry.timeline import slice as slice_data
 from telemetry.unittest_util import options_for_unittests
 from telemetry.unittest_util import page_test_test_case
-from telemetry.page import page as page_module
 
 util.AddDirToPythonPath(util.GetTelemetryDir(), 'third_party', 'mock')
 import mock  # pylint: disable=import-error
diff --git a/tools/perf/measurements/page_cycler_unittest.py b/tools/perf/measurements/page_cycler_unittest.py
index d98f3201..a570a64 100644
--- a/tools/perf/measurements/page_cycler_unittest.py
+++ b/tools/perf/measurements/page_cycler_unittest.py
@@ -6,8 +6,8 @@
 import unittest
 
 from telemetry.core import browser_options
+from telemetry.internal.results import page_test_results
 from telemetry.internal import story_runner
-from telemetry.results import page_test_results
 from telemetry.unittest_util import simple_mock
 
 from measurements import page_cycler
diff --git a/tools/perf/measurements/power.py b/tools/perf/measurements/power.py
index d5521fb..ef03596 100644
--- a/tools/perf/measurements/power.py
+++ b/tools/perf/measurements/power.py
@@ -35,6 +35,15 @@
     self._power_metric.AddResults(tab, results)
 
 
+class LoadPower(Power):
+  def WillNavigateToPage(self, page, tab):
+    self._network_metric.Start(page, tab)
+    self._power_metric.Start(page, tab)
+
+  def DidNavigateToPage(self, page, tab):
+    pass
+
+
 class QuiescentPower(page_test.PageTest):
   """Measures power draw and idle wakeups after the page finished loading."""
 
diff --git a/tools/perf/measurements/record_per_area.py b/tools/perf/measurements/record_per_area.py
deleted file mode 100644
index 367e548c..0000000
--- a/tools/perf/measurements/record_per_area.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import time
-
-from telemetry.page import page_test
-from telemetry.value import scalar
-
-from measurements import smoothness
-
-
-class RecordPerArea(page_test.PageTest):
-  def __init__(self, start_wait_time=2):
-    super(RecordPerArea, self).__init__(
-        needs_browser_restart_after_each_page=True)
-    self._start_wait_time = start_wait_time
-
-  def CustomizeBrowserOptions(self, options):
-    smoothness.Smoothness.CustomizeBrowserOptions(options)
-    options.AppendExtraBrowserArgs([
-        '--enable-impl-side-painting',
-        '--enable-threaded-compositing',
-        '--enable-gpu-benchmarking'
-    ])
-
-  def ValidateAndMeasurePage(self, page, tab, results):
-    # Wait until the page has loaded and come to a somewhat steady state.
-    # Needs to be adjusted for every device (~2 seconds for workstation).
-    time.sleep(self._start_wait_time)
-
-    # Enqueue benchmark
-    tab.ExecuteJavaScript("""
-        window.benchmark_results = {};
-        window.benchmark_results.done = false;
-        chrome.gpuBenchmarking.runMicroBenchmark(
-            "picture_record_benchmark",
-            function(value) {
-              window.benchmark_results.done = true;
-              window.benchmark_results.results = value;
-            }, [{width: 1, height: 1},
-                {width: 250, height: 250},
-                {width: 500, height: 500},
-                {width: 750, height: 750},
-                {width: 1000, height: 1000},
-                {width: 256, height: 1024},
-                {width: 1024, height: 256}]);
-    """)
-
-    tab.WaitForJavaScriptExpression('window.benchmark_results.done', 300)
-
-    all_data = tab.EvaluateJavaScript('window.benchmark_results.results')
-    for data in all_data:
-      width = data['width']
-      height = data['height']
-      area = width * height
-      time_ms = data['time_ms']
-
-      results.AddValue(scalar.ScalarValue(
-          results.current_page, 'area_%07d_%dx%d' % (area, width, height),
-          'ms', time_ms))
diff --git a/tools/perf/measurements/record_per_area_unittest.py b/tools/perf/measurements/record_per_area_unittest.py
deleted file mode 100644
index 7ee7119..0000000
--- a/tools/perf/measurements/record_per_area_unittest.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from telemetry.core import wpr_modes
-from telemetry import decorators
-from telemetry.unittest_util import options_for_unittests
-from telemetry.unittest_util import page_test_test_case
-
-from measurements import record_per_area
-
-
-class RecordPerAreaUnitTest(page_test_test_case.PageTestTestCase):
-  """Smoke test for record_per_area measurement
-
-     Runs record_per_area measurement on a simple page and verifies
-     that all metrics were added to the results. The test is purely functional,
-     i.e. it only checks if the metrics are present and non-zero.
-  """
-
-  def setUp(self):
-    self._options = options_for_unittests.GetCopy()
-    self._options.browser_options.wpr_mode = wpr_modes.WPR_OFF
-
-  @decorators.Disabled('android')
-  def testRecordPerArea(self):
-    ps = self.CreatePageSetFromFileInUnittestDataDir('scrollable_page.html')
-    measurement = record_per_area.RecordPerArea()
-    results = self.RunMeasurement(measurement, ps, options=self._options)
-    self.assertEquals(0, len(results.failures))
diff --git a/tools/perf/measurements/task_execution_time_unittest.py b/tools/perf/measurements/task_execution_time_unittest.py
index 38163fd..91564e6 100644
--- a/tools/perf/measurements/task_execution_time_unittest.py
+++ b/tools/perf/measurements/task_execution_time_unittest.py
@@ -4,8 +4,8 @@
 
 from telemetry.core import wpr_modes
 from telemetry import decorators
+from telemetry.internal.results import page_test_results
 from telemetry.page import page as page_module
-from telemetry.results import page_test_results
 from telemetry.timeline import model as model_module
 from telemetry.timeline import slice as slice_data
 from telemetry.unittest_util import options_for_unittests
diff --git a/tools/perf/measurements/v8_detached_context_age_in_gc_unittest.py b/tools/perf/measurements/v8_detached_context_age_in_gc_unittest.py
index 79962a6f..8a2376f7 100644
--- a/tools/perf/measurements/v8_detached_context_age_in_gc_unittest.py
+++ b/tools/perf/measurements/v8_detached_context_age_in_gc_unittest.py
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 from telemetry.core import wpr_modes
+from telemetry.internal.results import page_test_results
 from telemetry.page import page as page_module
-from telemetry.results import page_test_results
 from telemetry.unittest_util import options_for_unittests
 from telemetry.unittest_util import page_test_test_case
 
diff --git a/tools/perf/measurements/v8_gc_times_unittest.py b/tools/perf/measurements/v8_gc_times_unittest.py
index 9e0e199..e46d21c 100644
--- a/tools/perf/measurements/v8_gc_times_unittest.py
+++ b/tools/perf/measurements/v8_gc_times_unittest.py
@@ -2,10 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from telemetry import decorators
 from telemetry.core import wpr_modes
+from telemetry import decorators
+from telemetry.internal.results import page_test_results
 from telemetry.page import page as page_module
-from telemetry.results import page_test_results
 from telemetry.timeline import model as model_module
 from telemetry.unittest_util import options_for_unittests
 from telemetry.unittest_util import page_test_test_case
diff --git a/tools/perf/metrics/speedindex.py b/tools/perf/metrics/speedindex.py
index a069cd1..5d7fa3d 100644
--- a/tools/perf/metrics/speedindex.py
+++ b/tools/perf/metrics/speedindex.py
@@ -2,8 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from telemetry.image_processing import image_util
-from telemetry.image_processing import rgba_color
+from telemetry.util import image_util
+from telemetry.util import rgba_color
 from telemetry.value import scalar
 
 from metrics import Metric
diff --git a/tools/perf/metrics/speedindex_unittest.py b/tools/perf/metrics/speedindex_unittest.py
index 26e8412b..f46f3d00 100644
--- a/tools/perf/metrics/speedindex_unittest.py
+++ b/tools/perf/metrics/speedindex_unittest.py
@@ -7,8 +7,8 @@
 
 import unittest
 
-from telemetry.image_processing import histogram
-from telemetry.image_processing import rgba_color
+from telemetry.util import color_histogram
+from telemetry.util import rgba_color
 
 from metrics import speedindex
 
@@ -29,7 +29,7 @@
 
 class FakeBitmap(object):
   def __init__(self, r, g, b):
-    self._histogram = histogram.ColorHistogram(r, g, b, rgba_color.WHITE)
+    self._histogram = color_histogram.ColorHistogram(r, g, b, rgba_color.WHITE)
 
   # pylint: disable=W0613
   def ColorHistogram(self, ignore_color=None, tolerance=None):
diff --git a/tools/perf/page_sets/alexa1-10000.py b/tools/perf/page_sets/alexa1-10000.py
index db72102..1bdd3f3 100644
--- a/tools/perf/page_sets/alexa1-10000.py
+++ b/tools/perf/page_sets/alexa1-10000.py
@@ -4,8 +4,9 @@
 import json
 import os
 
-from telemetry.page.page import Page
-from telemetry.page.page_set import PageSet
+from telemetry.page import page as page_module
+from telemetry.page import page_set as page_set_module
+from telemetry.page import shared_page_state
 
 
 __location__ = os.path.realpath(
@@ -16,24 +17,26 @@
 _TOP_10000_ALEXA_FILE = os.path.join(__location__, 'alexa1-10000-urls.json')
 
 
-class Alexa1To10000Page(Page):
+class Alexa1To10000Page(page_module.Page):
 
   def __init__(self, url, page_set):
-    super(Alexa1To10000Page, self).__init__(url=url, page_set=page_set)
+    super(Alexa1To10000Page, self).__init__(
+        url=url, page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
 
   def RunPageInteractions(self, action_runner):
     with action_runner.CreateGestureInteraction('ScrollAction'):
       action_runner.ScrollPage()
 
 
-class Alexa1To10000PageSet(PageSet):
+class Alexa1To10000PageSet(page_set_module.PageSet):
   """ Top 1-10000 Alexa global.
       Generated on 2013-09-03 13:59:53.459117 by rmistry using
       create_page_set.py.
   """
 
   def __init__(self):
-    super(Alexa1To10000PageSet, self).__init__(user_agent_type='desktop')
+    super(Alexa1To10000PageSet, self).__init__()
 
     with open(_TOP_10000_ALEXA_FILE) as f:
       urls_list = json.load(f)
diff --git a/tools/perf/page_sets/blank_page_with_large_profile.py b/tools/perf/page_sets/blank_page_with_large_profile.py
new file mode 100644
index 0000000..ec8f0fb
--- /dev/null
+++ b/tools/perf/page_sets/blank_page_with_large_profile.py
@@ -0,0 +1,23 @@
+# 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.
+from page_sets import pregenerated_large_profile_shared_state
+from telemetry.page import page as page_module
+from telemetry.page import page_set as page_set_module
+
+
+class BlankPageWithLargeProfile(page_module.Page):
+  def __init__(self, url, page_set):
+    super(BlankPageWithLargeProfile, self).__init__(
+        url=url, page_set=page_set,
+        shared_page_state_class=pregenerated_large_profile_shared_state.
+        PregeneratedLargeProfileSharedState)
+
+
+class BlankPageSetWithLargeProfile(page_set_module.PageSet):
+  """A single blank page loaded with a large profile."""
+
+  def __init__(self):
+    super(BlankPageSetWithLargeProfile, self).__init__()
+    self.AddUserStory(BlankPageWithLargeProfile(
+        'file://blank_page/blank_page.html', self))
diff --git a/tools/perf/page_sets/chrome_signin.py b/tools/perf/page_sets/chrome_signin.py
new file mode 100644
index 0000000..0861d6a1
--- /dev/null
+++ b/tools/perf/page_sets/chrome_signin.py
@@ -0,0 +1,35 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from telemetry.page import page as page_module
+from telemetry.page import page_set as page_set_module
+
+from page_sets.login_helpers import chrome_login
+
+
+class ChromeSigninPage(page_module.Page):
+  """A page that signs in a user to Chrome."""
+
+  def __init__(self, page_set):
+    super(ChromeSigninPage, self).__init__(
+        url='chrome://signin-internals',
+        page_set=page_set,
+        credentials_path='data/chrome_signin_credentials.json',
+        credentials_bucket=page_set_module.INTERNAL_BUCKET)
+    self.user_agent_type = 'desktop'
+
+  def RunPageInteractions(self, action_runner):
+    # Use page.credentials_path because it is automatically translated into a
+    # full path relative to the page.
+    chrome_login.LoginChromeAccount(action_runner, 'chrome',
+        credentials_path=self.credentials_path)
+
+
+class ChromeSigninPageSet(page_set_module.PageSet):
+
+  def __init__(self):
+    super(ChromeSigninPageSet, self).__init__(
+        archive_data_file='data/chrome_signin_archive.json',
+        bucket=page_set_module.INTERNAL_BUCKET)
+    self.AddUserStory(ChromeSigninPage(self))
diff --git a/tools/perf/page_sets/data/chrome_signin_archive.json b/tools/perf/page_sets/data/chrome_signin_archive.json
new file mode 100644
index 0000000..5b5398a
--- /dev/null
+++ b/tools/perf/page_sets/data/chrome_signin_archive.json
@@ -0,0 +1,8 @@
+{
+    "description": "Describes the Web Page Replay archives for a user story set. Don't edit by hand! Use record_wpr for updating.", 
+    "archives": {
+        "chrome_signin_archive_000.wpr": [
+            "chrome://signin-internals"
+        ]
+    }
+}
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/chrome_signin_archive_000.wpr.sha1 b/tools/perf/page_sets/data/chrome_signin_archive_000.wpr.sha1
new file mode 100644
index 0000000..75eee871
--- /dev/null
+++ b/tools/perf/page_sets/data/chrome_signin_archive_000.wpr.sha1
@@ -0,0 +1 @@
+591616619b3ac4211c083ff47e93a5a11dbc02e9
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/chrome_signin_credentials.json.sha1 b/tools/perf/page_sets/data/chrome_signin_credentials.json.sha1
new file mode 100644
index 0000000..def751a
--- /dev/null
+++ b/tools/perf/page_sets/data/chrome_signin_credentials.json.sha1
@@ -0,0 +1 @@
+f9c19123b5413fbd5e111f79d7a2f65f6e42c717
\ No newline at end of file
diff --git a/tools/perf/page_sets/flash_energy_cases.py b/tools/perf/page_sets/flash_energy_cases.py
index f1738e5..c711a9f 100644
--- a/tools/perf/page_sets/flash_energy_cases.py
+++ b/tools/perf/page_sets/flash_energy_cases.py
@@ -3,13 +3,15 @@
 # found in the LICENSE file.
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
+from telemetry.page import shared_page_state
 
 
 class FlashEnergyCasesPage(page_module.Page):
 
   def __init__(self, url, page_set):
-    super(FlashEnergyCasesPage, self).__init__(url=url, page_set=page_set)
-    self.user_agent_type = 'desktop'
+    super(FlashEnergyCasesPage, self).__init__(
+        url=url, page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/flash_energy_cases.json'
 
 
@@ -19,7 +21,6 @@
 
   def __init__(self):
     super(FlashEnergyCasesPageSet, self).__init__(
-      user_agent_type='desktop',
       archive_data_file='data/flash_energy_cases.json',
       bucket=page_set_module.PARTNER_BUCKET)
 
diff --git a/tools/perf/page_sets/intl_es_fr_pt-BR.py b/tools/perf/page_sets/intl_es_fr_pt-BR.py
index 7d2f558..c06e633 100644
--- a/tools/perf/page_sets/intl_es_fr_pt-BR.py
+++ b/tools/perf/page_sets/intl_es_fr_pt-BR.py
@@ -3,13 +3,15 @@
 # found in the LICENSE file.
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
+from telemetry.page import shared_page_state
 
 
 class IntlEsFrPtBrPage(page_module.Page):
 
   def __init__(self, url, page_set):
-    super(IntlEsFrPtBrPage, self).__init__(url=url, page_set=page_set)
-    self.user_agent_type = 'desktop'
+    super(IntlEsFrPtBrPage, self).__init__(
+        url=url, page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/intl_es_fr_pt-BR.json'
 
 
@@ -21,7 +23,6 @@
 
   def __init__(self):
     super(IntlEsFrPtBrPageSet, self).__init__(
-      user_agent_type='desktop',
       archive_data_file='data/intl_es_fr_pt-BR.json',
       bucket=page_set_module.PARTNER_BUCKET)
 
diff --git a/tools/perf/page_sets/key_idle_power_cases/animated-10color.gif b/tools/perf/page_sets/key_idle_power_cases/animated-10color.gif
new file mode 100644
index 0000000..64b0c43
--- /dev/null
+++ b/tools/perf/page_sets/key_idle_power_cases/animated-10color.gif
Binary files differ
diff --git a/tools/telemetry/telemetry/image_processing/io/__init__.py b/tools/perf/page_sets/login_helpers/__init__.py
similarity index 62%
rename from tools/telemetry/telemetry/image_processing/io/__init__.py
rename to tools/perf/page_sets/login_helpers/__init__.py
index 4d6aabb9..50b23df 100644
--- a/tools/telemetry/telemetry/image_processing/io/__init__.py
+++ b/tools/perf/page_sets/login_helpers/__init__.py
@@ -1,3 +1,3 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/tools/perf/page_sets/login_helpers/chrome_login.py b/tools/perf/page_sets/login_helpers/chrome_login.py
new file mode 100644
index 0000000..33dad0fc
--- /dev/null
+++ b/tools/perf/page_sets/login_helpers/chrome_login.py
@@ -0,0 +1,57 @@
+# 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.
+
+from page_sets.login_helpers import login_utils
+from telemetry.core import util
+from telemetry.page import action_runner as action_runner_module
+
+
+def GetGaiaContext(tab):
+  """Returns Gaia's login page context."""
+  for context in tab.GetWebviewContexts():
+    if context.GetUrl().startswith('https://accounts.google.com/'):
+      return context
+  return None
+
+
+def LoginChromeAccount(action_runner, credential,
+                       credentials_path=login_utils.DEFAULT_CREDENTIAL_PATH):
+  """Logs in a Gaia account into Chrome.
+
+  This function navigates the tab into Chrome's login page and logs in a user
+  using credentials in |credential| part of the |credentials_path| file.
+
+  Args:
+    action_runner: Action runner responsible for running actions on the page.
+    credential: The credential to retrieve from the credentials file
+        (type string).
+    credentials_path: The string that specifies the path to credential file.
+
+  Raises:
+    exceptions.Error: See GetWebviewContexts() and ExecuteJavaScript()
+      for a detailed list of possible exceptions.
+  """
+  account_name, password = login_utils.GetAccountNameAndPassword(
+      credential, credentials_path=credentials_path)
+
+  action_runner.Navigate('chrome://chrome-signin')
+
+  # Get the Gaia webview context within the sign in extension to create a Gaia
+  # action_runner. The action runner will then execute JS in the Gaia context.
+  gaia_context = util.WaitFor(lambda: GetGaiaContext(action_runner.tab), 5)
+  if not gaia_context:
+    raise RuntimeError('Can not find GAIA webview context for sign in.')
+  gaia_action_runner = action_runner_module.ActionRunner(gaia_context)
+
+  new_flow = gaia_action_runner.EvaluateJavaScript(
+      'document.querySelector("#gaia_firsform") != null')
+  gaia_form_id = 'gaia_firstform' if new_flow else 'gaia_loginform'
+  login_utils.InputForm(gaia_action_runner, account_name, input_id='Email',
+                        form_id=gaia_form_id)
+  if new_flow:
+    gaia_action_runner.ClickElement(selector='#%s #next' % gaia_form_id)
+  login_utils.InputForm(gaia_action_runner, password, input_id='Passwd',
+                        form_id=gaia_form_id)
+  gaia_action_runner.ClickElement(selector='#signIn')
+  action_runner.WaitForNavigate()
diff --git a/tools/perf/page_sets/login_helpers/login_utils.py b/tools/perf/page_sets/login_helpers/login_utils.py
new file mode 100644
index 0000000..2445156
--- /dev/null
+++ b/tools/perf/page_sets/login_helpers/login_utils.py
@@ -0,0 +1,57 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import json
+
+
+DEFAULT_CREDENTIAL_PATH = os.path.join(
+    os.path.dirname(__file__), os.path.pardir, 'data', 'credentials.json')
+
+
+def GetAccountNameAndPassword(credential,
+                              credentials_path=DEFAULT_CREDENTIAL_PATH):
+  """Returns username and password for |credential| in credentials_path file.
+
+  Args:
+    credential: The credential to retrieve from the file (type string).
+    credentials_path: The string that specifies the path to credential file.
+
+  Returns:
+    A tuple (username, password) in which both are username and password
+    strings.
+  """
+  with open(credentials_path, 'r') as f:
+    credentials = json.load(f)
+  c = credentials.get(credential)
+  return c['username'], c['password']
+
+
+def InputForm(action_runner, input_text, input_id, form_id=None):
+  """Sets the text value of an input field in a form on the page.
+
+  Waits until the input element exists on the page. Then executes JS to populate
+  the value property of the element with |input_text|.
+
+  Args:
+    action_runner: ActionRunner instance to execute JS to populate form fields.
+    input_text: Text string to populate the input field with.
+    input_id: Id of the input field to populate. (type string).
+    form_id: Optional form id string to identify |input_id| in querySelector.
+
+  Raises:
+    exceptions.TimeoutException: If waiting to find the element times out.
+    exceptions.Error: See ExecuteJavaScript() for a detailed list of
+      possible exceptions.
+  """
+  if form_id and input_id:
+    element_selector = '#%s #%s' % (form_id, input_id)
+  elif input_id:
+    element_selector = '#%s' % (input_id)
+  else:
+    raise ValueError("Input ID can not be None or empty.")
+  action_runner.WaitForElement(selector=element_selector)
+  action_runner.ExecuteJavaScript(
+      'document.querySelector("%s").value = "%s";' %
+      (element_selector, input_text))
diff --git a/tools/perf/page_sets/new_tab_page.py b/tools/perf/page_sets/new_tab_page.py
index dbb2f89..c3ce437 100644
--- a/tools/perf/page_sets/new_tab_page.py
+++ b/tools/perf/page_sets/new_tab_page.py
@@ -5,6 +5,7 @@
 
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
+from telemetry.page import shared_page_state
 
 INTERACTION_NAME = 'Interaction.PageLoading'
 
@@ -18,9 +19,9 @@
     super(NewTabPagePage, self).__init__(
       name='newtabpagepage',
       url='chrome://newtab',
+      shared_page_state_class=shared_page_state.SharedDesktopPageState,
       page_set=page_set)
     self.archive_data_file = 'data/new_tab_page_page.json'
-    self.user_agent_type = 'desktop'
     self.script_to_evaluate_on_commit = (
         "console.time('" + INTERACTION_NAME + "');")
 
@@ -43,7 +44,6 @@
 class NewTabPagePageSet(page_set_module.PageSet):
   def __init__(self):
     super(NewTabPagePageSet, self).__init__(
-        user_agent_type='desktop',
         archive_data_file='data/new_tab_page_page.json',
         bucket=page_set_module.PUBLIC_BUCKET)
     self.AddUserStory(NewTabPagePage(page_set=self))
diff --git a/tools/perf/page_sets/pathological_mobile_sites.py b/tools/perf/page_sets/pathological_mobile_sites.py
index d508735e7..2d34449 100644
--- a/tools/perf/page_sets/pathological_mobile_sites.py
+++ b/tools/perf/page_sets/pathological_mobile_sites.py
@@ -3,14 +3,15 @@
 # found in the LICENSE file.
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
+from telemetry.page import shared_page_state
 
 
 class PathologicalMobileSitesPage(page_module.Page):
 
   def __init__(self, url, page_set):
     super(PathologicalMobileSitesPage, self).__init__(
-        url=url, page_set=page_set, credentials_path='data/credentials.json')
-    self.user_agent_type = 'mobile'
+        url=url, page_set=page_set, credentials_path='data/credentials.json',
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
     self.archive_data_file = 'data/pathological_mobile_sites.json'
 
   def RunPageInteractions(self, action_runner):
@@ -24,7 +25,6 @@
 
   def __init__(self):
     super(PathologicalMobileSitesPageSet, self).__init__(
-        user_agent_type='mobile',
         archive_data_file='data/pathological_mobile_sites.json',
         bucket=page_set_module.PARTNER_BUCKET)
 
diff --git a/tools/perf/page_sets/polymer.py b/tools/perf/page_sets/polymer.py
index e75fc09c..e40aac77 100644
--- a/tools/perf/page_sets/polymer.py
+++ b/tools/perf/page_sets/polymer.py
@@ -3,6 +3,8 @@
 # found in the LICENSE file.
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
+from telemetry.page import shared_page_state
+
 
 class PolymerPage(page_module.Page):
 
@@ -15,6 +17,7 @@
     """
     super(PolymerPage, self).__init__(
       url=url,
+      shared_page_state_class=shared_page_state.SharedMobilePageState,
       page_set=page_set)
     self.script_to_evaluate_on_commit = '''
       document.addEventListener("polymer-ready", function() {
@@ -216,7 +219,6 @@
 
   def __init__(self, run_no_page_interactions=False):
     super(PolymerPageSet, self).__init__(
-      user_agent_type='mobile',
       archive_data_file='data/polymer.json',
       bucket=page_set_module.PUBLIC_BUCKET)
 
diff --git a/tools/perf/page_sets/pregenerated_large_profile_shared_state.py b/tools/perf/page_sets/pregenerated_large_profile_shared_state.py
new file mode 100644
index 0000000..dad0cb8e
--- /dev/null
+++ b/tools/perf/page_sets/pregenerated_large_profile_shared_state.py
@@ -0,0 +1,11 @@
+# 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.
+from telemetry.page import shared_page_state
+
+
+class PregeneratedLargeProfileSharedState(shared_page_state.SharedPageState):
+  def __init__(self, test, finder_options, story_set):
+    super(PregeneratedLargeProfileSharedState, self).__init__(
+        test, finder_options, story_set)
+    self.SetPregeneratedProfileArchive('large_profile.zip')
diff --git a/tools/perf/page_sets/simple_mobile_sites.py b/tools/perf/page_sets/simple_mobile_sites.py
index be6fc8da..fc47819 100644
--- a/tools/perf/page_sets/simple_mobile_sites.py
+++ b/tools/perf/page_sets/simple_mobile_sites.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
+from telemetry.page import shared_page_state
 
 
 class SimplePage(page_module.Page):
@@ -11,6 +12,7 @@
     super(SimplePage, self).__init__(
         url=url,
         page_set=page_set,
+        shared_page_state_class=shared_page_state.Shared10InchTabletPageState,
         credentials_path='data/credentials.json')
     self.archive_data_file = 'data/simple_mobile_sites.json'
 
@@ -35,7 +37,6 @@
 
   def __init__(self):
     super(SimpleMobileSitesPageSet, self).__init__(
-      user_agent_type='tablet_10_inch',
       archive_data_file='data/simple_mobile_sites.json',
       bucket=page_set_module.PUBLIC_BUCKET)
 
diff --git a/tools/perf/page_sets/top_10_mobile.py b/tools/perf/page_sets/top_10_mobile.py
index a18048c3..eb249af 100644
--- a/tools/perf/page_sets/top_10_mobile.py
+++ b/tools/perf/page_sets/top_10_mobile.py
@@ -3,14 +3,14 @@
 # found in the LICENSE file.
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
-
+from telemetry.page import shared_page_state
 
 class Top10MobilePage(page_module.Page):
 
   def __init__(self, url, page_set, run_no_page_interactions):
     super(Top10MobilePage, self).__init__(
-        url=url, page_set=page_set, credentials_path = 'data/credentials.json')
-    self.user_agent_type = 'mobile'
+        url=url, page_set=page_set, credentials_path = 'data/credentials.json',
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
     self.archive_data_file = 'data/top_10_mobile.json'
     self._run_no_page_interactions = run_no_page_interactions
 
@@ -27,7 +27,6 @@
 
   def __init__(self, run_no_page_interactions=False):
     super(Top10MobilePageSet, self).__init__(
-      user_agent_type='mobile',
       archive_data_file='data/top_10_mobile.json',
       bucket=page_set_module.PARTNER_BUCKET)
 
diff --git a/tools/perf/page_sets/top_pages.py b/tools/perf/page_sets/top_pages.py
index 582cf98..49d2f9a 100644
--- a/tools/perf/page_sets/top_pages.py
+++ b/tools/perf/page_sets/top_pages.py
@@ -10,7 +10,6 @@
     super(TopPages, self).__init__(
         url=url, page_set=page_set, name=name,
         credentials_path='data/credentials.json')
-    self.user_agent_type = 'desktop'
     self.archive_data_file = 'data/top_25.json'
     self.credentials = credentials
 
diff --git a/tools/perf/page_sets/tough_layout_cases.py b/tools/perf/page_sets/tough_layout_cases.py
index d8887f0..d5b9b5fe 100644
--- a/tools/perf/page_sets/tough_layout_cases.py
+++ b/tools/perf/page_sets/tough_layout_cases.py
@@ -3,14 +3,15 @@
 # found in the LICENSE file.
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
+from telemetry.page import shared_page_state
 
 
 class ToughLayoutCasesPage(page_module.Page):
 
   def __init__(self, url, page_set):
     super(ToughLayoutCasesPage, self).__init__(
-        url=url, page_set=page_set, credentials_path = 'data/credentials.json')
-    self.user_agent_type = 'desktop'
+        url=url, page_set=page_set, credentials_path = 'data/credentials.json',
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/tough_layout_cases.json'
 
 
@@ -22,7 +23,6 @@
 
   def __init__(self):
     super(ToughLayoutCasesPageSet, self).__init__(
-      user_agent_type='desktop',
       archive_data_file='data/tough_layout_cases.json',
       bucket=page_set_module.PARTNER_BUCKET)
 
diff --git a/tools/perf/page_sets/tough_scheduling_cases.py b/tools/perf/page_sets/tough_scheduling_cases.py
index 6ea808e..8a4251ad 100644
--- a/tools/perf/page_sets/tough_scheduling_cases.py
+++ b/tools/perf/page_sets/tough_scheduling_cases.py
@@ -3,14 +3,15 @@
 # found in the LICENSE file.
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
+from telemetry.page import shared_page_state
 
 
 class ToughSchedulingCasesPage(page_module.Page):
 
   def __init__(self, url, page_set):
     super(ToughSchedulingCasesPage, self).__init__(
-        url=url, page_set=page_set, credentials_path='data/credentials.json')
-    self.user_agent_type = 'mobile'
+        url=url, page_set=page_set, credentials_path='data/credentials.json',
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
     self.archive_data_file = 'data/tough_scheduling_cases.json'
 
   def RunPageInteractions(self, action_runner):
@@ -394,7 +395,6 @@
 
   def __init__(self):
     super(ToughSchedulingCasesPageSet, self).__init__(
-        user_agent_type='mobile',
         archive_data_file='data/tough_scheduling_cases.json',
         bucket=page_set_module.INTERNAL_BUCKET)
 
diff --git a/tools/perf/page_sets/typical_10_mobile.py b/tools/perf/page_sets/typical_10_mobile.py
index 46bec683..2ef67e2 100644
--- a/tools/perf/page_sets/typical_10_mobile.py
+++ b/tools/perf/page_sets/typical_10_mobile.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
+from telemetry.page import shared_page_state
 
 
 class Typical10MobilePage(page_module.Page):
@@ -10,8 +11,8 @@
   def __init__(self, url, page_set, name=''):
     super(Typical10MobilePage, self).__init__(
         url=url, page_set=page_set, name=name,
-        credentials_path = 'data/credentials.json')
-    self.user_agent_type = 'mobile'
+        credentials_path = 'data/credentials.json',
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
     self.archive_data_file = 'data/typical_10_mobile.json'
 
   def RunPageInteractions(self, action_runner):
@@ -19,38 +20,61 @@
     action_runner.ScrollPage()
     action_runner.Wait(20)
 
+class Typical10MobileReloadPage(Typical10MobilePage):
+
+  def __init__(self, url, page_set, name=''):
+    super(Typical10MobileReloadPage, self).__init__(
+        url=url, page_set=page_set, name=name,)
+
+  def RunPageInteractions(self, action_runner):
+    for _ in range(0, 5):
+      action_runner.ReloadPage()
+      action_runner.WaitForJavaScriptCondition(
+          'document.readyState === "complete"')
+
+
+urls_list = [
+    # Why: Top site
+    'http://m.facebook.com/barackobama',
+    # Why: Wikipedia article with lots of pictures, German language
+    'http://de.m.wikipedia.org/wiki/K%C3%B6lner_Dom',
+    # Why: current top Q&A on popular Japanese site
+    'http://m.chiebukuro.yahoo.co.jp/detail/q10136829180',
+    # Why: news article on popular site
+    'http://m.huffpost.com/us/entry/6004486',
+    # Why: news article on popular site
+    'http://www.cnn.com/2014/03/31/showbiz/tv/himym-finale/index.html',
+    # Why: Popular RTL language site
+    'http://m.ynet.co.il',
+    # Why: Popular Russian language site
+    'http://www.rg.ru/2014/10/21/cska-site.html',
+    # Why: Popular shopping site
+    'http://m.ebay.com/itm/351157205404',
+    # Why: Popular viral site, lots of images
+    'http://siriuslymeg.tumblr.com/',
+    # Why: Popular Chinese language site.
+    'http://wapbaike.baidu.com/',
+]
+
 
 class Typical10MobilePageSet(page_set_module.PageSet):
   """10 typical mobile pages, used for power testing."""
 
   def __init__(self):
     super(Typical10MobilePageSet, self).__init__(
-        user_agent_type='mobile',
         archive_data_file='data/typical_10_mobile.json',
         bucket=page_set_module.PARTNER_BUCKET)
 
-    urls_list = [
-        # Why: Top site
-        'http://m.facebook.com/barackobama',
-        # Why: Wikipedia article with lots of pictures, German language
-        'http://de.m.wikipedia.org/wiki/K%C3%B6lner_Dom',
-        # Why: current top Q&A on popular Japanese site
-        'http://m.chiebukuro.yahoo.co.jp/detail/q10136829180',
-        # Why: news article on popular site
-        'http://m.huffpost.com/us/entry/6004486',
-        # Why: news article on popular site
-        'http://www.cnn.com/2014/03/31/showbiz/tv/himym-finale/index.html',
-        # Why: Popular RTL language site
-        'http://m.ynet.co.il',
-        # Why: Popular Russian language site
-        'http://www.rg.ru/2014/10/21/cska-site.html',
-        # Why: Popular shopping site
-        'http://m.ebay.com/itm/351157205404',
-        # Why: Popular viral site, lots of images
-        'http://siriuslymeg.tumblr.com/',
-        # Why: Popular Chinese language site.
-        'http://wapbaike.baidu.com/',
-    ]
-
     for url in urls_list:
       self.AddUserStory(Typical10MobilePage(url, self))
+
+class Typical10MobileReloadPageSet(page_set_module.PageSet):
+  """10 typical mobile pages, used for reloading power testing."""
+
+  def __init__(self):
+    super(Typical10MobileReloadPageSet, self).__init__(
+        archive_data_file='data/typical_10_mobile.json',
+        bucket=page_set_module.PARTNER_BUCKET)
+
+    for url in urls_list:
+      self.AddUserStory(Typical10MobileReloadPage(url, self))
diff --git a/tools/perf_expectations/perf_expectations.json b/tools/perf_expectations/perf_expectations.json
index 27235e6..9b45f298 100644
--- a/tools/perf_expectations/perf_expectations.json
+++ b/tools/perf_expectations/perf_expectations.json
@@ -1,4 +1,4 @@
-{"linux-release-64/sizes/chrome-bss/bss": {"reva": 311086, "revb": 311132, "type": "absolute", "better": "lower", "improve": 453296, "regress": 501029, "sha1": "d69fb86b"},
+{"linux-release-64/sizes/chrome-bss/bss": {"reva": 333423, "revb": 333458, "type": "absolute", "better": "lower", "improve": 970305, "regress": 1072846, "sha1": "76005951"},
  "linux-release-64/sizes/chrome-data/data": {"reva": 315738, "revb": 315881, "type": "absolute", "better": "lower", "improve": 4530816, "regress": 5008996, "sha1": "d3b1596a"},
  "linux-release-64/sizes/chrome-si/initializers": {"reva": 281711, "revb": 281711, "type": "absolute", "better": "lower", "improve": 7, "regress": 7, "tolerance": 0, "sha1": "b11fc43a"},
  "linux-release-64/sizes/chrome-text/text": {"reva": 319216, "revb": 319260, "type": "absolute", "better": "lower", "improve": 100175313, "regress": 110735624, "sha1": "bacf8d86"},
@@ -362,13 +362,12 @@
  "linux-release/media_tests_av_perf/ttp/Wifi_dartmoor2.ogg": {"reva": 155180, "revb": 155280, "type": "absolute", "better": "lower", "improve": 12393, "regress": 13715, "sha1": "a27bbec2"},
  "linux-release/media_tests_av_perf/ttp/Wifi_dartmoor2.wav": {"reva": 155180, "revb": 155280, "type": "absolute", "better": "lower", "improve": 6893, "regress": 7758, "sha1": "7a3ab979"},
  "linux-release/media_tests_av_perf/ttp/Wifi_roller.webm": {"reva": 175328, "revb": 176157, "type": "absolute", "better": "lower", "improve": 867.35, "regress": 1041.075, "sha1": "d99ce51c"},
- "linux-release/sizes/chrome-bss/bss": {"reva": 311086, "revb": 311132, "type": "absolute", "better": "lower", "improve": 318223, "regress": 351738, "sha1": "a1baf698"},
+ "linux-release/sizes/chrome-bss/bss": {"reva": 333423, "revb": 333458, "type": "absolute", "better": "lower", "improve": 832034, "regress": 919853, "sha1": "d89659bd"},
  "linux-release/sizes/chrome-data/data": {"reva": 325769, "revb": 325799, "type": "absolute", "better": "lower", "improve": 2432334, "regress": 2688954, "sha1": "e50a13ba"},
  "linux-release/sizes/chrome-si/initializers": {"reva": 281717, "revb": 281717, "type": "absolute", "better": "lower", "improve": 8, "regress": 8, "tolerance": 0, "sha1": "b639bbc4"},
  "linux-release/sizes/chrome-text/text": {"reva": 325561, "revb": 325600, "type": "absolute", "better": "lower", "improve": 107144132, "regress": 118425421, "sha1": "6c1bc544"},
- "linux-release/sizes/chrome-textrel/textrel": {"reva": 234134, "revb": 234142, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "61db9eaf"},
+ "linux-release/sizes/chrome-textrel/textrel": {"reva": 333423, "revb": 333458, "type": "absolute", "better": "lower", "improve": 1153, "regress": 1153, "sha1": "2ceaffba"},
  "linux-release/sizes/chrome/chrome": {"reva": 315765, "revb": 316804, "type": "absolute", "better": "lower", "improve": 145744151, "regress": 161295763, "sha1": "5bdd2fa3"},
- "linux-release/sizes/libffmpegsumo.so-textrel/textrel": {"reva": 200467, "revb": 203456, "type": "absolute", "better": "lower", "improve": 1075, "regress": 1189, "sha1": "a10d4ea4"},
  "linux-release/sizes/nacl_helper-bss/bss": {"reva": 282247, "revb": 282247, "type": "absolute", "better": "lower", "improve": 143640, "regress": 158760, "sha1": "95c4c516"},
  "linux-release/sizes/nacl_helper-data/data": {"reva": 315014, "revb": 315022, "type": "absolute", "better": "lower", "improve": 113042, "regress": 124942, "sha1": "d4f92fae"},
  "linux-release/sizes/nacl_helper-si/initializers": {"reva": 271321, "revb": 271321, "type": "absolute", "better": "lower", "improve": 6, "regress": 8, "sha1": "3394be7f"},
@@ -383,7 +382,7 @@
  "linux-release/sizes/totals-textrel/textrel": {"reva": 205083, "revb": 206071, "type": "absolute", "better": "lower", "improve": 1075, "regress": 1189, "sha1": "69d07fda"},
  "mac-release/sizes/Chromium.app/Chromium.app": {"reva": 333120, "revb": 333170, "type": "absolute", "better": "lower", "improve": 157534248, "regress": 160720896, "tolerance": 0.01, "sha1": "f5025410"},
  "mac-release/sizes/Chromium/Chromium": {"reva": 165473, "revb": 165473, "type": "absolute", "better": "lower", "improve": 8132, "regress": 8988, "sha1": "8e448691"},
- "mac-release/sizes/ChromiumFramework/ChromiumFramework": {"reva": 326940, "revb": 326990, "type": "absolute", "better": "lower", "improve": 102571179, "regress": 104681006, "tolerance": 0.01, "sha1": "f9819a70"},
+ "mac-release/sizes/ChromiumFramework/ChromiumFramework": {"reva": 333423, "revb": 333458, "type": "absolute", "better": "lower", "improve": 104344451, "regress": 106531871, "tolerance": 0.01, "sha1": "c32c56bd"},
  "mac-release/sizes/chrome-si/initializers": {"reva": 281731, "revb": 281731, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "tolerance": 0, "sha1": "01759b7f"},
  "win-release/media_tests_av_perf/audio_latency/latency": {"reva": 199840, "revb": 201303, "type": "absolute", "better": "lower", "improve": 57, "regress": 69, "sha1": "169d47dd"},
  "win-release/media_tests_av_perf/audio_latency/latency_bg_clip": {"reva": 199840, "revb": 201303, "type": "absolute", "better": "lower", "improve": 66, "regress": 78, "sha1": "708a71af"},
@@ -737,7 +736,7 @@
  "win-release/media_tests_av_perf/ttp/Wifi_roller.webm": {"reva": 175328, "revb": 176157, "type": "absolute", "better": "lower", "improve": 906.775, "regress": 1184.925, "sha1": "d49e638f"},
  "xp-release/sizes/chrome.dll/chrome.dll": {"reva": 309071, "revb": 309081, "type": "absolute", "better": "lower", "improve": 36382233, "regress": 40213018, "sha1": "af511cf1"},
  "xp-release/sizes/chrome.exe/chrome.exe": {"reva": 309071, "revb": 309081, "type": "absolute", "better": "lower", "improve": 612377, "regress": 676839, "sha1": "63dbfdc5"},
- "xp-release/sizes/chrome_child.dll/chrome_child.dll": {"reva": 314576, "revb": 314588, "type": "absolute", "better": "lower", "improve": 39555993, "regress": 43720858, "sha1": "46896665"},
+ "xp-release/sizes/chrome_child.dll/chrome_child.dll": {"reva": 333423, "revb": 333458, "type": "absolute", "better": "lower", "improve": 41918438, "regress": 46335207, "sha1": "223ee3af"},
  "xp-release/sizes/mini_installer.exe/mini_installer.exe": {"reva": 325850, "revb": 325904, "type": "absolute", "better": "lower", "improve": 34587904, "regress": 38335719, "sha1": "3846b983"},
  "xp-release/sizes/setup.exe/setup.exe": {"reva": 314972, "revb": 314998, "type": "absolute", "better": "lower", "improve": 882816, "regress": 975744, "sha1": "682290df"},
  "load": true
diff --git a/tools/profile_chrome/chrome_startup_controller.py b/tools/profile_chrome/chrome_startup_controller.py
index 87353e3..84c08d4 100644
--- a/tools/profile_chrome/chrome_startup_controller.py
+++ b/tools/profile_chrome/chrome_startup_controller.py
@@ -35,12 +35,19 @@
     if self._cold:
       self._device.EnableRoot()
       cache_control.CacheControl(self._device).DropRamCaches()
-    self._device.StartActivity(
-        intent.Intent(
-            package=self._package_info.package,
-            activity=self._package_info.activity,
-            data=self._url,
-            extras={'create_new_tab' : True}), blocking=True)
+    launch_intent = None
+    if self._url == '':
+      launch_intent = intent.Intent(
+          action='android.intent.action.MAIN',
+          package=self._package_info.package,
+          activity=self._package_info.activity)
+    else:
+      launch_intent = intent.Intent(
+          package=self._package_info.package,
+          activity=self._package_info.activity,
+          data=self._url,
+          extras={'create_new_tab': True})
+    self._device.StartActivity(launch_intent, blocking=True)
 
   def _TearDownTracing(self):
     changer = flag_changer.FlagChanger(
diff --git a/tools/profile_chrome_startup.py b/tools/profile_chrome_startup.py
index 850df863..0f84711 100755
--- a/tools/profile_chrome_startup.py
+++ b/tools/profile_chrome_startup.py
@@ -30,8 +30,9 @@
                                  'tool for detailed instructions for '
                                  'profiling.')
   parser.add_option('--url', help='URL to visit on startup. Default: '
-                    'https://www.google.com', default='https://www.google.com',
-                    metavar='URL')
+                    'https://www.google.com. An empty URL launches Chrome with'
+                    ' a MAIN action instead of VIEW.',
+                    default='https://www.google.com', metavar='URL')
   parser.add_option('--cold', help='Flush the OS page cache before starting the'
                     ' browser. Note that this require a device with root '
                     'access.', default=False, action='store_true')
diff --git a/tools/roll_angle.py b/tools/roll_angle.py
index 9589d30..999efc10 100755
--- a/tools/roll_angle.py
+++ b/tools/roll_angle.py
@@ -32,12 +32,16 @@
 
 # Use a shell for subcommands on Windows to get a PATH search.
 USE_SHELL = sys.platform.startswith('win')
-ANGLE_PATH = 'third_party/angle'
+ANGLE_PATH = os.path.join('third_party', 'angle')
 
 CommitInfo = collections.namedtuple('CommitInfo', ['git_commit',
                                                    'git_repo_url'])
 CLInfo = collections.namedtuple('CLInfo', ['issue', 'url', 'rietveld_server'])
 
+def _PosixPath(path):
+  """Convert a possibly-Windows path to a posix-style path."""
+  (_, path) = os.path.splitdrive(path)
+  return path.replace(os.sep, '/')
 
 def _ParseGitCommitHash(description):
   for line in description.splitlines():
@@ -67,25 +71,31 @@
   return local_scope
 
 
-def _GenerateCLDescription(angle_current, angle_new):
-  delim = ''
-  angle_str = ''
+def _GenerateCLDescriptionCommand(angle_current, angle_new, bugs):
   def GetChangeString(current_hash, new_hash):
     return '%s..%s' % (current_hash[0:7], new_hash[0:7]);
 
   def GetChangeLogURL(git_repo_url, change_string):
     return '%s/+log/%s' % (git_repo_url, change_string)
 
+  def GetBugString(bugs):
+    bug_str = 'BUG='
+    for bug in bugs:
+      bug_str += str(bug) + ','
+    return bug_str.rstrip(',')
+
   if angle_current.git_commit != angle_new.git_commit:
     change_str = GetChangeString(angle_current.git_commit,
                                  angle_new.git_commit)
     changelog_url = GetChangeLogURL(angle_current.git_repo_url,
                                     change_str)
 
-  description = 'Roll ANGLE ' + change_str + '\n\n'
-  description += '%s\n\n' % changelog_url
-  description += 'BUG=\nTEST=bots\n'
-  return description
+  return [
+    '-m', 'Roll ANGLE ' + change_str,
+    '-m', '%s' % changelog_url,
+    '-m', GetBugString(bugs),
+    '-m', 'TEST=bots',
+  ]
 
 
 class AutoRoller(object):
@@ -127,7 +137,7 @@
     return CommitInfo(_ParseGitCommitHash(ret), git_repo_url)
 
   def _GetDepsCommitInfo(self, deps_dict, path_below_src):
-    entry = deps_dict['deps']['src/%s' % path_below_src]
+    entry = deps_dict['deps'][_PosixPath('src/%s' % path_below_src)]
     at_index = entry.find('@')
     git_repo_url = entry[:at_index]
     git_hash = entry[at_index + 1:]
@@ -163,6 +173,27 @@
     logging.debug('Dirty/unversioned files:\n%s', '\n'.join(lines))
     return False
 
+  def _GetBugList(self, path_below_src, angle_current, angle_new):
+    working_dir = os.path.join(self._chromium_src, path_below_src)
+    lines = self._RunCommand(
+        ['git','log',
+            '%s..%s' % (angle_current.git_commit, angle_new.git_commit)],
+        working_dir=working_dir).split('\n')
+    bugs = set()
+    for line in lines:
+      line = line.strip()
+      bug_prefix = 'BUG='
+      if line.startswith(bug_prefix):
+        bugs_strings = line[len(bug_prefix):].split(',')
+        for bug_string in bugs_strings:
+          try:
+            bugs.add(int(bug_string))
+          except:
+            # skip this, it may be a project specific bug such as
+            # "angleproject:X" or an ill-formed BUG= message
+            pass
+    return bugs
+
   def _UpdateReadmeFile(self, readme_path, new_revision):
     readme = open(os.path.join(self._chromium_src, readme_path), 'r+')
     txt = readme.read()
@@ -203,19 +234,25 @@
     # Find ToT revisions.
     angle_latest = self._GetCommitInfo(ANGLE_PATH)
 
+    # Make sure the roll script doesn't use windows line endings
+    self._RunCommand(['git', 'config', 'core.autocrlf', 'true'])
+
     self._UpdateDep(deps_filename, ANGLE_PATH, angle_latest)
 
     if self._IsTreeClean():
       logging.debug('Tree is clean - no changes detected.')
       self._DeleteRollBranch()
     else:
-      description = _GenerateCLDescription(angle_current, angle_latest)
+      bugs = self._GetBugList(ANGLE_PATH, angle_current, angle_latest)
+      description = _GenerateCLDescriptionCommand(
+          angle_current, angle_latest, bugs)
       logging.debug('Committing changes locally.')
       self._RunCommand(['git', 'add', '--update', '.'])
-      self._RunCommand(['git', 'commit', '-m', description])
+      self._RunCommand(['git', 'commit'] + description)
       logging.debug('Uploading changes...')
-      self._RunCommand(['git', 'cl', 'upload', '-m', description],
+      self._RunCommand(['git', 'cl', 'upload'],
                        extra_env={'EDITOR': 'true'})
+      self._RunCommand(['git', 'cl', 'try'])
       cl_info = self._GetCLInfo()
       print 'Issue: %d URL: %s' % (cl_info.issue, cl_info.url)
 
@@ -225,7 +262,7 @@
     return 0
 
   def _UpdateDep(self, deps_filename, dep_relative_to_src, commit_info):
-    dep_name = os.path.join('src', dep_relative_to_src)
+    dep_name = _PosixPath(os.path.join('src', dep_relative_to_src))
 
     # roll_dep_svn.py relies on cwd being the Chromium checkout, so let's
     # temporarily change the working directory and then change back.
@@ -276,10 +313,6 @@
 
 
 def main():
-  if sys.platform in ('win32', 'cygwin'):
-    logging.error('Only Linux and Mac platforms are supported right now.')
-    return -1
-
   parser = argparse.ArgumentParser(
       description='Auto-generates a CL containing an ANGLE roll.')
   parser.add_argument('--abort',
diff --git a/tools/roll_webrtc.py b/tools/roll_webrtc.py
index 51754e1..0a6c00b 100755
--- a/tools/roll_webrtc.py
+++ b/tools/roll_webrtc.py
@@ -302,7 +302,7 @@
     self._UpdateDep(deps_filename, LIBJINGLE_PATH, libjingle_latest)
 
     if self._IsTreeClean():
-      logging.debug('Tree is clean - no changes detected.')
+      print 'The latest revision is already rolled for WebRTC and libjingle.'
       self._DeleteRollBranch()
     else:
       self._UpdateReadmeFile(LIBJINGLE_README, libjingle_latest.commit_position)
diff --git a/tools/telemetry/bootstrap_deps b/tools/telemetry/bootstrap_deps
index 1ae0cd82..52a48f6d 100644
--- a/tools/telemetry/bootstrap_deps
+++ b/tools/telemetry/bootstrap_deps
@@ -10,14 +10,11 @@
 
 deps = {
     "src/tools/telemetry": "",
-    "src/build/util": "",
     "src/chrome/test/data/extensions/profiles": "",
-    "src/third_party/android_testrunner": "",
     "src/third_party/android_tools/sdk/platform-tools": "",
     "src/third_party/chromite/ssh_keys": "",
     "src/third_party/webpagereplay": "",
     "src/third_party/trace-viewer": "",
     "src/third_party/typ": "",
-    "src/tools/crx_id": "",
     "src/tools/perf/unit-info.json": "",
 }
diff --git a/tools/telemetry/catapult_base/__init__.py b/tools/telemetry/catapult_base/__init__.py
new file mode 100644
index 0000000..860cc258
--- /dev/null
+++ b/tools/telemetry/catapult_base/__init__.py
@@ -0,0 +1,6 @@
+# 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.
+
+# All files in this directory should be moved to catapult/base/ after moving
+# to the new repo.
diff --git a/tools/telemetry/telemetry/util/cloud_storage.py b/tools/telemetry/catapult_base/cloud_storage.py
similarity index 100%
rename from tools/telemetry/telemetry/util/cloud_storage.py
rename to tools/telemetry/catapult_base/cloud_storage.py
diff --git a/tools/telemetry/telemetry/util/cloud_storage_unittest.py b/tools/telemetry/catapult_base/cloud_storage_unittest.py
similarity index 99%
rename from tools/telemetry/telemetry/util/cloud_storage_unittest.py
rename to tools/telemetry/catapult_base/cloud_storage_unittest.py
index f598b67..fb74522 100644
--- a/tools/telemetry/telemetry/util/cloud_storage_unittest.py
+++ b/tools/telemetry/catapult_base/cloud_storage_unittest.py
@@ -5,8 +5,8 @@
 import os
 import unittest
 
+from catapult_base import cloud_storage
 from telemetry.unittest_util import system_stub
-from telemetry.util import cloud_storage
 
 
 def _FakeFindGsutil():
diff --git a/tools/telemetry/telemetry/util/support_binaries.py b/tools/telemetry/catapult_base/support_binaries.py
similarity index 97%
rename from tools/telemetry/telemetry/util/support_binaries.py
rename to tools/telemetry/catapult_base/support_binaries.py
index a2fd6ac4..52bcd35d 100644
--- a/tools/telemetry/telemetry/util/support_binaries.py
+++ b/tools/telemetry/catapult_base/support_binaries.py
@@ -5,8 +5,8 @@
 import os
 import stat
 
+from catapult_base import cloud_storage
 from telemetry import decorators
-from telemetry.util import cloud_storage
 from telemetry.util import path
 
 
diff --git a/tools/telemetry/telemetry/util/support_binaries_unittest.py b/tools/telemetry/catapult_base/support_binaries_unittest.py
similarity index 92%
rename from tools/telemetry/telemetry/util/support_binaries_unittest.py
rename to tools/telemetry/catapult_base/support_binaries_unittest.py
index 2a84290..258fe25 100644
--- a/tools/telemetry/telemetry/util/support_binaries_unittest.py
+++ b/tools/telemetry/catapult_base/support_binaries_unittest.py
@@ -6,8 +6,8 @@
 import stat
 import unittest
 
+from catapult_base import support_binaries
 from telemetry import decorators
-from telemetry.util import support_binaries
 
 
 class SupportBinariesTest(unittest.TestCase):
diff --git a/tools/telemetry/experimental/measure_trace.py b/tools/telemetry/experimental/measure_trace.py
index 22fcc13..e3173fe6 100755
--- a/tools/telemetry/experimental/measure_trace.py
+++ b/tools/telemetry/experimental/measure_trace.py
@@ -9,9 +9,9 @@
 import sys
 
 sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from telemetry.internal.results import buildbot_output_formatter
+from telemetry.internal.results import page_test_results
 from telemetry.page import page as page_module
-from telemetry.results import buildbot_output_formatter
-from telemetry.results import page_test_results
 from telemetry.timeline import model
 from telemetry.timeline import tracing_timeline_data
 from telemetry.web_perf.metrics import smoothness
diff --git a/tools/telemetry/find_dependencies b/tools/telemetry/find_dependencies
index 131f24d..b6ebd4b9 100755
--- a/tools/telemetry/find_dependencies
+++ b/tools/telemetry/find_dependencies
@@ -3,7 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from telemetry.util import find_dependencies
+from telemetry.internal.util import find_dependencies
 
 
 if __name__ == '__main__':
diff --git a/tools/telemetry/telemetry/TELEMETRY_DEPS b/tools/telemetry/telemetry/TELEMETRY_DEPS
index d054d16..93ccb4912 100644
--- a/tools/telemetry/telemetry/TELEMETRY_DEPS
+++ b/tools/telemetry/telemetry/TELEMETRY_DEPS
@@ -12,21 +12,10 @@
     "third_party/typ/",
     "third_party/pexpect/",
     "third_party/webpagereplay/",
-    "tools/crx_id/",
     "tools/telemetry/"
   ],
   "file_deps": [
-    "build/util/BUILD.gn",
-    "build/util/LASTCHANGE",
-    "build/util/LASTCHANGE.blink",
     "build/util/lastchange.py",
-    "build/util/lib/common/__init__.py",
-    "build/util/lib/common/perf_result_data_type.py",
-    "build/util/lib/common/perf_tests_results_helper.py",
-    "build/util/lib/common/unittest_util.py",
-    "build/util/lib/common/util.py",
-    "build/util/version.gypi",
-    "build/util/version.py",
     "third_party/chromite/ssh_keys/testing_rsa",
     "third_party/chromite/ssh_keys/testing_rsa.pub",
     "tools/perf/unit-info.json"
diff --git a/tools/telemetry/telemetry/benchmark.py b/tools/telemetry/telemetry/benchmark.py
index 56224050..dc4f89b 100644
--- a/tools/telemetry/telemetry/benchmark.py
+++ b/tools/telemetry/telemetry/benchmark.py
@@ -2,24 +2,17 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import logging
 import optparse
-import os
-import shutil
-import sys
-import zipfile
 
-from telemetry.core import browser_finder
+from catapult_base import cloud_storage
 from telemetry.core import command_line
-from telemetry.core import util
 from telemetry import decorators
+from telemetry.internal.results import results_options
 from telemetry.internal import story_runner
 from telemetry import page
 from telemetry.page import page_set
 from telemetry.page import page_test
 from telemetry.page import test_expectations
-from telemetry.results import results_options
-from telemetry.util import cloud_storage
 from telemetry.util import exception_formatter
 from telemetry.web_perf import timeline_based_measurement
 
@@ -192,8 +185,6 @@
             'PageTest must be used with StorySet containing only '
             'telemetry.page.Page user stories.')
 
-    self._DownloadGeneratedProfileArchive(finder_options)
-
     benchmark_metadata = self.GetMetadata()
     with results_options.CreateResults(
         benchmark_metadata, finder_options,
@@ -214,71 +205,6 @@
       results.PrintSummary()
     return return_code
 
-  def _DownloadGeneratedProfileArchive(self, options):
-    """Download and extract profile directory archive if one exists."""
-    archive_name = getattr(self, 'generated_profile_archive', None)
-
-    # If attribute not specified, nothing to do.
-    if not archive_name:
-      return
-
-    # If profile dir specified on command line, nothing to do.
-    if options.browser_options.profile_dir:
-      logging.warning("Profile directory specified on command line: %s, this"
-          "overrides the benchmark's default profile directory.",
-          options.browser_options.profile_dir)
-      return
-
-    # Download profile directory from cloud storage.
-    found_browser = browser_finder.FindBrowser(options)
-    if found_browser.IsRemote():
-      return
-    test_data_dir = os.path.join(util.GetChromiumSrcDir(), 'tools', 'perf',
-        'generated_profiles',
-        found_browser.target_os)
-    generated_profile_archive_path = os.path.normpath(
-        os.path.join(test_data_dir, archive_name))
-
-    try:
-      cloud_storage.GetIfChanged(generated_profile_archive_path,
-          cloud_storage.PUBLIC_BUCKET)
-    except (cloud_storage.CredentialsError,
-            cloud_storage.PermissionError) as e:
-      if os.path.exists(generated_profile_archive_path):
-        # If the profile directory archive exists, assume the user has their
-        # own local copy simply warn.
-        logging.warning('Could not download Profile archive: %s',
-            generated_profile_archive_path)
-      else:
-        # If the archive profile directory doesn't exist, this is fatal.
-        logging.error('Can not run without required profile archive: %s. '
-                      'If you believe you have credentials, follow the '
-                      'instructions below.',
-                      generated_profile_archive_path)
-        logging.error(str(e))
-        sys.exit(-1)
-
-    # Unzip profile directory.
-    extracted_profile_dir_path = (
-        os.path.splitext(generated_profile_archive_path)[0])
-    if not os.path.isfile(generated_profile_archive_path):
-      raise Exception("Profile directory archive not downloaded: ",
-          generated_profile_archive_path)
-    with zipfile.ZipFile(generated_profile_archive_path) as f:
-      try:
-        f.extractall(os.path.dirname(generated_profile_archive_path))
-      except e:
-        # Cleanup any leftovers from unzipping.
-        if os.path.exists(extracted_profile_dir_path):
-          shutil.rmtree(extracted_profile_dir_path)
-        logging.error("Error extracting profile directory zip file: %s", e)
-        sys.exit(-1)
-
-    # Run with freshly extracted profile directory.
-    logging.info("Using profile archive directory: %s",
-        extracted_profile_dir_path)
-    options.browser_options.profile_dir = extracted_profile_dir_path
-
   def CreateTimelineBasedMeasurementOptions(self):
     """Return the TimelineBasedMeasurementOptions for this Benchmark.
 
@@ -329,6 +255,10 @@
     return self.page_set()
 
   def CreateStorySet(self, options):
+    """Creates the instance of StorySet used to run the benchmark.
+
+    Can be overridden by subclasses.
+    """
     return self.CreatePageSet(options)
 
   @classmethod
diff --git a/tools/telemetry/telemetry/core/_bitmap.py b/tools/telemetry/telemetry/core/_bitmap.py
index 808e939..b25b4ee 100644
--- a/tools/telemetry/telemetry/core/_bitmap.py
+++ b/tools/telemetry/telemetry/core/_bitmap.py
@@ -12,11 +12,11 @@
 import struct
 import subprocess
 
+from catapult_base import support_binaries
 from telemetry.core import platform
 from telemetry.core import util
-from telemetry.image_processing import histogram
-from telemetry.image_processing import rgba_color
-from telemetry.util import support_binaries
+from telemetry.util import color_histogram
+from telemetry.util import rgba_color
 
 util.AddDirToPythonPath(util.GetTelemetryDir(), 'third_party', 'png')
 import png  # pylint: disable=F0401
@@ -71,7 +71,7 @@
     out.fromstring(response)
     assert len(out) == 768, (
         'The ColorHistogram has the wrong number of buckets: %s' % len(out))
-    return histogram.ColorHistogram(out[:256], out[256:512], out[512:],
+    return color_histogram.ColorHistogram(out[:256], out[256:512], out[512:],
                                     ignore_color)
 
   def BoundingBox(self, color, tolerance):
diff --git a/tools/telemetry/telemetry/core/backends/adb_commands.py b/tools/telemetry/telemetry/core/backends/adb_commands.py
index 42eeb43..230fabb 100644
--- a/tools/telemetry/telemetry/core/backends/adb_commands.py
+++ b/tools/telemetry/telemetry/core/backends/adb_commands.py
@@ -10,9 +10,9 @@
 import shutil
 import stat
 
+from catapult_base import support_binaries
 from telemetry.core import platform
 from telemetry.core import util
-from telemetry.util import support_binaries
 
 # This is currently a thin wrapper around Chrome Android's
 # build scripts, located in chrome/build/android. This file exists mainly to
diff --git a/tools/telemetry/telemetry/core/backends/chrome/crx_id.py b/tools/telemetry/telemetry/core/backends/chrome/crx_id.py
index 427c5d44..21d17a2 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/crx_id.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/crx_id.py
@@ -1,13 +1,130 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# Copyright 2012 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-from __future__ import absolute_import
 
-from telemetry.core import util
+""" Read a CRX file and write out the App ID and the Full Hash of the ID.
+See: http://code.google.com/chrome/extensions/crx.html
+and 'http://stackoverflow.com/questions/'
+  + '1882981/google-chrome-alphanumeric-hashes-to-identify-extensions'
+for docs on the format.
+"""
 
-util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'tools')
-from crx_id import crx_id  # pylint: disable=F0401
+import base64
+import os
+import hashlib
+import json
 
+EXPECTED_CRX_MAGIC_NUM = 'Cr24'
+EXPECTED_CRX_VERSION = 2
 
-GetCRXAppID = crx_id.GetCRXAppID
-HasPublicKey = crx_id.HasPublicKey
+def HexToInt(hex_chars):
+  """ Convert bytes like \xab -> 171 """
+  val = 0
+  for i in xrange(len(hex_chars)):
+    val += pow(256, i) * ord(hex_chars[i])
+  return val
+
+def HexToMPDecimal(hex_chars):
+  """ Convert bytes to an MPDecimal string. Example \x00 -> "aa"
+      This gives us the AppID for a chrome extension.
+  """
+  result = ''
+  base = ord('a')
+  for i in xrange(len(hex_chars)):
+    value = ord(hex_chars[i])
+    dig1 = value / 16
+    dig2 = value % 16
+    result += chr(dig1 + base)
+    result += chr(dig2 + base)
+  return result
+
+def HexTo256(hex_chars):
+  """ Convert bytes to pairs of hex digits. E.g., \x00\x11 -> "{0x00, 0x11}"
+      The format is taylored for copy and paste into C code:
+      const uint8 sha256_hash[] = { ... }; """
+  result = []
+  for i in xrange(len(hex_chars)):
+    value = ord(hex_chars[i])
+    dig1 = value / 16
+    dig2 = value % 16
+    result.append('0x' + hex(dig1)[2:] + hex(dig2)[2:])
+  return '{%s}' % ', '.join(result)
+
+def GetPublicKeyPacked(f):
+  magic_num = f.read(4)
+  if magic_num != EXPECTED_CRX_MAGIC_NUM:
+    raise Exception('Invalid magic number: %s (expecting %s)' %
+                    (magic_num,
+                     EXPECTED_CRX_MAGIC_NUM))
+  version = f.read(4)
+  if not version[0] != EXPECTED_CRX_VERSION:
+    raise Exception('Invalid version number: %s (expecting %s)' %
+                    (version,
+                     EXPECTED_CRX_VERSION))
+  pub_key_len_bytes = HexToInt(f.read(4))
+  f.read(4)
+  return f.read(pub_key_len_bytes)
+
+def GetPublicKeyFromPath(filepath, is_win_path=False):
+  # Normalize the path for windows to have capital drive letters.
+  # We intentionally don't check if sys.platform == 'win32' and just
+  # check if this looks like drive letter so that we can test this
+  # even on posix systems.
+  if (len(filepath) >= 2 and
+      filepath[0].islower() and
+      filepath[1] == ':'):
+    filepath = filepath[0].upper() + filepath[1:]
+
+  # On Windows, filepaths are encoded using UTF-16, little endian byte order,
+  # using "wide characters" that are 16 bits in size. On POSIX systems, the
+  # encoding is generally UTF-8, which has the property of being equivalent to
+  # ASCII when only ASCII characters are in the path.
+  if is_win_path:
+    filepath = filepath.encode('utf-16le')
+
+  return filepath
+
+def GetPublicKeyUnpacked(f, filepath):
+  manifest = json.load(f)
+  if 'key' not in manifest:
+    # Use the path as the public key.
+    # See Extension::GenerateIdForPath in extension.cc
+    return GetPublicKeyFromPath(filepath)
+  else:
+    return base64.standard_b64decode(manifest['key'])
+
+def HasPublicKey(filename):
+  if os.path.isdir(filename):
+    with open(os.path.join(filename, 'manifest.json'), 'rb') as f:
+      manifest = json.load(f)
+      return 'key' in manifest
+  return False
+
+def GetPublicKey(filename, from_file_path, is_win_path=False):
+  if from_file_path:
+    return GetPublicKeyFromPath(
+        filename, is_win_path=is_win_path)
+
+  pub_key = ''
+  if os.path.isdir(filename):
+    # Assume it's an unpacked extension
+    f = open(os.path.join(filename, 'manifest.json'), 'rb')
+    pub_key = GetPublicKeyUnpacked(f, filename)
+    f.close()
+  else:
+    # Assume it's a packed extension.
+    f = open(filename, 'rb')
+    pub_key = GetPublicKeyPacked(f)
+    f.close()
+  return pub_key
+
+def GetCRXHash(filename, from_file_path=False, is_win_path=False):
+  pub_key = GetPublicKey(filename, from_file_path, is_win_path=is_win_path)
+  pub_key_hash = hashlib.sha256(pub_key).digest()
+  return HexTo256(pub_key_hash)
+
+def GetCRXAppID(filename, from_file_path=False, is_win_path=False):
+  pub_key = GetPublicKey(filename, from_file_path, is_win_path=is_win_path)
+  pub_key_hash = hashlib.sha256(pub_key).digest()
+  # AppID is the MPDecimal of only the first 128 bits of the hash.
+  return HexToMPDecimal(pub_key_hash[:128/8])
diff --git a/tools/crx_id/crx_id_unittest.py b/tools/telemetry/telemetry/core/backends/chrome/crx_id_unittest.py
old mode 100755
new mode 100644
similarity index 84%
rename from tools/crx_id/crx_id_unittest.py
rename to tools/telemetry/telemetry/core/backends/chrome/crx_id_unittest.py
index 4d0f80f..c544b359
--- a/tools/crx_id/crx_id_unittest.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/crx_id_unittest.py
@@ -1,21 +1,17 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Copyright 2012 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-
-"""Verify that crx_id.py generates a reasonable string for a canned CRX file.
-"""
-
-import crx_id
 import os
 import shutil
-import sys
 import unittest
 import tempfile
 
+from telemetry.core.backends.chrome import crx_id
+from telemetry.core import util
+
+
 class CrxIdUnittest(unittest.TestCase):
-  CRX_ID_DIR = os.path.abspath(os.path.dirname(sys.argv[0]))
+  CRX_ID_DIR = util.GetUnittestDataDir()
   PACKED_CRX = os.path.join(CRX_ID_DIR,
                             'jebgalgnebhfojomionfpkfelancnnkf.crx')
 
@@ -26,13 +22,6 @@
       ' 0x6e, 0x05, 0x6b, 0xe8, 0x73, 0x47, 0xf6, 0xc4,' \
       ' 0x11, 0x9f, 0xbc, 0xb3, 0x09, 0xb3, 0x5b, 0x40}'
 
-  def testPackedHashAppId(self):
-    """ Test the output generated for a canned, packed CRX. """
-    self.assertEqual(crx_id.GetCRXAppID(self.PACKED_CRX),
-                     self.PACKED_APP_ID)
-    self.assertEqual(crx_id.GetCRXHash(self.PACKED_CRX),
-                     self.PACKED_HASH_BYTES)
-
   UNPACKED_APP_ID = 'cbcdidchbppangcjoddlpdjlenngjldk'
   UNPACKED_HASH_BYTES = \
       '{0x21, 0x23, 0x83, 0x27, 0x1f, 0xf0, 0xd6, 0x29,' \
@@ -40,14 +29,19 @@
       ' 0xff, 0x7d, 0x6b, 0xc4, 0x78, 0x30, 0x47, 0xa6,' \
       ' 0x23, 0x12, 0x72, 0x84, 0x9b, 0x9a, 0xf6, 0x3c}'
 
+
+  def testPackedHashAppId(self):
+    """ Test the output generated for a canned, packed CRX. """
+    self.assertEqual(crx_id.GetCRXAppID(self.PACKED_CRX),
+                     self.PACKED_APP_ID)
+    self.assertEqual(crx_id.GetCRXHash(self.PACKED_CRX),
+                     self.PACKED_HASH_BYTES)
+
+
   def testUnpackedHashAppId(self):
     """ Test the output generated for a canned, unpacked extension. """
-    # Copy ../../chrome/test/data/extensions/unpacked/manifest_with_key.json
-    # to a temporary location.
     unpacked_test_manifest_path = os.path.join(
-        self.CRX_ID_DIR,
-        '..', '..', 'chrome', 'test', 'data', 'extensions', 'unpacked',
-        'manifest_with_key.json')
+        self.CRX_ID_DIR, 'manifest_with_key.json')
     temp_unpacked_crx = tempfile.mkdtemp()
     shutil.copy2(unpacked_test_manifest_path,
                  os.path.join(temp_unpacked_crx, 'manifest.json'))
@@ -58,12 +52,14 @@
     self.assertTrue(crx_id.HasPublicKey(temp_unpacked_crx))
     shutil.rmtree(temp_unpacked_crx)
 
+
   def testFromFilePath(self):
     """ Test calculation of extension id from file paths. """
     self.assertEqual(crx_id.GetCRXAppID('/tmp/temp_extension',
                                         from_file_path=True),
                      'ajbbicncdkdlchpjplgjaglppbcbmaji')
 
+
   def testFromWindowsPath(self):
     self.assertEqual(crx_id.GetCRXAppID(r'D:\Documents\chrome\test_extension',
                                         from_file_path=True,
@@ -80,6 +76,3 @@
                                         from_file_path=True,
                                         is_win_path=True),
                      kWinPathId)
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
index 4c303c2..7945d4b 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
@@ -15,12 +15,12 @@
 import tempfile
 import time
 
+from catapult_base import support_binaries
 from telemetry.core.backends import browser_backend
 from telemetry.core.backends.chrome import chrome_browser_backend
 from telemetry.core import exceptions
 from telemetry.core import util
 from telemetry.util import path
-from telemetry.util import support_binaries
 
 
 def ParseCrashpadDateTime(date_time_str):
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_page.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_page.py
index ed046231..2c3b087 100644
--- a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_page.py
+++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_page.py
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 import time
 
-from telemetry.image_processing import image_util
+from telemetry.util import image_util
 
 
 class InspectorPage(object):
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_page_unittest.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_page_unittest.py
index 7e00ec7..486e510 100644
--- a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_page_unittest.py
+++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_page_unittest.py
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 from telemetry import decorators
-from telemetry.image_processing import image_util
 from telemetry.unittest_util import tab_test_case
+from telemetry.util import image_util
 
 
 class InspectorPageTest(tab_test_case.TabTestCase):
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py
index 0db7face..f008196 100644
--- a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py
+++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_websocket_unittest.py
@@ -52,7 +52,7 @@
   def tearDown(self):
     self._mock_timer.Restore()
 
-  @decorators.Disabled('chromeos')  # crbug.com/483212
+  @decorators.Disabled('chromeos', 'mac')  # crbug.com/483212, crbug.com/498950
   def testDispatchNotification(self):
     inspector = inspector_websocket.InspectorWebsocket()
     fake_socket = FakeSocket(self._mock_timer)
diff --git a/tools/telemetry/telemetry/core/browser_unittest.py b/tools/telemetry/telemetry/core/browser_unittest.py
index 7048502..fea63ac 100644
--- a/tools/telemetry/telemetry/core/browser_unittest.py
+++ b/tools/telemetry/telemetry/core/browser_unittest.py
@@ -107,6 +107,7 @@
   def testGetSystemTotalMemory(self):
     self.assertTrue(self._browser.memory_stats['SystemTotalPhysicalMemory'] > 0)
 
+  @decorators.Disabled('mac')  # crbug.com/499208.
   def testIsTracingRunning(self):
     tracing_controller = self._browser.platform.tracing_controller
     if not tracing_controller.IsChromeTracingSupported():
diff --git a/tools/telemetry/telemetry/core/discover.py b/tools/telemetry/telemetry/core/discover.py
index 84fe5823..7f0fe81 100644
--- a/tools/telemetry/telemetry/core/discover.py
+++ b/tools/telemetry/telemetry/core/discover.py
@@ -9,6 +9,7 @@
 
 from telemetry.core import camel_case
 from telemetry import decorators
+from telemetry.internal.util import classes as classes_module
 
 
 @decorators.Cache
@@ -52,7 +53,7 @@
 # and class names, then always index by class name.
 @decorators.Cache
 def DiscoverClasses(start_dir, top_level_dir, base_class, pattern='*',
-                    index_by_class_name=True):
+                    index_by_class_name=True, directly_constructable=False):
   """Discover all classes in |start_dir| which subclass |base_class|.
 
   Base classes that contain subclasses are ignored by default.
@@ -64,6 +65,8 @@
     pattern: Unix shell-style pattern for filtering the filenames to import.
     index_by_class_name: If True, use class name converted to
         lowercase_with_underscores instead of module name in return dict keys.
+    directly_constructable: If True, will only return classes that can be
+        constructed without arguments
 
   Returns:
     dict of {module_name: class} or {underscored_class_name: class}
@@ -72,12 +75,13 @@
   classes = {}
   for module in modules:
     new_classes = DiscoverClassesInModule(
-        module, base_class, index_by_class_name)
+        module, base_class, index_by_class_name, directly_constructable)
     classes = dict(classes.items() + new_classes.items())
   return classes
 
 @decorators.Cache
-def DiscoverClassesInModule(module, base_class, index_by_class_name=False):
+def DiscoverClassesInModule(module, base_class, index_by_class_name=False,
+                            directly_constructable=False):
   """Discover all classes in |module| which subclass |base_class|.
 
   Base classes that contain subclasses are ignored by default.
@@ -114,7 +118,9 @@
       key_name = camel_case.ToUnderscore(obj.__name__)
     else:
       key_name = module.__name__.split('.')[-1]
-    classes[key_name] = obj
+    if (not directly_constructable or
+        classes_module.IsDirectlyConstructable(obj)):
+      classes[key_name] = obj
 
   return classes
 
diff --git a/tools/telemetry/telemetry/core/discover_unittest.py b/tools/telemetry/telemetry/core/discover_unittest.py
index 1bdcf87..c124d45 100644
--- a/tools/telemetry/telemetry/core/discover_unittest.py
+++ b/tools/telemetry/telemetry/core/discover_unittest.py
@@ -14,16 +14,32 @@
     self._start_dir = os.path.join(self._base_dir, 'discoverable_classes')
     self._base_class = Exception
 
+
   def testDiscoverClassesWithIndexByModuleName(self):
     classes = discover.DiscoverClasses(
         self._start_dir, self._base_dir, self._base_class,
-      index_by_class_name=False)
+        index_by_class_name=False)
 
     actual_classes = dict(
         (name, cls.__name__) for name, cls in classes.iteritems())
     expected_classes = {
-        'another_discover_dummyclass': 'DummyExceptionImpl2',
+        'another_discover_dummyclass': 'DummyExceptionWithParameterImpl1',
         'discover_dummyclass': 'DummyException',
+        'parameter_discover_dummyclass': 'DummyExceptionWithParameterImpl2'
+    }
+    self.assertEqual(actual_classes, expected_classes)
+
+  def testDiscoverDirectlyConstructableClassesWithIndexByClassName(self):
+    classes = discover.DiscoverClasses(
+        self._start_dir, self._base_dir, self._base_class,
+        directly_constructable=True)
+
+    actual_classes = dict(
+        (name, cls.__name__) for name, cls in classes.iteritems())
+    expected_classes = {
+        'dummy_exception': 'DummyException',
+        'dummy_exception_impl1': 'DummyExceptionImpl1',
+        'dummy_exception_impl2': 'DummyExceptionImpl2',
     }
     self.assertEqual(actual_classes, expected_classes)
 
@@ -36,10 +52,15 @@
     expected_classes = {
         'dummy_exception': 'DummyException',
         'dummy_exception_impl1': 'DummyExceptionImpl1',
-        'dummy_exception_impl2': 'DummyExceptionImpl2'
+        'dummy_exception_impl2': 'DummyExceptionImpl2',
+        'dummy_exception_with_parameter_impl1':
+          'DummyExceptionWithParameterImpl1',
+        'dummy_exception_with_parameter_impl2':
+          'DummyExceptionWithParameterImpl2'
     }
     self.assertEqual(actual_classes, expected_classes)
 
+
   def testDiscoverClassesWithPatternAndIndexByModule(self):
     classes = discover.DiscoverClasses(
         self._start_dir, self._base_dir, self._base_class,
@@ -48,7 +69,21 @@
     actual_classes = dict(
         (name, cls.__name__) for name, cls in classes.iteritems())
     expected_classes = {
-        'another_discover_dummyclass': 'DummyExceptionImpl2',
+        'another_discover_dummyclass': 'DummyExceptionWithParameterImpl1'
+    }
+    self.assertEqual(actual_classes, expected_classes)
+
+  def testDiscoverDirectlyConstructableClassesWithPatternAndIndexByClassName(
+      self):
+    classes = discover.DiscoverClasses(
+        self._start_dir, self._base_dir, self._base_class,
+        pattern='another*', directly_constructable=True)
+
+    actual_classes = dict(
+        (name, cls.__name__) for name, cls in classes.iteritems())
+    expected_classes = {
+        'dummy_exception_impl1': 'DummyExceptionImpl1',
+        'dummy_exception_impl2': 'DummyExceptionImpl2',
     }
     self.assertEqual(actual_classes, expected_classes)
 
@@ -61,6 +96,8 @@
         (name, cls.__name__) for name, cls in classes.iteritems())
     expected_classes = {
         'dummy_exception_impl1': 'DummyExceptionImpl1',
-        'dummy_exception_impl2': 'DummyExceptionImpl2'
+        'dummy_exception_impl2': 'DummyExceptionImpl2',
+        'dummy_exception_with_parameter_impl1':
+          'DummyExceptionWithParameterImpl1',
     }
     self.assertEqual(actual_classes, expected_classes)
diff --git a/tools/telemetry/telemetry/core/forwarders/android_forwarder.py b/tools/telemetry/telemetry/core/forwarders/android_forwarder.py
index 65be8cd..febcf19 100644
--- a/tools/telemetry/telemetry/core/forwarders/android_forwarder.py
+++ b/tools/telemetry/telemetry/core/forwarders/android_forwarder.py
@@ -9,11 +9,11 @@
 import struct
 import subprocess
 
+from catapult_base import support_binaries
 from telemetry.core.backends import adb_commands
 from telemetry.core import forwarders
 from telemetry.core import platform
 from telemetry.core import util
-from telemetry.util import support_binaries
 
 util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
 try:
diff --git a/tools/telemetry/telemetry/core/platform/android_platform_backend.py b/tools/telemetry/telemetry/core/platform/android_platform_backend.py
index 7f16e83..0464164 100644
--- a/tools/telemetry/telemetry/core/platform/android_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/android_platform_backend.py
@@ -44,7 +44,6 @@
 from pylib.perf import cache_control  # pylint: disable=import-error
 from pylib.perf import perf_control  # pylint: disable=import-error
 from pylib.perf import thermal_throttle  # pylint: disable=import-error
-from pylib.utils import device_temp_file  # pylint: disable=import-error
 
 try:
   from pylib.perf import surface_stats_collector  # pylint: disable=import-error
@@ -386,11 +385,7 @@
     command = 'ps'
     if pid:
       command += ' -p %d' % pid
-    with device_temp_file.DeviceTempFile(self._device.adb) as ps_out:
-      command += ' > %s' % ps_out.name
-      self._device.RunShellCommand(command)
-      # Get rid of trailing new line and header.
-      ps = self._device.ReadFile(ps_out.name).split('\n')[1:-1]
+    ps = self._device.RunShellCommand(command, large_output=True)[1:]
     output = []
     for line in ps:
       data = line.split()
diff --git a/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py b/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py
index bbfb5ff..def9c38d 100644
--- a/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py
@@ -5,8 +5,8 @@
 import os
 import subprocess
 
+from catapult_base import support_binaries
 from telemetry.core.platform import platform_backend
-from telemetry.util import support_binaries
 
 
 class DesktopPlatformBackend(platform_backend.PlatformBackend):
diff --git a/tools/telemetry/telemetry/core/platform/linux_platform_backend.py b/tools/telemetry/telemetry/core/platform/linux_platform_backend.py
index 6173325..74ffd47 100644
--- a/tools/telemetry/telemetry/core/platform/linux_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/linux_platform_backend.py
@@ -8,14 +8,14 @@
 import subprocess
 import sys
 
+from catapult_base import cloud_storage
+from catapult_base import support_binaries
 from telemetry.core.platform import linux_based_platform_backend
 from telemetry.core.platform import platform_backend
 from telemetry.core.platform import posix_platform_backend
 from telemetry.core.platform.power_monitor import msr_power_monitor
 from telemetry.core import util
 from telemetry import decorators
-from telemetry.util import cloud_storage
-from telemetry.util import support_binaries
 
 
 _POSSIBLE_PERFHOST_APPLICATIONS = [
diff --git a/tools/telemetry/telemetry/core/platform/profiler/android_prebuilt_profiler_helper.py b/tools/telemetry/telemetry/core/platform/profiler/android_prebuilt_profiler_helper.py
index 5974f1d..dc96ab2 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/android_prebuilt_profiler_helper.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/android_prebuilt_profiler_helper.py
@@ -7,8 +7,8 @@
 import logging
 import os
 
+from catapult_base import support_binaries
 from telemetry import decorators
-from telemetry.util import support_binaries
 
 _DEVICE_PROFILER_DIR = '/data/local/tmp/profilers/'
 
diff --git a/tools/telemetry/telemetry/core/platform/profiler/android_profiling_helper.py b/tools/telemetry/telemetry/core/platform/profiler/android_profiling_helper.py
index 4608e36..4a4b09b 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/android_profiling_helper.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/android_profiling_helper.py
@@ -11,11 +11,11 @@
 import shutil
 import subprocess
 
+from catapult_base import support_binaries
 from telemetry.core import platform as telemetry_platform
 from telemetry.core.platform.profiler import android_prebuilt_profiler_helper
 from telemetry.core import util
 from telemetry import decorators
-from telemetry.util import support_binaries
 
 util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
 from pylib.utils import md5sum  # pylint: disable=F0401
diff --git a/tools/telemetry/telemetry/core/platform/profiler/oomkiller_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/oomkiller_profiler.py
index be4643d..fe7a9ed0 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/oomkiller_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/oomkiller_profiler.py
@@ -4,10 +4,10 @@
 
 import os
 
+from catapult_base import support_binaries
 from telemetry.core.backends.chrome import android_browser_finder
 from telemetry.core.platform import profiler
 from telemetry.core import util
-from telemetry.util import support_binaries
 
 util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
 from pylib.device import intent  # pylint: disable=F0401
diff --git a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
index cbc88878..4906cf8 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
@@ -12,11 +12,11 @@
 
 from pylib.device import device_errors  # pylint: disable=F0401
 
+from catapult_base import support_binaries
 from telemetry.core import platform
 from telemetry.core.platform import profiler
 from telemetry.core.platform.profiler import android_profiling_helper
 from telemetry.core import util
-from telemetry.util import support_binaries
 
 util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
 from pylib.perf import perf_control  # pylint: disable=F0401
diff --git a/tools/telemetry/telemetry/core/platform/win_platform_backend.py b/tools/telemetry/telemetry/core/platform/win_platform_backend.py
index 938414e..e24f1f8 100644
--- a/tools/telemetry/telemetry/core/platform/win_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/win_platform_backend.py
@@ -17,13 +17,13 @@
 import time
 import zipfile
 
+from catapult_base import cloud_storage
 from telemetry.core import exceptions
 from telemetry.core.platform import desktop_platform_backend
 from telemetry.core.platform import platform_backend
 from telemetry.core.platform.power_monitor import msr_power_monitor
 from telemetry.core import util
 from telemetry import decorators
-from telemetry.util import cloud_storage
 from telemetry.util import path
 
 try:
diff --git a/tools/telemetry/telemetry/core/tab_unittest.py b/tools/telemetry/telemetry/core/tab_unittest.py
index 273d87c..d216e29c 100644
--- a/tools/telemetry/telemetry/core/tab_unittest.py
+++ b/tools/telemetry/telemetry/core/tab_unittest.py
@@ -11,10 +11,10 @@
 from telemetry.core import util
 from telemetry.core import video
 from telemetry import decorators
-from telemetry.image_processing import image_util
-from telemetry.image_processing import rgba_color
 from telemetry.timeline import model
 from telemetry.unittest_util import tab_test_case
+from telemetry.util import image_util
+from telemetry.util import rgba_color
 
 
 def _IsDocumentVisible(tab):
@@ -119,6 +119,7 @@
     self.assertTrue(found_video_start_event)
 
   @decorators.Enabled('has tabs')
+  @decorators.Disabled('mac')  # crbug.com/499207.
   def testGetRendererThreadFromTabId(self):
     self.assertEquals(self._tab.url, 'about:blank')
     # Create 3 tabs. The third tab is closed before we call
diff --git a/tools/telemetry/telemetry/core/video.py b/tools/telemetry/telemetry/core/video.py
index cb26ad3..b47a0c1 100644
--- a/tools/telemetry/telemetry/core/video.py
+++ b/tools/telemetry/telemetry/core/video.py
@@ -4,10 +4,10 @@
 
 import subprocess
 
+from catapult_base import cloud_storage
 from telemetry.core import platform
-from telemetry.image_processing import image_util
-from telemetry.image_processing import rgba_color
-from telemetry.util import cloud_storage
+from telemetry.util import image_util
+from telemetry.util import rgba_color
 
 HIGHLIGHT_ORANGE_FRAME = rgba_color.WEB_PAGE_TEST_ORANGE
 
diff --git a/tools/telemetry/telemetry/core/video_unittest.py b/tools/telemetry/telemetry/core/video_unittest.py
index 6df1a62..6ef4a10 100644
--- a/tools/telemetry/telemetry/core/video_unittest.py
+++ b/tools/telemetry/telemetry/core/video_unittest.py
@@ -10,7 +10,7 @@
 from telemetry.core import util
 from telemetry.core import video
 from telemetry import decorators
-from telemetry.image_processing import image_util
+from telemetry.util import image_util
 
 
 class VideoTest(unittest.TestCase):
diff --git a/tools/telemetry/telemetry/decorators.py b/tools/telemetry/telemetry/decorators.py
index de2bcc9..cd177e3 100644
--- a/tools/telemetry/telemetry/decorators.py
+++ b/tools/telemetry/telemetry/decorators.py
@@ -3,9 +3,13 @@
 # found in the LICENSE file.
 # pylint: disable=W0212
 
+import datetime
 import functools
+import os
 import inspect
 import types
+import warnings
+
 
 def Cache(obj):
   """Decorator for caching read-only properties.
@@ -32,6 +36,66 @@
   return Cacher
 
 
+class Deprecated(object):
+
+  def __init__(self, year, month, day, extra_guidance=''):
+    self._date_of_support_removal = datetime.date(year, month, day)
+    self._extra_guidance = extra_guidance
+
+  def _DisplayWarningMessage(self, target):
+    target_str = ''
+    if isinstance(target, types.FunctionType):
+      target_str = 'Function %s' % target.__name__
+    else:
+      target_str = 'Class %s' % target.__name__
+    warnings.warn('%s is deprecated. It will no longer be supported on %s. '
+                  'Please remove it or switch to an alternative before '
+                  'that time. %s\n'
+                  % (target_str,
+                     self._date_of_support_removal.strftime('%B %d, %Y'),
+                     self._extra_guidance),
+                  stacklevel=self._ComputeStackLevel())
+
+  def _ComputeStackLevel(self):
+    this_file, _ = os.path.splitext(__file__)
+    frame = inspect.currentframe()
+    i = 0
+    while True:
+      filename = frame.f_code.co_filename
+      if not filename.startswith(this_file):
+        return i
+      frame = frame.f_back
+      i += 1
+
+  def __call__(self, target):
+    if isinstance(target, types.FunctionType):
+      @functools.wraps(target)
+      def wrapper(*args, **kwargs):
+        self._DisplayWarningMessage(target)
+        target(*args, **kwargs)
+      return wrapper
+    elif inspect.isclass(target):
+      original_ctor = target.__init__
+
+      # We have to handle case original_ctor is object.__init__ seperately
+      # since object.__init__ does not have __module__ defined, which
+      # cause functools.wraps() to raise exception.
+      if original_ctor == object.__init__:
+        def new_ctor(*args, **kwargs):
+          self._DisplayWarningMessage(target)
+          return original_ctor(*args, **kwargs)
+      else:
+        @functools.wraps(original_ctor)
+        def new_ctor(*args, **kwargs):
+          self._DisplayWarningMessage(target)
+          return original_ctor(*args, **kwargs)
+
+      target.__init__ = new_ctor
+      return target
+    else:
+      raise TypeError('@Deprecated is only applicable to functions or classes')
+
+
 def Disabled(*args):
   """Decorator for disabling tests/benchmarks.
 
diff --git a/tools/telemetry/telemetry/decorators_unittest.py b/tools/telemetry/telemetry/decorators_unittest.py
index a39d9bb..d76f83d2 100644
--- a/tools/telemetry/telemetry/decorators_unittest.py
+++ b/tools/telemetry/telemetry/decorators_unittest.py
@@ -5,6 +5,10 @@
 import unittest
 
 from telemetry import decorators
+from telemetry.core import util
+
+util.AddDirToPythonPath(util.GetTelemetryDir(), 'third_party', 'mock')
+import mock  # pylint:disable=import-error
 
 
 class FakePlatform(object):
@@ -82,3 +86,78 @@
 
     test.SetDisabledStrings(['another_os_name', 'another_os_version_name'])
     self.assertFalse(decorators.ShouldSkip(test, possible_browser)[0])
+
+class TestDeprecation(unittest.TestCase):
+
+  @mock.patch('warnings.warn')
+  def testFunctionDeprecation(self, warn_mock):
+    @decorators.Deprecated(2015, 12, 1)
+    def Foo(x):
+      return x
+    Foo(1)
+    warn_mock.assert_called_with(
+        'Function Foo is deprecated. It will no longer be supported on '
+        'December 01, 2015. Please remove it or switch to an alternative '
+        'before that time. \n', stacklevel=4)
+
+  @mock.patch('warnings.warn')
+  def testMethodDeprecated(self, warn_mock):
+
+    class Bar(object):
+      @decorators.Deprecated(2015, 12, 1, 'Testing only.')
+      def Foo(self, x):
+        return x
+
+    Bar().Foo(1)
+    warn_mock.assert_called_with(
+        'Function Foo is deprecated. It will no longer be supported on '
+        'December 01, 2015. Please remove it or switch to an alternative '
+        'before that time. Testing only.\n', stacklevel=4)
+
+  @mock.patch('warnings.warn')
+  def testClassWithoutInitDefinedDeprecated(self, warn_mock):
+    @decorators.Deprecated(2015, 12, 1)
+    class Bar(object):
+      def Foo(self, x):
+        return x
+
+    Bar().Foo(1)
+    warn_mock.assert_called_with(
+        'Class Bar is deprecated. It will no longer be supported on '
+        'December 01, 2015. Please remove it or switch to an alternative '
+        'before that time. \n', stacklevel=4)
+
+  @mock.patch('warnings.warn')
+  def testClassWithInitDefinedDeprecated(self, warn_mock):
+
+    @decorators.Deprecated(2015, 12, 1)
+    class Bar(object):
+      def __init__(self):
+        pass
+      def Foo(self, x):
+        return x
+
+    Bar().Foo(1)
+    warn_mock.assert_called_with(
+        'Class Bar is deprecated. It will no longer be supported on '
+        'December 01, 2015. Please remove it or switch to an alternative '
+        'before that time. \n', stacklevel=4)
+
+  @mock.patch('warnings.warn')
+  def testInheritedClassDeprecated(self, warn_mock):
+    class Ba(object):
+      pass
+
+    @decorators.Deprecated(2015, 12, 1)
+    class Bar(Ba):
+      def Foo(self, x):
+        return x
+
+    class Baz(Bar):
+      pass
+
+    Baz().Foo(1)
+    warn_mock.assert_called_with(
+        'Class Bar is deprecated. It will no longer be supported on '
+        'December 01, 2015. Please remove it or switch to an alternative '
+        'before that time. \n', stacklevel=4)
diff --git a/tools/telemetry/telemetry/internal/__init__.py b/tools/telemetry/telemetry/internal/__init__.py
index 4d6aabb9..50b23df 100644
--- a/tools/telemetry/telemetry/internal/__init__.py
+++ b/tools/telemetry/telemetry/internal/__init__.py
@@ -1,3 +1,3 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/tools/telemetry/telemetry/image_processing/__init__.py b/tools/telemetry/telemetry/internal/image_processing/__init__.py
similarity index 100%
rename from tools/telemetry/telemetry/image_processing/__init__.py
rename to tools/telemetry/telemetry/internal/image_processing/__init__.py
diff --git a/tools/telemetry/telemetry/image_processing/cv_util.py b/tools/telemetry/telemetry/internal/image_processing/cv_util.py
similarity index 100%
rename from tools/telemetry/telemetry/image_processing/cv_util.py
rename to tools/telemetry/telemetry/internal/image_processing/cv_util.py
diff --git a/tools/telemetry/telemetry/image_processing/cv_util_unittest.py b/tools/telemetry/telemetry/internal/image_processing/cv_util_unittest.py
similarity index 98%
rename from tools/telemetry/telemetry/image_processing/cv_util_unittest.py
rename to tools/telemetry/telemetry/internal/image_processing/cv_util_unittest.py
index 4ef7580..23778fa7 100644
--- a/tools/telemetry/telemetry/image_processing/cv_util_unittest.py
+++ b/tools/telemetry/telemetry/internal/image_processing/cv_util_unittest.py
@@ -17,7 +17,7 @@
       # Import modules with dependencies that may not be preset in test setup so
       # that importing this unit test doesn't cause the test runner to raise an
       # exception.
-      from telemetry.image_processing import cv_util
+      from telemetry.internal.image_processing import cv_util
       self.cv_util = cv_util
 
     def testAreLinesOrthogonalish(self):
diff --git a/tools/telemetry/telemetry/image_processing/io/fake_frame_generator.py b/tools/telemetry/telemetry/internal/image_processing/fake_frame_generator.py
similarity index 93%
rename from tools/telemetry/telemetry/image_processing/io/fake_frame_generator.py
rename to tools/telemetry/telemetry/internal/image_processing/fake_frame_generator.py
index 8b356418..d1b6ab4 100644
--- a/tools/telemetry/telemetry/image_processing/io/fake_frame_generator.py
+++ b/tools/telemetry/telemetry/internal/image_processing/fake_frame_generator.py
@@ -2,13 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from telemetry.image_processing.io.frame_generator import FrameGenerator
+from telemetry.internal.image_processing import frame_generator
 from telemetry.util import external_modules
 
 np = external_modules.ImportRequiredModule('numpy')
 
 
-class FakeFrameGenerator(FrameGenerator):
+class FakeFrameGenerator(frame_generator.FrameGenerator):
   """ Fakes a Frame Generator, for testing.
 
   Attributes:
diff --git a/tools/telemetry/telemetry/image_processing/io/frame_generator.py b/tools/telemetry/telemetry/internal/image_processing/frame_generator.py
similarity index 100%
rename from tools/telemetry/telemetry/image_processing/io/frame_generator.py
rename to tools/telemetry/telemetry/internal/image_processing/frame_generator.py
diff --git a/tools/telemetry/telemetry/image_processing/image_util_bitmap_impl.py b/tools/telemetry/telemetry/internal/image_processing/image_util_bitmap_impl.py
similarity index 100%
rename from tools/telemetry/telemetry/image_processing/image_util_bitmap_impl.py
rename to tools/telemetry/telemetry/internal/image_processing/image_util_bitmap_impl.py
diff --git a/tools/telemetry/telemetry/image_processing/image_util_numpy_impl.py b/tools/telemetry/telemetry/internal/image_processing/image_util_numpy_impl.py
similarity index 96%
rename from tools/telemetry/telemetry/image_processing/image_util_numpy_impl.py
rename to tools/telemetry/telemetry/internal/image_processing/image_util_numpy_impl.py
index ea72d07..0bb7b70 100644
--- a/tools/telemetry/telemetry/image_processing/image_util_numpy_impl.py
+++ b/tools/telemetry/telemetry/internal/image_processing/image_util_numpy_impl.py
@@ -5,9 +5,9 @@
 from __future__ import division
 
 from telemetry.core import util
-from telemetry.image_processing import histogram
-from telemetry.image_processing import rgba_color
 from telemetry.util import external_modules
+from telemetry.util import color_histogram
+from telemetry.util import rgba_color
 
 util.AddDirToPythonPath(util.GetTelemetryDir(), 'third_party', 'png')
 import png  # pylint: disable=F0401
@@ -176,10 +176,10 @@
                   (filtered[:, 2] < colorm[2]) | (filtered[:, 2] > colorp[2]))
       filtered = np.compress(in_range, filtered, axis=0)
     if len(filtered[:, 0]) == 0:
-      return histogram.ColorHistogram(np.zeros((256)), np.zeros((256)),
+      return color_histogram.ColorHistogram(np.zeros((256)), np.zeros((256)),
                                       np.zeros((256)), ignore_color)
     hist_b = np.bincount(filtered[:, 0], minlength=256)
     hist_g = np.bincount(filtered[:, 1], minlength=256)
     hist_r = np.bincount(filtered[:, 2], minlength=256)
 
-  return histogram.ColorHistogram(hist_r, hist_g, hist_b, ignore_color)
+  return color_histogram.ColorHistogram(hist_r, hist_g, hist_b, ignore_color)
diff --git a/tools/telemetry/telemetry/image_processing/screen_finder.py b/tools/telemetry/telemetry/internal/image_processing/screen_finder.py
similarity index 99%
rename from tools/telemetry/telemetry/image_processing/screen_finder.py
rename to tools/telemetry/telemetry/internal/image_processing/screen_finder.py
index 1dcfbef..25f4d07 100755
--- a/tools/telemetry/telemetry/image_processing/screen_finder.py
+++ b/tools/telemetry/telemetry/internal/image_processing/screen_finder.py
@@ -18,10 +18,10 @@
 if __name__ == '__main__':
   sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
 
-from telemetry.image_processing import cv_util
-from telemetry.image_processing.io import frame_generator as \
+from telemetry.internal.image_processing import cv_util
+from telemetry.internal.image_processing import frame_generator as \
     frame_generator_module
-from telemetry.image_processing.io import video_file_frame_generator
+from telemetry.internal.image_processing import video_file_frame_generator
 from telemetry.util import external_modules
 
 np = external_modules.ImportRequiredModule('numpy')
diff --git a/tools/telemetry/telemetry/image_processing/screen_finder_unittest.py b/tools/telemetry/telemetry/internal/image_processing/screen_finder_unittest.py
similarity index 98%
rename from tools/telemetry/telemetry/image_processing/screen_finder_unittest.py
rename to tools/telemetry/telemetry/internal/image_processing/screen_finder_unittest.py
index 3750079f..0d5a2ec 100644
--- a/tools/telemetry/telemetry/image_processing/screen_finder_unittest.py
+++ b/tools/telemetry/telemetry/internal/image_processing/screen_finder_unittest.py
@@ -23,9 +23,9 @@
       # Import modules with dependencies that may not be preset in test setup so
       # that importing this unit test doesn't cause the test runner to raise an
       # exception.
-      from telemetry.image_processing.io import fake_frame_generator
-      from telemetry.image_processing.io import video_file_frame_generator
-      from telemetry.image_processing import screen_finder
+      from telemetry.internal.image_processing import fake_frame_generator
+      from telemetry.internal.image_processing import screen_finder
+      from telemetry.internal.image_processing import video_file_frame_generator
       self.FakeFrameGenerator = fake_frame_generator.FakeFrameGenerator
       self.VideoFileFrameGenerator = \
           video_file_frame_generator.VideoFileFrameGenerator
diff --git a/tools/telemetry/telemetry/image_processing/io/video_file_frame_generator.py b/tools/telemetry/telemetry/internal/image_processing/video_file_frame_generator.py
similarity index 97%
rename from tools/telemetry/telemetry/image_processing/io/video_file_frame_generator.py
rename to tools/telemetry/telemetry/internal/image_processing/video_file_frame_generator.py
index a3d0a22c..4c09b3b 100644
--- a/tools/telemetry/telemetry/image_processing/io/video_file_frame_generator.py
+++ b/tools/telemetry/telemetry/internal/image_processing/video_file_frame_generator.py
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from telemetry.image_processing.io import frame_generator
+from telemetry.internal.image_processing import frame_generator
 from telemetry.util import external_modules
 
 cv2 = external_modules.ImportRequiredModule('cv2')
diff --git a/tools/telemetry/telemetry/image_processing/io/video_file_frame_generator_unittest.py b/tools/telemetry/telemetry/internal/image_processing/video_file_frame_generator_unittest.py
similarity index 94%
rename from tools/telemetry/telemetry/image_processing/io/video_file_frame_generator_unittest.py
rename to tools/telemetry/telemetry/internal/image_processing/video_file_frame_generator_unittest.py
index c877773..021012e 100644
--- a/tools/telemetry/telemetry/image_processing/io/video_file_frame_generator_unittest.py
+++ b/tools/telemetry/telemetry/internal/image_processing/video_file_frame_generator_unittest.py
@@ -6,7 +6,7 @@
 import unittest
 
 from telemetry.core import util
-from telemetry.image_processing.io import frame_generator
+from telemetry.internal.image_processing import frame_generator
 from telemetry.util import external_modules
 
 try:
@@ -20,7 +20,7 @@
       # Import modules with dependencies that may not be preset in test setup so
       # that importing this unit test doesn't cause the test runner to raise an
       # exception.
-      from telemetry.image_processing.io import video_file_frame_generator
+      from telemetry.internal.image_processing import video_file_frame_generator
       self.VideoFileFrameGenerator = \
           video_file_frame_generator.VideoFileFrameGenerator
 
diff --git a/tools/telemetry/telemetry/results/__init__.py b/tools/telemetry/telemetry/internal/results/__init__.py
similarity index 100%
rename from tools/telemetry/telemetry/results/__init__.py
rename to tools/telemetry/telemetry/internal/results/__init__.py
diff --git a/tools/telemetry/telemetry/results/base_test_results_unittest.py b/tools/telemetry/telemetry/internal/results/base_test_results_unittest.py
similarity index 100%
rename from tools/telemetry/telemetry/results/base_test_results_unittest.py
rename to tools/telemetry/telemetry/internal/results/base_test_results_unittest.py
diff --git a/tools/telemetry/telemetry/results/buildbot_output_formatter.py b/tools/telemetry/telemetry/internal/results/buildbot_output_formatter.py
similarity index 97%
rename from tools/telemetry/telemetry/results/buildbot_output_formatter.py
rename to tools/telemetry/telemetry/internal/results/buildbot_output_formatter.py
index 2e39ef9..6685382 100644
--- a/tools/telemetry/telemetry/results/buildbot_output_formatter.py
+++ b/tools/telemetry/telemetry/internal/results/buildbot_output_formatter.py
@@ -2,8 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from telemetry import perf_tests_helper
-from telemetry.results import output_formatter
+from telemetry.internal.results import output_formatter
+from telemetry.util import perf_tests_helper
 from telemetry import value as value_module
 from telemetry.value import summary as summary_module
 
diff --git a/tools/telemetry/telemetry/results/chart_json_output_formatter.py b/tools/telemetry/telemetry/internal/results/chart_json_output_formatter.py
similarity index 97%
rename from tools/telemetry/telemetry/results/chart_json_output_formatter.py
rename to tools/telemetry/telemetry/internal/results/chart_json_output_formatter.py
index 9dfa117..6b906ee 100644
--- a/tools/telemetry/telemetry/results/chart_json_output_formatter.py
+++ b/tools/telemetry/telemetry/internal/results/chart_json_output_formatter.py
@@ -6,7 +6,7 @@
 import itertools
 import json
 
-from telemetry.results import output_formatter
+from telemetry.internal.results import output_formatter
 from telemetry.value import summary as summary_module
 
 def ResultsAsChartDict(benchmark_metadata, page_specific_values,
diff --git a/tools/telemetry/telemetry/results/chart_json_output_formatter_unittest.py b/tools/telemetry/telemetry/internal/results/chart_json_output_formatter_unittest.py
similarity index 96%
rename from tools/telemetry/telemetry/results/chart_json_output_formatter_unittest.py
rename to tools/telemetry/telemetry/internal/results/chart_json_output_formatter_unittest.py
index 4c103f4d..a4733ed9 100644
--- a/tools/telemetry/telemetry/results/chart_json_output_formatter_unittest.py
+++ b/tools/telemetry/telemetry/internal/results/chart_json_output_formatter_unittest.py
@@ -8,16 +8,16 @@
 import unittest
 
 from telemetry import benchmark
+from telemetry.internal.results import chart_json_output_formatter
+from telemetry.internal.results import page_test_results
 from telemetry import page as page_module
 from telemetry.page import page_set
-from telemetry.results import chart_json_output_formatter
-from telemetry.results import page_test_results
 from telemetry.value import list_of_scalar_values
 from telemetry.value import scalar
 
 
 def _MakePageSet():
-  ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+  ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
   ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
   ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
   return ps
diff --git a/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py b/tools/telemetry/telemetry/internal/results/csv_pivot_table_output_formatter.py
similarity index 97%
rename from tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py
rename to tools/telemetry/telemetry/internal/results/csv_pivot_table_output_formatter.py
index c7f66fd3..4613fc8 100644
--- a/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py
+++ b/tools/telemetry/telemetry/internal/results/csv_pivot_table_output_formatter.py
@@ -4,7 +4,7 @@
 
 import csv
 
-from telemetry.results import output_formatter
+from telemetry.internal.results import output_formatter
 from telemetry.value import scalar
 
 
diff --git a/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter_unittest.py b/tools/telemetry/telemetry/internal/results/csv_pivot_table_output_formatter_unittest.py
similarity index 94%
rename from tools/telemetry/telemetry/results/csv_pivot_table_output_formatter_unittest.py
rename to tools/telemetry/telemetry/internal/results/csv_pivot_table_output_formatter_unittest.py
index 4f1e0c1..79b88862 100644
--- a/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter_unittest.py
+++ b/tools/telemetry/telemetry/internal/results/csv_pivot_table_output_formatter_unittest.py
@@ -5,15 +5,15 @@
 import StringIO
 import unittest
 
+from telemetry.internal.results import csv_pivot_table_output_formatter
+from telemetry.internal.results import page_test_results
 from telemetry import page as page_module
 from telemetry.page import page_set
-from telemetry.results import csv_pivot_table_output_formatter
-from telemetry.results import page_test_results
 from telemetry.value import scalar
 
 
 def _MakePageSet():
-  ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+  ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
   ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
   ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
   return ps
diff --git a/tools/telemetry/telemetry/results/gtest_progress_reporter.py b/tools/telemetry/telemetry/internal/results/gtest_progress_reporter.py
similarity index 98%
rename from tools/telemetry/telemetry/results/gtest_progress_reporter.py
rename to tools/telemetry/telemetry/internal/results/gtest_progress_reporter.py
index 87c03f7..2b26c444 100644
--- a/tools/telemetry/telemetry/results/gtest_progress_reporter.py
+++ b/tools/telemetry/telemetry/internal/results/gtest_progress_reporter.py
@@ -4,7 +4,7 @@
 
 import time
 
-from telemetry.results import progress_reporter
+from telemetry.internal.results import progress_reporter
 from telemetry.value import failure
 from telemetry.value import skip
 
diff --git a/tools/telemetry/telemetry/results/gtest_progress_reporter_unittest.py b/tools/telemetry/telemetry/internal/results/gtest_progress_reporter_unittest.py
similarity index 96%
rename from tools/telemetry/telemetry/results/gtest_progress_reporter_unittest.py
rename to tools/telemetry/telemetry/internal/results/gtest_progress_reporter_unittest.py
index a5f0856e..b7e543d8 100644
--- a/tools/telemetry/telemetry/results/gtest_progress_reporter_unittest.py
+++ b/tools/telemetry/telemetry/internal/results/gtest_progress_reporter_unittest.py
@@ -5,11 +5,11 @@
 import os
 import traceback
 
+from telemetry.internal.results import base_test_results_unittest
+from telemetry.internal.results import gtest_progress_reporter
+from telemetry.internal.results import page_test_results
 from telemetry import page as page_module
 from telemetry.page import page_set
-from telemetry.results import base_test_results_unittest
-from telemetry.results import gtest_progress_reporter
-from telemetry.results import page_test_results
 from telemetry.unittest_util import simple_mock
 from telemetry.unittest_util import stream
 from telemetry.value import failure
@@ -17,7 +17,7 @@
 
 
 def _MakePageSet():
-  ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+  ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
   ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
   ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
   ps.AddUserStory(page_module.Page('http://www.baz.com/', ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/results/html_output_formatter.py b/tools/telemetry/telemetry/internal/results/html_output_formatter.py
similarity index 97%
rename from tools/telemetry/telemetry/results/html_output_formatter.py
rename to tools/telemetry/telemetry/internal/results/html_output_formatter.py
index d9930f5..b375e381 100644
--- a/tools/telemetry/telemetry/results/html_output_formatter.py
+++ b/tools/telemetry/telemetry/internal/results/html_output_formatter.py
@@ -8,11 +8,11 @@
 import os
 import re
 
-from telemetry import value as value_module
+from catapult_base import cloud_storage
 from telemetry.core import util
-from telemetry.results import chart_json_output_formatter
-from telemetry.results import output_formatter
-from telemetry.util import cloud_storage
+from telemetry.internal.results import chart_json_output_formatter
+from telemetry.internal.results import output_formatter
+from telemetry import value as value_module
 
 util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'util')
 import lastchange  # pylint: disable=F0401
diff --git a/tools/telemetry/telemetry/results/html_output_formatter_unittest.py b/tools/telemetry/telemetry/internal/results/html_output_formatter_unittest.py
similarity index 97%
rename from tools/telemetry/telemetry/results/html_output_formatter_unittest.py
rename to tools/telemetry/telemetry/internal/results/html_output_formatter_unittest.py
index 4fdf206..f7033b0b 100644
--- a/tools/telemetry/telemetry/results/html_output_formatter_unittest.py
+++ b/tools/telemetry/telemetry/internal/results/html_output_formatter_unittest.py
@@ -6,15 +6,15 @@
 import unittest
 
 from telemetry import benchmark
+from telemetry.internal.results import html_output_formatter
+from telemetry.internal.results import page_test_results
 from telemetry import page as page_module
 from telemetry.page import page_set
-from telemetry.results import html_output_formatter
-from telemetry.results import page_test_results
 from telemetry.value import scalar
 
 
 def _MakePageSet():
-  ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+  ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
   ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
   ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
   ps.AddUserStory(page_module.Page('http://www.baz.com/', ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/results/json_output_formatter.py b/tools/telemetry/telemetry/internal/results/json_output_formatter.py
similarity index 96%
rename from tools/telemetry/telemetry/results/json_output_formatter.py
rename to tools/telemetry/telemetry/internal/results/json_output_formatter.py
index 7564755..04d893c 100644
--- a/tools/telemetry/telemetry/results/json_output_formatter.py
+++ b/tools/telemetry/telemetry/internal/results/json_output_formatter.py
@@ -4,7 +4,7 @@
 
 import json
 
-from telemetry.results import output_formatter
+from telemetry.internal.results import output_formatter
 
 
 def ResultsAsDict(page_test_results, benchmark_metadata):
diff --git a/tools/telemetry/telemetry/results/json_output_formatter_unittest.py b/tools/telemetry/telemetry/internal/results/json_output_formatter_unittest.py
similarity index 95%
rename from tools/telemetry/telemetry/results/json_output_formatter_unittest.py
rename to tools/telemetry/telemetry/internal/results/json_output_formatter_unittest.py
index 398843fa4..aa9e7473 100644
--- a/tools/telemetry/telemetry/results/json_output_formatter_unittest.py
+++ b/tools/telemetry/telemetry/internal/results/json_output_formatter_unittest.py
@@ -9,17 +9,17 @@
 import unittest
 
 from telemetry import benchmark
+from telemetry.internal.results import json_output_formatter
+from telemetry.internal.results import page_test_results
 from telemetry import page as page_module
 from telemetry.page import page_set
-from telemetry.results import json_output_formatter
-from telemetry.results import page_test_results
 from telemetry.timeline import trace_data
 from telemetry.value import scalar
 from telemetry.value import trace
 
 
 def _MakePageSet():
-  ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+  ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
   ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
   ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
   return ps
diff --git a/tools/telemetry/telemetry/results/output_formatter.py b/tools/telemetry/telemetry/internal/results/output_formatter.py
similarity index 100%
rename from tools/telemetry/telemetry/results/output_formatter.py
rename to tools/telemetry/telemetry/internal/results/output_formatter.py
diff --git a/tools/telemetry/telemetry/results/page_test_results.py b/tools/telemetry/telemetry/internal/results/page_test_results.py
similarity index 96%
rename from tools/telemetry/telemetry/results/page_test_results.py
rename to tools/telemetry/telemetry/internal/results/page_test_results.py
index 90ac871..e40bcf9 100644
--- a/tools/telemetry/telemetry/results/page_test_results.py
+++ b/tools/telemetry/telemetry/internal/results/page_test_results.py
@@ -10,9 +10,9 @@
 import sys
 import traceback
 
-from telemetry.results import progress_reporter as progress_reporter_module
-from telemetry.results import user_story_run
-from telemetry.util import cloud_storage
+from catapult_base import cloud_storage
+from telemetry.internal.results import progress_reporter as reporter_module
+from telemetry.internal.results import user_story_run
 from telemetry import value as value_module
 from telemetry.value import failure
 from telemetry.value import skip
@@ -47,7 +47,7 @@
     self._output_stream = output_stream
     self._progress_reporter = (
         progress_reporter if progress_reporter is not None
-        else progress_reporter_module.ProgressReporter())
+        else reporter_module.ProgressReporter())
     self._output_formatters = (
         output_formatters if output_formatters is not None else [])
     self._trace_tag = trace_tag
@@ -200,7 +200,7 @@
     self._progress_reporter.DidFinishAllTests(self)
 
     # Only serialize the trace if output_format is json.
-    from telemetry.results import json_output_formatter
+    from telemetry.internal.results import json_output_formatter
     if (self._output_dir and
         any(isinstance(o, json_output_formatter.JsonOutputFormatter)
             for o in self._output_formatters)):
diff --git a/tools/telemetry/telemetry/results/page_test_results_unittest.py b/tools/telemetry/telemetry/internal/results/page_test_results_unittest.py
similarity index 97%
rename from tools/telemetry/telemetry/results/page_test_results_unittest.py
rename to tools/telemetry/telemetry/internal/results/page_test_results_unittest.py
index 6fdb7f7..7737076 100644
--- a/tools/telemetry/telemetry/results/page_test_results_unittest.py
+++ b/tools/telemetry/telemetry/internal/results/page_test_results_unittest.py
@@ -5,10 +5,10 @@
 import os
 import unittest
 
+from telemetry.internal.results import base_test_results_unittest
+from telemetry.internal.results import page_test_results
 from telemetry import page as page_module
 from telemetry.page import page_set
-from telemetry.results import base_test_results_unittest
-from telemetry.results import page_test_results
 from telemetry.timeline import trace_data
 from telemetry.value import failure
 from telemetry.value import histogram
@@ -18,7 +18,7 @@
 
 class PageTestResultsTest(base_test_results_unittest.BaseTestResultsUnittest):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page("http://www.bar.com/", ps, ps.base_dir))
     ps.AddUserStory(page_module.Page("http://www.baz.com/", ps, ps.base_dir))
     ps.AddUserStory(page_module.Page("http://www.foo.com/", ps, ps.base_dir))
@@ -238,7 +238,7 @@
 
 class PageTestResultsFilterTest(unittest.TestCase):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
     self.page_set = ps
diff --git a/tools/telemetry/telemetry/results/progress_reporter.py b/tools/telemetry/telemetry/internal/results/progress_reporter.py
similarity index 100%
rename from tools/telemetry/telemetry/results/progress_reporter.py
rename to tools/telemetry/telemetry/internal/results/progress_reporter.py
diff --git a/tools/telemetry/telemetry/results/results_options.py b/tools/telemetry/telemetry/internal/results/results_options.py
similarity index 92%
rename from tools/telemetry/telemetry/results/results_options.py
rename to tools/telemetry/telemetry/internal/results/results_options.py
index 26d76bfc..f8c558c 100644
--- a/tools/telemetry/telemetry/results/results_options.py
+++ b/tools/telemetry/telemetry/internal/results/results_options.py
@@ -7,14 +7,14 @@
 import sys
 
 from telemetry.core import util
-from telemetry.results import buildbot_output_formatter
-from telemetry.results import chart_json_output_formatter
-from telemetry.results import csv_pivot_table_output_formatter
-from telemetry.results import gtest_progress_reporter
-from telemetry.results import html_output_formatter
-from telemetry.results import json_output_formatter
-from telemetry.results import page_test_results
-from telemetry.results import progress_reporter
+from telemetry.internal.results import buildbot_output_formatter
+from telemetry.internal.results import chart_json_output_formatter
+from telemetry.internal.results import csv_pivot_table_output_formatter
+from telemetry.internal.results import gtest_progress_reporter
+from telemetry.internal.results import html_output_formatter
+from telemetry.internal.results import json_output_formatter
+from telemetry.internal.results import page_test_results
+from telemetry.internal.results import progress_reporter
 
 # Allowed output formats. The default is the first item in the list.
 _OUTPUT_FORMAT_CHOICES = ('html', 'buildbot', 'gtest', 'json',
diff --git a/tools/telemetry/telemetry/results/user_story_run.py b/tools/telemetry/telemetry/internal/results/user_story_run.py
similarity index 100%
rename from tools/telemetry/telemetry/results/user_story_run.py
rename to tools/telemetry/telemetry/internal/results/user_story_run.py
diff --git a/tools/telemetry/telemetry/results/user_story_run_unittest.py b/tools/telemetry/telemetry/internal/results/user_story_run_unittest.py
similarity index 97%
rename from tools/telemetry/telemetry/results/user_story_run_unittest.py
rename to tools/telemetry/telemetry/internal/results/user_story_run_unittest.py
index c4be99c9..2b1b988 100644
--- a/tools/telemetry/telemetry/results/user_story_run_unittest.py
+++ b/tools/telemetry/telemetry/internal/results/user_story_run_unittest.py
@@ -4,7 +4,7 @@
 
 import unittest
 
-from telemetry.results import user_story_run
+from telemetry.internal.results import user_story_run
 from telemetry.story import shared_state
 from telemetry.story import story_set
 from telemetry import user_story as user_story_module
diff --git a/tools/telemetry/telemetry/internal/story_runner.py b/tools/telemetry/telemetry/internal/story_runner.py
index 4fa7155..e437b98 100644
--- a/tools/telemetry/telemetry/internal/story_runner.py
+++ b/tools/telemetry/telemetry/internal/story_runner.py
@@ -8,13 +8,13 @@
 import sys
 import time
 
+from catapult_base import cloud_storage
 from telemetry.core import exceptions
 from telemetry.core import wpr_modes
 from telemetry.internal.actions import page_action
+from telemetry.internal.results import results_options
 from telemetry.page import page_test
-from telemetry.results import results_options
 from telemetry import story
-from telemetry.util import cloud_storage
 from telemetry.util import exception_formatter
 from telemetry.value import failure
 from telemetry.value import skip
diff --git a/tools/telemetry/telemetry/internal/story_runner_unittest.py b/tools/telemetry/telemetry/internal/story_runner_unittest.py
index 390aeb56..719181c 100644
--- a/tools/telemetry/telemetry/internal/story_runner_unittest.py
+++ b/tools/telemetry/telemetry/internal/story_runner_unittest.py
@@ -6,20 +6,20 @@
 import sys
 import unittest
 
+from catapult_base import cloud_storage
 from telemetry import benchmark
-from telemetry import decorators
 from telemetry.core import exceptions
+from telemetry import decorators
+from telemetry.internal.results import results_options
 from telemetry.internal import story_runner
 from telemetry.page import page as page_module
 from telemetry.page import page_test
 from telemetry.page import test_expectations
-from telemetry.results import results_options
 from telemetry import story
 from telemetry.story import shared_state
 from telemetry.unittest_util import options_for_unittests
 from telemetry.unittest_util import system_stub
 from telemetry import user_story as user_story_module
-from telemetry.util import cloud_storage
 from telemetry.util import exception_formatter as exception_formatter_module
 from telemetry.value import list_of_scalar_values
 from telemetry.value import scalar
diff --git a/tools/telemetry/telemetry/image_processing/io/__init__.py b/tools/telemetry/telemetry/internal/util/__init__.py
similarity index 62%
copy from tools/telemetry/telemetry/image_processing/io/__init__.py
copy to tools/telemetry/telemetry/internal/util/__init__.py
index 4d6aabb9..50b23df 100644
--- a/tools/telemetry/telemetry/image_processing/io/__init__.py
+++ b/tools/telemetry/telemetry/internal/util/__init__.py
@@ -1,3 +1,3 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
diff --git a/tools/telemetry/telemetry/util/bootstrap.py b/tools/telemetry/telemetry/internal/util/bootstrap.py
similarity index 100%
rename from tools/telemetry/telemetry/util/bootstrap.py
rename to tools/telemetry/telemetry/internal/util/bootstrap.py
diff --git a/tools/telemetry/telemetry/util/classes.py b/tools/telemetry/telemetry/internal/util/classes.py
similarity index 100%
rename from tools/telemetry/telemetry/util/classes.py
rename to tools/telemetry/telemetry/internal/util/classes.py
diff --git a/tools/telemetry/telemetry/util/classes_unittest.py b/tools/telemetry/telemetry/internal/util/classes_unittest.py
similarity index 96%
rename from tools/telemetry/telemetry/util/classes_unittest.py
rename to tools/telemetry/telemetry/internal/util/classes_unittest.py
index a74581a0..dc7ac51 100644
--- a/tools/telemetry/telemetry/util/classes_unittest.py
+++ b/tools/telemetry/telemetry/internal/util/classes_unittest.py
@@ -4,7 +4,7 @@
 
 import unittest
 
-from telemetry.util import classes
+from telemetry.internal.util import classes
 
 
 class ClassWithoutInitDefOne: # pylint: disable=old-style-class, no-init
diff --git a/tools/telemetry/telemetry/util/find_dependencies.py b/tools/telemetry/telemetry/internal/util/find_dependencies.py
similarity index 98%
rename from tools/telemetry/telemetry/util/find_dependencies.py
rename to tools/telemetry/telemetry/internal/util/find_dependencies.py
index 6d223f3..e3d2e077 100644
--- a/tools/telemetry/telemetry/util/find_dependencies.py
+++ b/tools/telemetry/telemetry/internal/util/find_dependencies.py
@@ -11,13 +11,13 @@
 import sys
 import zipfile
 
+from catapult_base import cloud_storage
 from telemetry import benchmark
 from telemetry.core import command_line
 from telemetry.core import discover
-from telemetry.util import bootstrap
-from telemetry.util import cloud_storage
+from telemetry.internal.util import bootstrap
+from telemetry.internal.util import path_set
 from telemetry.util import path
-from telemetry.util import path_set
 
 DEPS_FILE = 'bootstrap_deps'
 
diff --git a/tools/telemetry/telemetry/util/find_dependencies_unittest.py b/tools/telemetry/telemetry/internal/util/find_dependencies_unittest.py
similarity index 96%
rename from tools/telemetry/telemetry/util/find_dependencies_unittest.py
rename to tools/telemetry/telemetry/internal/util/find_dependencies_unittest.py
index 67cb4bbe..7376fbc 100644
--- a/tools/telemetry/telemetry/util/find_dependencies_unittest.py
+++ b/tools/telemetry/telemetry/internal/util/find_dependencies_unittest.py
@@ -12,8 +12,8 @@
 import unittest
 import zipfile
 
-from telemetry.util import cloud_storage
-from telemetry.util import find_dependencies
+from catapult_base import cloud_storage
+from telemetry.internal.util import find_dependencies
 
 
 class FindDependenciesTest(unittest.TestCase):
diff --git a/tools/telemetry/telemetry/util/path_set.py b/tools/telemetry/telemetry/internal/util/path_set.py
similarity index 100%
rename from tools/telemetry/telemetry/util/path_set.py
rename to tools/telemetry/telemetry/internal/util/path_set.py
diff --git a/tools/telemetry/telemetry/util/path_set_unittest.py b/tools/telemetry/telemetry/internal/util/path_set_unittest.py
similarity index 95%
rename from tools/telemetry/telemetry/util/path_set_unittest.py
rename to tools/telemetry/telemetry/internal/util/path_set_unittest.py
index b205b93..6cc0ec1 100755
--- a/tools/telemetry/telemetry/util/path_set_unittest.py
+++ b/tools/telemetry/telemetry/internal/util/path_set_unittest.py
@@ -6,7 +6,7 @@
 import os
 import unittest
 
-from telemetry.util import path_set
+from telemetry.internal.util import path_set
 
 
 class PathSetTest(unittest.TestCase):
diff --git a/tools/telemetry/telemetry/page/__init__.py b/tools/telemetry/telemetry/page/__init__.py
index be27f47..fa32127 100644
--- a/tools/telemetry/telemetry/page/__init__.py
+++ b/tools/telemetry/telemetry/page/__init__.py
@@ -6,9 +6,9 @@
 import os
 import urlparse
 
+from catapult_base import cloud_storage
 from telemetry.page import shared_page_state
 from telemetry import user_story
-from telemetry.util import cloud_storage
 from telemetry.util import path
 
 
diff --git a/tools/telemetry/telemetry/page/action_runner.py b/tools/telemetry/telemetry/page/action_runner.py
index a5633669..a48dabc2 100644
--- a/tools/telemetry/telemetry/page/action_runner.py
+++ b/tools/telemetry/telemetry/page/action_runner.py
@@ -32,6 +32,11 @@
     self._tab = tab
     self._skip_waits = skip_waits
 
+  @property
+  def tab(self):
+    """Returns the tab on which actions are performed."""
+    return self._tab
+
   def _RunAction(self, action):
     action.WillRunAction(self._tab)
     action.RunAction(self._tab)
diff --git a/tools/telemetry/telemetry/page/page_run_end_to_end_unittest.py b/tools/telemetry/telemetry/page/page_run_end_to_end_unittest.py
index 15b3548..e4dca475 100644
--- a/tools/telemetry/telemetry/page/page_run_end_to_end_unittest.py
+++ b/tools/telemetry/telemetry/page/page_run_end_to_end_unittest.py
@@ -11,18 +11,18 @@
 import unittest
 
 from telemetry import benchmark
-from telemetry import decorators
 from telemetry.core import browser_finder
 from telemetry.core import exceptions
 from telemetry.core import user_agent
 from telemetry.core import util
+from telemetry import decorators
+from telemetry.internal.results import results_options
 from telemetry.internal import story_runner
 from telemetry.page import page as page_module
 from telemetry.page import page_set
 from telemetry.page import page_test
 from telemetry.page import shared_page_state
 from telemetry.page import test_expectations
-from telemetry.results import results_options
 from telemetry.unittest_util import options_for_unittests
 from telemetry.unittest_util import system_stub
 from telemetry.util import exception_formatter
diff --git a/tools/telemetry/telemetry/page/page_set.py b/tools/telemetry/telemetry/page/page_set.py
index 0287c51..020f518 100644
--- a/tools/telemetry/telemetry/page/page_set.py
+++ b/tools/telemetry/telemetry/page/page_set.py
@@ -5,28 +5,29 @@
 import os
 
 from telemetry.page import page as page_module
+from telemetry import decorators
 from telemetry import story
 
 PUBLIC_BUCKET = story.PUBLIC_BUCKET
 PARTNER_BUCKET = story.PARTNER_BUCKET
 INTERNAL_BUCKET = story.INTERNAL_BUCKET
 
-
+@decorators.Deprecated(
+    2015, 6, 25, 'Please use the UserStory class instead (crbug.com/439512). '
+    'Instructions for conversion can be found in: https://goo.gl/JsaEez')
 class PageSet(story.StorySet):
-  def __init__(self, file_path=None, archive_data_file='', user_agent_type=None,
+  """
+  This class contains all Chromium-specific configurations necessary to run a
+  Telemetry benchmark.
+  """
+  def __init__(self, base_dir=None, archive_data_file='', user_agent_type=None,
                serving_dirs=None, bucket=None):
-    # The default value of file_path is location of the file that define this
-    # page set instance's class.
-    # TODO(aiolos): When migrating page_sets over to story_sets, make
-    # sure that we are passing a valid directory path in to base_dir, and not
-    # a file path like we curerntly do in some cases for file_path.
-    dir_name = file_path
-    if file_path and os.path.isfile(file_path):
-      dir_name = os.path.dirname(file_path)
+    if base_dir and not os.path.isdir(base_dir):
+      raise ValueError('Invalid base_dir value')
 
     super(PageSet, self).__init__(
         archive_data_file=archive_data_file, cloud_storage_bucket=bucket,
-        base_dir=dir_name, serving_dirs=serving_dirs)
+        base_dir=base_dir, serving_dirs=serving_dirs)
 
     # These attributes can be set dynamically by the page set.
     self.user_agent_type = user_agent_type
diff --git a/tools/telemetry/telemetry/page/page_set_unittest.py b/tools/telemetry/telemetry/page/page_set_unittest.py
index 9545c70..5edec41 100644
--- a/tools/telemetry/telemetry/page/page_set_unittest.py
+++ b/tools/telemetry/telemetry/page/page_set_unittest.py
@@ -15,7 +15,7 @@
   def testServingDirs(self):
     directory_path = tempfile.mkdtemp()
     try:
-      ps = page_set.PageSet(serving_dirs=['a/b'], file_path=directory_path)
+      ps = page_set.PageSet(serving_dirs=['a/b'], base_dir=directory_path)
       ps.AddUserStory(page.Page('file://c/test.html', ps, ps.base_dir))
       ps.AddUserStory(page.Page('file://c/test.js', ps, ps.base_dir))
       ps.AddUserStory(page.Page('file://d/e/../test.html', ps, ps.base_dir))
@@ -34,7 +34,7 @@
     directory_path = tempfile.mkdtemp()
     try:
       absolute_dir = os.path.join(directory_path, 'a', 'b')
-      ps = page_set.PageSet(file_path=directory_path,
+      ps = page_set.PageSet(base_dir=directory_path,
                             serving_dirs=['', directory_path, absolute_dir])
       real_directory_path = os.path.realpath(directory_path)
       real_absolute_dir = os.path.realpath(absolute_dir)
diff --git a/tools/telemetry/telemetry/page/page_unittest.py b/tools/telemetry/telemetry/page/page_unittest.py
index 22e5a0a..8f2e1ba 100644
--- a/tools/telemetry/telemetry/page/page_unittest.py
+++ b/tools/telemetry/telemetry/page/page_unittest.py
@@ -42,7 +42,7 @@
                     (os.altsep and apage.file_path_url.endswith(os.altsep)))
 
   def testSort(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page.Page('http://www.foo.com/', ps, ps.base_dir))
     ps.AddUserStory(page.Page('http://www.bar.com/', ps, ps.base_dir))
 
@@ -54,13 +54,13 @@
   def testGetUrlBaseDirAndFileForUrlBaseDir(self):
     base_dir = os.path.dirname(__file__)
     file_path = os.path.join(os.path.dirname(base_dir), 'otherdir', 'file.html')
-    ps = page_set.PageSet(file_path=base_dir,
+    ps = page_set.PageSet(base_dir=base_dir,
                           serving_dirs=[os.path.join('..', 'somedir', '')])
     ps.AddUserStory(page.Page('file://../otherdir/file.html', ps, ps.base_dir))
     self.assertPathEqual(ps[0].file_path, file_path)
 
   def testDisplayUrlForHttp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page.Page('http://www.foo.com/', ps, ps.base_dir))
     ps.AddUserStory(page.Page('http://www.bar.com/', ps, ps.base_dir))
 
@@ -68,7 +68,7 @@
     self.assertEquals(ps[1].display_name, 'http://www.bar.com/')
 
   def testDisplayUrlForHttps(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page.Page('http://www.foo.com/', ps, ps.base_dir))
     ps.AddUserStory(page.Page('https://www.bar.com/', ps, ps.base_dir))
 
@@ -76,7 +76,7 @@
     self.assertEquals(ps[1].display_name, 'https://www.bar.com/')
 
   def testDisplayUrlForFile(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page.Page(
         'file://../../otherdir/foo.html', ps, ps.base_dir))
     ps.AddUserStory(page.Page(
@@ -86,7 +86,7 @@
     self.assertEquals(ps[1].display_name, 'bar.html')
 
   def testDisplayUrlForFilesDifferingBySuffix(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page.Page(
         'file://../../otherdir/foo.html', ps, ps.base_dir))
     ps.AddUserStory(page.Page(
@@ -96,7 +96,7 @@
     self.assertEquals(ps[1].display_name, 'foo1.html')
 
   def testDisplayUrlForFileOfDifferentPaths(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page.Page('file://../../somedir/foo.html', ps, ps.base_dir))
     ps.AddUserStory(page.Page(
         'file://../../otherdir/bar.html', ps, ps.base_dir))
@@ -105,7 +105,7 @@
     self.assertEquals(ps[1].display_name, 'otherdir/bar.html')
 
   def testDisplayUrlForFileDirectories(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page.Page('file://../../otherdir/foo', ps, ps.base_dir))
     ps.AddUserStory(page.Page('file://../../otherdir/bar', ps, ps.base_dir))
 
@@ -113,14 +113,14 @@
     self.assertEquals(ps[1].display_name, 'bar')
 
   def testDisplayUrlForSingleFile(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page.Page(
         'file://../../otherdir/foo.html', ps, ps.base_dir))
 
     self.assertEquals(ps[0].display_name, 'foo.html')
 
   def testDisplayUrlForSingleDirectory(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page.Page('file://../../otherdir/foo', ps, ps.base_dir))
 
     self.assertEquals(ps[0].display_name, 'foo')
diff --git a/tools/telemetry/telemetry/page/shared_page_state.py b/tools/telemetry/telemetry/page/shared_page_state.py
index 833b694..d817fed4 100644
--- a/tools/telemetry/telemetry/page/shared_page_state.py
+++ b/tools/telemetry/telemetry/page/shared_page_state.py
@@ -3,8 +3,11 @@
 # found in the LICENSE file.
 import logging
 import os
+import shutil
 import sys
+import zipfile
 
+from catapult_base import cloud_storage
 from telemetry.core import browser_finder
 from telemetry.core import browser_finder_exceptions
 from telemetry.core import browser_info as browser_info_module
@@ -34,6 +37,10 @@
                                            finder_options)
 
 class SharedPageState(shared_state.SharedState):
+  """
+  This class contains all specific logic necessary to run a Chrome browser
+  benchmark.
+  """
 
   _device_type = None
 
@@ -59,6 +66,7 @@
     self._current_page = None
     self._current_tab = None
 
+    self._pregenerated_profile_archive = None
     self._test.SetOptions(self._finder_options)
 
   def _GetPossibleBrowser(self, test, finder_options):
@@ -129,6 +137,9 @@
         browser_options.extra_wpr_args, make_javascript_deterministic)
 
   def WillRunUserStory(self, page):
+    if self._ShouldDownloadPregeneratedProfileArchive():
+      self._DownloadPregeneratedProfileArchive()
+
     page_set = page.page_set
     self._current_page = page
     if self._test.RestartBrowserBeforeEachPage() or page.startup_url:
@@ -303,6 +314,97 @@
           results.AddProfilingFile(self._current_page,
                                    file_handle.FromFilePath(f))
 
+  def GetPregeneratedProfileArchive(self):
+    return self._pregenerated_profile_archive
+
+  def SetPregeneratedProfileArchive(self, archive):
+    """
+    Benchmarks can set a pre-generated profile archive to indicate that when
+    Chrome is launched, it should have a --user-data-dir set to the
+    pregenerated profile, rather than to an empty profile.
+
+    If the benchmark is invoked with the option --profile-dir=<dir>, that
+    option overrides this value.
+    """
+    self._pregenerated_profile_archive = archive
+
+  def _ShouldDownloadPregeneratedProfileArchive(self):
+    """Whether to download a pre-generated profile archive."""
+    # There is no pre-generated profile archive.
+    if not self.GetPregeneratedProfileArchive():
+      return False
+
+    # If profile dir is specified on command line, use that instead.
+    if self._finder_options.browser_options.profile_dir:
+      logging.warning("Profile directory specified on command line: %s, this"
+          "overrides the benchmark's default profile directory.",
+          self._finder_options.browser_options.profile_dir)
+      return False
+
+    # If the browser is remote, a local download has no effect.
+    if self._possible_browser.IsRemote():
+      return False
+
+    return True
+
+  def _DownloadPregeneratedProfileArchive(self):
+    """Download and extract the profile directory archive if one exists.
+
+    On success, updates self._finder_options.browser_options.profile_dir with
+    the directory of the extracted profile.
+    """
+    # Download profile directory from cloud storage.
+    test_data_dir = os.path.join(util.GetChromiumSrcDir(), 'tools', 'perf',
+        'generated_profiles',
+        self._possible_browser.target_os)
+    archive_name = self.GetPregeneratedProfileArchive()
+    generated_profile_archive_path = os.path.normpath(
+        os.path.join(test_data_dir, archive_name))
+
+    try:
+      cloud_storage.GetIfChanged(generated_profile_archive_path,
+          cloud_storage.PUBLIC_BUCKET)
+    except (cloud_storage.CredentialsError,
+            cloud_storage.PermissionError) as e:
+      if os.path.exists(generated_profile_archive_path):
+        # If the profile directory archive exists, assume the user has their
+        # own local copy simply warn.
+        logging.warning('Could not download Profile archive: %s',
+            generated_profile_archive_path)
+      else:
+        # If the archive profile directory doesn't exist, this is fatal.
+        logging.error('Can not run without required profile archive: %s. '
+                      'If you believe you have credentials, follow the '
+                      'instructions below.',
+                      generated_profile_archive_path)
+        logging.error(str(e))
+        sys.exit(-1)
+
+    # Check to make sure the zip file exists.
+    if not os.path.isfile(generated_profile_archive_path):
+      raise Exception("Profile directory archive not downloaded: ",
+          generated_profile_archive_path)
+
+    # The location to extract the profile into.
+    extracted_profile_dir_path = (
+        os.path.splitext(generated_profile_archive_path)[0])
+
+    # Unzip profile directory.
+    with zipfile.ZipFile(generated_profile_archive_path) as f:
+      try:
+        f.extractall(os.path.dirname(generated_profile_archive_path))
+      except e:
+        # Cleanup any leftovers from unzipping.
+        if os.path.exists(extracted_profile_dir_path):
+          shutil.rmtree(extracted_profile_dir_path)
+        logging.error("Error extracting profile directory zip file: %s", e)
+        sys.exit(-1)
+
+    # Run with freshly extracted profile directory.
+    logging.info("Using profile archive directory: %s",
+        extracted_profile_dir_path)
+    self._finder_options.browser_options.profile_dir = (
+        extracted_profile_dir_path)
 
 class SharedMobilePageState(SharedPageState):
   _device_type = 'mobile'
diff --git a/tools/telemetry/telemetry/record_wpr.py b/tools/telemetry/telemetry/record_wpr.py
index 0899a3d..34e8dff 100644
--- a/tools/telemetry/telemetry/record_wpr.py
+++ b/tools/telemetry/telemetry/record_wpr.py
@@ -11,11 +11,11 @@
 from telemetry.core import discover
 from telemetry.core import util
 from telemetry.core import wpr_modes
+from telemetry.internal.results import results_options
 from telemetry.internal import story_runner
 from telemetry.page import page_set
 from telemetry.page import page_test
 from telemetry.page import test_expectations
-from telemetry.results import results_options
 
 
 class RecorderPageTest(page_test.PageTest):
diff --git a/tools/telemetry/telemetry/story/__init__.py b/tools/telemetry/telemetry/story/__init__.py
index 27a57738..f91e643 100644
--- a/tools/telemetry/telemetry/story/__init__.py
+++ b/tools/telemetry/telemetry/story/__init__.py
@@ -2,10 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from catapult_base import cloud_storage
 from telemetry.story.shared_state import SharedState
-from telemetry.story.story_set import StorySet
 from telemetry.story.story_filter import StoryFilter
-from telemetry.util import cloud_storage
+from telemetry.story.story_set import StorySet
 
 
 PUBLIC_BUCKET = cloud_storage.PUBLIC_BUCKET
diff --git a/tools/telemetry/telemetry/telemetry_dependencies_unittest.py b/tools/telemetry/telemetry/telemetry_dependencies_unittest.py
index 45603b9f..302833c 100644
--- a/tools/telemetry/telemetry/telemetry_dependencies_unittest.py
+++ b/tools/telemetry/telemetry/telemetry_dependencies_unittest.py
@@ -6,8 +6,8 @@
 import os
 import unittest
 
+from telemetry.internal.util import find_dependencies
 from telemetry.util import path
-from telemetry.util import find_dependencies
 
 
 _TELEMETRY_DEPS_PATH = os.path.join(
diff --git a/tools/telemetry/telemetry/unittest_util/page_set_smoke_test.py b/tools/telemetry/telemetry/unittest_util/page_set_smoke_test.py
index bc432da..c5d85285 100644
--- a/tools/telemetry/telemetry/unittest_util/page_set_smoke_test.py
+++ b/tools/telemetry/telemetry/unittest_util/page_set_smoke_test.py
@@ -9,7 +9,6 @@
 from telemetry.core import browser_credentials
 from telemetry.core import discover
 from telemetry.page import page_set as page_set_module
-from telemetry.util import classes
 from telemetry.wpr import archive_info
 
 
@@ -131,13 +130,12 @@
     Subclass of PageSetSmokeTest is supposed to call this in some test
     method to run smoke test.
     """
+    # We can't test page sets that aren't directly constructable since we
+    # don't know what arguments to put for the constructor.
     page_sets = discover.DiscoverClasses(page_sets_dir, top_level_dir,
-                                         page_set_module.PageSet).values()
+                                         page_set_module.PageSet,
+                                         directly_constructable=True).values()
     for page_set_class in page_sets:
-      if not classes.IsDirectlyConstructable(page_set_class):
-        # We can't test page sets that aren't directly constructable since we
-        # don't know what arguments to put for the constructor.
-        continue
       page_set = page_set_class()
       logging.info('Testing %s', page_set.file_path)
       self.CheckArchive(page_set)
diff --git a/tools/telemetry/telemetry/unittest_util/page_test_test_case.py b/tools/telemetry/telemetry/unittest_util/page_test_test_case.py
index 5446b512..9634f314 100644
--- a/tools/telemetry/telemetry/unittest_util/page_test_test_case.py
+++ b/tools/telemetry/telemetry/unittest_util/page_test_test_case.py
@@ -9,12 +9,12 @@
 from telemetry import benchmark
 from telemetry.core import exceptions
 from telemetry.core import util
+from telemetry.internal.results import results_options
 from telemetry.internal import story_runner
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
 from telemetry.page import page_test
 from telemetry.page import test_expectations
-from telemetry.results import results_options
 from telemetry.unittest_util import options_for_unittests
 
 
@@ -43,7 +43,7 @@
 
   def CreateEmptyPageSet(self):
     base_dir = util.GetUnittestDataDir()
-    ps = page_set_module.PageSet(file_path=base_dir)
+    ps = page_set_module.PageSet(base_dir=base_dir)
     return ps
 
   def RunMeasurement(self, measurement, ps,
diff --git a/tools/telemetry/telemetry/unittest_util/test_page_test_results.py b/tools/telemetry/telemetry/unittest_util/test_page_test_results.py
index d2fb256..82e72a7 100644
--- a/tools/telemetry/telemetry/unittest_util/test_page_test_results.py
+++ b/tools/telemetry/telemetry/unittest_util/test_page_test_results.py
@@ -2,8 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from telemetry.internal.results import page_test_results
 from telemetry.page import page as page_module
-from telemetry.results import page_test_results
 from telemetry.value import scalar
 
 
diff --git a/tools/telemetry/telemetry/image_processing/histogram.py b/tools/telemetry/telemetry/util/color_histogram.py
similarity index 95%
rename from tools/telemetry/telemetry/image_processing/histogram.py
rename to tools/telemetry/telemetry/util/color_histogram.py
index 0fe1029a..2527f13fd 100644
--- a/tools/telemetry/telemetry/image_processing/histogram.py
+++ b/tools/telemetry/telemetry/util/color_histogram.py
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Provides implementations of functions that operate on histograms."""
+"""Color Histograms and implementations of functions operating on them."""
 
 from __future__ import division
 
diff --git a/tools/telemetry/telemetry/image_processing/histogram_unittest.py b/tools/telemetry/telemetry/util/color_histogram_unittest.py
similarity index 71%
rename from tools/telemetry/telemetry/image_processing/histogram_unittest.py
rename to tools/telemetry/telemetry/util/color_histogram_unittest.py
index 94a4d4b..a853d534 100644
--- a/tools/telemetry/telemetry/image_processing/histogram_unittest.py
+++ b/tools/telemetry/telemetry/util/color_histogram_unittest.py
@@ -4,48 +4,48 @@
 
 import unittest
 
-from telemetry.image_processing import histogram
-from telemetry.image_processing import image_util
-from telemetry.image_processing.rgba_color import RgbaColor
+from telemetry.util import color_histogram
+from telemetry.util import image_util
+from telemetry.util import rgba_color
 
 class HistogramDistanceTest(unittest.TestCase):
   def testNoData(self):
     hist1 = []
     hist2 = []
-    self.assertEqual(histogram.HistogramDistance(hist1, hist2), 0)
+    self.assertEqual(color_histogram.HistogramDistance(hist1, hist2), 0)
 
     hist1 = [0, 0, 0]
     hist2 = [0, 0, 0]
     self.assertRaises(
-        ValueError, lambda: histogram.HistogramDistance(hist1, hist2))
+        ValueError, lambda: color_histogram.HistogramDistance(hist1, hist2))
 
   def testWrongSizes(self):
     hist1 = [1]
     hist2 = [1, 0]
     self.assertRaises(
-        ValueError, lambda: histogram.HistogramDistance(hist1, hist2))
+        ValueError, lambda: color_histogram.HistogramDistance(hist1, hist2))
 
   def testNoDistance(self):
     hist1 = [2, 4, 1, 8, 0, 0]
     hist2 = [2, 4, 1, 8, 0, 0]
-    self.assertEqual(histogram.HistogramDistance(hist1, hist2), 0)
+    self.assertEqual(color_histogram.HistogramDistance(hist1, hist2), 0)
 
   def testNormalizeCounts(self):
     hist1 = [0, 0, 1, 0, 0]
     hist2 = [0, 0, 0, 0, 7]
-    self.assertEqual(histogram.HistogramDistance(hist1, hist2), 2)
-    self.assertEqual(histogram.HistogramDistance(hist2, hist1), 2)
+    self.assertEqual(color_histogram.HistogramDistance(hist1, hist2), 2)
+    self.assertEqual(color_histogram.HistogramDistance(hist2, hist1), 2)
 
   def testDistance(self):
     hist1 = [2, 0, 1, 3, 4]
     hist2 = [3, 1, 2, 4, 0]
-    self.assertEqual(histogram.HistogramDistance(hist1, hist2), 1)
-    self.assertEqual(histogram.HistogramDistance(hist2, hist1), 1)
+    self.assertEqual(color_histogram.HistogramDistance(hist1, hist2), 1)
+    self.assertEqual(color_histogram.HistogramDistance(hist2, hist1), 1)
 
     hist1 = [0, 1, 3, 1]
     hist2 = [2, 2, 1, 0]
-    self.assertEqual(histogram.HistogramDistance(hist1, hist2), 1.2)
-    self.assertEqual(histogram.HistogramDistance(hist2, hist1), 1.2)
+    self.assertEqual(color_histogram.HistogramDistance(hist1, hist2), 1.2)
+    self.assertEqual(color_histogram.HistogramDistance(hist2, hist1), 1.2)
 
 
 class HistogramTest(unittest.TestCase):
@@ -75,8 +75,8 @@
               1, 2, 3, 8, 7, 6, 5, 4, 6, 1, 2, 3]
     bmp = image_util.FromRGBPixels(4, 3, pixels)
 
-    hist = image_util.GetColorHistogram(bmp,
-                                        ignore_color=RgbaColor(1, 2, 3))
+    hist = image_util.GetColorHistogram(
+        bmp, ignore_color=rgba_color.RgbaColor(1, 2, 3))
     self.assertEquals(hist.r[1], 0)
     self.assertEquals(hist.r[5], 2)
     self.assertEquals(hist.r[8], 2)
@@ -92,7 +92,7 @@
     bmp = image_util.FromRGBPixels(2, 2, pixels)
 
     hist = image_util.GetColorHistogram(
-        bmp, ignore_color=RgbaColor(0, 1, 2), tolerance=1)
+        bmp, ignore_color=rgba_color.RgbaColor(0, 1, 2), tolerance=1)
     self.assertEquals(hist.r[1], 0)
     self.assertEquals(hist.r[4], 1)
     self.assertEquals(hist.r[7], 1)
@@ -110,7 +110,8 @@
               1, 2, 3, 1, 2, 3]
     bmp = image_util.FromRGBPixels(2, 2, pixels)
 
-    hist1 = image_util.GetColorHistogram(bmp, ignore_color=RgbaColor(1, 2, 3))
+    hist1 = image_util.GetColorHistogram(
+        bmp, ignore_color=rgba_color.RgbaColor(1, 2, 3))
     hist2 = image_util.GetColorHistogram(bmp)
 
     self.assertEquals(hist1.Distance(hist2), 0)
diff --git a/tools/telemetry/telemetry/image_processing/image_util.py b/tools/telemetry/telemetry/util/image_util.py
similarity index 95%
rename from tools/telemetry/telemetry/image_processing/image_util.py
rename to tools/telemetry/telemetry/util/image_util.py
index c0aaa2f..4e4ea5c0 100644
--- a/tools/telemetry/telemetry/image_processing/image_util.py
+++ b/tools/telemetry/telemetry/util/image_util.py
@@ -18,10 +18,10 @@
 np = external_modules.ImportOptionalModule('numpy')
 
 if np is None:
-  from telemetry.image_processing import image_util_bitmap_impl
+  from telemetry.internal.image_processing import image_util_bitmap_impl
   impl = image_util_bitmap_impl
 else:
-  from telemetry.image_processing import image_util_numpy_impl
+  from telemetry.internal.image_processing import image_util_numpy_impl
   impl = image_util_numpy_impl
 
 
diff --git a/tools/telemetry/telemetry/image_processing/image_util_unittest.py b/tools/telemetry/telemetry/util/image_util_unittest.py
similarity index 95%
rename from tools/telemetry/telemetry/image_processing/image_util_unittest.py
rename to tools/telemetry/telemetry/util/image_util_unittest.py
index 9f4d213..4cb10e6e 100644
--- a/tools/telemetry/telemetry/image_processing/image_util_unittest.py
+++ b/tools/telemetry/telemetry/util/image_util_unittest.py
@@ -7,8 +7,8 @@
 import unittest
 
 from telemetry.core import util
-from telemetry.image_processing import image_util
-from telemetry.image_processing.rgba_color import RgbaColor
+from telemetry.util import image_util
+from telemetry.util import rgba_color
 
 # This is a simple base64 encoded 2x2 PNG which contains, in order, a single
 # Red, Yellow, Blue, and Green pixel.
@@ -106,11 +106,11 @@
               0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
     bmp = image_util.FromRGBPixels(4, 3, pixels)
-    box, count = image_util.GetBoundingBox(bmp, RgbaColor(1, 0, 0))
+    box, count = image_util.GetBoundingBox(bmp, rgba_color.RgbaColor(1, 0, 0))
     self.assertEquals(box, (1, 1, 2, 1))
     self.assertEquals(count, 2)
 
-    box, count = image_util.GetBoundingBox(bmp, RgbaColor(0, 1, 0))
+    box, count = image_util.GetBoundingBox(bmp, rgba_color.RgbaColor(0, 1, 0))
     self.assertEquals(box, None)
     self.assertEquals(count, 0)
 
diff --git a/tools/telemetry/telemetry/util/mac/keychain_helper.py b/tools/telemetry/telemetry/util/mac/keychain_helper.py
index 00f6033..14a3de4 100644
--- a/tools/telemetry/telemetry/util/mac/keychain_helper.py
+++ b/tools/telemetry/telemetry/util/mac/keychain_helper.py
@@ -4,8 +4,8 @@
 
 import subprocess
 
+from catapult_base import support_binaries
 from telemetry.core import platform
-from telemetry.util import support_binaries
 
 def _PathForExecutable(executable_name):
   """Fetches the executable from cloud storage, and returns its path."""
diff --git a/tools/telemetry/telemetry/util/perf_result_data_type.py b/tools/telemetry/telemetry/util/perf_result_data_type.py
new file mode 100644
index 0000000..dbaf7949
--- /dev/null
+++ b/tools/telemetry/telemetry/util/perf_result_data_type.py
@@ -0,0 +1,20 @@
+# 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.
+
+DEFAULT = 'default'
+UNIMPORTANT = 'unimportant'
+HISTOGRAM = 'histogram'
+UNIMPORTANT_HISTOGRAM = 'unimportant-histogram'
+INFORMATIONAL = 'informational'
+
+ALL_TYPES = [DEFAULT, UNIMPORTANT, HISTOGRAM, UNIMPORTANT_HISTOGRAM,
+             INFORMATIONAL]
+
+
+def IsValidType(datatype):
+  return datatype in ALL_TYPES
+
+
+def IsHistogram(datatype):
+  return datatype == HISTOGRAM or datatype == UNIMPORTANT_HISTOGRAM
diff --git a/tools/telemetry/telemetry/perf_tests_helper.py b/tools/telemetry/telemetry/util/perf_tests_helper.py
similarity index 64%
rename from tools/telemetry/telemetry/perf_tests_helper.py
rename to tools/telemetry/telemetry/util/perf_tests_helper.py
index 168bddc0..aaf51be 100644
--- a/tools/telemetry/telemetry/perf_tests_helper.py
+++ b/tools/telemetry/telemetry/util/perf_tests_helper.py
@@ -1,13 +1,7 @@
 # Copyright 2014 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-from __future__ import absolute_import
-
-from telemetry.core import util
-
-util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'util', 'lib',
-                        'common')
-import perf_tests_results_helper  # pylint: disable=F0401
+from telemetry.util import perf_tests_results_helper
 
 
 FlattenList = \
diff --git a/tools/telemetry/telemetry/util/perf_tests_results_helper.py b/tools/telemetry/telemetry/util/perf_tests_results_helper.py
new file mode 100644
index 0000000..548cff48
--- /dev/null
+++ b/tools/telemetry/telemetry/util/perf_tests_results_helper.py
@@ -0,0 +1,165 @@
+# 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.
+
+import re
+import sys
+
+import json
+import math
+
+from telemetry.util import perf_result_data_type
+
+
+# Mapping from result type to test output
+RESULT_TYPES = {perf_result_data_type.UNIMPORTANT: 'RESULT ',
+                perf_result_data_type.DEFAULT: '*RESULT ',
+                perf_result_data_type.INFORMATIONAL: '',
+                perf_result_data_type.UNIMPORTANT_HISTOGRAM: 'HISTOGRAM ',
+                perf_result_data_type.HISTOGRAM: '*HISTOGRAM '}
+
+
+def _EscapePerfResult(s):
+  """Escapes |s| for use in a perf result."""
+  return re.sub('[\:|=/#&,]', '_', s)
+
+
+def FlattenList(values):
+  """Returns a simple list without sub-lists."""
+  ret = []
+  for entry in values:
+    if isinstance(entry, list):
+      ret.extend(FlattenList(entry))
+    else:
+      ret.append(entry)
+  return ret
+
+
+def GeomMeanAndStdDevFromHistogram(histogram_json):
+  histogram = json.loads(histogram_json)
+  # Handle empty histograms gracefully.
+  if not 'buckets' in histogram:
+    return 0.0, 0.0
+  count = 0
+  sum_of_logs = 0
+  for bucket in histogram['buckets']:
+    if 'high' in bucket:
+      bucket['mean'] = (bucket['low'] + bucket['high']) / 2.0
+    else:
+      bucket['mean'] = bucket['low']
+    if bucket['mean'] > 0:
+      sum_of_logs += math.log(bucket['mean']) * bucket['count']
+      count += bucket['count']
+
+  if count == 0:
+    return 0.0, 0.0
+
+  sum_of_squares = 0
+  geom_mean = math.exp(sum_of_logs / count)
+  for bucket in histogram['buckets']:
+    if bucket['mean'] > 0:
+      sum_of_squares += (bucket['mean'] - geom_mean) ** 2 * bucket['count']
+  return geom_mean, math.sqrt(sum_of_squares / count)
+
+
+def _ValueToString(v):
+  # Special case for floats so we don't print using scientific notation.
+  if isinstance(v, float):
+    return '%f' % v
+  else:
+    return str(v)
+
+
+def _MeanAndStdDevFromList(values):
+  avg = None
+  sd = None
+  if len(values) > 1:
+    try:
+      value = '[%s]' % ','.join([_ValueToString(v) for v in values])
+      avg = sum([float(v) for v in values]) / len(values)
+      sqdiffs = [(float(v) - avg) ** 2 for v in values]
+      variance = sum(sqdiffs) / (len(values) - 1)
+      sd = math.sqrt(variance)
+    except ValueError:
+      value = ', '.join(values)
+  else:
+    value = values[0]
+  return value, avg, sd
+
+
+def PrintPages(page_list):
+  """Prints list of pages to stdout in the format required by perf tests."""
+  print 'Pages: [%s]' % ','.join([_EscapePerfResult(p) for p in page_list])
+
+
+def PrintPerfResult(measurement, trace, values, units,
+                    result_type=perf_result_data_type.DEFAULT,
+                    print_to_stdout=True):
+  """Prints numerical data to stdout in the format required by perf tests.
+
+  The string args may be empty but they must not contain any colons (:) or
+  equals signs (=).
+  This is parsed by the buildbot using:
+  http://src.chromium.org/viewvc/chrome/trunk/tools/build/scripts/slave/process_log_utils.py
+
+  Args:
+    measurement: A description of the quantity being measured, e.g. "vm_peak".
+        On the dashboard, this maps to a particular graph. Mandatory.
+    trace: A description of the particular data point, e.g. "reference".
+        On the dashboard, this maps to a particular "line" in the graph.
+        Mandatory.
+    values: A list of numeric measured values. An N-dimensional list will be
+        flattened and treated as a simple list.
+    units: A description of the units of measure, e.g. "bytes".
+    result_type: Accepts values of perf_result_data_type.ALL_TYPES.
+    print_to_stdout: If True, prints the output in stdout instead of returning
+        the output to caller.
+
+    Returns:
+      String of the formated perf result.
+  """
+  assert perf_result_data_type.IsValidType(result_type), \
+         'result type: %s is invalid' % result_type
+
+  trace_name = _EscapePerfResult(trace)
+
+  if (result_type == perf_result_data_type.UNIMPORTANT or
+      result_type == perf_result_data_type.DEFAULT or
+      result_type == perf_result_data_type.INFORMATIONAL):
+    assert isinstance(values, list)
+    assert '/' not in measurement
+    flattened_values = FlattenList(values)
+    assert len(flattened_values)
+    value, avg, sd = _MeanAndStdDevFromList(flattened_values)
+    output = '%s%s: %s%s%s %s' % (
+        RESULT_TYPES[result_type],
+        _EscapePerfResult(measurement),
+        trace_name,
+        # Do not show equal sign if the trace is empty. Usually it happens when
+        # measurement is enough clear to describe the result.
+        '= ' if trace_name else '',
+        value,
+        units)
+  else:
+    assert perf_result_data_type.IsHistogram(result_type)
+    assert isinstance(values, list)
+    # The histograms can only be printed individually, there's no computation
+    # across different histograms.
+    assert len(values) == 1
+    value = values[0]
+    output = '%s%s: %s= %s %s' % (
+        RESULT_TYPES[result_type],
+        _EscapePerfResult(measurement),
+        trace_name,
+        value,
+        units)
+    avg, sd = GeomMeanAndStdDevFromHistogram(value)
+
+  if avg:
+    output += '\nAvg %s: %f%s' % (measurement, avg, units)
+  if sd:
+    output += '\nSd  %s: %f%s' % (measurement, sd, units)
+  if print_to_stdout:
+    print output
+    sys.stdout.flush()
+  return output
diff --git a/tools/telemetry/telemetry/image_processing/rgba_color.py b/tools/telemetry/telemetry/util/rgba_color.py
similarity index 100%
rename from tools/telemetry/telemetry/image_processing/rgba_color.py
rename to tools/telemetry/telemetry/util/rgba_color.py
diff --git a/tools/telemetry/telemetry/value/failure.py b/tools/telemetry/telemetry/value/failure.py
index 027672d..4551a7c 100644
--- a/tools/telemetry/telemetry/value/failure.py
+++ b/tools/telemetry/telemetry/value/failure.py
@@ -43,9 +43,9 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.name
+      page_name = self.page.display_name
     else:
-      page_name = None
+      page_name = 'None'
     return 'FailureValue(%s, %s)' % (
         page_name, GetStringFromExcInfo(self._exc_info))
 
diff --git a/tools/telemetry/telemetry/value/failure_unittest.py b/tools/telemetry/telemetry/value/failure_unittest.py
index df7d8f5..6eca4ec 100644
--- a/tools/telemetry/telemetry/value/failure_unittest.py
+++ b/tools/telemetry/telemetry/value/failure_unittest.py
@@ -15,7 +15,7 @@
 
 class TestBase(unittest.TestCase):
   def setUp(self):
-    self.page_set = page_set.PageSet(file_path=os.path.dirname(__file__))
+    self.page_set = page_set.PageSet(base_dir=os.path.dirname(__file__))
     self.page_set.AddUserStory(page_module.Page(
         'http://www.bar.com/', self.page_set, self.page_set.base_dir))
 
diff --git a/tools/telemetry/telemetry/value/histogram.py b/tools/telemetry/telemetry/value/histogram.py
index 64766c8..2e024c0 100644
--- a/tools/telemetry/telemetry/value/histogram.py
+++ b/tools/telemetry/telemetry/value/histogram.py
@@ -3,10 +3,11 @@
 # found in the LICENSE file.
 import json
 
-from telemetry import perf_tests_helper
+from telemetry.util import perf_tests_helper
 from telemetry import value as value_module
 from telemetry.value import histogram_util
 
+
 class HistogramValueBucket(object):
   def __init__(self, low, high, count=0):
     self.low = low
@@ -48,9 +49,9 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.name
+      page_name = self.page.display_name
     else:
-      page_name = None
+      page_name = 'None'
     return ('HistogramValue(%s, %s, %s, raw_json_string="%s", '
             'important=%s, description=%s, tir_label=%s') % (
                 page_name,
diff --git a/tools/telemetry/telemetry/value/histogram_unittest.py b/tools/telemetry/telemetry/value/histogram_unittest.py
index cc73bdf2..1113cf9 100644
--- a/tools/telemetry/telemetry/value/histogram_unittest.py
+++ b/tools/telemetry/telemetry/value/histogram_unittest.py
@@ -12,7 +12,7 @@
 
 class TestBase(unittest.TestCase):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page("http://www.bar.com/", ps, ps.base_dir))
     ps.AddUserStory(page_module.Page("http://www.baz.com/", ps, ps.base_dir))
     ps.AddUserStory(page_module.Page("http://www.foo.com/", ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/value/list_of_scalar_values.py b/tools/telemetry/telemetry/value/list_of_scalar_values.py
index e061c0ff..fd5ca6d 100644
--- a/tools/telemetry/telemetry/value/list_of_scalar_values.py
+++ b/tools/telemetry/telemetry/value/list_of_scalar_values.py
@@ -30,9 +30,9 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.name
+      page_name = self.page.display_name
     else:
-      page_name = None
+      page_name = 'None'
     if self.same_page_merge_policy == value_module.CONCATENATE:
       merge_policy = 'CONCATENATE'
     else:
diff --git a/tools/telemetry/telemetry/value/list_of_scalar_values_unittest.py b/tools/telemetry/telemetry/value/list_of_scalar_values_unittest.py
index 336c8c7..d8b3702 100644
--- a/tools/telemetry/telemetry/value/list_of_scalar_values_unittest.py
+++ b/tools/telemetry/telemetry/value/list_of_scalar_values_unittest.py
@@ -13,7 +13,7 @@
 
 class TestBase(unittest.TestCase):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.baz.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/value/list_of_string_values.py b/tools/telemetry/telemetry/value/list_of_string_values.py
index 929e449c..c3d679c 100644
--- a/tools/telemetry/telemetry/value/list_of_string_values.py
+++ b/tools/telemetry/telemetry/value/list_of_string_values.py
@@ -24,9 +24,9 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.name
+      page_name = self.page.display_name
     else:
-      page_name = None
+      page_name = 'None'
     if self.same_page_merge_policy == value_module.CONCATENATE:
       merge_policy = 'CONCATENATE'
     else:
diff --git a/tools/telemetry/telemetry/value/list_of_string_values_unittest.py b/tools/telemetry/telemetry/value/list_of_string_values_unittest.py
index f60a1c3..1d5c7e1 100644
--- a/tools/telemetry/telemetry/value/list_of_string_values_unittest.py
+++ b/tools/telemetry/telemetry/value/list_of_string_values_unittest.py
@@ -13,7 +13,7 @@
 
 class TestBase(unittest.TestCase):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.baz.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/value/merge_values_unittest.py b/tools/telemetry/telemetry/value/merge_values_unittest.py
index 20f2754..ba5a096a 100644
--- a/tools/telemetry/telemetry/value/merge_values_unittest.py
+++ b/tools/telemetry/telemetry/value/merge_values_unittest.py
@@ -13,7 +13,7 @@
 
 class TestBase(unittest.TestCase):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.baz.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/value/scalar.py b/tools/telemetry/telemetry/value/scalar.py
index 8cabfa8..d1411af 100644
--- a/tools/telemetry/telemetry/value/scalar.py
+++ b/tools/telemetry/telemetry/value/scalar.py
@@ -28,9 +28,9 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.name
+      page_name = self.page.display_name
     else:
-      page_name = None
+      page_name = 'None'
     return ('ScalarValue(%s, %s, %s, %s, important=%s, description=%s, '
             'tir_label=%s') % (
                 page_name,
diff --git a/tools/telemetry/telemetry/value/scalar_unittest.py b/tools/telemetry/telemetry/value/scalar_unittest.py
index 16f2df1..b9a0eae3 100644
--- a/tools/telemetry/telemetry/value/scalar_unittest.py
+++ b/tools/telemetry/telemetry/value/scalar_unittest.py
@@ -13,7 +13,7 @@
 
 class TestBase(unittest.TestCase):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.baz.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/value/skip.py b/tools/telemetry/telemetry/value/skip.py
index 4f418e9..036ab595 100644
--- a/tools/telemetry/telemetry/value/skip.py
+++ b/tools/telemetry/telemetry/value/skip.py
@@ -18,7 +18,7 @@
     self._reason = reason
 
   def __repr__(self):
-    page_name = self.page.name
+    page_name = self.page.display_name
     return 'SkipValue(%s, %s)' % (page_name, self._reason)
 
   @property
diff --git a/tools/telemetry/telemetry/value/skip_unittest.py b/tools/telemetry/telemetry/value/skip_unittest.py
index e0a1bac..6e325f6b 100644
--- a/tools/telemetry/telemetry/value/skip_unittest.py
+++ b/tools/telemetry/telemetry/value/skip_unittest.py
@@ -13,7 +13,7 @@
 
 class TestBase(unittest.TestCase):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
     self.page_set = ps
 
diff --git a/tools/telemetry/telemetry/value/string.py b/tools/telemetry/telemetry/value/string.py
index 8568dd40..2fff02d 100644
--- a/tools/telemetry/telemetry/value/string.py
+++ b/tools/telemetry/telemetry/value/string.py
@@ -26,9 +26,9 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.name
+      page_name = self.page.display_name
     else:
-      page_name = None
+      page_name = 'None'
     return ('StringValue(%s, %s, %s, %s, important=%s, description=%s, '
             'tir_label=%s)') % (
                 page_name,
diff --git a/tools/telemetry/telemetry/value/string_unittest.py b/tools/telemetry/telemetry/value/string_unittest.py
index d5085eb..be084dc 100644
--- a/tools/telemetry/telemetry/value/string_unittest.py
+++ b/tools/telemetry/telemetry/value/string_unittest.py
@@ -13,7 +13,7 @@
 
 class TestBase(unittest.TestCase):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page("http://www.bar.com/", ps, ps.base_dir))
     ps.AddUserStory(page_module.Page("http://www.baz.com/", ps, ps.base_dir))
     ps.AddUserStory(page_module.Page("http://www.foo.com/", ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/value/summary_unittest.py b/tools/telemetry/telemetry/value/summary_unittest.py
index 8905185..6b43f228 100644
--- a/tools/telemetry/telemetry/value/summary_unittest.py
+++ b/tools/telemetry/telemetry/value/summary_unittest.py
@@ -5,18 +5,19 @@
 import os
 import unittest
 
+from telemetry.internal.results import page_test_results
 from telemetry import page as page_module
 from telemetry.page import page_set
-from telemetry.results import page_test_results
 from telemetry.value import failure
 from telemetry.value import histogram
 from telemetry.value import list_of_scalar_values
 from telemetry.value import scalar
 from telemetry.value import summary as summary_module
 
+
 class TestBase(unittest.TestCase):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.baz.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/value/trace.py b/tools/telemetry/telemetry/value/trace.py
index c522f9c6..f553c29f1 100644
--- a/tools/telemetry/telemetry/value/trace.py
+++ b/tools/telemetry/telemetry/value/trace.py
@@ -11,9 +11,9 @@
 import sys
 import tempfile
 
-from telemetry.timeline import trace_data as trace_data_module
+from catapult_base import cloud_storage
 from telemetry.core import util
-from telemetry.util import cloud_storage
+from telemetry.timeline import trace_data as trace_data_module
 from telemetry.util import file_handle
 from telemetry import value as value_module
 
@@ -56,9 +56,9 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.name
+      page_name = self.page.display_name
     else:
-      page_name = None
+      page_name = 'None'
     return 'TraceValue(%s, %s)' % (page_name, self.name)
 
   def CleanUp(self):
diff --git a/tools/telemetry/telemetry/value/trace_unittest.py b/tools/telemetry/telemetry/value/trace_unittest.py
index 7d747d6..1859da1 100644
--- a/tools/telemetry/telemetry/value/trace_unittest.py
+++ b/tools/telemetry/telemetry/value/trace_unittest.py
@@ -17,7 +17,7 @@
 class TestBase(unittest.TestCase):
 
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.baz.com/', ps, ps.base_dir))
     ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/value/value_unittest.py b/tools/telemetry/telemetry/value/value_unittest.py
index 9504f08..1028699 100644
--- a/tools/telemetry/telemetry/value/value_unittest.py
+++ b/tools/telemetry/telemetry/value/value_unittest.py
@@ -11,7 +11,7 @@
 
 class TestBase(unittest.TestCase):
   def setUp(self):
-    ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     ps.AddUserStory(page_module.Page("http://www.bar.com/", ps, ps.base_dir))
     ps.AddUserStory(page_module.Page("http://www.baz.com/", ps, ps.base_dir))
     ps.AddUserStory(page_module.Page("http://www.foo.com/", ps, ps.base_dir))
diff --git a/tools/telemetry/telemetry/web_perf/metrics/blob_timeline_unittest.py b/tools/telemetry/telemetry/web_perf/metrics/blob_timeline_unittest.py
index 00a626e..21e561b 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/blob_timeline_unittest.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/blob_timeline_unittest.py
@@ -5,8 +5,8 @@
 import unittest
 
 from collections import namedtuple
+from telemetry.internal.results import page_test_results
 from telemetry.page import page
-from telemetry.results import page_test_results
 from telemetry.web_perf.metrics import blob_timeline
 from telemetry.web_perf import timeline_interaction_record
 
diff --git a/tools/telemetry/telemetry/web_perf/metrics/layout_unittest.py b/tools/telemetry/telemetry/web_perf/metrics/layout_unittest.py
index d2227ef..ca4c5eee 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/layout_unittest.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/layout_unittest.py
@@ -5,8 +5,8 @@
 import unittest
 
 from collections import namedtuple
+from telemetry.internal.results import page_test_results
 from telemetry.page import page
-from telemetry.results import page_test_results
 from telemetry.web_perf.metrics import layout
 from telemetry.web_perf import timeline_interaction_record
 
diff --git a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py
index 757d2d5..4e708a91 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats_unittest.py
@@ -5,10 +5,10 @@
 import random
 import unittest
 
-from telemetry import perf_tests_helper
 from telemetry.timeline import async_slice
 from telemetry.timeline import bounds
 from telemetry.timeline import model
+from telemetry.util import perf_tests_helper
 from telemetry.util import statistics
 from telemetry.web_perf.metrics import rendering_stats
 
diff --git a/tools/telemetry/telemetry/web_perf/metrics/smoothness.py b/tools/telemetry/telemetry/web_perf/metrics/smoothness.py
index 42445ab..2bc7e55 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/smoothness.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/smoothness.py
@@ -3,7 +3,8 @@
 # found in the LICENSE file.
 
 import logging
-from telemetry.perf_tests_helper import FlattenList
+
+from telemetry.util import perf_tests_helper
 from telemetry.util import statistics
 from telemetry.value import list_of_scalar_values
 from telemetry.value import scalar
@@ -164,7 +165,7 @@
     latency_discrepancy = None
     none_value_reason = None
     if self._HasEnoughFrames(stats.frame_timestamps):
-      latency_list = FlattenList(list_of_latency_lists)
+      latency_list = perf_tests_helper.FlattenList(list_of_latency_lists)
       if len(latency_list) == 0:
         return ()
       mean_latency = round(statistics.ArithmeticMean(latency_list), 3)
@@ -188,7 +189,8 @@
     first_gesture_scroll_update_latency = None
     none_value_reason = None
     if self._HasEnoughFrames(stats.frame_timestamps):
-      latency_list = FlattenList(stats.gesture_scroll_update_latency)
+      latency_list = perf_tests_helper.FlattenList(
+          stats.gesture_scroll_update_latency)
       if len(latency_list) == 0:
         return ()
       first_gesture_scroll_update_latency = round(latency_list[0], 4)
@@ -212,7 +214,8 @@
     if 'frame_queueing_durations' in stats.errors:
       none_value_reason = stats.errors['frame_queueing_durations']
     elif self._HasEnoughFrames(stats.frame_timestamps):
-      queueing_durations = FlattenList(stats.frame_queueing_durations)
+      queueing_durations = perf_tests_helper.FlattenList(
+          stats.frame_queueing_durations)
       if len(queueing_durations) == 0:
         queueing_durations = None
         none_value_reason = 'No frame queueing durations recorded.'
@@ -239,7 +242,7 @@
     percentage_smooth = None
     none_value_reason = None
     if self._HasEnoughFrames(stats.frame_timestamps):
-      frame_times = FlattenList(stats.frame_times)
+      frame_times = perf_tests_helper.FlattenList(stats.frame_times)
       mean_frame_time = round(statistics.ArithmeticMean(frame_times), 3)
       # We use 17ms as a somewhat looser threshold, instead of 1000.0/60.0.
       smooth_threshold = 17.0
@@ -294,7 +297,8 @@
     none_value_reason = None
     if self._HasEnoughFrames(stats.frame_timestamps):
       mean_pixels_approximated = round(statistics.ArithmeticMean(
-          FlattenList(stats.approximated_pixel_percentages)), 3)
+          perf_tests_helper.FlattenList(
+              stats.approximated_pixel_percentages)), 3)
     else:
       none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE
     return scalar.ScalarValue(
@@ -318,7 +322,8 @@
             rendering_stats.CHECKERBOARDED_PIXEL_ERROR]
       else:
         mean_pixels_checkerboarded = round(statistics.ArithmeticMean(
-            FlattenList(stats.checkerboarded_pixel_percentages)), 3)
+            perf_tests_helper.FlattenList(
+                stats.checkerboarded_pixel_percentages)), 3)
     else:
       none_value_reason = NOT_ENOUGH_FRAMES_MESSAGE
     return scalar.ScalarValue(
diff --git a/tools/telemetry/telemetry/web_perf/metrics/smoothness_unittest.py b/tools/telemetry/telemetry/web_perf/metrics/smoothness_unittest.py
index 11b817f7..192c623a 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/smoothness_unittest.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/smoothness_unittest.py
@@ -4,8 +4,8 @@
 
 import unittest
 
+from telemetry.internal.results import page_test_results
 from telemetry.page import page as page_module
-from telemetry.results import page_test_results
 from telemetry.web_perf.metrics import rendering_stats
 from telemetry.web_perf.metrics import smoothness
 
diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py b/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py
index 21dc698..9c662246 100644
--- a/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py
+++ b/tools/telemetry/telemetry/web_perf/timeline_based_measurement_unittest.py
@@ -5,9 +5,9 @@
 import os
 import unittest
 
+from telemetry.internal.results import page_test_results
 from telemetry.page import page as page_module
 from telemetry.page import page_set
-from telemetry.results import page_test_results
 from telemetry.timeline import async_slice
 from telemetry.timeline import model as model_module
 from telemetry.value import scalar
@@ -80,7 +80,7 @@
     self._model.FinalizeImport()
     self._threads_to_records_map = (
       tbm_module._GetRendererThreadsToInteractionRecordsMap(self._model))
-    self._ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+    self._ps = page_set.PageSet(base_dir=os.path.dirname(__file__))
     self._ps.AddUserStory(page_module.Page(
         'http://www.bar.com/', self._ps, self._ps.base_dir))
     self._results.WillRunPage(self._ps.pages[0])
diff --git a/tools/telemetry/telemetry/wpr/archive_info.py b/tools/telemetry/telemetry/wpr/archive_info.py
index 9abce276..db3e2e3b 100644
--- a/tools/telemetry/telemetry/wpr/archive_info.py
+++ b/tools/telemetry/telemetry/wpr/archive_info.py
@@ -9,7 +9,7 @@
 import shutil
 import tempfile
 
-from telemetry.util import cloud_storage
+from catapult_base import cloud_storage
 
 
 def AssertValidCloudStorageBucket(bucket):
diff --git a/tools/telemetry/telemetry/wpr/archive_info_unittest.py b/tools/telemetry/telemetry/wpr/archive_info_unittest.py
index 97f8768..6e4f718 100644
--- a/tools/telemetry/telemetry/wpr/archive_info_unittest.py
+++ b/tools/telemetry/telemetry/wpr/archive_info_unittest.py
@@ -7,9 +7,9 @@
 import tempfile
 import unittest
 
+from catapult_base import cloud_storage
 from telemetry.page import page
 from telemetry.unittest_util import system_stub
-from telemetry.util import cloud_storage
 from telemetry.wpr import archive_info
 
 
diff --git a/tools/telemetry/unittest_data/discoverable_classes/another_discover_dummyclass.py b/tools/telemetry/unittest_data/discoverable_classes/another_discover_dummyclass.py
index b7413ca..be8a75c 100644
--- a/tools/telemetry/unittest_data/discoverable_classes/another_discover_dummyclass.py
+++ b/tools/telemetry/unittest_data/discoverable_classes/another_discover_dummyclass.py
@@ -9,16 +9,25 @@
 # Suppress complaints about unable to import class.  The directory path is
 # added at runtime by telemetry test runner.
 #pylint: disable=F0401
-from discoverable_classes.discover_dummyclass import DummyException
+from unittest_data.discoverable_classes import discover_dummyclass
 
 
-class _PrivateDummyException(DummyException):
-  pass
+class _PrivateDummyException(discover_dummyclass.DummyException):
+  def __init__(self):
+    super(_PrivateDummyException, self).__init__()
 
 
 class DummyExceptionImpl1(_PrivateDummyException):
-  pass
+  def __init__(self):
+    super(DummyExceptionImpl1, self).__init__()
 
 
 class DummyExceptionImpl2(_PrivateDummyException):
-  pass
+  def __init__(self):
+    super(DummyExceptionImpl2, self).__init__()
+
+
+class DummyExceptionWithParameterImpl1(_PrivateDummyException):
+  def __init__(self, parameter):
+    super(DummyExceptionWithParameterImpl1, self).__init__()
+    del parameter
diff --git a/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py b/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py
index e41eccc4..15dcb35 100644
--- a/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py
+++ b/tools/telemetry/unittest_data/discoverable_classes/discover_dummyclass.py
@@ -5,4 +5,5 @@
 """A dummy exception subclass used by core/discover.py's unit tests."""
 
 class DummyException(Exception):
-  pass
+  def __init__(self):
+    super(DummyException, self).__init__()
diff --git a/tools/telemetry/unittest_data/discoverable_classes/parameter_discover_dummyclass.py b/tools/telemetry/unittest_data/discoverable_classes/parameter_discover_dummyclass.py
new file mode 100644
index 0000000..f299f82
--- /dev/null
+++ b/tools/telemetry/unittest_data/discoverable_classes/parameter_discover_dummyclass.py
@@ -0,0 +1,11 @@
+# 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.
+
+"""A dummy exception subclass used by core/discover.py's unit tests."""
+from unittest_data.discoverable_classes import discover_dummyclass
+
+class DummyExceptionWithParameterImpl2(discover_dummyclass.DummyException):
+  def __init__(self, parameter1, parameter2):
+    super(DummyExceptionWithParameterImpl2, self).__init__()
+    del parameter1, parameter2
diff --git a/tools/crx_id/jebgalgnebhfojomionfpkfelancnnkf.crx b/tools/telemetry/unittest_data/jebgalgnebhfojomionfpkfelancnnkf.crx
similarity index 100%
rename from tools/crx_id/jebgalgnebhfojomionfpkfelancnnkf.crx
rename to tools/telemetry/unittest_data/jebgalgnebhfojomionfpkfelancnnkf.crx
Binary files differ
diff --git a/tools/telemetry/unittest_data/manifest_with_key.json b/tools/telemetry/unittest_data/manifest_with_key.json
new file mode 100644
index 0000000..4b41dd4
--- /dev/null
+++ b/tools/telemetry/unittest_data/manifest_with_key.json
@@ -0,0 +1,7 @@
+{
+  "name": "unpacked extension",
+  "description": "this is an unpacked extension with a key in it",
+  "version": "1",
+  "manifest_version": 2,
+  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCoq+cJMuoIaoL2hx//QoIeHnNkXLAEu3IJGcLpM95qbmw9VnAplFI0tpSv4IpuJ1DPPsdsEMhONu1mPhK9xd3BHCtzqXRfRsnx/uOap4NTcUimxiUH3uuX9xkCNWO8EihdV0atnrKROhhnyIxmhgKmKfAYLheOrSGSXP0A4SqaBQIDAQAB"
+}
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index 28e73ca5..aa734ce7 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -772,3 +772,27 @@
 ntdll.dll!RtlDosPathNameToNtPathName_U_WithStatus
 ntdll.dll!RtlDosPathNameToNtPathName_U_WithStatus
 ntdll.dll!RtlIntegerToUnicodeString
+
+UNINITIALIZED READ
+name=http://crbug.com/498519_a
+blink_web.dll!blink::Element::styleForLayoutObject
+blink_web.dll!blink::LayoutTreeBuilderForElement::style
+blink_web.dll!blink::LayoutTreeBuilderForElement::shouldCreateLayoutObject
+
+UNINITIALIZED READ
+name=http://crbug.com/498519_b
+blink_web.dll!blink::Element::styleForLayoutObject
+blink_web.dll!blink::Element::recalcOwnStyle
+blink_web.dll!blink::Element::recalcStyle
+
+UNINITIALIZED READ
+name=http://crbug.com/498519_c
+webcore_shared.dll!blink::Element::styleForLayoutObject
+webcore_shared.dll!blink::Element::recalcOwnStyle
+webcore_shared.dll!blink::Element::recalcStyle
+
+UNINITIALIZED READ
+name=http://crbug.com/498519_d
+webcore_shared.dll!blink::Element::styleForLayoutObject
+webcore_shared.dll!blink::LayoutTreeBuilderForElement::style
+webcore_shared.dll!blink::LayoutTreeBuilderForElement::shouldCreateLayoutObject
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index f9634acc..d42189b7 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -3366,7 +3366,6 @@
    fun:av_packet_unpack_dictionary
    fun:add_metadata_from_side_data
    fun:avcodec_decode_*
-   fun:avcodec_decode_*
 }
 {
    bug_448700_a
diff --git a/ui/accelerated_widget_mac/BUILD.gn b/ui/accelerated_widget_mac/BUILD.gn
index 0c066dd..2ca4299 100644
--- a/ui/accelerated_widget_mac/BUILD.gn
+++ b/ui/accelerated_widget_mac/BUILD.gn
@@ -8,6 +8,8 @@
     "accelerated_widget_mac.h",
     "accelerated_widget_mac.mm",
     "accelerated_widget_mac_export.h",
+    "display_link_mac.cc",
+    "display_link_mac.h",
     "io_surface_context.h",
     "io_surface_context.mm",
     "io_surface_layer.h",
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.gyp b/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
index d46b2e629..2e13b11 100644
--- a/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
+++ b/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
@@ -15,12 +15,14 @@
         'accelerated_widget_mac.h',
         'accelerated_widget_mac.mm',
         'accelerated_widget_mac_export.h',
+        'display_link_mac.cc',
+        'display_link_mac.h',
         'io_surface_context.h',
         'io_surface_context.mm',
         'io_surface_layer.h',
         'io_surface_layer.mm',
-        "io_surface_ns_gl_surface.h",
-        "io_surface_ns_gl_surface.mm",
+        'io_surface_ns_gl_surface.h',
+        'io_surface_ns_gl_surface.mm',
         'io_surface_texture.h',
         'io_surface_texture.mm',
         'software_layer.h',
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.h b/ui/accelerated_widget_mac/accelerated_widget_mac.h
index d4646bf5..db01c50 100644
--- a/ui/accelerated_widget_mac/accelerated_widget_mac.h
+++ b/ui/accelerated_widget_mac/accelerated_widget_mac.h
@@ -18,6 +18,7 @@
 #import <Cocoa/Cocoa.h>
 #import "base/mac/scoped_nsobject.h"
 #import "ui/accelerated_widget_mac/io_surface_layer.h"
+#import "ui/accelerated_widget_mac/io_surface_ns_gl_surface.h"
 #import "ui/accelerated_widget_mac/software_layer.h"
 #include "ui/base/cocoa/remote_layer_api.h"
 #endif  // __OBJC__
@@ -52,7 +53,7 @@
 // GotAcceleratedFrame and GotSoftwareFrame. The CALayers may be installed
 // in an NSView by setting the AcceleratedWidgetMacNSView for the helper.
 class ACCELERATED_WIDGET_MAC_EXPORT AcceleratedWidgetMac
-    : public IOSurfaceLayerClient {
+    : public IOSurfaceLayerClient, public IOSurfaceNSGLSurfaceClient {
  public:
   explicit AcceleratedWidgetMac(bool needs_gl_finish_workaround);
   virtual ~AcceleratedWidgetMac();
@@ -92,6 +93,9 @@
   void IOSurfaceLayerDidDrawFrame() override;
   void IOSurfaceLayerHitError() override;
 
+  // IOSurfaceNSGLSurfaceClient implementation:
+  void IOSurfaceNSGLSurfaceDidDrawFrame() override;
+
   void GotAcceleratedCAContextFrame(CAContextID ca_context_id,
                                     const gfx::Size& pixel_size,
                                     float scale_factor);
@@ -114,6 +118,7 @@
       base::scoped_nsobject<CALayerHost> ca_context_layer);
   void DestroyIOSurfaceLayer(
       base::scoped_nsobject<IOSurfaceLayer> io_surface_layer);
+  void DestroyIOSurfaceNSGLSurface();
   void DestroySoftwareLayer();
 
   // The AcceleratedWidgetMacNSView that is using this as its internals.
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.mm b/ui/accelerated_widget_mac/accelerated_widget_mac.mm
index 19beee03..06b272d 100644
--- a/ui/accelerated_widget_mac/accelerated_widget_mac.mm
+++ b/ui/accelerated_widget_mac/accelerated_widget_mac.mm
@@ -6,7 +6,6 @@
 
 #include <map>
 
-#include "base/command_line.h"
 #include "base/lazy_instance.h"
 #include "base/message_loop/message_loop.h"
 #include "base/trace_event/trace_event.h"
@@ -15,7 +14,6 @@
 #include "ui/accelerated_widget_mac/io_surface_ns_gl_surface.h"
 #include "ui/accelerated_widget_mac/surface_handle_types.h"
 #include "ui/base/cocoa/animation_utils.h"
-#include "ui/base/ui_base_switches.h"
 #include "ui/gfx/geometry/dip_util.h"
 #include "ui/gl/scoped_cgl.h"
 
@@ -96,8 +94,8 @@
   [flipped_layer_ removeFromSuperlayer];
   DestroyIOSurfaceLayer(io_surface_layer_);
   DestroyCAContextLayer(ca_context_layer_);
+  DestroyIOSurfaceNSGLSurface();
   DestroySoftwareLayer();
-  io_surface_ns_gl_surface_.reset();
 
   last_swap_size_dip_ = gfx::Size();
   view_ = NULL;
@@ -111,6 +109,8 @@
 int AcceleratedWidgetMac::GetRendererID() const {
   if (io_surface_layer_)
     return [io_surface_layer_ rendererID];
+  if (io_surface_ns_gl_surface_)
+    return io_surface_ns_gl_surface_->GetRendererID();
   return 0;
 }
 
@@ -135,10 +135,6 @@
     float scale_factor,
     const gfx::Rect& pixel_damage_rect,
     const base::Closure& drawn_callback) {
-  static bool use_ns_gl_surfaces =
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableNSGLSurfaces);
-
   // Record the surface and latency info to use when acknowledging this frame.
   DCHECK(accelerated_frame_drawn_callback_.is_null());
   accelerated_frame_drawn_callback_ = drawn_callback;
@@ -158,7 +154,8 @@
   switch (GetSurfaceHandleType(surface_handle)) {
     case kSurfaceHandleTypeIOSurface: {
       IOSurfaceID io_surface_id = IOSurfaceIDFromSurfaceHandle(surface_handle);
-      if (use_ns_gl_surfaces) {
+      if (IOSurfaceNSGLSurface::CanUseNSGLSurfaceForView(
+              view_->AcceleratedWidgetGetNSView())) {
         GotAcceleratedIOSurfaceFrameNSGL(
             io_surface_id, pixel_size, scale_factor, pixel_damage_rect);
       } else {
@@ -207,6 +204,7 @@
 
   // Remove any different-type layers that this is replacing.
   DestroyIOSurfaceLayer(io_surface_layer_);
+  DestroyIOSurfaceNSGLSurface();
   DestroySoftwareLayer();
 }
 
@@ -215,9 +213,13 @@
     const gfx::Size& pixel_size,
     float scale_factor,
     const gfx::Rect& pixel_damage_rect) {
-  if (!io_surface_ns_gl_surface_) {
+  if (!io_surface_ns_gl_surface_ ||
+      io_surface_ns_gl_surface_->NeedsToBeRecreated()) {
     io_surface_ns_gl_surface_.reset(
-        IOSurfaceNSGLSurface::Create(view_->AcceleratedWidgetGetNSView()));
+        IOSurfaceNSGLSurface::Create(
+            this,
+            view_->AcceleratedWidgetGetNSView(),
+            needs_gl_finish_workaround_));
   }
 
   if (!io_surface_ns_gl_surface_) {
@@ -228,7 +230,11 @@
 
   io_surface_ns_gl_surface_->GotFrame(
       io_surface_id, pixel_size, scale_factor, pixel_damage_rect);
-  AcknowledgeAcceleratedFrame();
+
+  // Remove any different-type layers that this is replacing.
+  DestroyCAContextLayer(ca_context_layer_);
+  DestroyIOSurfaceLayer(io_surface_layer_);
+  DestroySoftwareLayer();
 }
 
 void AcceleratedWidgetMac::GotAcceleratedIOSurfaceFrame(
@@ -299,6 +305,7 @@
 
   // Remove any different-type layers that this is replacing.
   DestroyCAContextLayer(ca_context_layer_);
+  DestroyIOSurfaceNSGLSurface();
   DestroySoftwareLayer();
 }
 
@@ -330,6 +337,7 @@
   // Remove any different-type layers that this is replacing.
   DestroyCAContextLayer(ca_context_layer_);
   DestroyIOSurfaceLayer(io_surface_layer_);
+  DestroyIOSurfaceNSGLSurface();
 }
 
 void AcceleratedWidgetMac::DestroyCAContextLayer(
@@ -351,6 +359,10 @@
     io_surface_layer_.reset();
 }
 
+void AcceleratedWidgetMac::DestroyIOSurfaceNSGLSurface() {
+  io_surface_ns_gl_surface_.reset();
+}
+
 void AcceleratedWidgetMac::DestroySoftwareLayer() {
   if (!software_layer_)
     return;
@@ -370,6 +382,10 @@
   AcknowledgeAcceleratedFrame();
 }
 
+void AcceleratedWidgetMac::IOSurfaceNSGLSurfaceDidDrawFrame() {
+  AcknowledgeAcceleratedFrame();
+}
+
 void AcceleratedWidgetMac::AcknowledgeAcceleratedFrame() {
   if (accelerated_frame_drawn_callback_.is_null())
     return;
diff --git a/content/browser/renderer_host/display_link_mac.cc b/ui/accelerated_widget_mac/display_link_mac.cc
similarity index 92%
rename from content/browser/renderer_host/display_link_mac.cc
rename to ui/accelerated_widget_mac/display_link_mac.cc
index 79920f6..c9a30699 100644
--- a/content/browser/renderer_host/display_link_mac.cc
+++ b/ui/accelerated_widget_mac/display_link_mac.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/renderer_host/display_link_mac.h"
+#include "ui/accelerated_widget_mac/display_link_mac.h"
 
 #include "base/logging.h"
+#include "base/message_loop/message_loop.h"
 #include "base/trace_event/trace_event.h"
-#include "content/browser/renderer_host/render_widget_resize_helper.h"
 
 namespace base {
 
@@ -22,7 +22,7 @@
 
 }  // namespace base
 
-namespace content {
+namespace ui {
 
 // static
 scoped_refptr<DisplayLinkMac> DisplayLinkMac::GetForDisplay(
@@ -46,7 +46,6 @@
 
   scoped_refptr<DisplayLinkMac> display_link_mac;
   display_link_mac = new DisplayLinkMac(display_id, display_link);
-
   ret = CVDisplayLinkSetOutputCallback(
       display_link_mac->display_link_,
       &DisplayLinkCallback,
@@ -62,7 +61,9 @@
 DisplayLinkMac::DisplayLinkMac(
     CGDirectDisplayID display_id,
     base::ScopedTypeRef<CVDisplayLinkRef> display_link)
-      : display_id_(display_id),
+      : main_thread_task_runner_(
+            base::MessageLoop::current()->task_runner()),
+        display_id_(display_id),
         display_link_(display_link),
         timebase_and_interval_valid_(false) {
   DCHECK(display_map_.Get().find(display_id) == display_map_.Get().end());
@@ -105,7 +106,7 @@
 }
 
 void DisplayLinkMac::Tick(const CVTimeStamp& cv_time) {
-  TRACE_EVENT0("browser", "DisplayLinkMac::Tick");
+  TRACE_EVENT0("ui", "DisplayLinkMac::Tick");
 
   // Verify that videoRefreshPeriod is 32 bits.
   DCHECK((cv_time.videoRefreshPeriod & ~0xffffFFFFull) == 0ull);
@@ -155,9 +156,9 @@
     CVOptionFlags flags_in,
     CVOptionFlags* flags_out,
     void* context) {
-  TRACE_EVENT0("browser", "DisplayLinkMac::DisplayLinkCallback");
+  TRACE_EVENT0("ui", "DisplayLinkMac::DisplayLinkCallback");
   DisplayLinkMac* display_link_mac = static_cast<DisplayLinkMac*>(context);
-  RenderWidgetResizeHelper::Get()->task_runner()->PostTask(
+  display_link_mac->main_thread_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&DisplayLinkMac::Tick, display_link_mac, *output_time));
   return kCVReturnSuccess;
@@ -179,5 +180,5 @@
 base::LazyInstance<DisplayLinkMac::DisplayMap>
     DisplayLinkMac::display_map_ = LAZY_INSTANCE_INITIALIZER;
 
-}  // content
+}  // ui
 
diff --git a/content/browser/renderer_host/display_link_mac.h b/ui/accelerated_widget_mac/display_link_mac.h
similarity index 81%
rename from content/browser/renderer_host/display_link_mac.h
rename to ui/accelerated_widget_mac/display_link_mac.h
index 479e064..1ec7a720 100644
--- a/content/browser/renderer_host/display_link_mac.h
+++ b/ui/accelerated_widget_mac/display_link_mac.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_DISPLAY_LINK_MAC_H_
-#define CONTENT_BROWSER_RENDERER_HOST_DISPLAY_LINK_MAC_H_
+#ifndef UI_ACCELERATED_WIDGET_MAC_DISPLAY_LINK_MAC_H_
+#define UI_ACCELERATED_WIDGET_MAC_DISPLAY_LINK_MAC_H_
 
 #include <QuartzCore/CVDisplayLink.h>
 #include <map>
@@ -14,10 +14,12 @@
 #include "base/synchronization/lock.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h"
 
-namespace content {
+namespace ui {
 
-class DisplayLinkMac : public base::RefCounted<DisplayLinkMac> {
+class ACCELERATED_WIDGET_MAC_EXPORT DisplayLinkMac :
+    public base::RefCounted<DisplayLinkMac> {
  public:
   static scoped_refptr<DisplayLinkMac> GetForDisplay(
       CGDirectDisplayID display_id);
@@ -56,6 +58,9 @@
       CGDisplayChangeSummaryFlags flags,
       void* user_info);
 
+  // The task runner to post tasks to from the display link thread.
+  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+
   // The display that this display link is attached to.
   CGDirectDisplayID display_id_;
 
@@ -73,6 +78,6 @@
   static base::LazyInstance<DisplayMap> display_map_;
 };
 
-}  // content
+}  // ui
 
-#endif  // CONTENT_BROWSER_RENDERER_HOST_DISPLAY_LINK_MAC_H_
+#endif  // UI_ACCELERATED_WIDGET_MAC_DISPLAY_LINK_MAC_H_
diff --git a/ui/accelerated_widget_mac/io_surface_layer.mm b/ui/accelerated_widget_mac/io_surface_layer.mm
index 56a6391..d880316d 100644
--- a/ui/accelerated_widget_mac/io_surface_layer.mm
+++ b/ui/accelerated_widget_mac/io_surface_layer.mm
@@ -174,7 +174,8 @@
   if (self = [super init]) {
     helper_.reset(new ui::IOSurfaceLayerHelper(client, self));
 
-    iosurface_ = ui::IOSurfaceTexture::Create(needs_gl_finish_workaround);
+    iosurface_ = ui::IOSurfaceTexture::Create(
+        needs_gl_finish_workaround, false);
     context_ = ui::IOSurfaceContext::Get(
         ui::IOSurfaceContext::kCALayerContext);
     if (!iosurface_.get() || !context_.get()) {
diff --git a/ui/accelerated_widget_mac/io_surface_ns_gl_surface.h b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.h
index 7cfb4969..cb373ca 100644
--- a/ui/accelerated_widget_mac/io_surface_ns_gl_surface.h
+++ b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.h
@@ -9,30 +9,69 @@
 #include <OpenGL/OpenGL.h>
 
 #include "base/mac/scoped_nsobject.h"
+#include "base/synchronization/lock.h"
+#include "ui/accelerated_widget_mac/display_link_mac.h"
 #include "ui/accelerated_widget_mac/io_surface_context.h"
 #include "ui/accelerated_widget_mac/io_surface_texture.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gl/gpu_switching_observer.h"
 
 namespace ui {
 
-class IOSurfaceNSGLSurface {
+class IOSurfaceNSGLSurfaceClient {
  public:
-  static IOSurfaceNSGLSurface* Create(NSView* view);
-  ~IOSurfaceNSGLSurface();
+  virtual void IOSurfaceNSGLSurfaceDidDrawFrame() = 0;
+};
 
-  // Called on the UI thread.
+class IOSurfaceNSGLSurface : public ui::GpuSwitchingObserver {
+ public:
+  static IOSurfaceNSGLSurface* Create(
+      IOSurfaceNSGLSurfaceClient* client,
+      NSView* view,
+      bool needs_gl_finish_workaround);
+  virtual ~IOSurfaceNSGLSurface();
+
+  static bool CanUseNSGLSurfaceForView(NSView* view);
+
   bool GotFrame(IOSurfaceID io_surface_id,
                 gfx::Size pixel_size,
                 float scale_factor,
                 gfx::Rect pixel_damage_rect);
 
+  int GetRendererID();
+
+  bool NeedsToBeRecreated() const { return needs_to_be_recreated_; }
+
+  // ui::GpuSwitchingObserver implementation.
+  void OnGpuSwitched() override;
+
  private:
   explicit IOSurfaceNSGLSurface(
+      IOSurfaceNSGLSurfaceClient* client,
       NSView* view,
+      bool needs_gl_finish_workaround,
       base::scoped_nsobject<NSOpenGLContext> ns_gl_context,
       scoped_refptr<ui::IOSurfaceTexture> iosurface);
+
+  void DoPendingDrawIfNeeded();
+
+  IOSurfaceNSGLSurfaceClient* client_;
   NSView* view_;
-  scoped_refptr<ui::IOSurfaceTexture> iosurface_;
+  scoped_refptr<IOSurfaceTexture> iosurface_;
   base::scoped_nsobject<NSOpenGLContext> ns_gl_context_;
+
+  // The size and scale factor of the backbuffer.
+  gfx::Size contents_pixel_size_;
+  float contents_scale_factor_;
+
+  // The state of a draw that has been sent to the surface, but has not been
+  // flushed yet.
+  bool pending_draw_exists_;
+  gfx::Rect pending_draw_damage_rect_;
+
+  // If the context has hit an error or has changed GPUs, then this will be
+  // set to true.
+  bool needs_to_be_recreated_;
 };
 
 }  // namespace ui
diff --git a/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm
index 68d00bdf..9d1c26cd 100644
--- a/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm
+++ b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm
@@ -4,20 +4,30 @@
 
 #include "ui/accelerated_widget_mac/io_surface_ns_gl_surface.h"
 
+#include <OpenGL/CGLRenderers.h>
 #include <OpenGL/GL.h>
 
 #include "base/callback_helpers.h"
+#include "base/command_line.h"
 #include "base/mac/bind_objc_block.h"
+#include "base/mac/mac_util.h"
 #include "base/mac/sdk_forward_declarations.h"
+#include "base/message_loop/message_loop.h"
+#include "base/trace_event/trace_event.h"
 #include "ui/base/cocoa/animation_utils.h"
+#include "ui/base/ui_base_switches.h"
 #include "ui/gfx/geometry/dip_util.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gl/gpu_switching_manager.h"
 
 namespace ui {
 
-IOSurfaceNSGLSurface* IOSurfaceNSGLSurface::Create(NSView* view) {
-  scoped_refptr<IOSurfaceTexture> iosurface = IOSurfaceTexture::Create(false);
+IOSurfaceNSGLSurface* IOSurfaceNSGLSurface::Create(
+    IOSurfaceNSGLSurfaceClient* client,
+    NSView* view,
+    bool needs_gl_finish_workaround) {
+  scoped_refptr<IOSurfaceTexture> iosurface =
+      IOSurfaceTexture::Create(needs_gl_finish_workaround, true);
   if (!iosurface)
     return NULL;
 
@@ -44,68 +54,151 @@
     return NULL;
   }
 
-  return new IOSurfaceNSGLSurface(view, ns_gl_context, iosurface);
+  return new IOSurfaceNSGLSurface(
+      client, view, needs_gl_finish_workaround, ns_gl_context, iosurface);
 }
 
 IOSurfaceNSGLSurface::IOSurfaceNSGLSurface(
+    IOSurfaceNSGLSurfaceClient* client,
     NSView* view,
+    bool needs_gl_finish_workaround,
     base::scoped_nsobject<NSOpenGLContext> ns_gl_context,
     scoped_refptr<ui::IOSurfaceTexture> iosurface)
-    : view_(view), iosurface_(iosurface), ns_gl_context_(ns_gl_context) {
+    : client_(client), view_(view), iosurface_(iosurface),
+      ns_gl_context_(ns_gl_context), contents_scale_factor_(1),
+      pending_draw_exists_(false), needs_to_be_recreated_(false) {
   [[view_ layer] setContentsGravity:kCAGravityTopLeft];
-  [ns_gl_context_ setView:view_];
+  ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
 }
 
 IOSurfaceNSGLSurface::~IOSurfaceNSGLSurface() {
+  ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
+  DoPendingDrawIfNeeded();
   [ns_gl_context_ makeCurrentContext];
   iosurface_ = NULL;
   [NSOpenGLContext clearCurrentContext];
   [ns_gl_context_ clearDrawable];
+
+  ScopedCAActionDisabler disabler;
+  [[view_ layer] setContents:nil];
 }
 
 bool IOSurfaceNSGLSurface::GotFrame(IOSurfaceID io_surface_id,
                                     gfx::Size frame_pixel_size,
                                     float frame_scale_factor,
                                     gfx::Rect pixel_damage_rect) {
-  // The OpenGL framebuffer's scale factor and pixel size are updated to match
-  // the CALayer's contentsScale and bounds at setView. The pixel size is the
-  // stored in the GL_VIEWPORT state of the context.
-  gfx::Size contents_pixel_size;
-  float contents_scale_factor = [[view_ layer] contentsScale];
-  {
-    [ns_gl_context_ makeCurrentContext];
-    GLint viewport[4];
-    glGetIntegerv(GL_VIEWPORT, viewport);
-    [NSOpenGLContext clearCurrentContext];
-    contents_pixel_size = gfx::Size(viewport[2], viewport[3]);
-  }
+  TRACE_EVENT0("ui", "IOSurfaceNSGLSurface::GotFrame");
+  pending_draw_exists_ = true;
+  pending_draw_damage_rect_.Union(pixel_damage_rect);
 
   // If the OpenGL framebuffer does not match the frame in scale factor or
   // pixel size, then re-latch them. Note that they will latch to the layer's
   // bounds, which will not necessarily match the frame's pixel size.
-  bool full_damage = false;
-  if (frame_pixel_size != contents_pixel_size ||
-      frame_scale_factor != contents_scale_factor) {
+  if (!iosurface_->IsUpToDate(io_surface_id, frame_pixel_size) ||
+      [ns_gl_context_ view] != view_ ||
+      frame_pixel_size != contents_pixel_size_ ||
+      frame_scale_factor != contents_scale_factor_) {
     ScopedCAActionDisabler disabler;
     [ns_gl_context_ clearDrawable];
     [[view_ layer] setContentsScale:frame_scale_factor];
-    [ns_gl_context_ setView:view_];
 
-    // The front buffer may have been destroyed at re-creation, so re-draw
-    // everything.
-    full_damage = true;
+    // The OpenGL framebuffer's scale factor and pixel size are updated to match
+    // the CALayer's contentsScale and bounds at setView. The pixel size is the
+    // stored in the GL_VIEWPORT state of the context.
+    [ns_gl_context_ setView:view_];
+    [ns_gl_context_ makeCurrentContext];
+
+    // Use a clear instead of explicitly drawing background-color quads, since
+    // quads do not always cover the screen.
+    glClearColor(1, 1, 1, 1);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    // Retrieve the backbuffer's size from the GL viewport state.
+    GLint viewport[4];
+    glGetIntegerv(GL_VIEWPORT, viewport);
+    contents_pixel_size_ = gfx::Size(viewport[2], viewport[3]);
+    contents_scale_factor_ = frame_scale_factor;
+
+    bool result = iosurface_->SetIOSurface(io_surface_id, frame_pixel_size);
+    [NSOpenGLContext clearCurrentContext];
+    if (!result) {
+      LOG(ERROR) << "Failed to set IOSurface, poisoning NSOpenGLContext.";
+      needs_to_be_recreated_ = true;
+      return false;
+    }
+
+    pending_draw_damage_rect_ = gfx::Rect(frame_pixel_size);
   }
 
-  bool result = true;
-  [ns_gl_context_ makeCurrentContext];
-  result &= iosurface_->SetIOSurface(io_surface_id, frame_pixel_size);
-  if (full_damage)
-    result &= iosurface_->DrawIOSurface();
-  else
-    result &= iosurface_->DrawIOSurfaceWithDamageRect(pixel_damage_rect);
-  glFlush();
-  [NSOpenGLContext clearCurrentContext];
-  return result;
+  DoPendingDrawIfNeeded();
+  return true;
 }
 
-};
+void IOSurfaceNSGLSurface::DoPendingDrawIfNeeded() {
+  if (!pending_draw_exists_)
+    return;
+
+  {
+    TRACE_EVENT0("ui", "IOSurfaceNSGLSurface::Draw");
+    [ns_gl_context_ makeCurrentContext];
+    bool result = iosurface_->DrawIOSurfaceWithDamageRect(
+        pending_draw_damage_rect_);
+    if (!result) {
+      LOG(ERROR) << "Failed to draw IOSurface, poisoning NSOpenGLContext.";
+      needs_to_be_recreated_ = true;
+    }
+    glFlush();
+    [NSOpenGLContext clearCurrentContext];
+  }
+
+  pending_draw_exists_ = false;
+  pending_draw_damage_rect_ = gfx::Rect();
+
+  client_->IOSurfaceNSGLSurfaceDidDrawFrame();
+}
+
+int IOSurfaceNSGLSurface::GetRendererID() {
+  GLint current_renderer_id = -1;
+  CGLContextObj cgl_context = static_cast<CGLContextObj>(
+      [ns_gl_context_ CGLContextObj]);
+  if (CGLGetParameter(cgl_context,
+                      kCGLCPCurrentRendererID,
+                      &current_renderer_id) == kCGLNoError) {
+    return current_renderer_id & kCGLRendererIDMatchingMask;
+  }
+  return -1;
+}
+
+void IOSurfaceNSGLSurface::OnGpuSwitched() {
+  needs_to_be_recreated_ = true;
+}
+
+// static
+bool IOSurfaceNSGLSurface::CanUseNSGLSurfaceForView(NSView* view) {
+  // This must be explicitly enabled at the command line.
+  static bool use_ns_gl_surfaces =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableNSGLSurfaces);
+  if (!use_ns_gl_surfaces)
+    return false;
+
+  // Do not attempt this before 10.9. The power savings are not worth the
+  // stability risk and testing burden.
+  if (!base::mac::IsOSMavericksOrLater())
+    return false;
+
+  // If the NSView being attached to the NSOpenGLContext is not on the main
+  // monitor, then, due to an OS X bug, the IOSurface will be thrashed,
+  // resulting in hangs of 50 msec or more.
+  CGDirectDisplayID main_display = CGMainDisplayID();
+  NSScreen* screen = [[view window] screen];
+  NSDictionary* screen_description = [screen deviceDescription];
+  NSNumber* screen_number = [screen_description objectForKey:@"NSScreenNumber"];
+  CGDirectDisplayID display_id = [screen_number unsignedIntValue];
+  if (display_id != main_display)
+    return false;
+
+  return true;
+}
+
+}  // namespace ui
diff --git a/ui/accelerated_widget_mac/io_surface_texture.h b/ui/accelerated_widget_mac/io_surface_texture.h
index 2cdd235..2278045 100644
--- a/ui/accelerated_widget_mac/io_surface_texture.h
+++ b/ui/accelerated_widget_mac/io_surface_texture.h
@@ -41,7 +41,13 @@
     : public base::RefCounted<IOSurfaceTexture> {
  public:
   static scoped_refptr<IOSurfaceTexture> Create(
-      bool needs_gl_finish_workaround);
+      bool needs_gl_finish_workaround,
+      bool use_ns_apis);
+
+  // Returns true if there is no need to call SetIOSurface with the provided
+  // values.
+  bool IsUpToDate(
+      IOSurfaceID io_surface_id, const gfx::Size& pixel_size) const;
 
   // Set IOSurfaceTexture that will be drawn on the next NSView drawRect.
   bool SetIOSurface(
@@ -64,13 +70,10 @@
 
   IOSurfaceTexture(
       const scoped_refptr<IOSurfaceContext>& context,
+      bool use_ns_apis,
       bool needs_gl_finish_workaround);
   ~IOSurfaceTexture();
 
-  // Draw the sepecified rect of the IOSurface. If |draw_boundary| is true,
-  // clear any overflow regions with white.
-  bool DrawIOSurfaceInternal(gfx::Rect damage_rect, bool draw_boundary);
-
   // Unref the IOSurfaceTexture and delete the associated GL texture. If the GPU
   // process is no longer referencing it, this will delete the IOSurface.
   void ReleaseIOSurfaceAndTexture();
@@ -112,8 +115,12 @@
   void EvictionMarkEvicted();
   EvictionQueue::iterator eviction_queue_iterator_;
   bool eviction_has_been_drawn_since_updated_;
+
   const bool needs_gl_finish_workaround_;
 
+  // Set if this is for access through NS APIs.
+  const bool using_ns_apis_;
+
   static void EvictionScheduleDoEvict();
   static void EvictionDoEvict();
   static base::LazyInstance<EvictionQueue> eviction_queue_;
diff --git a/ui/accelerated_widget_mac/io_surface_texture.mm b/ui/accelerated_widget_mac/io_surface_texture.mm
index d3898a4..1069a0b 100644
--- a/ui/accelerated_widget_mac/io_surface_texture.mm
+++ b/ui/accelerated_widget_mac/io_surface_texture.mm
@@ -29,12 +29,10 @@
 
 // static
 scoped_refptr<IOSurfaceTexture> IOSurfaceTexture::Create(
-    bool needs_gl_finish_workaround) {
-  static bool use_ns_gl_surfaces =
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableNSGLSurfaces);
+    bool needs_gl_finish_workaround,
+    bool use_ns_apis) {
   scoped_refptr<IOSurfaceContext> offscreen_context;
-  if (!use_ns_gl_surfaces) {
+  if (!use_ns_apis) {
     offscreen_context = IOSurfaceContext::Get(
         IOSurfaceContext::kOffscreenContext);
     if (!offscreen_context.get()) {
@@ -42,18 +40,21 @@
       return NULL;
     }
   }
-  return new IOSurfaceTexture(offscreen_context, needs_gl_finish_workaround);
+  return new IOSurfaceTexture(
+      offscreen_context, use_ns_apis, needs_gl_finish_workaround);
 }
 
 IOSurfaceTexture::IOSurfaceTexture(
     const scoped_refptr<IOSurfaceContext>& offscreen_context,
+    bool use_ns_apis,
     bool needs_gl_finish_workaround)
     : offscreen_context_(offscreen_context),
       texture_(0),
       gl_error_(GL_NO_ERROR),
       eviction_queue_iterator_(eviction_queue_.Get().end()),
       eviction_has_been_drawn_since_updated_(false),
-      needs_gl_finish_workaround_(needs_gl_finish_workaround) {
+      needs_gl_finish_workaround_(needs_gl_finish_workaround),
+      using_ns_apis_(use_ns_apis) {
 }
 
 IOSurfaceTexture::~IOSurfaceTexture() {
@@ -63,16 +64,11 @@
 }
 
 bool IOSurfaceTexture::DrawIOSurface() {
-  return DrawIOSurfaceInternal(gfx::Rect(pixel_size_), true);
+  return DrawIOSurfaceWithDamageRect(gfx::Rect(pixel_size_));
 }
 
 bool IOSurfaceTexture::DrawIOSurfaceWithDamageRect(gfx::Rect damage_rect) {
-  return DrawIOSurfaceInternal(damage_rect, false);
-}
-
-bool IOSurfaceTexture::DrawIOSurfaceInternal(
-    gfx::Rect damage_rect, bool draw_boundary) {
-  TRACE_EVENT0("browser", "IOSurfaceTexture::DrawIOSurfaceInternal");
+  TRACE_EVENT0("browser", "IOSurfaceTexture::DrawIOSurfaceWithDamageRect");
   DCHECK(CGLGetCurrentContext());
 
   // If we have release the IOSurface, clear the screen to light grey and
@@ -121,28 +117,6 @@
   glBegin(GL_TRIANGLES);
   glEnd();
 
-  // If the viewport is larger than the texture, clear out the overflow to
-  // white.
-  if (draw_boundary) {
-    if (pixel_size_.width() < viewport_rect.width()) {
-      glBegin(GL_QUADS);
-      glVertex2f(pixel_size_.width(), 0);
-      glVertex2f(pixel_size_.width(), viewport_rect.height());
-      glVertex2f(viewport_rect.width(), viewport_rect.height());
-      glVertex2f(viewport_rect.width(), 0);
-      glEnd();
-    }
-    if (pixel_size_.height() < viewport_rect.height()) {
-      int non_surface_height = viewport_rect.height() - pixel_size_.height();
-      glBegin(GL_QUADS);
-      glVertex2f(0, 0);
-      glVertex2f(0, non_surface_height);
-      glVertex2f(pixel_size_.width(), non_surface_height);
-      glVertex2f(pixel_size_.width(), 0);
-      glEnd();
-    }
-  }
-
   if (needs_gl_finish_workaround_) {
     TRACE_EVENT0("gpu", "glFinish");
     glFinish();
@@ -164,9 +138,15 @@
   return result;
 }
 
+bool IOSurfaceTexture::IsUpToDate(
+    IOSurfaceID io_surface_id, const gfx::Size& pixel_size) const {
+  return io_surface_ &&
+         io_surface_id == IOSurfaceGetID(io_surface_) &&
+         pixel_size == pixel_size_;
+}
+
 bool IOSurfaceTexture::SetIOSurface(
-    IOSurfaceID io_surface_id,
-    const gfx::Size& pixel_size) {
+    IOSurfaceID io_surface_id, const gfx::Size& pixel_size) {
   TRACE_EVENT0("browser", "IOSurfaceTexture::MapIOSurfaceToTexture");
 
   // Destroy the old IOSurface and texture if it is no longer needed.
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl
index 4bc678a..c6fead9f 100644
--- a/ui/accessibility/ax_enums.idl
+++ b/ui/accessibility/ax_enums.idl
@@ -244,7 +244,6 @@
     container_live_status,
     description,
     display,
-    dropeffect,
     help,
     html_tag,
     // Only used when invalid_state == invalid_state_other.
@@ -255,7 +254,6 @@
     placeholder,
     role,
     shortcut,
-    text_input_type,
     url,
     value
   };
@@ -374,11 +372,7 @@
     // Set if this node is the host of an external AXTree, for
     // example a web view that's a child of a native view, or a
     // web iframe that's the child of another web frame.
-    is_ax_tree_host,
-
-    // Set if this node has been selected for dragging in
-    // a drag-n-drop operation.
-    grabbed
+    is_ax_tree_host
   };
 
   [cpp_enum_prefix_override="ax_attr"] enum AXIntListAttribute {
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index 8cdc67b..44394ed 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -201,7 +201,7 @@
     const char* html_attr, std::string* value) const {
   for (size_t i = 0; i < html_attributes.size(); ++i) {
     const std::string& attr = html_attributes[i].first;
-    if (LowerCaseEqualsASCII(attr, html_attr)) {
+    if (base::LowerCaseEqualsASCII(attr, html_attr)) {
       *value = html_attributes[i].second;
       return true;
     }
@@ -499,9 +499,6 @@
       case AX_ATTR_DISPLAY:
         result += " display=" + value;
         break;
-      case AX_ATTR_DROPEFFECT:
-        result += " dropeffect=" + value;
-        break;
       case AX_ATTR_HELP:
         result += " help=" + value;
         break;
@@ -532,9 +529,6 @@
       case AX_ATTR_SHORTCUT:
         result += " shortcut=" + value;
         break;
-     case AX_ATTR_TEXT_INPUT_TYPE:
-        result += " text_input_type=" + value;
-        break;
       case AX_ATTR_URL:
         result += " url=" + value;
         break;
@@ -608,9 +602,6 @@
       case AX_ATTR_IS_AX_TREE_HOST:
         result += " is_ax_tree_host=" + value;
         break;
-      case AX_ATTR_GRABBED:
-        result += " grabbed=" + value;
-        break;
       case AX_BOOL_ATTRIBUTE_NONE:
         break;
     }
diff --git a/ui/android/java/src/org/chromium/ui/VSyncMonitor.java b/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
index c074501..0396135 100644
--- a/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
+++ b/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
@@ -6,6 +6,7 @@
 
 import android.content.Context;
 import android.os.Handler;
+import android.os.Looper;
 import android.view.Choreographer;
 import android.view.WindowManager;
 
@@ -108,10 +109,12 @@
     }
 
     /**
-     * Request to be notified of the closest display vsync events.
+     * Request to be notified of the closest display vsync events. This should
+     * always be called on the same thread used to create the VSyncMonitor.
      * Listener.onVSync() will be called soon after the upcoming vsync pulses.
      */
     public void requestUpdate() {
+        assert mHandler.getLooper() == Looper.myLooper();
         postCallback();
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java
index c83a0ca..7e31ec95 100644
--- a/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java
@@ -7,8 +7,15 @@
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
+import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender.SendIntentException;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.SparseArray;
 import android.view.View;
 
 import org.chromium.base.ActivityState;
@@ -16,6 +23,8 @@
 import org.chromium.ui.UiUtils;
 
 import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 
 /**
  * The class provides the WindowAndroid's implementation which requires
@@ -31,6 +40,12 @@
     private static final String TAG = "ActivityWindowAndroid";
 
     private final WeakReference<Activity> mActivityRef;
+    private final Handler mHandler;
+    private final SparseArray<PermissionCallback> mOutstandingPermissionRequests;
+    private final Runnable mClearPermissionRequestsTask;
+
+    private Method mRequestPermissionsMethod;
+
     private int mNextRequestCode = 0;
 
     /**
@@ -51,6 +66,17 @@
     public ActivityWindowAndroid(Activity activity, boolean listenToActivityState) {
         super(activity.getApplicationContext());
         mActivityRef = new WeakReference<Activity>(activity);
+        mHandler = new Handler();
+        mOutstandingPermissionRequests = new SparseArray<PermissionCallback>();
+        mClearPermissionRequestsTask = new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < mOutstandingPermissionRequests.size(); i++) {
+                    mOutstandingPermissionRequests.valueAt(i).onRequestPermissionAborted();
+                }
+                mOutstandingPermissionRequests.clear();
+            }
+        };
         if (listenToActivityState) {
             ApplicationStatus.registerStateListenerForActivity(this, activity);
         }
@@ -113,7 +139,13 @@
         activity.finishActivity(requestCode);
     }
 
-    @Override
+    /**
+     * Responds to the intent result if the intent was created by the native window.
+     * @param requestCode Request code of the requested intent.
+     * @param resultCode Result code of the requested intent.
+     * @param data The data returned by the intent.
+     * @return Boolean value of whether the intent was started by the native window.
+     */
     public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
         IntentCallback callback = mOutstandingIntents.get(requestCode);
         mOutstandingIntents.delete(requestCode);
@@ -132,6 +164,92 @@
         return false;
     }
 
+    private static boolean hasPermission(Context context, String permission) {
+        return context.checkPermission(permission, Process.myPid(), Process.myUid())
+                != PackageManager.PERMISSION_DENIED;
+    }
+
+    @Override
+    public void requestPermissions(
+            final String[] permissions, final PermissionCallback callback) {
+        // If the permission request was not sent successfully, just post a response to the
+        // callback with whatever the current permission state is for all the requested
+        // permissions.  The response is posted to keep the async behavior of this method
+        // consistent.
+        if (!requestPermissionsInternal(permissions, callback)) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    int[] results = new int[permissions.length];
+                    for (int i = 0; i < permissions.length; i++) {
+                        results[i] = hasPermission(mApplicationContext, permissions[i])
+                                ? PackageManager.PERMISSION_GRANTED
+                                : PackageManager.PERMISSION_DENIED;
+                    }
+                    callback.onRequestPermissionsResult(permissions, results);
+                }
+            });
+        }
+    }
+
+    /**
+     * Issues the permission request and returns whether it was sent successfully.
+     */
+    private boolean requestPermissionsInternal(String[] permissions, PermissionCallback callback) {
+        mHandler.removeCallbacks(mClearPermissionRequestsTask);
+
+        // TODO(tedchoc): Remove the MNC check once the SDK version is bumped.
+        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1
+                && !TextUtils.equals("MNC", Build.VERSION.CODENAME)) {
+            return false;
+        }
+
+        // TODO(tedchoc): Remove the reflection aspect of this once a public M SDK is available.
+        Activity activity = mActivityRef.get();
+        if (activity == null) return false;
+
+        if (mRequestPermissionsMethod == null) {
+            try {
+                mRequestPermissionsMethod = Activity.class.getMethod(
+                        "requestPermissions", String[].class, int.class);
+            } catch (NoSuchMethodException e) {
+                return false;
+            }
+        }
+
+        int requestCode = generateNextRequestCode();
+        mOutstandingPermissionRequests.put(requestCode, callback);
+
+        try {
+            mRequestPermissionsMethod.invoke(activity, permissions, requestCode);
+            return true;
+        } catch (IllegalAccessException e) {
+            mOutstandingPermissionRequests.delete(requestCode);
+        } catch (IllegalArgumentException e) {
+            mOutstandingPermissionRequests.delete(requestCode);
+        } catch (InvocationTargetException e) {
+            mOutstandingPermissionRequests.delete(requestCode);
+        }
+
+        return false;
+    }
+
+    /**
+     * Responds to a pending permission result.
+     * @param requestCode The unique code for the permission request.
+     * @param permissions The list of permissions in the result.
+     * @param grantResults Whether the permissions were granted.
+     * @return Whether the permission request corresponding to a pending permission request.
+     */
+    public boolean onRequestPermissionsResult(int requestCode, String[] permissions,
+            int[] grantResults) {
+        PermissionCallback callback = mOutstandingPermissionRequests.get(requestCode);
+        mOutstandingPermissionRequests.delete(requestCode);
+        if (callback == null) return false;
+        callback.onRequestPermissionsResult(permissions, grantResults);
+        return true;
+    }
+
     @Override
     public WeakReference<Activity> getActivity() {
         // Return a new WeakReference to prevent clients from releasing our internal WeakReference.
@@ -144,6 +262,11 @@
             onActivityPaused();
         } else if (newState == ActivityState.RESUMED) {
             onActivityResumed();
+
+            // Work around an issue where we do not always get an onRequestPermissionsResult
+            // callback if the user hits the back button in the permission dialog instead
+            // of taking an action.
+            mHandler.post(mClearPermissionRequestsTask);
         }
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
index 84a3499..d0dde3d 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -214,6 +214,16 @@
     }
 
     /**
+     * Requests the specified permissions are granted for further use.
+     * @param permissions The list of permissions to request access to.
+     * @param callback The callback to be notified whether the permissions were granted.
+     */
+    public void requestPermissions(String[] permissions, PermissionCallback callback) {
+        Log.w(TAG, "Cannot request permissions as the context is not an Activity");
+        assert false : "Failed to request permissions using a WindowAndroid without an Activity";
+    }
+
+    /**
      * Displays an error message with a provided error message string.
      * @param error The error message string to be displayed.
      */
@@ -305,17 +315,6 @@
         nativeOnActivityResumed(mNativeWindowAndroid);
     }
 
-    /**
-     * Responds to the intent result if the intent was created by the native window.
-     * @param requestCode Request code of the requested intent.
-     * @param resultCode Result code of the requested intent.
-     * @param data The data returned by the intent.
-     * @return Boolean value of whether the intent was started by the native window.
-     */
-    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
-        return false;
-    }
-
     @CalledByNative
     private void requestVSyncUpdate() {
         mVSyncMonitor.requestUpdate();
@@ -337,6 +336,23 @@
     }
 
     /**
+     * Callback for permission requests.
+     */
+    public interface PermissionCallback {
+        /**
+         * Called upon completing a permission request.
+         * @param permissions The list of permissions in the result.
+         * @param grantResults Whether the permissions were granted.
+         */
+        void onRequestPermissionsResult(String[] permissions, int[] grantResults);
+
+        /**
+         * Called when a permission request has been aborted.
+         */
+        void onRequestPermissionAborted();
+    }
+
+    /**
      * Tests that an activity is available to handle the passed in intent.
      * @param  intent The intent to check.
      * @return True if an activity is available to process this intent when started, meaning that
diff --git a/ui/app_list/views/app_list_view_unittest.cc b/ui/app_list/views/app_list_view_unittest.cc
index a8fc4e0..a36882e9 100644
--- a/ui/app_list/views/app_list_view_unittest.cc
+++ b/ui/app_list/views/app_list_view_unittest.cc
@@ -32,6 +32,7 @@
 #include "ui/app_list/views/tile_item_view.h"
 #include "ui/events/event_utils.h"
 #include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/test/test_views_delegate.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/views_delegate.h"
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
@@ -705,7 +706,7 @@
 
   // testing::Test overrides:
   void SetUp() override {
-    set_views_delegate(new AppListViewTestViewsDelegate(this));
+    set_views_delegate(make_scoped_ptr(new AppListViewTestViewsDelegate(this)));
     views::ViewsTestBase::SetUp();
     test_context_.reset(new AppListViewTestContext(GetParam(), NULL));
   }
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc
index 7d6d89b..18733c7 100644
--- a/ui/aura/client/aura_constants.cc
+++ b/ui/aura/client/aura_constants.cc
@@ -34,7 +34,6 @@
 DEFINE_OWNED_WINDOW_PROPERTY_KEY(gfx::Rect, kRestoreBoundsKey, NULL);
 DEFINE_WINDOW_PROPERTY_KEY(
     ui::WindowShowState, kRestoreShowStateKey, ui::SHOW_STATE_DEFAULT);
-DEFINE_WINDOW_PROPERTY_KEY(ui::InputMethod*, kRootWindowInputMethodKey, NULL);
 DEFINE_WINDOW_PROPERTY_KEY(
     ui::WindowShowState, kShowStateKey, ui::SHOW_STATE_DEFAULT);
 
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h
index d346098..5999b85 100644
--- a/ui/aura/client/aura_constants.h
+++ b/ui/aura/client/aura_constants.h
@@ -56,10 +56,6 @@
 AURA_EXPORT extern const WindowProperty<ui::WindowShowState>* const
     kRestoreShowStateKey;
 
-// A property key to store an input method object that handles a key event.
-AURA_EXPORT extern const WindowProperty<ui::InputMethod*>* const
-    kRootWindowInputMethodKey;
-
 // A property key to store ui::WindowShowState for a window.
 // See ui/base/ui_base_types.h for its definition.
 AURA_EXPORT extern const WindowProperty<ui::WindowShowState>* const
diff --git a/ui/aura/remote_window_tree_host_win.cc b/ui/aura/remote_window_tree_host_win.cc
index 8ffa617..842598c 100644
--- a/ui/aura/remote_window_tree_host_win.cc
+++ b/ui/aura/remote_window_tree_host_win.cc
@@ -11,7 +11,6 @@
 #include "base/message_loop/message_loop.h"
 #include "ipc/ipc_message.h"
 #include "ipc/ipc_sender.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_property.h"
@@ -271,10 +270,6 @@
   NOTIMPLEMENTED();
 }
 
-ui::EventProcessor* RemoteWindowTreeHostWin::GetEventProcessor() {
-  return dispatcher();
-}
-
 void RemoteWindowTreeHostWin::CancelComposition() {
   if (!host_)
     return;
@@ -433,9 +428,7 @@
 
 ui::RemoteInputMethodPrivateWin*
 RemoteWindowTreeHostWin::GetRemoteInputMethodPrivate() {
-  ui::InputMethod* input_method = GetAshWindow()->GetProperty(
-      aura::client::kRootWindowInputMethodKey);
-  return ui::RemoteInputMethodPrivateWin::Get(input_method);
+  return ui::RemoteInputMethodPrivateWin::Get(GetInputMethod());
 }
 
 void RemoteWindowTreeHostWin::OnImeCandidatePopupChanged(bool visible) {
diff --git a/ui/aura/remote_window_tree_host_win.h b/ui/aura/remote_window_tree_host_win.h
index 5db2b47..340d75f 100644
--- a/ui/aura/remote_window_tree_host_win.h
+++ b/ui/aura/remote_window_tree_host_win.h
@@ -40,7 +40,6 @@
 // frontend process, which forwards input events to this class.
 class AURA_EXPORT RemoteWindowTreeHostWin
     : public WindowTreeHost,
-      public ui::EventSource,
       public ui::internal::RemoteInputMethodDelegateWin {
  public:
   // Returns the current RemoteWindowTreeHostWin. This does *not* create a
@@ -129,9 +128,6 @@
   void MoveCursorToNative(const gfx::Point& location) override;
   void OnCursorVisibilityChangedNative(bool show) override;
 
-  // ui::EventSource:
-  ui::EventProcessor* GetEventProcessor() override;
-
   // ui::internal::RemoteInputMethodDelegateWin overrides:
   void CancelComposition() override;
   void OnTextInputClientUpdated(
diff --git a/ui/aura/test/aura_test_helper.cc b/ui/aura/test/aura_test_helper.cc
index 837f81e..2cc8b0d 100644
--- a/ui/aura/test/aura_test_helper.cc
+++ b/ui/aura/test/aura_test_helper.cc
@@ -6,7 +6,6 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/default_capture_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/env.h"
@@ -16,8 +15,9 @@
 #include "ui/aura/test/test_focus_client.h"
 #include "ui/aura/test/test_screen.h"
 #include "ui/aura/test/test_window_tree_client.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
-#include "ui/base/ime/dummy_input_method.h"
+#include "ui/base/ime/input_method_factory.h"
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/layer_animator.h"
@@ -62,6 +62,7 @@
   // from RootWindow.
   EnvTestHelper(Env::GetInstance()).SetInputStateLookup(nullptr);
 
+  ui::SetUpInputMethodFactoryForTesting();
   ui::InitializeInputMethodForTesting();
 
   gfx::Size host_size(800, 600);
@@ -73,10 +74,6 @@
   client::SetFocusClient(root_window(), focus_client_.get());
   stacking_client_.reset(new TestWindowTreeClient(root_window()));
   capture_client_.reset(new client::DefaultCaptureClient(root_window()));
-  test_input_method_.reset(new ui::DummyInputMethod);
-  root_window()->SetProperty(
-      client::kRootWindowInputMethodKey,
-      test_input_method_.get());
 
   root_window()->Show();
   // Ensure width != height so tests won't confuse them.
@@ -85,7 +82,6 @@
 
 void AuraTestHelper::TearDown() {
   teardown_called_ = true;
-  test_input_method_.reset();
   stacking_client_.reset();
   capture_client_.reset();
   focus_client_.reset();
diff --git a/ui/aura/test/aura_test_helper.h b/ui/aura/test/aura_test_helper.h
index 68650255..e4820f0 100644
--- a/ui/aura/test/aura_test_helper.h
+++ b/ui/aura/test/aura_test_helper.h
@@ -60,7 +60,6 @@
   scoped_ptr<WindowTreeHost> host_;
   scoped_ptr<TestWindowTreeClient> stacking_client_;
   scoped_ptr<client::DefaultCaptureClient> capture_client_;
-  scoped_ptr<ui::InputMethod> test_input_method_;
   scoped_ptr<client::FocusClient> focus_client_;
   scoped_ptr<TestScreen> test_screen_;
   scoped_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_;
diff --git a/ui/aura/window_targeter.cc b/ui/aura/window_targeter.cc
index 7303e22..192bd60 100644
--- a/ui/aura/window_targeter.cc
+++ b/ui/aura/window_targeter.cc
@@ -12,55 +12,28 @@
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/events/event_target.h"
+#include "ui/events/event_target_iterator.h"
 
 namespace aura {
 
-namespace {
-
-bool IsLocatedEvent(const ui::Event& event) {
-  return event.IsMouseEvent() || event.IsTouchEvent() ||
-         event.IsScrollEvent() || event.IsGestureEvent();
-}
-
-}  // namespace
-
 WindowTargeter::WindowTargeter() {}
 WindowTargeter::~WindowTargeter() {}
 
-ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root,
-                                                    ui::Event* event) {
-  Window* window = static_cast<Window*>(root);
-  Window* target = event->IsKeyEvent() ?
-      FindTargetForKeyEvent(window, *static_cast<ui::KeyEvent*>(event)) :
-      static_cast<Window*>(EventTargeter::FindTargetForEvent(root, event));
-  if (target && !window->parent() && !window->Contains(target)) {
-    // |window| is the root window, but |target| is not a descendent of
-    // |window|. So do not allow dispatching from here. Instead, dispatch the
-    // event through the WindowEventDispatcher that owns |target|.
-    aura::Window* new_root = target->GetRootWindow();
-    if (IsLocatedEvent(*event)) {
-      // The event has been transformed to be in |target|'s coordinate system.
-      // But dispatching the event through the EventProcessor requires the event
-      // to be in the host's coordinate system. So, convert the event to be in
-      // the root's coordinate space, and then to the host's coordinate space by
-      // applying the host's transform.
-      ui::LocatedEvent* located_event = static_cast<ui::LocatedEvent*>(event);
-      located_event->ConvertLocationToTarget(target, new_root);
-      located_event->UpdateForRootTransform(
-          new_root->GetHost()->GetRootTransform());
+Window* WindowTargeter::FindTargetForLocatedEvent(Window* window,
+                                                  ui::LocatedEvent* event) {
+  if (!window->parent()) {
+    Window* target = FindTargetInRootWindow(window, *event);
+    if (target) {
+      window->ConvertEventToTarget(target, event);
+      return target;
     }
-    ignore_result(
-        new_root->GetHost()->event_processor()->OnEventFromSource(event));
-
-    target = NULL;
   }
-  return target;
+  return FindTargetForLocatedEventRecursively(window, event);
 }
 
 bool WindowTargeter::SubtreeCanAcceptEvent(
-    ui::EventTarget* target,
+    Window* window,
     const ui::LocatedEvent& event) const {
-  aura::Window* window = static_cast<aura::Window*>(target);
   if (!window->IsVisible())
     return false;
   if (window->ignore_events())
@@ -78,27 +51,56 @@
 }
 
 bool WindowTargeter::EventLocationInsideBounds(
-    ui::EventTarget* target,
+    Window* window,
     const ui::LocatedEvent& event) const {
-  aura::Window* window = static_cast<aura::Window*>(target);
   gfx::Point point = event.location();
   if (window->parent())
-    aura::Window::ConvertPointToTarget(window->parent(), window, &point);
+    Window::ConvertPointToTarget(window->parent(), window, &point);
   return gfx::Rect(window->bounds().size()).Contains(point);
 }
 
-ui::EventTarget* WindowTargeter::FindTargetForLocatedEvent(
-    ui::EventTarget* root,
-    ui::LocatedEvent* event) {
+ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root,
+                                                    ui::Event* event) {
   Window* window = static_cast<Window*>(root);
-  if (!window->parent()) {
-    Window* target = FindTargetInRootWindow(window, *event);
-    if (target) {
-      window->ConvertEventToTarget(target, event);
-      return target;
+  Window* target =
+      event->IsKeyEvent()
+          ? FindTargetForKeyEvent(window, *static_cast<ui::KeyEvent*>(event))
+          : FindTargetForNonKeyEvent(window, event);
+  if (target && !window->parent() && !window->Contains(target)) {
+    // |window| is the root window, but |target| is not a descendent of
+    // |window|. So do not allow dispatching from here. Instead, dispatch the
+    // event through the WindowEventDispatcher that owns |target|.
+    Window* new_root = target->GetRootWindow();
+    if (event->IsLocatedEvent()) {
+      // The event has been transformed to be in |target|'s coordinate system.
+      // But dispatching the event through the EventProcessor requires the event
+      // to be in the host's coordinate system. So, convert the event to be in
+      // the root's coordinate space, and then to the host's coordinate space by
+      // applying the host's transform.
+      ui::LocatedEvent* located_event = static_cast<ui::LocatedEvent*>(event);
+      located_event->ConvertLocationToTarget(target, new_root);
+      located_event->UpdateForRootTransform(
+          new_root->GetHost()->GetRootTransform());
     }
+    ignore_result(
+        new_root->GetHost()->event_processor()->OnEventFromSource(event));
+
+    target = nullptr;
   }
-  return EventTargeter::FindTargetForLocatedEvent(root, event);
+  return target;
+}
+
+ui::EventTarget* WindowTargeter::FindNextBestTarget(
+    ui::EventTarget* previous_target,
+    ui::Event* event) {
+  return nullptr;
+}
+
+bool WindowTargeter::SubtreeShouldBeExploredForEvent(
+    Window* window,
+    const ui::LocatedEvent& event) {
+  return SubtreeCanAcceptEvent(window, event) &&
+         EventLocationInsideBounds(window, event);
 }
 
 Window* WindowTargeter::FindTargetForKeyEvent(Window* window,
@@ -112,12 +114,20 @@
   client::EventClient* event_client = client::GetEventClient(root_window);
   if (event_client &&
       !event_client->CanProcessEventsWithinSubtree(focused_window)) {
-    focus_client->FocusWindow(NULL);
-    return NULL;
+    focus_client->FocusWindow(nullptr);
+    return nullptr;
   }
   return focused_window ? focused_window : window;
 }
 
+Window* WindowTargeter::FindTargetForNonKeyEvent(Window* root_window,
+                                                 ui::Event* event) {
+  if (!event->IsLocatedEvent())
+    return root_window;
+  return FindTargetForLocatedEvent(root_window,
+                                   static_cast<ui::LocatedEvent*>(event));
+}
+
 Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
                                                const ui::LocatedEvent& event) {
   DCHECK_EQ(root_window, root_window->GetRootWindow());
@@ -153,7 +163,35 @@
       return root_window;
   }
 
-  return NULL;
+  return nullptr;
+}
+
+Window* WindowTargeter::FindTargetForLocatedEventRecursively(
+    Window* root_window,
+    ui::LocatedEvent* event) {
+  scoped_ptr<ui::EventTargetIterator> iter = root_window->GetChildIterator();
+  if (iter) {
+    ui::EventTarget* target = root_window;
+    for (ui::EventTarget* child = iter->GetNextTarget(); child;
+         child = iter->GetNextTarget()) {
+      WindowTargeter* targeter =
+          static_cast<WindowTargeter*>(child->GetEventTargeter());
+      if (!targeter)
+        targeter = this;
+      if (!targeter->SubtreeShouldBeExploredForEvent(
+              static_cast<Window*>(child), *event)) {
+        continue;
+      }
+      target->ConvertEventToTarget(child, event);
+      target = child;
+      Window* child_target_window =
+          static_cast<Window*>(targeter->FindTargetForEvent(child, event));
+      if (child_target_window)
+        return child_target_window;
+    }
+    target->ConvertEventToTarget(root_window, event);
+  }
+  return root_window->CanAcceptEvent(*event) ? root_window : nullptr;
 }
 
 }  // namespace aura
diff --git a/ui/aura/window_targeter.h b/ui/aura/window_targeter.h
index 9571f2ab..048d8ad2 100644
--- a/ui/aura/window_targeter.h
+++ b/ui/aura/window_targeter.h
@@ -5,9 +5,15 @@
 #ifndef UI_AURA_WINDOW_TARGETER_H_
 #define UI_AURA_WINDOW_TARGETER_H_
 
+#include "base/macros.h"
 #include "ui/aura/aura_export.h"
 #include "ui/events/event_targeter.h"
 
+namespace ui {
+class KeyEvent;
+class LocatedEvent;
+}  // namespace ui
+
 namespace aura {
 
 class Window;
@@ -17,22 +23,50 @@
   WindowTargeter();
   ~WindowTargeter() override;
 
+  // Returns true if |window| or one of its descendants can be a target of
+  // |event|. This requires that |window| and its descendants are not
+  // prohibited from accepting the event, and that the event is within an
+  // actionable region of the target's bounds. Note that the location etc. of
+  // |event| is in |window|'s parent's coordinate system.
+  virtual bool SubtreeShouldBeExploredForEvent(Window* window,
+                                               const ui::LocatedEvent& event);
+
  protected:
+  // Same as FindTargetForEvent(), but used for positional events. The location
+  // etc. of |event| are in |root|'s coordinate system. When finding the target
+  // for the event, the targeter can mutate the |event| (e.g. change the
+  // coordinate to be in the returned target's coordinate system) so that it can
+  // be dispatched to the target without any further modification.
+  virtual Window* FindTargetForLocatedEvent(Window* window,
+                                            ui::LocatedEvent* event);
+
+  // Returns false if neither |window| nor any of its descendants are allowed
+  // to accept |event| for reasons unrelated to the event's location or the
+  // target's bounds. For example, overrides of this function may consider
+  // attributes such as the visibility or enabledness of |window|. Note that
+  // the location etc. of |event| is in |window|'s parent's coordinate system.
+  virtual bool SubtreeCanAcceptEvent(Window* window,
+                                     const ui::LocatedEvent& event) const;
+
+  // Returns whether the location of the event is in an actionable region of the
+  // target. Note that the location etc. of |event| is in the |window|'s
+  // parent's coordinate system.
+  virtual bool EventLocationInsideBounds(Window* target,
+                                         const ui::LocatedEvent& event) const;
+
   // ui::EventTargeter:
   ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
                                       ui::Event* event) override;
-  ui::EventTarget* FindTargetForLocatedEvent(ui::EventTarget* root,
-                                             ui::LocatedEvent* event) override;
-  bool SubtreeCanAcceptEvent(ui::EventTarget* target,
-                             const ui::LocatedEvent& event) const override;
-  bool EventLocationInsideBounds(ui::EventTarget* target,
-                                 const ui::LocatedEvent& event) const override;
+  ui::EventTarget* FindNextBestTarget(ui::EventTarget* previous_target,
+                                      ui::Event* event) override;
 
  private:
-  Window* FindTargetForKeyEvent(Window* root_window,
-                                const ui::KeyEvent& event);
+  Window* FindTargetForKeyEvent(Window* root_window, const ui::KeyEvent& event);
+  Window* FindTargetForNonKeyEvent(Window* root_window, ui::Event* event);
   Window* FindTargetInRootWindow(Window* root_window,
                                  const ui::LocatedEvent& event);
+  Window* FindTargetForLocatedEventRecursively(Window* root_window,
+                                               ui::LocatedEvent* event);
 
   DISALLOW_COPY_AND_ASSIGN(WindowTargeter);
 };
diff --git a/ui/aura/window_targeter_unittest.cc b/ui/aura/window_targeter_unittest.cc
index 02217271..14dea716 100644
--- a/ui/aura/window_targeter_unittest.cc
+++ b/ui/aura/window_targeter_unittest.cc
@@ -14,16 +14,16 @@
 namespace aura {
 
 // Always returns the same window.
-class StaticWindowTargeter : public ui::EventTargeter {
+class StaticWindowTargeter : public WindowTargeter {
  public:
   explicit StaticWindowTargeter(aura::Window* window)
       : window_(window) {}
   ~StaticWindowTargeter() override {}
 
  private:
-  // ui::EventTargeter:
-  ui::EventTarget* FindTargetForLocatedEvent(ui::EventTarget* root,
-                                             ui::LocatedEvent* event) override {
+  // aura::WindowTargeter:
+  Window* FindTargetForLocatedEvent(Window* window,
+                                    ui::LocatedEvent* event) override {
     return window_;
   }
 
@@ -175,4 +175,121 @@
   }
 }
 
+class IdCheckingEventTargeter : public WindowTargeter {
+ public:
+  IdCheckingEventTargeter(int id) : id_(id) {}
+  ~IdCheckingEventTargeter() override {}
+
+ protected:
+  // WindowTargeter:
+  bool SubtreeShouldBeExploredForEvent(Window* window,
+                                       const ui::LocatedEvent& event) override {
+    return (window->id() == id_ &&
+            WindowTargeter::SubtreeShouldBeExploredForEvent(window, event));
+  }
+
+ private:
+  int id_;
+};
+
+TEST_F(WindowTargeterTest, Bounds) {
+  test::TestWindowDelegate delegate;
+  scoped_ptr<Window> parent(CreateNormalWindow(1, root_window(), &delegate));
+  scoped_ptr<Window> child(CreateNormalWindow(1, parent.get(), &delegate));
+  scoped_ptr<Window> grandchild(CreateNormalWindow(1, child.get(), &delegate));
+
+  parent->SetBounds(gfx::Rect(0, 0, 30, 30));
+  child->SetBounds(gfx::Rect(5, 5, 20, 20));
+  grandchild->SetBounds(gfx::Rect(5, 5, 5, 5));
+
+  ASSERT_EQ(1u, root_window()->children().size());
+  ASSERT_EQ(1u, root_window()->children()[0]->children().size());
+  ASSERT_EQ(1u, root_window()->children()[0]->children()[0]->children().size());
+
+  Window* parent_r = root_window()->children()[0];
+  Window* child_r = parent_r->children()[0];
+  Window* grandchild_r = child_r->children()[0];
+
+  ui::EventTarget* root_target = root_window();
+  ui::EventTargeter* targeter = root_target->GetEventTargeter();
+
+  // Dispatch a mouse event that falls on the parent, but not on the child. When
+  // the default event-targeter used, the event will still reach |grandchild|,
+  // because the default targeter does not look at the bounds.
+  ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(1, 1), gfx::Point(1, 1),
+                       ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+  EXPECT_EQ(parent_r, targeter->FindTargetForEvent(root_target, &mouse));
+
+  // Install a targeter on the |child| that looks at the window id as well
+  // as the bounds and makes sure the event reaches the target only if the id of
+  // the window is equal to 2 (incorrect). This causes the event to get handled
+  // by |parent|.
+  ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(8, 8), gfx::Point(8, 8),
+                        ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+  scoped_ptr<ui::EventTargeter> original_targeter = child_r->SetEventTargeter(
+      scoped_ptr<ui::EventTargeter>(new IdCheckingEventTargeter(2)));
+  EXPECT_EQ(parent_r, targeter->FindTargetForEvent(root_target, &mouse2));
+
+  // Now install a targeter on the |child| that looks at the window id as well
+  // as the bounds and makes sure the event reaches the target only if the id of
+  // the window is equal to 1 (correct).
+  ui::MouseEvent mouse3(ui::ET_MOUSE_MOVED, gfx::Point(8, 8), gfx::Point(8, 8),
+                        ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+  child_r->SetEventTargeter(
+      scoped_ptr<ui::EventTargeter>(new IdCheckingEventTargeter(1)));
+  EXPECT_EQ(child_r, targeter->FindTargetForEvent(root_target, &mouse3));
+
+  // restore original WindowTargeter for |child|.
+  child_r->SetEventTargeter(original_targeter.Pass());
+
+  // Target |grandchild| location.
+  ui::MouseEvent second(ui::ET_MOUSE_MOVED, gfx::Point(12, 12),
+                        gfx::Point(12, 12), ui::EventTimeForNow(), ui::EF_NONE,
+                        ui::EF_NONE);
+  EXPECT_EQ(grandchild_r, targeter->FindTargetForEvent(root_target, &second));
+
+  // Target |child| location.
+  ui::MouseEvent third(ui::ET_MOUSE_MOVED, gfx::Point(8, 8), gfx::Point(8, 8),
+                       ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
+  EXPECT_EQ(child_r, targeter->FindTargetForEvent(root_target, &third));
+}
+
+class IgnoreWindowTargeter : public WindowTargeter {
+ public:
+  IgnoreWindowTargeter() {}
+  ~IgnoreWindowTargeter() override {}
+
+ private:
+  // WindowTargeter:
+  bool SubtreeShouldBeExploredForEvent(Window* window,
+                                       const ui::LocatedEvent& event) override {
+    return false;
+  }
+};
+
+// Verifies that an EventTargeter installed on an EventTarget can dictate
+// whether the target itself can process an event.
+TEST_F(WindowTargeterTest, TargeterChecksOwningEventTarget) {
+  test::TestWindowDelegate delegate;
+  scoped_ptr<Window> child(CreateNormalWindow(1, root_window(), &delegate));
+
+  ui::EventTarget* root_target = root_window();
+  ui::EventTargeter* targeter = root_target->GetEventTargeter();
+
+  ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
+                       gfx::Point(10, 10), ui::EventTimeForNow(), ui::EF_NONE,
+                       ui::EF_NONE);
+  EXPECT_EQ(child.get(), targeter->FindTargetForEvent(root_target, &mouse));
+
+  // Install an event targeter on |child| which always prevents the target from
+  // receiving event.
+  child->SetEventTargeter(
+      scoped_ptr<ui::EventTargeter>(new IgnoreWindowTargeter()));
+
+  ui::MouseEvent mouse2(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
+                        gfx::Point(10, 10), ui::EventTimeForNow(), ui::EF_NONE,
+                        ui::EF_NONE);
+  EXPECT_EQ(root_window(), targeter->FindTargetForEvent(root_target, &mouse2));
+}
+
 }  // namespace aura
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index 772b020..2beb0ea 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -13,6 +13,8 @@
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_targeter.h"
 #include "ui/aura/window_tree_host_observer.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/input_method_factory.h"
 #include "ui/base/view_prop.h"
 #include "ui/compositor/dip_util.h"
 #include "ui/compositor/layer.h"
@@ -41,6 +43,10 @@
 
 WindowTreeHost::~WindowTreeHost() {
   DCHECK(!compositor_) << "compositor must be destroyed before root window";
+  if (owned_input_method_) {
+    delete input_method_;
+    input_method_ = nullptr;
+  }
 }
 
 #if defined(OS_ANDROID)
@@ -50,7 +56,7 @@
   // adding the CHECK.
   // TODO(sky): decide if we want a factory.
   CHECK(false);
-  return NULL;
+  return nullptr;
 }
 #endif
 
@@ -172,6 +178,33 @@
   MoveCursorToInternal(root_location, host_location);
 }
 
+ui::InputMethod* WindowTreeHost::GetInputMethod() {
+  if (!input_method_) {
+    input_method_ =
+        ui::CreateInputMethod(this, GetAcceleratedWidget()).release();
+    // Makes sure the input method is focused by default when created, because
+    // some environment doesn't have activated/focused state in WindowTreeHost.
+    // TODO(shuchen): move this to DisplayController so it's only for Ash.
+    input_method_->OnFocus();
+    owned_input_method_ = true;
+  }
+  return input_method_;
+}
+
+void WindowTreeHost::SetSharedInputMethod(ui::InputMethod* input_method) {
+  DCHECK(!input_method_);
+  input_method_ = input_method;
+  owned_input_method_ = false;
+}
+
+bool WindowTreeHost::DispatchKeyEventPostIME(const ui::KeyEvent& event) {
+  ui::KeyEvent copied_event(event);
+  ui::EventDispatchDetails details =
+      event_processor()->OnEventFromSource(&copied_event);
+  DCHECK(!details.dispatcher_destroyed);
+  return copied_event.handled();
+}
+
 void WindowTreeHost::Show() {
   if (compositor())
     compositor()->SetVisible(true);
@@ -188,8 +221,10 @@
 // WindowTreeHost, protected:
 
 WindowTreeHost::WindowTreeHost()
-    : window_(new Window(NULL)),
-      last_cursor_(ui::kCursorNull) {
+    : window_(new Window(nullptr)),
+      last_cursor_(ui::kCursorNull),
+      input_method_(nullptr),
+      owned_input_method_(false) {
 }
 
 void WindowTreeHost::DestroyCompositor() {
@@ -198,7 +233,7 @@
 
 void WindowTreeHost::DestroyDispatcher() {
   delete window_;
-  window_ = NULL;
+  window_ = nullptr;
   dispatcher_.reset();
 
   // TODO(beng): this comment is no longer quite valid since this function
@@ -271,6 +306,24 @@
     capture_window->ReleaseCapture();
 }
 
+ui::EventProcessor* WindowTreeHost::GetEventProcessor() {
+  return event_processor();
+}
+
+ui::EventDispatchDetails WindowTreeHost::DeliverEventToProcessor(
+    ui::Event* event) {
+  if (event->IsKeyEvent()) {
+    if (GetInputMethod()->DispatchKeyEvent(
+            *static_cast<ui::KeyEvent*>(event))) {
+      event->StopPropagation();
+      // TODO(shuchen): pass around the EventDispatchDetails from
+      // DispatchKeyEventPostIME instead of creating new from here.
+      return ui::EventDispatchDetails();
+    }
+  }
+  return ui::EventSource::DeliverEventToProcessor(event);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // WindowTreeHost, private:
 
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h
index 27b104c0..0460c065 100644
--- a/ui/aura/window_tree_host.h
+++ b/ui/aura/window_tree_host.h
@@ -11,6 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "ui/aura/aura_export.h"
 #include "ui/base/cursor/cursor.h"
+#include "ui/base/ime/input_method_delegate.h"
 #include "ui/events/event_source.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -25,6 +26,7 @@
 namespace ui {
 class Compositor;
 class EventProcessor;
+class InputMethod;
 class ViewProp;
 }
 
@@ -39,9 +41,10 @@
 // WindowTreeHost bridges between a native window and the embedded RootWindow.
 // It provides the accelerated widget and maps events from the native os to
 // aura.
-class AURA_EXPORT WindowTreeHost {
+class AURA_EXPORT WindowTreeHost : public ui::internal::InputMethodDelegate,
+                                   public ui::EventSource {
  public:
-  virtual ~WindowTreeHost();
+  ~WindowTreeHost() override;
 
   // Creates a new WindowTreeHost. The caller owns the returned value.
   static WindowTreeHost* Create(const gfx::Rect& bounds);
@@ -116,6 +119,33 @@
 
   gfx::NativeCursor last_cursor() const { return last_cursor_; }
 
+  // Gets the InputMethod instance, if NULL, creates & owns it.
+  ui::InputMethod* GetInputMethod();
+
+  // Sets a shared unowned InputMethod. This is used when there is a singleton
+  // InputMethod shared between multiple WindowTreeHost instances.
+  //
+  // This is used for Ash only. There are 2 reasons:
+  // 1) ChromeOS virtual keyboard needs to receive ShowImeIfNeeded notification
+  // from InputMethod. Multiple InputMethod instances makes it hard to
+  // register/unregister the observer for that notification.
+  // 2) For Ozone, there is no native focus state for the root window and
+  // WindowTreeHost. See DrmWindowHost::CanDispatchEvent, the key events always
+  // goes to the primary WindowTreeHost. And after InputMethod processed the key
+  // event and continue dispatching it, WindowTargeter::FindTargetForEvent may
+  // re-dispatch it to a different WindowTreeHost. So the singleton InputMethod
+  // can make sure the correct InputMethod instance processes the key event no
+  // matter which WindowTreeHost is the target for event. Please refer to the
+  // test: ExtendedDesktopTest.KeyEventsOnLockScreen.
+  //
+  // TODO(shuchen): remove this method after above reasons become invalid.
+  // A possible solution is to make sure DrmWindowHost can find the correct
+  // WindowTreeHost to dispatch events.
+  void SetSharedInputMethod(ui::InputMethod* input_method);
+
+  // Overridden from ui::internal::InputMethodDelegate:
+  bool DispatchKeyEventPostIME(const ui::KeyEvent& event) override;
+
   // Returns the EventSource responsible for dispatching events to the window
   // tree.
   virtual ui::EventSource* GetEventSource() = 0;
@@ -172,6 +202,10 @@
   // Hides the WindowTreeHost.
   virtual void HideImpl() = 0;
 
+  // Overridden from ui::EventSource:
+  ui::EventProcessor* GetEventProcessor() override;
+  ui::EventDispatchDetails DeliverEventToProcessor(ui::Event* event) override;
+
  private:
   friend class test::WindowTreeHostTestApi;
 
@@ -198,6 +232,14 @@
 
   scoped_ptr<ui::ViewProp> prop_;
 
+  // The InputMethod instance used to process key events.
+  // If owned it, it is created in GetInputMethod() method;
+  // If not owned it, it is passed in through SetSharedInputMethod() method.
+  ui::InputMethod* input_method_;
+
+  // Whether the InputMethod instance is owned by this WindowTreeHost.
+  bool owned_input_method_;
+
   DISALLOW_COPY_AND_ASSIGN(WindowTreeHost);
 };
 
diff --git a/ui/aura/window_tree_host_ozone.cc b/ui/aura/window_tree_host_ozone.cc
index a4287f8..fd2854c6 100644
--- a/ui/aura/window_tree_host_ozone.cc
+++ b/ui/aura/window_tree_host_ozone.cc
@@ -109,10 +109,6 @@
 void WindowTreeHostOzone::OnActivationChanged(bool active) {
 }
 
-ui::EventProcessor* WindowTreeHostOzone::GetEventProcessor() {
-  return dispatcher();
-}
-
 // static
 WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
   return new WindowTreeHostOzone(bounds);
diff --git a/ui/aura/window_tree_host_ozone.h b/ui/aura/window_tree_host_ozone.h
index e771109..67f01d99 100644
--- a/ui/aura/window_tree_host_ozone.h
+++ b/ui/aura/window_tree_host_ozone.h
@@ -7,7 +7,6 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "ui/aura/window_tree_host.h"
-#include "ui/events/event_source.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/platform_window/platform_window_delegate.h"
 
@@ -18,7 +17,6 @@
 namespace aura {
 
 class AURA_EXPORT WindowTreeHostOzone : public WindowTreeHost,
-                                        public ui::EventSource,
                                         public ui::PlatformWindowDelegate {
  public:
   explicit WindowTreeHostOzone(const gfx::Rect& bounds);
@@ -53,9 +51,6 @@
   void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override;
   void OnActivationChanged(bool active) override;
 
-  // ui::EventSource overrides.
-  ui::EventProcessor* GetEventProcessor() override;
-
   // Platform-specific part of this WindowTreeHost.
   scoped_ptr<ui::PlatformWindow> platform_window_;
 
diff --git a/ui/aura/window_tree_host_win.cc b/ui/aura/window_tree_host_win.cc
index 5e188333..3252093 100644
--- a/ui/aura/window_tree_host_win.cc
+++ b/ui/aura/window_tree_host_win.cc
@@ -112,10 +112,6 @@
   NOTIMPLEMENTED();
 }
 
-ui::EventProcessor* WindowTreeHostWin::GetEventProcessor() {
-  return dispatcher();
-}
-
 void WindowTreeHostWin::OnBoundsChanged(const gfx::Rect& new_bounds) {
   gfx::Rect old_bounds = bounds_;
   bounds_ = new_bounds;
diff --git a/ui/aura/window_tree_host_win.h b/ui/aura/window_tree_host_win.h
index f0fc384c..6d0054c 100644
--- a/ui/aura/window_tree_host_win.h
+++ b/ui/aura/window_tree_host_win.h
@@ -9,7 +9,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "ui/aura/aura_export.h"
 #include "ui/aura/window_tree_host.h"
-#include "ui/events/event_source.h"
 #include "ui/platform_window/platform_window.h"
 #include "ui/platform_window/platform_window_delegate.h"
 
@@ -17,7 +16,6 @@
 
 class AURA_EXPORT WindowTreeHostWin
     : public WindowTreeHost,
-      public ui::EventSource,
       public NON_EXPORTED_BASE(ui::PlatformWindowDelegate) {
  public:
   explicit WindowTreeHostWin(const gfx::Rect& bounds);
@@ -37,9 +35,6 @@
   void MoveCursorToNative(const gfx::Point& location) override;
   void OnCursorVisibilityChangedNative(bool show) override;
 
-  // ui::EventSource:
-  ui::EventProcessor* GetEventProcessor() override;
-
  protected:
   gfx::AcceleratedWidget hwnd() const { return widget_; }
 
diff --git a/ui/aura/window_tree_host_x11.cc b/ui/aura/window_tree_host_x11.cc
index 9eb85929..65fbc49a 100644
--- a/ui/aura/window_tree_host_x11.cc
+++ b/ui/aura/window_tree_host_x11.cc
@@ -564,10 +564,6 @@
 void WindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
 }
 
-ui::EventProcessor* WindowTreeHostX11::GetEventProcessor() {
-  return dispatcher();
-}
-
 void WindowTreeHostX11::DispatchXI2Event(const base::NativeEvent& event) {
   ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
   XEvent* xev = event;
diff --git a/ui/aura/window_tree_host_x11.h b/ui/aura/window_tree_host_x11.h
index 56b900d..bc994a7e 100644
--- a/ui/aura/window_tree_host_x11.h
+++ b/ui/aura/window_tree_host_x11.h
@@ -8,7 +8,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "ui/aura/aura_export.h"
 #include "ui/aura/window_tree_host.h"
-#include "ui/events/event_source.h"
 #include "ui/events/platform/platform_event_dispatcher.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
@@ -30,7 +29,6 @@
 }
 
 class AURA_EXPORT WindowTreeHostX11 : public WindowTreeHost,
-                                      public ui::EventSource,
                                       public ui::PlatformEventDispatcher {
 
  public:
@@ -55,9 +53,6 @@
   void MoveCursorToNative(const gfx::Point& location) override;
   void OnCursorVisibilityChangedNative(bool show) override;
 
-  // ui::EventSource overrides.
-  ui::EventProcessor* GetEventProcessor() override;
-
  protected:
   // Called when X Configure Notify event is recevied.
   virtual void OnConfigureNotify();
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index e869be2..bb9cf41 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -402,7 +402,7 @@
     sources -= [ "idle/idle_linux.cc" ]
   }
 
-  if (is_chromeos || (use_aura && is_linux && !use_x11)) {
+  if (is_chromeos || (use_aura && ((is_linux && !use_x11) || is_android))) {
     sources += [
       "dragdrop/os_exchange_data_provider_aura.cc",
       "dragdrop/os_exchange_data_provider_aura.h",
@@ -498,16 +498,11 @@
     ]
   }
 
-  if (!toolkit_views) {
+  if (!toolkit_views && !use_aura) {
     sources -= [
       "dragdrop/drag_drop_types.h",
       "dragdrop/drop_target_event.cc",
       "dragdrop/drop_target_event.h",
-    ]
-  }
-
-  if (!toolkit_views && !use_aura) {
-    sources -= [
       "dragdrop/os_exchange_data.cc",
       "dragdrop/os_exchange_data.h",
       "nine_image_painter_factory.cc",
@@ -516,7 +511,18 @@
   }
 
   if (is_android) {
+    deps += [
+      "//cc",
+      ":ui_base_jni_headers",
+      "//ui/android:ui_java",
+    ]
+
+    libs += [ "jnigraphics" ]
+  }
+
+  if (is_android && !use_aura) {
     sources -= [
+      "cursor/cursor_android.cc",
       "cursor/image_cursors.cc",
       "cursor/image_cursors.h",
       "default_theme_provider.cc",
@@ -529,26 +535,14 @@
       "touch/touch_editing_controller.cc",
       "ui_base_types.cc",
     ]
-
-    deps += [
-      "//cc",
-      ":ui_base_jni_headers",
-      "//ui/android:ui_java",
-    ]
-
-    libs += [ "jnigraphics" ]
-  }
-
-  if (is_android && !use_aura) {
-    sources -= [ "cursor/cursor_android.cc" ]
   }
 
   # Aura clipboard.
   if (use_aura) {
     if (use_x11) {
       sources += [ "clipboard/clipboard_aurax11.cc" ]
-    } else if (!is_win) {
-      # This file is used for all non-X11, non-Windows aura Builds.
+    } else if (!is_win && !is_android) {
+      # This file is used for all non-X11, non-Windows, non-Android aura Builds.
       sources += [ "clipboard/clipboard_aura.cc" ]
     }
   }
@@ -575,6 +569,8 @@
     "test/ui_controls_internal_win.h",
     "test/ui_controls_mac.mm",
     "test/ui_controls_win.cc",
+    "test/windowed_nsnotification_observer.h",
+    "test/windowed_nsnotification_observer.mm",
   ]
 
   public_deps = [
diff --git a/ui/base/accelerators/accelerator_manager_unittest.cc b/ui/base/accelerators/accelerator_manager_unittest.cc
index 1c3402d7..1f8db027 100644
--- a/ui/base/accelerators/accelerator_manager_unittest.cc
+++ b/ui/base/accelerators/accelerator_manager_unittest.cc
@@ -151,12 +151,8 @@
     // The non-registered accelerators are not processed.
     accelerator.set_type(ET_UNKNOWN);
     EXPECT_FALSE(manager_.Process(accelerator)) << text;  // different type
-    accelerator.set_type(ET_TRANSLATED_KEY_PRESS);
-    EXPECT_FALSE(manager_.Process(accelerator)) << text;  // different type
     accelerator.set_type(ET_KEY_RELEASED);
     EXPECT_FALSE(manager_.Process(accelerator)) << text;  // different type
-    accelerator.set_type(ET_TRANSLATED_KEY_RELEASE);
-    EXPECT_FALSE(manager_.Process(accelerator)) << text;  // different type
 
     EXPECT_FALSE(manager_.Process(GetAccelerator(VKEY_UNKNOWN, mask)))
         << text;  // different vkey
diff --git a/ui/base/cocoa/OWNERS b/ui/base/cocoa/OWNERS
index d73ec1b5..f5de6bf4 100644
--- a/ui/base/cocoa/OWNERS
+++ b/ui/base/cocoa/OWNERS
@@ -1,3 +1,4 @@
 avi@chromium.org
 rsesek@chromium.org
+tapted@chromium.org
 thakis@chromium.org
diff --git a/ui/base/cocoa/tracking_area.h b/ui/base/cocoa/tracking_area.h
index df37686..361fd6d 100644
--- a/ui/base/cocoa/tracking_area.h
+++ b/ui/base/cocoa/tracking_area.h
@@ -22,7 +22,7 @@
 
 // Designated initializer. Forwards all arguments to the superclass, but wraps
 // |owner| in a proxy object.
-- (id)initWithRect:(NSRect)rect
+- (instancetype)initWithRect:(NSRect)rect
            options:(NSTrackingAreaOptions)options
              owner:(id)owner
           userInfo:(NSDictionary*)userInfo;
diff --git a/ui/base/cocoa/tracking_area.mm b/ui/base/cocoa/tracking_area.mm
index 5a203da6..e68fb5b 100644
--- a/ui/base/cocoa/tracking_area.mm
+++ b/ui/base/cocoa/tracking_area.mm
@@ -23,14 +23,14 @@
   Class ownerClass_;
 }
 @property(nonatomic, assign) BOOL alive;
-- (id)initWithOwner:(id)owner;
+- (instancetype)initWithOwner:(id)owner;
 @end
 
 @implementation CrTrackingAreaOwnerProxy
 
 @synthesize alive = alive_;
 
-- (id)initWithOwner:(id)owner {
+- (instancetype)initWithOwner:(id)owner {
   if ((self = [super init])) {
     alive_ = YES;
     owner_ = owner;
@@ -67,7 +67,7 @@
 
 @implementation CrTrackingArea
 
-- (id)initWithRect:(NSRect)rect
+- (instancetype)initWithRect:(NSRect)rect
            options:(NSTrackingAreaOptions)options
              owner:(id)owner
           userInfo:(NSDictionary*)userInfo{
diff --git a/ui/base/ime/chromeos/component_extension_ime_manager.cc b/ui/base/ime/chromeos/component_extension_ime_manager.cc
index 5ed6933..0f3d95b 100644
--- a/ui/base/ime/chromeos/component_extension_ime_manager.cc
+++ b/ui/base/ime/chromeos/component_extension_ime_manager.cc
@@ -65,12 +65,12 @@
 int GetInputMethodCategory(const std::string& id) {
   const std::string engine_id =
       chromeos::extension_ime_util::GetComponentIDByInputMethodID(id);
-  if (StartsWithASCII(engine_id, "xkb:", true))
+  if (base::StartsWithASCII(engine_id, "xkb:", true))
     return 0;
-  if (StartsWithASCII(engine_id, "vkd_", true))
+  if (base::StartsWithASCII(engine_id, "vkd_", true))
     return 1;
   if (engine_id.find("-t-i0-") != std::string::npos &&
-      !StartsWithASCII(engine_id, "zh-", true)) {
+      !base::StartsWithASCII(engine_id, "zh-", true)) {
     return 2;
   }
   return 3;
diff --git a/ui/base/ime/chromeos/extension_ime_util.cc b/ui/base/ime/chromeos/extension_ime_util.cc
index 84a111c..f6960d4 100644
--- a/ui/base/ime/chromeos/extension_ime_util.cc
+++ b/ui/base/ime/chromeos/extension_ime_util.cc
@@ -61,28 +61,28 @@
 }
 
 std::string GetInputMethodIDByEngineID(const std::string& engine_id) {
-  if (StartsWithASCII(engine_id, kComponentExtensionIMEPrefix, true) ||
-      StartsWithASCII(engine_id, kExtensionIMEPrefix, true)) {
+  if (base::StartsWithASCII(engine_id, kComponentExtensionIMEPrefix, true) ||
+      base::StartsWithASCII(engine_id, kExtensionIMEPrefix, true)) {
     return engine_id;
   }
-  if (StartsWithASCII(engine_id, "xkb:", true))
+  if (base::StartsWithASCII(engine_id, "xkb:", true))
     return GetComponentInputMethodID(kXkbExtensionId, engine_id);
-  if (StartsWithASCII(engine_id, "vkd_", true))
+  if (base::StartsWithASCII(engine_id, "vkd_", true))
     return GetComponentInputMethodID(kM17nExtensionId, engine_id);
-  if (StartsWithASCII(engine_id, "nacl_mozc_", true))
+  if (base::StartsWithASCII(engine_id, "nacl_mozc_", true))
     return GetComponentInputMethodID(kMozcExtensionId, engine_id);
-  if (StartsWithASCII(engine_id, "hangul_", true))
+  if (base::StartsWithASCII(engine_id, "hangul_", true))
     return GetComponentInputMethodID(kHangulExtensionId, engine_id);
 
-  if (StartsWithASCII(engine_id, "zh-", true) &&
+  if (base::StartsWithASCII(engine_id, "zh-", true) &&
       engine_id.find("pinyin") != std::string::npos) {
     return GetComponentInputMethodID(kChinesePinyinExtensionId, engine_id);
   }
-  if (StartsWithASCII(engine_id, "zh-", true) &&
+  if (base::StartsWithASCII(engine_id, "zh-", true) &&
       engine_id.find("zhuyin") != std::string::npos) {
     return GetComponentInputMethodID(kChineseZhuyinExtensionId, engine_id);
   }
-  if (StartsWithASCII(engine_id, "zh-", true) &&
+  if (base::StartsWithASCII(engine_id, "zh-", true) &&
       engine_id.find("cangjie") != std::string::npos) {
     return GetComponentInputMethodID(kChineseCangjieExtensionId, engine_id);
   }
@@ -93,32 +93,30 @@
 }
 
 bool IsExtensionIME(const std::string& input_method_id) {
-  return StartsWithASCII(input_method_id,
-                         kExtensionIMEPrefix,
-                         true /* Case sensitive */) &&
-      input_method_id.size() > kExtensionIMEPrefixLength +
-          kExtensionIdLength;
+  return base::StartsWithASCII(input_method_id, kExtensionIMEPrefix,
+                               true /* Case sensitive */) &&
+         input_method_id.size() >
+             kExtensionIMEPrefixLength + kExtensionIdLength;
 }
 
 bool IsComponentExtensionIME(const std::string& input_method_id) {
-  return StartsWithASCII(input_method_id,
-                         kComponentExtensionIMEPrefix,
-                         true /* Case sensitive */) &&
-      input_method_id.size() > kComponentExtensionIMEPrefixLength +
-          kExtensionIdLength;
+  return base::StartsWithASCII(input_method_id, kComponentExtensionIMEPrefix,
+                               true /* Case sensitive */) &&
+         input_method_id.size() >
+             kComponentExtensionIMEPrefixLength + kExtensionIdLength;
 }
 
 bool IsMemberOfExtension(const std::string& input_method_id,
                          const std::string& extension_id) {
-  return StartsWithASCII(input_method_id,
-                         kExtensionIMEPrefix + extension_id,
-                         true /* Case sensitive */);
+  return base::StartsWithASCII(input_method_id,
+                               kExtensionIMEPrefix + extension_id,
+                               true /* Case sensitive */);
 }
 
 bool IsKeyboardLayoutExtension(const std::string& input_method_id) {
   if (IsComponentExtensionIME(input_method_id))
-    return StartsWithASCII(GetComponentIDByInputMethodID(input_method_id),
-                           "xkb:", true);
+    return base::StartsWithASCII(GetComponentIDByInputMethodID(input_method_id),
+                                 "xkb:", true);
   return false;
 }
 
diff --git a/ui/base/ime/chromeos/input_method_descriptor.cc b/ui/base/ime/chromeos/input_method_descriptor.cc
index 5bdf592..19d6cca 100644
--- a/ui/base/ime/chromeos/input_method_descriptor.cc
+++ b/ui/base/ime/chromeos/input_method_descriptor.cc
@@ -44,10 +44,12 @@
   // If indicator is empty, use the first two character in its preferred
   // keyboard layout or language code.
   if (indicator_.empty()) {
-    if (extension_ime_util::IsKeyboardLayoutExtension(id_))
-      return StringToUpperASCII(GetPreferredKeyboardLayout().substr(0, 2));
+    if (extension_ime_util::IsKeyboardLayoutExtension(id_)) {
+      return base::StringToUpperASCII(
+          GetPreferredKeyboardLayout().substr(0, 2));
+    }
     DCHECK(language_codes_.size() > 0);
-    return StringToUpperASCII(language_codes_[0].substr(0, 2));
+    return base::StringToUpperASCII(language_codes_[0].substr(0, 2));
   }
   return indicator_;
 }
diff --git a/ui/base/ime/input_method_chromeos.cc b/ui/base/ime/input_method_chromeos.cc
index e6491e3..6763262ec 100644
--- a/ui/base/ime/input_method_chromeos.cc
+++ b/ui/base/ime/input_method_chromeos.cc
@@ -50,7 +50,8 @@
   // We are dead, so we need to ask the client to stop relying on us.
   OnInputMethodChanged();
 
-  chromeos::IMEBridge::Get()->SetInputContextHandler(NULL);
+  if (chromeos::IMEBridge::Get())
+    chromeos::IMEBridge::Get()->SetInputContextHandler(NULL);
 }
 
 void InputMethodChromeOS::OnFocus() {
@@ -92,7 +93,7 @@
 }
 
 bool InputMethodChromeOS::DispatchKeyEvent(const ui::KeyEvent& event) {
-  DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED);
+  DCHECK(event.IsKeyEvent());
   DCHECK(system_toplevel_window_focused());
 
   // For linux_chromeos, the ime keyboard cannot track the caps lock state by
@@ -112,7 +113,6 @@
     }
   }
 
-  handling_key_event_ = true;
   // If |context_| is not usable, then we can only dispatch the key event as is.
   // We only dispatch the key event to input method when the |context_| is an
   // normal input field (not a password field).
@@ -133,6 +133,7 @@
     return true;
   }
 
+  handling_key_event_ = true;
   if (GetEngine()->IsInterestedInKeyEvent()) {
     GetEngine()->ProcessKeyEvent(
         event,
diff --git a/ui/base/ime/input_method_factory.cc b/ui/base/ime/input_method_factory.cc
index c80e75a3..0076083 100644
--- a/ui/base/ime/input_method_factory.cc
+++ b/ui/base/ime/input_method_factory.cc
@@ -14,7 +14,8 @@
 #include "ui/base/ime/remote_input_method_win.h"
 #elif defined(OS_MACOSX)
 #include "ui/base/ime/input_method_mac.h"
-#elif defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#elif defined(USE_AURA) && defined(OS_LINUX) && defined(USE_X11) && \
+      !defined(OS_CHROMEOS)
 #include "ui/base/ime/input_method_auralinux.h"
 #else
 #include "ui/base/ime/input_method_minimal.h"
@@ -47,7 +48,8 @@
   return make_scoped_ptr(new InputMethodWin(delegate, widget));
 #elif defined(OS_MACOSX)
   return make_scoped_ptr(new InputMethodMac(delegate));
-#elif defined(USE_AURA) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#elif defined(USE_AURA) && defined(OS_LINUX) && defined(USE_X11) && \
+      !defined(OS_CHROMEOS)
   return make_scoped_ptr(new InputMethodAuraLinux(delegate));
 #else
   return make_scoped_ptr(new InputMethodMinimal(delegate));
diff --git a/ui/base/ime/mock_input_method.cc b/ui/base/ime/mock_input_method.cc
index 1ea1203..6a93643b 100644
--- a/ui/base/ime/mock_input_method.cc
+++ b/ui/base/ime/mock_input_method.cc
@@ -4,19 +4,24 @@
 
 #include "ui/base/ime/mock_input_method.h"
 
+#include "ui/base/ime/input_method_delegate.h"
 #include "ui/base/ime/text_input_focus_manager.h"
 #include "ui/base/ui_base_switches_util.h"
+#include "ui/events/event.h"
 
 namespace ui {
 
 MockInputMethod::MockInputMethod(internal::InputMethodDelegate* delegate)
-    : text_input_client_(NULL) {
+    : text_input_client_(NULL), delegate_(delegate) {
 }
 
 MockInputMethod::~MockInputMethod() {
+  FOR_EACH_OBSERVER(InputMethodObserver, observer_list_,
+                    OnInputMethodDestroyed(this));
 }
 
 void MockInputMethod::SetDelegate(internal::InputMethodDelegate* delegate) {
+  delegate_ = delegate;
 }
 
 void MockInputMethod::SetFocusedTextInputClient(TextInputClient* client) {
@@ -44,7 +49,7 @@
 }
 
 bool MockInputMethod::DispatchKeyEvent(const ui::KeyEvent& event) {
-  return false;
+  return delegate_->DispatchKeyEventPostIME(event);
 }
 
 void MockInputMethod::OnFocus() {
diff --git a/ui/base/ime/mock_input_method.h b/ui/base/ime/mock_input_method.h
index 305a80f..d91757c 100644
--- a/ui/base/ime/mock_input_method.h
+++ b/ui/base/ime/mock_input_method.h
@@ -57,6 +57,7 @@
  private:
   TextInputClient* text_input_client_;
   base::ObserverList<InputMethodObserver> observer_list_;
+  internal::InputMethodDelegate* delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(MockInputMethod);
 };
diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc
index 23ca7ce1..426c8b5 100644
--- a/ui/base/l10n/l10n_util.cc
+++ b/ui/base/l10n/l10n_util.cc
@@ -201,7 +201,7 @@
   };
 
   // Skip all the es_Foo other than es_419 for now.
-  if (StartsWithASCII(locale_name, "es_", false))
+  if (base::StartsWithASCII(locale_name, "es_", false))
     return !EndsWith(locale_name, "419", true);
 
   for (size_t i = 0; i < arraysize(kDuplicateNames); ++i) {
@@ -288,9 +288,9 @@
       std::replace(locale_name.begin(), locale_name.end(), '_', '-');
 
       // Map the Chinese locale names over to zh-CN and zh-TW.
-      if (LowerCaseEqualsASCII(locale_name, "zh-hans")) {
+      if (base::LowerCaseEqualsASCII(locale_name, "zh-hans")) {
         locale_name = "zh-CN";
-      } else if (LowerCaseEqualsASCII(locale_name, "zh-hant")) {
+      } else if (base::LowerCaseEqualsASCII(locale_name, "zh-hant")) {
         locale_name = "zh-TW";
       }
       locales->push_back(locale_name);
@@ -341,26 +341,26 @@
     std::string tmp_locale(lang);
     // Map es-RR other than es-ES to es-419 (Chrome's Latin American
     // Spanish locale).
-    if (LowerCaseEqualsASCII(lang, "es") &&
-        !LowerCaseEqualsASCII(region, "es")) {
+    if (base::LowerCaseEqualsASCII(lang, "es") &&
+        !base::LowerCaseEqualsASCII(region, "es")) {
       tmp_locale.append("-419");
-    } else if (LowerCaseEqualsASCII(lang, "zh")) {
+    } else if (base::LowerCaseEqualsASCII(lang, "zh")) {
       // Map zh-HK and zh-MO to zh-TW. Otherwise, zh-FOO is mapped to zh-CN.
-      if (LowerCaseEqualsASCII(region, "hk") ||
-          LowerCaseEqualsASCII(region, "mo")) { // Macao
+      if (base::LowerCaseEqualsASCII(region, "hk") ||
+          base::LowerCaseEqualsASCII(region, "mo")) {  // Macao
         tmp_locale.append("-TW");
       } else {
         tmp_locale.append("-CN");
       }
-    } else if (LowerCaseEqualsASCII(lang, "en")) {
+    } else if (base::LowerCaseEqualsASCII(lang, "en")) {
       // Map Australian, Canadian, New Zealand and South African English
       // to British English for now.
       // TODO(jungshik): en-CA may have to change sides once
       // we have OS locale separate from app locale (Chrome's UI language).
-      if (LowerCaseEqualsASCII(region, "au") ||
-          LowerCaseEqualsASCII(region, "ca") ||
-          LowerCaseEqualsASCII(region, "nz") ||
-          LowerCaseEqualsASCII(region, "za")) {
+      if (base::LowerCaseEqualsASCII(region, "au") ||
+          base::LowerCaseEqualsASCII(region, "ca") ||
+          base::LowerCaseEqualsASCII(region, "nz") ||
+          base::LowerCaseEqualsASCII(region, "za")) {
         tmp_locale.append("-GB");
       } else {
         tmp_locale.append("-US");
@@ -384,7 +384,7 @@
   };
 
   for (size_t i = 0; i < arraysize(alias_map); ++i) {
-    if (LowerCaseEqualsASCII(lang, alias_map[i].source)) {
+    if (base::LowerCaseEqualsASCII(lang, alias_map[i].source)) {
       std::string tmp_locale(alias_map[i].dest);
       if (IsLocaleAvailable(tmp_locale)) {
         resolved_locale->swap(tmp_locale);
@@ -539,7 +539,7 @@
   // zh-Hant because the current Android Java API doesn't support scripts.
   // TODO(wangxianzhu): remove the special handling of zh-Hans and zh-Hant once
   // Android Java API supports scripts.
-  if (!StartsWithASCII(locale_code, "zh-Han", true)) {
+  if (!base::StartsWithASCII(locale_code, "zh-Han", true)) {
     display_name = GetDisplayNameForLocale(locale_code, display_locale);
   } else
 #endif
diff --git a/ui/base/l10n/l10n_util_posix.cc b/ui/base/l10n/l10n_util_posix.cc
index 590cfb7..6415ff8 100644
--- a/ui/base/l10n/l10n_util_posix.cc
+++ b/ui/base/l10n/l10n_util_posix.cc
@@ -18,7 +18,7 @@
   // to return true.
   static const char kUnsupportedLocales[][3] = {"am", "sw"};
   for (size_t i = 0; i < arraysize(kUnsupportedLocales); ++i) {
-    if (LowerCaseEqualsASCII(locale, kUnsupportedLocales[i]))
+    if (base::LowerCaseEqualsASCII(locale, kUnsupportedLocales[i]))
       return false;
   }
   return true;
diff --git a/ui/base/l10n/l10n_util_win.cc b/ui/base/l10n/l10n_util_win.cc
index 4e2f7f4..bfe12a7 100644
--- a/ui/base/l10n/l10n_util_win.cc
+++ b/ui/base/l10n/l10n_util_win.cc
@@ -111,7 +111,8 @@
   // 'Abyssinica SIL' in the resource bundle to use in the UI. Check
   // for its presence to determine whether or not to support Amharic UI on XP.
   return (base::win::GetVersion() >= base::win::VERSION_VISTA ||
-      !LowerCaseEqualsASCII(locale, "am") || IsFontPresent(L"Abyssinica SIL"));
+      !base::LowerCaseEqualsASCII(locale, "am") ||
+      IsFontPresent(L"Abyssinica SIL"));
 }
 
 bool NeedOverrideDefaultUIFont(base::string16* override_font_family,
diff --git a/ui/base/models/table_model.cc b/ui/base/models/table_model.cc
index 4592bd7..b8b18ad0 100644
--- a/ui/base/models/table_model.cc
+++ b/ui/base/models/table_model.cc
@@ -20,7 +20,8 @@
       width(-1),
       percent(),
       min_visible_width(0),
-      sortable(false) {
+      sortable(false),
+      initial_sort_is_ascending(true) {
 }
 
 TableColumn::TableColumn(int id, Alignment alignment, int width, float percent)
@@ -30,7 +31,8 @@
       width(width),
       percent(percent),
       min_visible_width(0),
-      sortable(false) {
+      sortable(false),
+      initial_sort_is_ascending(true) {
 }
 
 // TableModel -----------------------------------------------------------------
diff --git a/ui/base/models/table_model.h b/ui/base/models/table_model.h
index 68cf202..16e68a9 100644
--- a/ui/base/models/table_model.h
+++ b/ui/base/models/table_model.h
@@ -125,12 +125,14 @@
   float percent;
 
   // The minimum width required for all items in this column
-  // (including the header)
-  // to be visible.
+  // (including the header) to be visible.
   int min_visible_width;
 
-  // Is this column sortable? Default is false
+  // Is this column sortable? Default is false.
   bool sortable;
+
+  // Determines what sort order to apply initially. Default is true.
+  bool initial_sort_is_ascending;
 };
 
 }  // namespace ui
diff --git a/ui/base/test/OWNERS b/ui/base/test/OWNERS
new file mode 100644
index 0000000..14acb3d
--- /dev/null
+++ b/ui/base/test/OWNERS
@@ -0,0 +1,7 @@
+sadrul@chromium.org
+sky@chromium.org
+
+# Mac stuff
+avi@chromium.org
+tapted@chromium.org
+thakis@chromium.org
diff --git a/ui/base/test/windowed_nsnotification_observer.h b/ui/base/test/windowed_nsnotification_observer.h
new file mode 100644
index 0000000..92b897a
--- /dev/null
+++ b/ui/base/test/windowed_nsnotification_observer.h
@@ -0,0 +1,40 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_BASE_TEST_WINDOWED_NSNOTIFICATION_OBSERVER_H_
+#define UI_BASE_TEST_WINDOWED_NSNOTIFICATION_OBSERVER_H_
+
+#import <Foundation/Foundation.h>
+
+#import "base/mac/scoped_nsobject.h"
+
+namespace base {
+class RunLoop;
+}
+
+// Like WindowedNotificationObserver in content/public/test/test_utils.h, this
+// starts watching for a notification upon construction and can wait until the
+// notification is observed. This guarantees that a notification fired between
+// calls to init and wait will be caught.
+@interface WindowedNSNotificationObserver : NSObject {
+ @private
+  base::scoped_nsobject<NSString> bundleId_;
+  BOOL notificationReceived_;
+  base::RunLoop* runLoop_;
+}
+
+// Watch for an NSNotification on the default notification center.
+- (id)initForNotification:(NSString*)name;
+
+// Watch for an NSNotification on the shared workspace notification center for
+// the
+// given application.
+- (id)initForWorkspaceNotification:(NSString*)name bundleId:(NSString*)bundleId;
+
+// Returns if the notification has been observed, or spins a RunLoop until it
+// is. Stops observing.
+- (void)wait;
+@end
+
+#endif  // UI_BASE_TEST_WINDOWED_NSNOTIFICATION_OBSERVER_H_
diff --git a/ui/base/test/windowed_nsnotification_observer.mm b/ui/base/test/windowed_nsnotification_observer.mm
new file mode 100644
index 0000000..02f45179
--- /dev/null
+++ b/ui/base/test/windowed_nsnotification_observer.mm
@@ -0,0 +1,67 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ui/base/test/windowed_nsnotification_observer.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/run_loop.h"
+
+@interface WindowedNSNotificationObserver ()
+- (void)onNotification:(NSNotification*)notification;
+@end
+
+@implementation WindowedNSNotificationObserver
+
+- (id)initForNotification:(NSString*)name {
+  if ((self = [super init])) {
+    [[NSNotificationCenter defaultCenter] addObserver:self
+                                             selector:@selector(onNotification:)
+                                                 name:name
+                                               object:nil];
+  }
+  return self;
+}
+
+- (id)initForWorkspaceNotification:(NSString*)name
+                          bundleId:(NSString*)bundleId {
+  if ((self = [super init])) {
+    bundleId_.reset([bundleId copy]);
+    [[[NSWorkspace sharedWorkspace] notificationCenter]
+        addObserver:self
+           selector:@selector(onNotification:)
+               name:name
+             object:nil];
+  }
+  return self;
+}
+
+- (void)onNotification:(NSNotification*)notification {
+  if (bundleId_) {
+    NSRunningApplication* application =
+        [[notification userInfo] objectForKey:NSWorkspaceApplicationKey];
+    if (![[application bundleIdentifier] isEqualToString:bundleId_])
+      return;
+
+    [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
+  } else {
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+  }
+
+  notificationReceived_ = YES;
+  if (runLoop_)
+    runLoop_->Quit();
+}
+
+- (void)wait {
+  if (notificationReceived_)
+    return;
+
+  base::RunLoop runLoop;
+  runLoop_ = &runLoop;
+  runLoop.Run();
+  runLoop_ = nullptr;
+}
+
+@end
diff --git a/ui/base/ui_base.gyp b/ui/base/ui_base.gyp
index 3ffa361..fd53083 100644
--- a/ui/base/ui_base.gyp
+++ b/ui/base/ui_base.gyp
@@ -675,6 +675,8 @@
             'ime/dummy_text_input_client.h',
             'test/nswindow_fullscreen_notification_waiter.h',
             'test/nswindow_fullscreen_notification_waiter.mm',
+            'test/windowed_nsnotification_observer.h',
+            'test/windowed_nsnotification_observer.mm',
           ],
         }],
         ['use_aura==1', {
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index 7c09a4d4..a8a3214 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -1251,7 +1251,7 @@
       return WM_FLUXBOX;
     if (name == "i3")
       return WM_I3;
-    if (StartsWithASCII(name, "IceWM", true))
+    if (base::StartsWithASCII(name, "IceWM", true))
       return WM_ICE_WM;
     if (name == "ion3")
       return WM_ION3;
diff --git a/ui/compositor/compositor_switches.cc b/ui/compositor/compositor_switches.cc
index a8cb801..e4cad588 100644
--- a/ui/compositor/compositor_switches.cc
+++ b/ui/compositor/compositor_switches.cc
@@ -20,7 +20,7 @@
 const char kUIEnableCompositorAnimationTimelines[] =
     "ui-enable-compositor-animation-timelines";
 
-const char kUIEnableImplSidePainting[] = "ui-enable-impl-side-painting";
+const char kUIDisableImplSidePainting[] = "ui-disable-impl-side-painting";
 
 const char kUIDisableSlimmingPaint[] = "ui-disable-slimming-paint";
 
@@ -35,7 +35,8 @@
 bool IsUIImplSidePaintingEnabled() {
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
-  return command_line.HasSwitch(switches::kUIEnableImplSidePainting);
+
+  return !command_line.HasSwitch(switches::kUIDisableImplSidePainting);
 }
 
 bool IsUIZeroCopyEnabled() {
diff --git a/ui/compositor/compositor_switches.h b/ui/compositor/compositor_switches.h
index 9bce2c7..b5e5bac 100644
--- a/ui/compositor/compositor_switches.h
+++ b/ui/compositor/compositor_switches.h
@@ -14,7 +14,7 @@
 COMPOSITOR_EXPORT extern const char kUIDisableSlimmingPaint[];
 COMPOSITOR_EXPORT extern const char kUIDisableThreadedCompositing[];
 COMPOSITOR_EXPORT extern const char kUIEnableCompositorAnimationTimelines[];
-COMPOSITOR_EXPORT extern const char kUIEnableImplSidePainting[];
+COMPOSITOR_EXPORT extern const char kUIDisableImplSidePainting[];
 COMPOSITOR_EXPORT extern const char kUIEnableZeroCopy[];
 COMPOSITOR_EXPORT extern const char kUIShowPaintRects[];
 
diff --git a/ui/compositor/test/in_process_context_provider.cc b/ui/compositor/test/in_process_context_provider.cc
index 4885c60..a29bb9d 100644
--- a/ui/compositor/test/in_process_context_provider.cc
+++ b/ui/compositor/test/in_process_context_provider.cc
@@ -189,13 +189,6 @@
   return &context_lock_;
 }
 
-bool InProcessContextProvider::IsContextLost() {
-  DCHECK(context_thread_checker_.CalledOnValidThread());
-
-  base::AutoLock lock(destroyed_lock_);
-  return destroyed_;
-}
-
 void InProcessContextProvider::VerifyContexts() {
 }
 
diff --git a/ui/compositor/test/in_process_context_provider.h b/ui/compositor/test/in_process_context_provider.h
index dbeb0f4b..4edc464 100644
--- a/ui/compositor/test/in_process_context_provider.h
+++ b/ui/compositor/test/in_process_context_provider.h
@@ -59,7 +59,6 @@
   void InvalidateGrContext(uint32_t state) override;
   void SetupLock() override;
   base::Lock* GetLock() override;
-  bool IsContextLost() override;
   void VerifyContexts() override;
   void DeleteCachedResources() override;
   bool DestroyedOnMainThread() override;
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index 4fe11f4..0add919 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -105,7 +105,6 @@
     "event_target.cc",
     "event_target.h",
     "event_target_iterator.h",
-    "event_targeter.cc",
     "event_targeter.h",
     "event_utils.cc",
     "event_utils.h",
@@ -254,6 +253,8 @@
     "test/test_event_processor.h",
     "test/test_event_target.cc",
     "test/test_event_target.h",
+    "test/test_event_targeter.cc",
+    "test/test_event_targeter.h",
   ]
 
   public_deps = [
diff --git a/ui/events/devices/device_util_linux.cc b/ui/events/devices/device_util_linux.cc
index 858ee84..e53a1e4 100644
--- a/ui/events/devices/device_util_linux.cc
+++ b/ui/events/devices/device_util_linux.cc
@@ -17,7 +17,7 @@
 InputDeviceType GetInputDeviceTypeFromPath(const base::FilePath& path) {
   DCHECK(!base::MessageLoopForUI::IsCurrent());
   std::string event_node = path.BaseName().value();
-  if (event_node.empty() || !StartsWithASCII(event_node, "event", false))
+  if (event_node.empty() || !base::StartsWithASCII(event_node, "event", false))
     return InputDeviceType::INPUT_DEVICE_UNKNOWN;
 
   // Find sysfs device path for this device.
diff --git a/ui/events/event.cc b/ui/events/event.cc
index f2d69056..953220d 100644
--- a/ui/events/event.cc
+++ b/ui/events/event.cc
@@ -56,8 +56,6 @@
     CASE_TYPE(ET_TOUCH_MOVED);
     CASE_TYPE(ET_TOUCH_CANCELLED);
     CASE_TYPE(ET_DROP_TARGET_EVENT);
-    CASE_TYPE(ET_TRANSLATED_KEY_PRESS);
-    CASE_TYPE(ET_TRANSLATED_KEY_RELEASE);
     CASE_TYPE(ET_GESTURE_SCROLL_BEGIN);
     CASE_TYPE(ET_GESTURE_SCROLL_END);
     CASE_TYPE(ET_GESTURE_SCROLL_UPDATE);
@@ -901,35 +899,6 @@
     set_flags(flags() & ~mask);
 }
 
-bool KeyEvent::IsTranslated() const {
-  switch (type()) {
-    case ET_KEY_PRESSED:
-    case ET_KEY_RELEASED:
-      return false;
-    case ET_TRANSLATED_KEY_PRESS:
-    case ET_TRANSLATED_KEY_RELEASE:
-      return true;
-    default:
-      NOTREACHED();
-      return false;
-  }
-}
-
-void KeyEvent::SetTranslated(bool translated) {
-  switch (type()) {
-    case ET_KEY_PRESSED:
-    case ET_TRANSLATED_KEY_PRESS:
-      SetType(translated ? ET_TRANSLATED_KEY_PRESS : ET_KEY_PRESSED);
-      break;
-    case ET_KEY_RELEASED:
-    case ET_TRANSLATED_KEY_RELEASE:
-      SetType(translated ? ET_TRANSLATED_KEY_RELEASE : ET_KEY_RELEASED);
-      break;
-    default:
-      NOTREACHED();
-  }
-}
-
 KeyboardCode KeyEvent::GetLocatedWindowsKeyboardCode() const {
   return NonLocatedToLocatedKeyboardCode(key_code_, code_);
 }
diff --git a/ui/events/event.h b/ui/events/event.h
index 30d6cb56..e1e4e8e 100644
--- a/ui/events/event.h
+++ b/ui/events/event.h
@@ -94,10 +94,7 @@
   bool IsRepeat() const { return (flags_ & EF_IS_REPEAT) != 0; }
 
   bool IsKeyEvent() const {
-    return type_ == ET_KEY_PRESSED ||
-           type_ == ET_KEY_RELEASED ||
-           type_ == ET_TRANSLATED_KEY_PRESS ||
-           type_ == ET_TRANSLATED_KEY_RELEASE;
+    return type_ == ET_KEY_PRESSED || type_ == ET_KEY_RELEASED;
   }
 
   bool IsMouseEvent() const {
@@ -602,8 +599,7 @@
 //
 // For a keystroke event,
 // -- is_char_ is false.
-// -- Event::type() can be any one of ET_KEY_PRESSED, ET_KEY_RELEASED,
-//    ET_TRANSLATED_KEY_PRESS, or ET_TRANSLATED_KEY_RELEASE.
+// -- Event::type() can be any one of ET_KEY_PRESSED, ET_KEY_RELEASED.
 // -- code_ and Event::flags() represent the physical key event.
 //    - code_ is a platform-independent representation of the physical key,
 //      based on DOM KeyboardEvent |code| values. It does not vary depending
@@ -744,12 +740,6 @@
   // (Native X11 event flags describe the state before the event.)
   void NormalizeFlags();
 
-  // Returns true if the key event has already been processed by an input method
-  // and there is no need to pass the key event to the input method again.
-  bool IsTranslated() const;
-  // Marks this key event as translated or not translated.
-  void SetTranslated(bool translated);
-
  protected:
   friend class KeyEventTestApi;
 
diff --git a/ui/events/event_constants.h b/ui/events/event_constants.h
index 05d98b43..44589ab7a 100644
--- a/ui/events/event_constants.h
+++ b/ui/events/event_constants.h
@@ -25,8 +25,6 @@
   ET_TOUCH_MOVED,
   ET_TOUCH_CANCELLED,
   ET_DROP_TARGET_EVENT,
-  ET_TRANSLATED_KEY_PRESS,
-  ET_TRANSLATED_KEY_RELEASE,
 
   // GestureEvent types
   ET_GESTURE_SCROLL_BEGIN,
diff --git a/ui/events/event_processor_unittest.cc b/ui/events/event_processor_unittest.cc
index 4bf4f0d..a0ab5b6 100644
--- a/ui/events/event_processor_unittest.cc
+++ b/ui/events/event_processor_unittest.cc
@@ -6,12 +6,14 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/event.h"
+#include "ui/events/event_target_iterator.h"
 #include "ui/events/event_targeter.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/test/events_test_utils.h"
 #include "ui/events/test/test_event_handler.h"
 #include "ui/events/test/test_event_processor.h"
 #include "ui/events/test/test_event_target.h"
+#include "ui/events/test/test_event_targeter.h"
 
 typedef std::vector<std::string> HandlerSequenceRecorder;
 
@@ -23,11 +25,13 @@
   EventProcessorTest() {}
   ~EventProcessorTest() override {}
 
+ protected:
   // testing::Test:
   void SetUp() override {
-    processor_.SetRoot(scoped_ptr<EventTarget>(new TestEventTarget()));
+    processor_.SetRoot(make_scoped_ptr(new TestEventTarget()));
     processor_.Reset();
-    root()->SetEventTargeter(make_scoped_ptr(new EventTargeter()));
+    root()->SetEventTargeter(
+        make_scoped_ptr(new TestEventTargeter(root(), false)));
   }
 
   TestEventTarget* root() {
@@ -42,7 +46,12 @@
     processor_.OnEventFromSource(event);
   }
 
- protected:
+  void SetTarget(TestEventTarget* target) {
+    static_cast<TestEventTargeter*>(root()->GetEventTargeter())
+        ->set_target(target);
+  }
+
+ private:
   TestEventProcessor processor_;
 
   DISALLOW_COPY_AND_ASSIGN(EventProcessorTest);
@@ -50,6 +59,9 @@
 
 TEST_F(EventProcessorTest, Basic) {
   scoped_ptr<TestEventTarget> child(new TestEventTarget());
+  child->SetEventTargeter(
+      make_scoped_ptr(new TestEventTargeter(child.get(), false)));
+  SetTarget(child.get());
   root()->AddChild(child.Pass());
 
   MouseEvent mouse(ET_MOUSE_MOVED, gfx::Point(10, 10), gfx::Point(10, 10),
@@ -58,121 +70,12 @@
   EXPECT_TRUE(root()->child_at(0)->DidReceiveEvent(ET_MOUSE_MOVED));
   EXPECT_FALSE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
 
+  SetTarget(root());
   root()->RemoveChild(root()->child_at(0));
   DispatchEvent(&mouse);
   EXPECT_TRUE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
 }
 
-template<typename T>
-class BoundsEventTargeter : public EventTargeter {
- public:
-  ~BoundsEventTargeter() override {}
-
- protected:
-  bool SubtreeShouldBeExploredForEvent(
-      EventTarget* target, const LocatedEvent& event) override {
-    T* t = static_cast<T*>(target);
-    return (t->bounds().Contains(event.location()));
-  }
-};
-
-class BoundsTestTarget : public TestEventTarget {
- public:
-  BoundsTestTarget() {}
-  ~BoundsTestTarget() override {}
-
-  void set_bounds(gfx::Rect rect) { bounds_ = rect; }
-  gfx::Rect bounds() const { return bounds_; }
-
-  static void ConvertPointToTarget(BoundsTestTarget* source,
-                                   BoundsTestTarget* target,
-                                   gfx::Point* location) {
-    gfx::Vector2d vector;
-    if (source->Contains(target)) {
-      for (; target && target != source;
-           target = static_cast<BoundsTestTarget*>(target->parent())) {
-        vector += target->bounds().OffsetFromOrigin();
-      }
-      *location -= vector;
-    } else if (target->Contains(source)) {
-      for (; source && source != target;
-           source = static_cast<BoundsTestTarget*>(source->parent())) {
-        vector += source->bounds().OffsetFromOrigin();
-      }
-      *location += vector;
-    } else {
-      NOTREACHED();
-    }
-  }
-
- private:
-  // EventTarget:
-  void ConvertEventToTarget(EventTarget* target, LocatedEvent* event) override {
-    event->ConvertLocationToTarget(this,
-                                   static_cast<BoundsTestTarget*>(target));
-  }
-
-  gfx::Rect bounds_;
-
-  DISALLOW_COPY_AND_ASSIGN(BoundsTestTarget);
-};
-
-TEST_F(EventProcessorTest, Bounds) {
-  scoped_ptr<BoundsTestTarget> parent(new BoundsTestTarget());
-  scoped_ptr<BoundsTestTarget> child(new BoundsTestTarget());
-  scoped_ptr<BoundsTestTarget> grandchild(new BoundsTestTarget());
-
-  parent->set_bounds(gfx::Rect(0, 0, 30, 30));
-  child->set_bounds(gfx::Rect(5, 5, 20, 20));
-  grandchild->set_bounds(gfx::Rect(5, 5, 5, 5));
-
-  child->AddChild(scoped_ptr<TestEventTarget>(grandchild.Pass()));
-  parent->AddChild(scoped_ptr<TestEventTarget>(child.Pass()));
-  root()->AddChild(scoped_ptr<TestEventTarget>(parent.Pass()));
-
-  ASSERT_EQ(1u, root()->child_count());
-  ASSERT_EQ(1u, root()->child_at(0)->child_count());
-  ASSERT_EQ(1u, root()->child_at(0)->child_at(0)->child_count());
-
-  TestEventTarget* parent_r = root()->child_at(0);
-  TestEventTarget* child_r = parent_r->child_at(0);
-  TestEventTarget* grandchild_r = child_r->child_at(0);
-
-  // Dispatch a mouse event that falls on the parent, but not on the child. When
-  // the default event-targeter used, the event will still reach |grandchild|,
-  // because the default targeter does not look at the bounds.
-  MouseEvent mouse(ET_MOUSE_MOVED, gfx::Point(1, 1), gfx::Point(1, 1),
-                   EventTimeForNow(), EF_NONE, EF_NONE);
-  DispatchEvent(&mouse);
-  EXPECT_FALSE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_FALSE(parent_r->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_FALSE(child_r->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_TRUE(grandchild_r->DidReceiveEvent(ET_MOUSE_MOVED));
-  grandchild_r->ResetReceivedEvents();
-
-  // Now install a targeter on the parent that looks at the bounds and makes
-  // sure the event reaches the target only if the location of the event within
-  // the bounds of the target.
-  MouseEvent mouse2(ET_MOUSE_MOVED, gfx::Point(1, 1), gfx::Point(1, 1),
-                    EventTimeForNow(), EF_NONE, EF_NONE);
-  parent_r->SetEventTargeter(scoped_ptr<EventTargeter>(
-      new BoundsEventTargeter<BoundsTestTarget>()));
-  DispatchEvent(&mouse2);
-  EXPECT_FALSE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_TRUE(parent_r->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_FALSE(child_r->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_FALSE(grandchild_r->DidReceiveEvent(ET_MOUSE_MOVED));
-  parent_r->ResetReceivedEvents();
-
-  MouseEvent second(ET_MOUSE_MOVED, gfx::Point(12, 12), gfx::Point(12, 12),
-                    EventTimeForNow(), EF_NONE, EF_NONE);
-  DispatchEvent(&second);
-  EXPECT_FALSE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_FALSE(parent_r->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_FALSE(child_r->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_TRUE(grandchild_r->DidReceiveEvent(ET_MOUSE_MOVED));
-}
-
 // ReDispatchEventHandler is used to receive mouse events and forward them
 // to a specified EventProcessor. Verifies that the event has the correct
 // target and phase both before and after the nested event processing. Also
@@ -216,14 +119,16 @@
 TEST_F(EventProcessorTest, NestedEventProcessing) {
   // Add one child to the default event processor used in this test suite.
   scoped_ptr<TestEventTarget> child(new TestEventTarget());
+  SetTarget(child.get());
   root()->AddChild(child.Pass());
 
   // Define a second root target and child.
   scoped_ptr<EventTarget> second_root_scoped(new TestEventTarget());
   TestEventTarget* second_root =
       static_cast<TestEventTarget*>(second_root_scoped.get());
-  second_root->SetEventTargeter(make_scoped_ptr(new EventTargeter()));
   scoped_ptr<TestEventTarget> second_child(new TestEventTarget());
+  second_root->SetEventTargeter(
+      make_scoped_ptr(new TestEventTargeter(second_child.get(), false)));
   second_root->AddChild(second_child.Pass());
 
   // Define a second event processor which owns the second root.
@@ -267,6 +172,7 @@
 TEST_F(EventProcessorTest, OnEventProcessingFinished) {
   scoped_ptr<TestEventTarget> child(new TestEventTarget());
   child->set_mark_events_as_handled(true);
+  SetTarget(child.get());
   root()->AddChild(child.Pass());
 
   // Dispatch a mouse event. We expect the event to be seen by the target,
@@ -286,6 +192,7 @@
 // OnEventProcessingFinished() is also called in either case.
 TEST_F(EventProcessorTest, OnEventProcessingStarted) {
   scoped_ptr<TestEventTarget> child(new TestEventTarget());
+  SetTarget(child.get());
   root()->AddChild(child.Pass());
 
   // Dispatch a mouse event. We expect the event to be seen by the target,
@@ -319,77 +226,15 @@
   EXPECT_EQ(1, processor()->num_times_processing_finished());
 }
 
-class IgnoreEventTargeter : public EventTargeter {
- public:
-  IgnoreEventTargeter() {}
-  ~IgnoreEventTargeter() override {}
-
- private:
-  // EventTargeter:
-  bool SubtreeShouldBeExploredForEvent(EventTarget* target,
-                                       const LocatedEvent& event) override {
-    return false;
-  }
-};
-
-// Verifies that the EventTargeter installed on an EventTarget can dictate
-// whether the target itself can process an event.
-TEST_F(EventProcessorTest, TargeterChecksOwningEventTarget) {
-  scoped_ptr<TestEventTarget> child(new TestEventTarget());
-  root()->AddChild(child.Pass());
-
-  MouseEvent mouse(ET_MOUSE_MOVED, gfx::Point(10, 10), gfx::Point(10, 10),
-                   EventTimeForNow(), EF_NONE, EF_NONE);
-  DispatchEvent(&mouse);
-  EXPECT_TRUE(root()->child_at(0)->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_FALSE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
-  root()->child_at(0)->ResetReceivedEvents();
-
-  // Install an event handler on |child| which always prevents the target from
-  // receiving event.
-  root()->child_at(0)->SetEventTargeter(
-      scoped_ptr<EventTargeter>(new IgnoreEventTargeter()));
-  MouseEvent mouse2(ET_MOUSE_MOVED, gfx::Point(10, 10), gfx::Point(10, 10),
-                    EventTimeForNow(), EF_NONE, EF_NONE);
-  DispatchEvent(&mouse2);
-  EXPECT_FALSE(root()->child_at(0)->DidReceiveEvent(ET_MOUSE_MOVED));
-  EXPECT_TRUE(root()->DidReceiveEvent(ET_MOUSE_MOVED));
-}
-
-// An EventTargeter which is used to allow a bubbling behaviour in event
-// dispatch: if an event is not handled after being dispatched to its
-// initial target, the event is dispatched to the next-best target as
-// specified by FindNextBestTarget().
-class BubblingEventTargeter : public EventTargeter {
- public:
-  explicit BubblingEventTargeter(TestEventTarget* initial_target)
-    : initial_target_(initial_target) {}
-  ~BubblingEventTargeter() override {}
-
- private:
-  // EventTargeter:
-  EventTarget* FindTargetForEvent(EventTarget* root, Event* event) override {
-    return initial_target_;
-  }
-
-  EventTarget* FindNextBestTarget(EventTarget* previous_target,
-                                  Event* event) override {
-    return previous_target->GetParentTarget();
-  }
-
-  TestEventTarget* initial_target_;
-
-  DISALLOW_COPY_AND_ASSIGN(BubblingEventTargeter);
-};
-
 // Tests that unhandled events are correctly dispatched to the next-best
-// target as decided by the BubblingEventTargeter.
+// target as decided by the TestEventTargeter.
 TEST_F(EventProcessorTest, DispatchToNextBestTarget) {
   scoped_ptr<TestEventTarget> child(new TestEventTarget());
   scoped_ptr<TestEventTarget> grandchild(new TestEventTarget());
 
+  // Install a TestEventTargeter which permits bubbling.
   root()->SetEventTargeter(
-      scoped_ptr<EventTargeter>(new BubblingEventTargeter(grandchild.get())));
+      make_scoped_ptr(new TestEventTargeter(grandchild.get(), true)));
   child->AddChild(grandchild.Pass());
   root()->AddChild(child.Pass());
 
@@ -400,8 +245,9 @@
   TestEventTarget* child_r = root()->child_at(0);
   TestEventTarget* grandchild_r = child_r->child_at(0);
 
-  // When the root has a BubblingEventTargeter installed, events targeted
-  // at the grandchild target should be dispatched to all three targets.
+  // When the root has a TestEventTargeter installed which permits bubbling,
+  // events targeted at the grandchild target should be dispatched to all three
+  // targets.
   KeyEvent key_event(ET_KEY_PRESSED, VKEY_ESCAPE, EF_NONE);
   DispatchEvent(&key_event);
   EXPECT_TRUE(root()->DidReceiveEvent(ET_KEY_PRESSED));
@@ -455,13 +301,14 @@
 
 // Tests that unhandled events are seen by the correct sequence of
 // targets, pre-target handlers, and post-target handlers when
-// a BubblingEventTargeter is installed on the root target.
+// a TestEventTargeter is installed on the root target which permits bubbling.
 TEST_F(EventProcessorTest, HandlerSequence) {
   scoped_ptr<TestEventTarget> child(new TestEventTarget());
   scoped_ptr<TestEventTarget> grandchild(new TestEventTarget());
 
+  // Install a TestEventTargeter which permits bubbling.
   root()->SetEventTargeter(
-      scoped_ptr<EventTargeter>(new BubblingEventTargeter(grandchild.get())));
+      make_scoped_ptr(new TestEventTargeter(grandchild.get(), true)));
   child->AddChild(grandchild.Pass());
   root()->AddChild(child.Pass());
 
diff --git a/ui/events/event_source.h b/ui/events/event_source.h
index ca8b00f..f545eea 100644
--- a/ui/events/event_source.h
+++ b/ui/events/event_source.h
@@ -34,12 +34,12 @@
 
  protected:
   EventDispatchDetails SendEventToProcessor(Event* event);
+  virtual EventDispatchDetails DeliverEventToProcessor(Event* event);
 
  private:
   friend class EventSourceTestApi;
 
   typedef std::vector<EventRewriter*> EventRewriterList;
-  EventDispatchDetails DeliverEventToProcessor(Event* event);
   EventRewriterList rewriter_list_;
   DISALLOW_COPY_AND_ASSIGN(EventSource);
 };
diff --git a/ui/events/event_targeter.cc b/ui/events/event_targeter.cc
deleted file mode 100644
index 5d43b29..0000000
--- a/ui/events/event_targeter.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 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.
-
-#include "ui/events/event_targeter.h"
-
-#include "ui/events/event.h"
-#include "ui/events/event_target.h"
-#include "ui/events/event_target_iterator.h"
-
-namespace ui {
-
-EventTargeter::~EventTargeter() {
-}
-
-EventTarget* EventTargeter::FindTargetForEvent(EventTarget* root,
-                                               Event* event) {
-  if (event->IsMouseEvent() ||
-      event->IsScrollEvent() ||
-      event->IsTouchEvent() ||
-      event->IsGestureEvent()) {
-    return FindTargetForLocatedEvent(root,
-                                     static_cast<LocatedEvent*>(event));
-  }
-  return root;
-}
-
-EventTarget* EventTargeter::FindTargetForLocatedEvent(EventTarget* root,
-                                                      LocatedEvent* event) {
-  scoped_ptr<EventTargetIterator> iter = root->GetChildIterator();
-  if (iter) {
-    EventTarget* target = root;
-    for (EventTarget* child = iter->GetNextTarget(); child;
-         child = iter->GetNextTarget()) {
-      EventTargeter* targeter = child->GetEventTargeter();
-      if (!targeter)
-        targeter = this;
-      if (!targeter->SubtreeShouldBeExploredForEvent(child, *event))
-        continue;
-      target->ConvertEventToTarget(child, event);
-      target = child;
-      EventTarget* child_target =
-          targeter->FindTargetForLocatedEvent(child, event);
-      if (child_target)
-        return child_target;
-    }
-    target->ConvertEventToTarget(root, event);
-  }
-  return root->CanAcceptEvent(*event) ? root : NULL;
-}
-
-bool EventTargeter::SubtreeShouldBeExploredForEvent(EventTarget* target,
-                                                    const LocatedEvent& event) {
-  return SubtreeCanAcceptEvent(target, event) &&
-         EventLocationInsideBounds(target, event);
-}
-
-EventTarget* EventTargeter::FindNextBestTarget(EventTarget* previous_target,
-                                               Event* event) {
-  return NULL;
-}
-
-bool EventTargeter::SubtreeCanAcceptEvent(EventTarget* target,
-                                          const LocatedEvent& event) const {
-  return true;
-}
-
-bool EventTargeter::EventLocationInsideBounds(EventTarget* target,
-                                              const LocatedEvent& event) const {
-  return true;
-}
-
-}  // namespace ui
diff --git a/ui/events/event_targeter.h b/ui/events/event_targeter.h
index 23b1261..fbe7a0e 100644
--- a/ui/events/event_targeter.h
+++ b/ui/events/event_targeter.h
@@ -6,18 +6,16 @@
 #define UI_EVENTS_EVENT_TARGETER_H_
 
 #include "base/compiler_specific.h"
-#include "ui/events/event.h"
 #include "ui/events/events_export.h"
 
 namespace ui {
 
 class Event;
 class EventTarget;
-class LocatedEvent;
 
 class EVENTS_EXPORT EventTargeter {
  public:
-  virtual ~EventTargeter();
+  virtual ~EventTargeter() {}
 
   // Returns the target |event| should be dispatched to. If there is no such
   // target, return NULL. If |event| is a located event, the location of |event|
@@ -25,28 +23,7 @@
   // the event (e.g., by changing the location of the event to be in the
   // returned target's coordinate space) so that it can be dispatched to the
   // target without any further modification.
-  virtual EventTarget* FindTargetForEvent(EventTarget* root,
-                                          Event* event);
-
-  // Same as FindTargetForEvent(), but used for positional events. The location
-  // etc. of |event| are in |root|'s coordinate system. When finding the target
-  // for the event, the targeter can mutate the |event| (e.g. change the
-  // coordinate to be in the returned target's coordinate system) so that it can
-  // be dispatched to the target without any further modification.
-  // TODO(tdanderson|sadrul): This should not be in the public API of
-  //                          EventTargeter.
-  virtual EventTarget* FindTargetForLocatedEvent(EventTarget* root,
-                                                 LocatedEvent* event);
-
-  // Returns true if |target| or one of its descendants can be a target of
-  // |event|. This requires that |target| and its descendants are not
-  // prohibited from accepting the event, and that the event is within an
-  // actionable region of the target's bounds. Note that the location etc. of
-  // |event| is in |target|'s parent's coordinate system.
-  // TODO(tdanderson|sadrul): This function should be made non-virtual and
-  //                          non-public.
-  virtual bool SubtreeShouldBeExploredForEvent(EventTarget* target,
-                                               const LocatedEvent& event);
+  virtual EventTarget* FindTargetForEvent(EventTarget* root, Event* event) = 0;
 
   // Returns the next best target for |event| as compared to |previous_target|.
   // |event| is in the local coordinate space of |previous_target|.
@@ -54,22 +31,7 @@
   // (e.g., by changing |event|'s location to be in the returned target's
   // coordinate space).
   virtual EventTarget* FindNextBestTarget(EventTarget* previous_target,
-                                          Event* event);
-
- protected:
-  // Returns false if neither |target| nor any of its descendants are allowed
-  // to accept |event| for reasons unrelated to the event's location or the
-  // target's bounds. For example, overrides of this function may consider
-  // attributes such as the visibility or enabledness of |target|. Note that
-  // the location etc. of |event| is in |target|'s parent's coordinate system.
-  virtual bool SubtreeCanAcceptEvent(EventTarget* target,
-                                     const LocatedEvent& event) const;
-
-  // Returns whether the location of the event is in an actionable region of the
-  // target. Note that the location etc. of |event| is in the |target|'s
-  // parent's coordinate system.
-  virtual bool EventLocationInsideBounds(EventTarget* target,
-                                         const LocatedEvent& event) const;
+                                          Event* event) = 0;
 };
 
 }  // namespace ui
diff --git a/ui/events/event_utils.cc b/ui/events/event_utils.cc
index 021ac27..1b3d7a9 100644
--- a/ui/events/event_utils.cc
+++ b/ui/events/event_utils.cc
@@ -25,12 +25,6 @@
       event.reset(new KeyEvent(native_event));
       break;
 
-    case ET_TRANSLATED_KEY_PRESS:
-    case ET_TRANSLATED_KEY_RELEASE:
-      // These should not be generated by native events.
-      NOTREACHED();
-      break;
-
     case ET_MOUSE_PRESSED:
     case ET_MOUSE_DRAGGED:
     case ET_MOUSE_RELEASED:
diff --git a/ui/events/events.gyp b/ui/events/events.gyp
index aea07ae..a914952 100644
--- a/ui/events/events.gyp
+++ b/ui/events/events.gyp
@@ -126,7 +126,6 @@
         'event_target.cc',
         'event_target.h',
         'event_target_iterator.h',
-        'event_targeter.cc',
         'event_targeter.h',
         'event_utils.cc',
         'event_utils.h',
@@ -324,6 +323,8 @@
         'test/test_event_processor.h',
         'test/test_event_target.cc',
         'test/test_event_target.h',
+        'test/test_event_targeter.cc',
+        'test/test_event_targeter.h',
       ],
       'conditions': [
         ['OS=="ios"', {
diff --git a/ui/events/keycodes/dom/dom_key_data.inc b/ui/events/keycodes/dom/dom_key_data.inc
index 52fce73..e809b8dd 100644
--- a/ui/events/keycodes/dom/dom_key_data.inc
+++ b/ui/events/keycodes/dom/dom_key_data.inc
@@ -64,6 +64,12 @@
   DOM_KEY_MAP("Symbol",               SYMBOL),
   DOM_KEY_MAP("SymbolLock",           SYMBOL_LOCK),
 
+  // Non-standard value corresponding to XKB keysym ISO_Level5_Shift,
+  // an additional printable-character modifier like Shift and AltGraph,
+  // used by such layouts as Neo (German) and Multix (French-Canadian).
+  //          Key                     Enum
+  DOM_KEY_MAP("ShiftLevel5",          SHIFT_LEVEL5),
+
   // ============================================================
   // Whitespace Keys
   // http://www.w3.org/TR/DOM-Level-3-Events-key/#keys-whitespace
diff --git a/ui/events/keycodes/keyboard_code_conversion_xkb.cc b/ui/events/keycodes/keyboard_code_conversion_xkb.cc
index 7e14288..22172a11 100644
--- a/ui/events/keycodes/keyboard_code_conversion_xkb.cc
+++ b/ui/events/keycodes/keyboard_code_conversion_xkb.cc
@@ -340,6 +340,8 @@
       return DomKey::PRINT_SCREEN;
     case XKB_KEY_ISO_Level3_Shift:
       return DomKey::ALT_GRAPH;
+    case XKB_KEY_ISO_Level5_Shift:
+      return DomKey::SHIFT_LEVEL5;
     case XKB_KEY_ISO_Next_Group:
       return DomKey::GROUP_NEXT;
     case XKB_KEY_ISO_Prev_Group:
diff --git a/ui/events/latency_info.cc b/ui/events/latency_info.cc
index 54acb7f..bd233ae 100644
--- a/ui/events/latency_info.cc
+++ b/ui/events/latency_info.cc
@@ -338,7 +338,7 @@
                                   "data", AsTraceableData(*this));
     }
 
-    TRACE_EVENT_FLOW_END0(
+    TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0(
         "input,benchmark", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id));
   }
 }
diff --git a/ui/events/null_event_targeter.cc b/ui/events/null_event_targeter.cc
index 89073844..9a946a9b0 100644
--- a/ui/events/null_event_targeter.cc
+++ b/ui/events/null_event_targeter.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/logging.h"
 #include "ui/events/null_event_targeter.h"
 
 namespace ui {
@@ -17,4 +18,10 @@
   return nullptr;
 }
 
+EventTarget* NullEventTargeter::FindNextBestTarget(EventTarget* previous_target,
+                                                   Event* event) {
+  NOTREACHED();
+  return nullptr;
+}
+
 }  // namespace ui
diff --git a/ui/events/null_event_targeter.h b/ui/events/null_event_targeter.h
index 010c060..c22e7a7 100644
--- a/ui/events/null_event_targeter.h
+++ b/ui/events/null_event_targeter.h
@@ -3,17 +3,23 @@
 // found in the LICENSE file.
 
 #include "base/compiler_specific.h"
+#include "base/macros.h"
 #include "ui/events/event_targeter.h"
 #include "ui/events/events_export.h"
 
 namespace ui {
 
+// NullEventTargeter can be installed on a root window to prevent it from
+// dispatching events such as during shutdown.
 class EVENTS_EXPORT NullEventTargeter : public EventTargeter {
  public:
   NullEventTargeter();
   ~NullEventTargeter() override;
 
+  // EventTargeter:
   EventTarget* FindTargetForEvent(EventTarget* root, Event* event) override;
+  EventTarget* FindNextBestTarget(EventTarget* previous_target,
+                                  Event* event) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(NullEventTargeter);
diff --git a/ui/events/ozone/device/udev/device_manager_udev.cc b/ui/events/ozone/device/udev/device_manager_udev.cc
index 4e28e39..ca7daa26 100644
--- a/ui/events/ozone/device/udev/device_manager_udev.cc
+++ b/ui/events/ozone/device/udev/device_manager_udev.cc
@@ -162,10 +162,10 @@
 
   DeviceEvent::DeviceType device_type;
   if (!strcmp(subsystem, "input") &&
-      StartsWithASCII(path, "/dev/input/event", true))
+      base::StartsWithASCII(path, "/dev/input/event", true))
     device_type = DeviceEvent::INPUT;
   else if (!strcmp(subsystem, "drm") &&
-           StartsWithASCII(path, "/dev/dri/card", true))
+           base::StartsWithASCII(path, "/dev/dri/card", true))
     device_type = DeviceEvent::DISPLAY;
   else
     return nullptr;
diff --git a/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc b/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc
index 8fe624d..47725bd 100644
--- a/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc
+++ b/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc
@@ -9,12 +9,12 @@
 KeyEventParams::KeyEventParams(int device_id,
                                unsigned int code,
                                bool down,
-                               bool enable_repeat,
+                               bool suppress_auto_repeat,
                                base::TimeDelta timestamp)
     : device_id(device_id),
       code(code),
       down(down),
-      enable_repeat(enable_repeat),
+      suppress_auto_repeat(suppress_auto_repeat),
       timestamp(timestamp) {
 }
 
diff --git a/ui/events/ozone/evdev/device_event_dispatcher_evdev.h b/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
index c49cff0..0ff64be3 100644
--- a/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
+++ b/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
@@ -23,7 +23,7 @@
   KeyEventParams(int device_id,
                  unsigned int code,
                  bool down,
-                 bool enable_repeat,
+                 bool suppress_auto_repeat,
                  base::TimeDelta timestamp);
   KeyEventParams(const KeyEventParams& other);
   ~KeyEventParams();
@@ -31,7 +31,7 @@
   int device_id;
   unsigned int code;
   bool down;
-  bool enable_repeat;
+  bool suppress_auto_repeat;
   base::TimeDelta timestamp;
 };
 
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.cc b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
index 23c6f143..1718c7c 100644
--- a/ui/events/ozone/evdev/event_converter_evdev_impl.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
@@ -188,8 +188,9 @@
   // State transition: !(down) -> (down)
   key_state_.set(key, down);
 
-  dispatcher_->DispatchKeyEvent(KeyEventParams(
-      input_device_.id, key, down, true /* enable_repeat */, timestamp));
+  dispatcher_->DispatchKeyEvent(KeyEventParams(input_device_.id, key, down,
+                                               false /* suppress_auto_repeat */,
+                                               timestamp));
 }
 
 void EventConverterEvdevImpl::ReleaseKeys() {
diff --git a/ui/events/ozone/evdev/event_device_info.cc b/ui/events/ozone/evdev/event_device_info.cc
index e3c9f73..fba26d3f 100644
--- a/ui/events/ozone/evdev/event_device_info.cc
+++ b/ui/events/ozone/evdev/event_device_info.cc
@@ -411,7 +411,7 @@
   if (HasKeyEvent(BTN_TOOL_FINGER) && HasKeyEvent(BTN_TOUCH))
     return LegacyAbsoluteDeviceType::LADT_TOUCHPAD;
 
-  if (HasKeyEvent(BTN_TOUCH))
+  if (HasKeyEvent(BTN_TOUCH) || HasKeyEvent(BTN_LEFT))
     return LegacyAbsoluteDeviceType::LADT_TOUCHSCREEN;
 
   return LegacyAbsoluteDeviceType::LADT_NONE;
diff --git a/ui/events/ozone/evdev/event_device_info_unittest.cc b/ui/events/ozone/evdev/event_device_info_unittest.cc
index cc7af80b..63187a1d 100644
--- a/ui/events/ozone/evdev/event_device_info_unittest.cc
+++ b/ui/events/ozone/evdev/event_device_info_unittest.cc
@@ -136,4 +136,16 @@
   EXPECT_FALSE(devinfo.HasTablet());
 }
 
+TEST_F(EventDeviceInfoTest, AbsoluteMouseTouchscreen) {
+  EventDeviceInfo devinfo;
+  EXPECT_TRUE(CapabilitiesToDeviceInfo(kElo_TouchSystems_2700, &devinfo));
+
+  // This touchscreen uses BTN_LEFT for touch contact.
+  EXPECT_FALSE(devinfo.HasKeyboard());
+  EXPECT_FALSE(devinfo.HasMouse());
+  EXPECT_FALSE(devinfo.HasTouchpad());
+  EXPECT_TRUE(devinfo.HasTouchscreen());
+  EXPECT_FALSE(devinfo.HasTablet());
+}
+
 }  // namespace ui
diff --git a/ui/events/ozone/evdev/event_device_test_util.cc b/ui/events/ozone/evdev/event_device_test_util.cc
index cb4116ca..4d5407c12 100644
--- a/ui/events/ozone/evdev/event_device_test_util.cc
+++ b/ui/events/ozone/evdev/event_device_test_util.cc
@@ -363,6 +363,36 @@
     arraysize(kLogitechTouchKeyboardK400AbsAxes),
 };
 
+// Captured from Elo TouchSystems 2700 touchscreen.
+const DeviceAbsoluteAxis kElo_TouchSystems_2700AbsAxes[] = {
+    {ABS_X, {0, 0, 4095, 0, 0, 0}},
+    {ABS_Y, {0, 0, 4095, 0, 0, 0}},
+    {ABS_MISC, {0, 0, 256, 0, 0, 0}},
+};
+const DeviceCapabilities kElo_TouchSystems_2700 = {
+    /* path */ "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/"
+               "input/input9/event9",
+    /* name */ "Elo TouchSystems, Inc. Elo TouchSystems 2700 IntelliTouch(r) "
+               "USB Touchmonitor Interface",
+    /* phys */ "usb-0000:00:1d.0-1.3/input0",
+    /* uniq */ "20A01347",
+    /* bustype */ "0003",
+    /* vendor */ "04e7",
+    /* product */ "0020",
+    /* version */ "0100",
+    /* prop */ "0",
+    /* ev */ "1b",
+    /* key */ "10000 0 0 0 0",
+    /* rel */ "0",
+    /* abs */ "10000000003",
+    /* msc */ "10",
+    /* sw */ "0",
+    /* led */ "0",
+    /* ff */ "0",
+    kElo_TouchSystems_2700AbsAxes,
+    arraysize(kElo_TouchSystems_2700AbsAxes),
+};
+
 bool CapabilitiesToDeviceInfo(const DeviceCapabilities& capabilities,
                               EventDeviceInfo* devinfo) {
   std::vector<unsigned long> ev_bits;
diff --git a/ui/events/ozone/evdev/event_device_test_util.h b/ui/events/ozone/evdev/event_device_test_util.h
index 46afb6ab..b02f74a 100644
--- a/ui/events/ozone/evdev/event_device_test_util.h
+++ b/ui/events/ozone/evdev/event_device_test_util.h
@@ -68,6 +68,7 @@
 extern const DeviceCapabilities kWacomIntuosPtS_Pen;
 extern const DeviceCapabilities kWacomIntuosPtS_Finger;
 extern const DeviceCapabilities kLogitechTouchKeyboardK400;
+extern const DeviceCapabilities kElo_TouchSystems_2700;
 
 }  // namspace ui
 
diff --git a/ui/events/ozone/evdev/event_factory_evdev.cc b/ui/events/ozone/evdev/event_factory_evdev.cc
index fff6aaa1..ad141e6 100644
--- a/ui/events/ozone/evdev/event_factory_evdev.cc
+++ b/ui/events/ozone/evdev/event_factory_evdev.cc
@@ -152,7 +152,7 @@
 void EventFactoryEvdev::DispatchKeyEvent(const KeyEventParams& params) {
   TRACE_EVENT1("evdev", "EventFactoryEvdev::DispatchKeyEvent", "device",
                params.device_id);
-  keyboard_.OnKeyChange(params.code, params.down, params.enable_repeat,
+  keyboard_.OnKeyChange(params.code, params.down, params.suppress_auto_repeat,
                         params.timestamp, params.device_id);
 }
 
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc
index 11a8f1e..a909ba53 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev.cc
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -250,8 +250,8 @@
     ApplyCapsLockLed();
   }
 
-  if (--pending_device_changes_ == 0)
-    NotifyDevicesUpdated();
+  --pending_device_changes_;
+  NotifyDevicesUpdated();
 }
 
 void InputDeviceFactoryEvdev::DetachInputDevice(const base::FilePath& path) {
@@ -405,6 +405,8 @@
 }
 
 void InputDeviceFactoryEvdev::NotifyDevicesUpdated() {
+  if (pending_device_changes_)
+    return;  // No update until pending opens complete.
   if (touchscreen_list_dirty_)
     NotifyTouchscreensUpdated();
   if (keyboard_list_dirty_)
diff --git a/ui/events/ozone/evdev/input_injector_evdev.cc b/ui/events/ozone/evdev/input_injector_evdev.cc
index 86bc35b..7c37fe9 100644
--- a/ui/events/ozone/evdev/input_injector_evdev.cc
+++ b/ui/events/ozone/evdev/input_injector_evdev.cc
@@ -66,18 +66,18 @@
       kDeviceIdForInjection, cursor_->GetLocation(), EventTimeForNow()));
 }
 
-void InputInjectorEvdev::InjectKeyPress(DomCode physical_key,
+void InputInjectorEvdev::InjectKeyEvent(DomCode physical_key,
                                         bool down,
-                                        bool enable_repeat) {
+                                        bool suppress_auto_repeat) {
   if (physical_key == DomCode::NONE)
     return;
 
   int native_keycode = KeycodeConverter::DomCodeToNativeKeycode(physical_key);
   int evdev_code = NativeCodeToEvdevCode(native_keycode);
 
-  dispatcher_->DispatchKeyEvent(KeyEventParams(kDeviceIdForInjection,
-                                               evdev_code, down, enable_repeat,
-                                               EventTimeForNow()));
+  dispatcher_->DispatchKeyEvent(
+      KeyEventParams(kDeviceIdForInjection, evdev_code, down,
+                     suppress_auto_repeat, EventTimeForNow()));
 }
 
 }  // namespace ui
diff --git a/ui/events/ozone/evdev/input_injector_evdev.h b/ui/events/ozone/evdev/input_injector_evdev.h
index 59b5e36..cdb60fa 100644
--- a/ui/events/ozone/evdev/input_injector_evdev.h
+++ b/ui/events/ozone/evdev/input_injector_evdev.h
@@ -27,9 +27,9 @@
   void InjectMouseButton(EventFlags button, bool down) override;
   void InjectMouseWheel(int delta_x, int delta_y) override;
   void MoveCursorTo(const gfx::PointF& location) override;
-  void InjectKeyPress(DomCode physical_key,
+  void InjectKeyEvent(DomCode physical_key,
                       bool down,
-                      bool enable_repeat) override;
+                      bool suppress_auto_repeat) override;
 
  private:
   // Shared cursor state.
diff --git a/ui/events/ozone/evdev/keyboard_evdev.cc b/ui/events/ozone/evdev/keyboard_evdev.cc
index 36f2bf6..06e6c60 100644
--- a/ui/events/ozone/evdev/keyboard_evdev.cc
+++ b/ui/events/ozone/evdev/keyboard_evdev.cc
@@ -18,6 +18,15 @@
 
 namespace ui {
 
+// We can't include ui/events/keycodes/dom/dom_code.h here because of
+// conflicts with preprocessor macros in <linux/input.h>, so we use the
+// same underlying data with an additional prefix.
+#define USB_KEYMAP(usb, xkb, win, mac, code, id) DOM_CODE_ ## id = usb
+#define USB_KEYMAP_DECLARATION enum class DomCode
+#include "ui/events/keycodes/dom/keycode_converter_data.inc"
+#undef USB_KEYMAP
+#undef USB_KEYMAP_DECLARATION
+
 namespace {
 
 const int kRepeatDelayMs = 500;
@@ -35,6 +44,8 @@
       return EVDEV_MODIFIER_ALT;
     case EF_ALTGR_DOWN:
       return EVDEV_MODIFIER_ALTGR;
+    case EF_MOD3_DOWN:
+      return EVDEV_MODIFIER_MOD3;
     case EF_LEFT_MOUSE_BUTTON:
       return EVDEV_MODIFIER_LEFT_MOUSE_BUTTON;
     case EF_MIDDLE_MOUSE_BUTTON:
@@ -60,7 +71,7 @@
     : callback_(callback),
       modifiers_(modifiers),
       keyboard_layout_engine_(keyboard_layout_engine),
-      repeat_enabled_(true),
+      auto_repeat_enabled_(true),
       repeat_key_(KEY_RESERVED),
       repeat_sequence_(0),
       repeat_device_id_(0),
@@ -74,20 +85,20 @@
 
 void KeyboardEvdev::OnKeyChange(unsigned int key,
                                 bool down,
-                                bool enable_repeat,
+                                bool suppress_auto_repeat,
                                 base::TimeDelta timestamp,
                                 int device_id) {
   if (key > KEY_MAX)
     return;
 
   bool was_down = key_state_.test(key);
-  bool repeat = down && was_down;
+  bool is_repeat = down && was_down;
   if (!down && !was_down)
     return;  // Key already released.
 
   key_state_.set(key, down);
-  UpdateKeyRepeat(key, down, enable_repeat, device_id);
-  DispatchKey(key, down, repeat, timestamp, device_id);
+  UpdateKeyRepeat(key, down, suppress_auto_repeat, device_id);
+  DispatchKey(key, down, is_repeat, timestamp, device_id);
 }
 
 void KeyboardEvdev::SetCapsLockEnabled(bool enabled) {
@@ -99,11 +110,11 @@
 }
 
 bool KeyboardEvdev::IsAutoRepeatEnabled() {
-  return repeat_enabled_;
+  return auto_repeat_enabled_;
 }
 
 void KeyboardEvdev::SetAutoRepeatEnabled(bool enabled) {
-  repeat_enabled_ = enabled;
+  auto_repeat_enabled_ = enabled;
 }
 
 void KeyboardEvdev::SetAutoRepeatRate(const base::TimeDelta& delay,
@@ -141,9 +152,9 @@
 
 void KeyboardEvdev::UpdateKeyRepeat(unsigned int key,
                                     bool down,
-                                    bool enable_repeat,
+                                    bool suppress_auto_repeat,
                                     int device_id) {
-  if (!repeat_enabled_ || !enable_repeat)
+  if (!auto_repeat_enabled_ || suppress_auto_repeat)
     StopKeyRepeat();
   else if (key != repeat_key_ && down)
     StartKeyRepeat(key, device_id);
@@ -200,9 +211,7 @@
                                 int device_id) {
   DomCode dom_code =
       KeycodeConverter::NativeKeycodeToDomCode(EvdevCodeToNativeCode(key));
-  // DomCode constants are not included here because of conflicts with
-  // evdev preprocessor macros.
-  if (!static_cast<int>(dom_code))
+  if (dom_code == DomCode::DOM_CODE_NONE)
     return;
   int flags = modifiers_->GetModifierFlags();
   DomKey dom_key;
@@ -213,8 +222,16 @@
                                        &key_code, &platform_keycode)) {
     return;
   }
-  if (!repeat)
-    UpdateModifier(ModifierDomKeyToEventFlag(dom_key), down);
+  if (!repeat) {
+    int flag = ModifierDomKeyToEventFlag(dom_key);
+    UpdateModifier(flag, down);
+    // X11 XKB, using the configuration as modified for ChromeOS, always sets
+    // EF_MOD3_DOWN for the physical CapsLock key, even if the layout maps
+    // it to something else, so we imitate this to make certain layouts (e.g.
+    // German Neo2) work. crbug.com/495277
+    if (dom_code == DomCode::DOM_CODE_CAPS_LOCK)
+      UpdateModifier(EF_MOD3_DOWN, down);
+  }
 
   KeyEvent event(down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code, dom_code,
                  modifiers_->GetModifierFlags(), dom_key, character, timestamp);
@@ -223,5 +240,4 @@
     event.set_platform_keycode(platform_keycode);
   callback_.Run(&event);
 }
-
 }  // namespace ui
diff --git a/ui/events/ozone/evdev/keyboard_evdev.h b/ui/events/ozone/evdev/keyboard_evdev.h
index 7071831..34e5162 100644
--- a/ui/events/ozone/evdev/keyboard_evdev.h
+++ b/ui/events/ozone/evdev/keyboard_evdev.h
@@ -34,9 +34,14 @@
   ~KeyboardEvdev();
 
   // Handlers for raw key presses & releases.
+  //
+  // |code| is a Linux key code (from <linux/input.h>). |down| represents the
+  // key state. |suppress_auto_repeat| prevents the event from triggering
+  // auto-repeat, if enabled. |device_id| uniquely identifies the source
+  // keyboard device.
   void OnKeyChange(unsigned int code,
                    bool down,
-                   bool enable_repeat,
+                   bool suppress_auto_repeat,
                    base::TimeDelta timestamp,
                    int device_id);
 
@@ -56,7 +61,7 @@
   void UpdateCapsLockLed();
   void UpdateKeyRepeat(unsigned int key,
                        bool down,
-                       bool enable_repeat,
+                       bool suppress_auto_repeat,
                        int device_id);
   void StartKeyRepeat(unsigned int key, int device_id);
   void StopKeyRepeat();
@@ -88,7 +93,7 @@
   KeyboardLayoutEngine* keyboard_layout_engine_;
 
   // Key repeat state.
-  bool repeat_enabled_;
+  bool auto_repeat_enabled_;
   unsigned int repeat_key_;
   unsigned int repeat_sequence_;
   int repeat_device_id_;
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
index db41c1c8..dad9f01 100644
--- a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
+++ b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
@@ -452,7 +452,7 @@
 
       // Dispatch key press or release to keyboard.
       dispatcher_->DispatchKeyEvent(
-          KeyEventParams(id_, key, value, true /* enable_repeat */,
+          KeyEventParams(id_, key, value, false /* suppress_auto_repeat */,
                          StimeToTimedelta(timestamp)));
     }
   }
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
index b3289ffc..3adb358 100644
--- a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
+++ b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
@@ -505,17 +505,19 @@
 
 // Check if a match criteria is a device type one.
 bool IsMatchDeviceType(const std::string& match_type) {
-  return StartsWithASCII(match_type, "MatchIs", true);
+  return base::StartsWithASCII(match_type, "MatchIs", true);
 }
 
 // Parse a boolean value keyword (e.g., on/off, true/false).
 int ParseBooleanKeyword(const std::string& value) {
-  for (size_t i = 0; i < arraysize(kTrue); ++i)
-    if (LowerCaseEqualsASCII(value, kTrue[i]))
+  for (size_t i = 0; i < arraysize(kTrue); ++i) {
+    if (base::LowerCaseEqualsASCII(value, kTrue[i]))
       return 1;
-  for (size_t i = 0; i < arraysize(kFalse); ++i)
-    if (LowerCaseEqualsASCII(value, kFalse[i]))
+  }
+  for (size_t i = 0; i < arraysize(kFalse); ++i) {
+    if (base::LowerCaseEqualsASCII(value, kFalse[i]))
       return -1;
+  }
   return 0;
 }
 
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.cc b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
index 2427f894..a5e9c19 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
@@ -137,6 +137,9 @@
     current_slot_ = 0;
   }
 
+  quirk_left_mouse_button_ =
+      !has_mt_ && !info.HasKeyEvent(BTN_TOUCH) && info.HasKeyEvent(BTN_LEFT);
+
   // Apply --touch-calibration.
   if (type() == INPUT_DEVICE_INTERNAL) {
     TouchCalibration cal = {};
@@ -178,6 +181,7 @@
     }
   } else {
     // TODO(spang): Add key state to EventDeviceInfo to allow initial contact.
+    // (and make sure to take into account quirk_left_mouse_button_)
     events_[0].x = 0;
     events_[0].y = 0;
     events_[0].tracking_id = kTrackingIdForUnusedSlot;
@@ -259,6 +263,8 @@
     }
   } else if (input.type == EV_KEY) {
     ProcessKey(input);
+  } else if (input.type == EV_MSC) {
+    // Ignored.
   } else {
     NOTIMPLEMENTED() << "invalid type: " << input.type;
   }
@@ -272,18 +278,22 @@
     emulated_event.code = AbsCodeToMtCode(event.code);
     if (emulated_event.code >= 0)
       ProcessMultitouchEvent(emulated_event);
-  } else if (event.type == EV_KEY && event.code == BTN_TOUCH) {
-    emulated_event.type = EV_ABS;
-    emulated_event.code = ABS_MT_TRACKING_ID;
-    emulated_event.value =
-        event.value ? NextTrackingId() : kTrackingIdForUnusedSlot;
-    ProcessMultitouchEvent(emulated_event);
+  } else if (event.type == EV_KEY) {
+    if (event.code == BTN_TOUCH ||
+        (quirk_left_mouse_button_ && event.code == BTN_LEFT)) {
+      emulated_event.type = EV_ABS;
+      emulated_event.code = ABS_MT_TRACKING_ID;
+      emulated_event.value =
+          event.value ? NextTrackingId() : kTrackingIdForUnusedSlot;
+      ProcessMultitouchEvent(emulated_event);
+    }
   }
 }
 
 void TouchEventConverterEvdev::ProcessKey(const input_event& input) {
   switch (input.code) {
     case BTN_TOUCH:
+    case BTN_LEFT:
       break;
     default:
       NOTIMPLEMENTED() << "invalid code for EV_KEY: " << input.code;
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.h b/ui/events/ozone/evdev/touch_event_converter_evdev.h
index 7cd7576a2..edddea6b 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev.h
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev.h
@@ -83,6 +83,9 @@
   // Device has multitouch capability.
   bool has_mt_;
 
+  // Use BTN_LEFT instead of BT_TOUCH.
+  bool quirk_left_mouse_button_ = false;
+
   // Pressure values.
   int pressure_min_;
   int pressure_max_;  // Used to normalize pressure values.
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
index 77eeef6..96a1f32 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
@@ -47,6 +47,12 @@
   device->Initialize(devinfo);
 }
 
+void InitEloTouchscreen(TouchEventConverterEvdev* device) {
+  EventDeviceInfo devinfo;
+  EXPECT_TRUE(CapabilitiesToDeviceInfo(kElo_TouchSystems_2700, &devinfo));
+  device->Initialize(devinfo);
+}
+
 }  // namespace
 
 class MockTouchEventConverterEvdev : public TouchEventConverterEvdev {
@@ -541,6 +547,92 @@
   EXPECT_EQ(0, ev2.slot);
 }
 
+// crbug.com/477695
+TEST_F(TouchEventConverterEvdevTest, ShouldUseLeftButtonIfNoTouchButton) {
+  ui::MockTouchEventConverterEvdev* dev = device();
+
+  InitEloTouchscreen(dev);
+
+  // Captured from Elo TouchSystems 2700.
+  timeval time;
+  time = {1433965490, 837958};
+  struct input_event mock_kernel_queue_press[] = {
+      {time, EV_ABS, ABS_X, 3654},
+      {time, EV_ABS, ABS_Y, 1054},
+      {time, EV_ABS, ABS_MISC, 18},
+      {time, EV_SYN, SYN_REPORT, 0},
+
+      {time, EV_MSC, MSC_SCAN, 90001},
+      {time, EV_KEY, BTN_LEFT, 1},
+      {time, EV_ABS, ABS_Y, 1055},
+      {time, EV_ABS, ABS_MISC, 25},
+      {time, EV_SYN, SYN_REPORT, 0},
+  };
+  time = {1433965491, 1953};
+  struct input_event mock_kernel_queue_move[] = {
+      {time, EV_ABS, ABS_X, 3644},
+      {time, EV_ABS, ABS_Y, 1059},
+      {time, EV_ABS, ABS_MISC, 36},
+      {time, EV_SYN, SYN_REPORT, 0},
+  };
+  time = {1433965491, 225959};
+  struct input_event mock_kernel_queue_release[] = {
+      {time, EV_MSC, MSC_SCAN, 90001},
+      {time, EV_KEY, BTN_LEFT, 0},
+      {time, EV_ABS, ABS_MISC, 0},
+      {time, EV_SYN, SYN_REPORT, 0},
+  };
+
+  // Press.
+  dev->ConfigureReadMock(mock_kernel_queue_press,
+                         arraysize(mock_kernel_queue_press), 0);
+  dev->ReadNow();
+  EXPECT_EQ(1u, size());
+  ui::TouchEventParams event = dispatched_event(0);
+  EXPECT_EQ(ui::ET_TOUCH_PRESSED, event.type);
+  EXPECT_EQ(base::TimeDelta::FromMicroseconds(1433965490837958),
+            event.timestamp);
+  EXPECT_EQ(3654, event.location.x());
+  EXPECT_EQ(1055, event.location.y());
+  EXPECT_EQ(0, event.slot);
+  EXPECT_FLOAT_EQ(0.f, event.radii.x());
+  EXPECT_FLOAT_EQ(0.f, event.pressure);
+
+  // Move.
+  dev->ConfigureReadMock(mock_kernel_queue_move,
+                         arraysize(mock_kernel_queue_move), 0);
+  dev->ReadNow();
+  EXPECT_EQ(2u, size());
+  event = dispatched_event(1);
+  EXPECT_EQ(ui::ET_TOUCH_MOVED, event.type);
+  EXPECT_EQ(base::TimeDelta::FromMicroseconds(1433965491001953),
+            event.timestamp);
+  EXPECT_EQ(3644, event.location.x());
+  EXPECT_EQ(1059, event.location.y());
+  EXPECT_EQ(0, event.slot);
+  EXPECT_FLOAT_EQ(0.f, event.radii.x());
+  EXPECT_FLOAT_EQ(0.f, event.pressure);
+
+  // Release.
+  dev->ConfigureReadMock(mock_kernel_queue_release,
+                         arraysize(mock_kernel_queue_release), 0);
+  dev->ReadNow();
+  EXPECT_EQ(3u, size());
+  event = dispatched_event(2);
+  EXPECT_EQ(ui::ET_TOUCH_RELEASED, event.type);
+  EXPECT_EQ(base::TimeDelta::FromMicroseconds(1433965491225959),
+            event.timestamp);
+  EXPECT_EQ(3644, event.location.x());
+  EXPECT_EQ(1059, event.location.y());
+  EXPECT_EQ(0, event.slot);
+  EXPECT_FLOAT_EQ(0.f, event.radii.x());
+  EXPECT_FLOAT_EQ(0.f, event.pressure);
+
+  // No dispatch on destruction.
+  DestroyDevice();
+  EXPECT_EQ(3u, size());
+}
+
 // crbug.com/407386
 TEST_F(TouchEventConverterEvdevTest,
        DontChangeMultitouchPositionFromLegacyAxes) {
diff --git a/ui/events/ozone/layout/layout_util.cc b/ui/events/ozone/layout/layout_util.cc
index 4d69673..6864d4a 100644
--- a/ui/events/ozone/layout/layout_util.cc
+++ b/ui/events/ozone/layout/layout_util.cc
@@ -23,15 +23,13 @@
       return EF_CAPS_LOCK_DOWN;
     case DomKey::CONTROL:
       return EF_CONTROL_DOWN;
-    case DomKey::HYPER:
-      return EF_MOD3_DOWN;
     case DomKey::META:
       return EF_ALT_DOWN;
     case DomKey::OS:
       return EF_COMMAND_DOWN;
     case DomKey::SHIFT:
       return EF_SHIFT_DOWN;
-    case DomKey::SUPER:
+    case DomKey::SHIFT_LEVEL5:
       return EF_MOD3_DOWN;
     default:
       return EF_NONE;
@@ -40,9 +38,10 @@
   //   DomKey::ACCEL
   //   DomKey::FN
   //   DomKey::FN_LOCK
+  //   DomKey::HYPER
   //   DomKey::NUM_LOCK
   //   DomKey::SCROLL_LOCK
-  //   DomKey::SYMBOL
+  //   DomKey::SUPER
   //   DomKey::SYMBOL_LOCK
 }
 
diff --git a/ui/events/test/test_event_target.h b/ui/events/test/test_event_target.h
index 17969be..06ddc991 100644
--- a/ui/events/test/test_event_target.h
+++ b/ui/events/test/test_event_target.h
@@ -50,6 +50,9 @@
     target_name_ = target_name;
   }
 
+  // EventTarget:
+  EventTargeter* GetEventTargeter() override;
+
  protected:
   bool Contains(TestEventTarget* target) const;
 
@@ -57,7 +60,6 @@
   bool CanAcceptEvent(const ui::Event& event) override;
   EventTarget* GetParentTarget() override;
   scoped_ptr<EventTargetIterator> GetChildIterator() const override;
-  EventTargeter* GetEventTargeter() override;
 
   // EventHandler:
   void OnEvent(Event* event) override;
diff --git a/ui/events/test/test_event_targeter.cc b/ui/events/test/test_event_targeter.cc
new file mode 100644
index 0000000..0794d45
--- /dev/null
+++ b/ui/events/test/test_event_targeter.cc
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/test/test_event_targeter.h"
+
+#include "ui/events/test/test_event_target.h"
+
+namespace ui {
+namespace test {
+
+TestEventTargeter::TestEventTargeter(TestEventTarget* initial_target,
+                                     bool should_bubble)
+    : target_(initial_target), should_bubble_(should_bubble) {
+}
+
+TestEventTargeter::~TestEventTargeter() {
+}
+
+void TestEventTargeter::set_target(TestEventTarget* target) {
+  target_ = target;
+}
+
+EventTarget* TestEventTargeter::FindTargetForEvent(EventTarget* root,
+                                                   Event* event) {
+  return target_;
+}
+
+EventTarget* TestEventTargeter::FindNextBestTarget(EventTarget* previous_target,
+                                                   Event* event) {
+  if (!should_bubble_)
+    return nullptr;
+  return previous_target->GetParentTarget();
+}
+
+}  // namespace test
+}  // namespace ui
diff --git a/ui/events/test/test_event_targeter.h b/ui/events/test/test_event_targeter.h
new file mode 100644
index 0000000..ee2502c4
--- /dev/null
+++ b/ui/events/test/test_event_targeter.h
@@ -0,0 +1,44 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_EVENTS_TEST_TEST_EVENT_TARGETER_H_
+#define UI_EVENTS_TEST_TEST_EVENT_TARGETER_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "ui/events/event_targeter.h"
+
+namespace ui {
+namespace test {
+
+class TestEventTarget;
+
+// An EventTargeter which is used to allow a bubbling behaviour in event
+// dispatch: if an event is not handled after being dispatched to its
+// |initial_target|, the event is dispatched to the next-best target as
+// specified by FindNextBestTarget().
+// Bubbling behaviour is controlled by |should_bubble| at creation time.
+class TestEventTargeter : public EventTargeter {
+ public:
+  TestEventTargeter(TestEventTarget* initial_target, bool should_bubble);
+  ~TestEventTargeter() override;
+
+  void set_target(TestEventTarget* target);
+
+ private:
+  // EventTargeter:
+  EventTarget* FindTargetForEvent(EventTarget* root, Event* event) override;
+  EventTarget* FindNextBestTarget(EventTarget* previous_target,
+                                  Event* event) override;
+
+  TestEventTarget* target_;
+  bool should_bubble_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestEventTargeter);
+};
+
+}  // namespace test
+}  // namespace ui
+
+#endif  // UI_EVENTS_TEST_TEST_EVENT_TARGETER_H_
diff --git a/ui/file_manager/audio_player/audio_player.html b/ui/file_manager/audio_player/audio_player.html
index 0fecd84..8afb682 100644
--- a/ui/file_manager/audio_player/audio_player.html
+++ b/ui/file_manager/audio_player/audio_player.html
@@ -13,6 +13,8 @@
   <title>&#xFEFF;</title>
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" type="text/css" href="css/audio_player.css">
+
+  <script src="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/common/js/polymer_config.js"></script>
   <link rel="import" href="elements/audio_player.html">
 </head>
 <body>
@@ -20,42 +22,6 @@
     <!-- Place the audio player. -->
     <audio-player></audio-player>
   </div>
-
-  <!-- Don't load mediaplayer_scripts.js when flattening is disabled -->
-  <if expr="False"><!-- </if>
-    <script src="js/audio_player_scripts.js"></script>
-  <if expr="False"> --></if>
-  <if expr="False">
-    <!-- This section is used when the file manager is loaded with
-         'filemgr-ext-path' command-line flag. -->
-    <!-- Keep the list in sync with audio_player_scripts.js. -->
-    <script src="../../webui//resources/js/cr.js"></script>
-    <script src="../../webui/resources/js/cr/event_target.js"></script>
-    <script src="../../webui/resources/js/cr/ui/array_data_model.js"></script>
-
-    <script src="../../../third_party/polymer/polymer/polymer.js"></script>
-
-    <!-- Base classes. -->
-    <script src="../file_manager/foreground/js/metadata/metadata_cache_set.js"></script>
-    <script src="../file_manager/foreground/js/metadata/new_metadata_provider.js"></script>
-
-    <script src="../file_manager/common/js/async_util.js"></script>
-    <script src="../file_manager/common/js/file_type.js"></script>
-    <script src="../file_manager/common/js/util.js"></script>
-    <script src="../file_manager/common/js/volume_manager_common.js"></script>
-    <script src="../file_manager/foreground/js/volume_manager_wrapper.js"></script>
-
-    <script src="../file_manager/foreground/js/metadata/content_metadata_provider.js"></script>
-    <script src="../file_manager/foreground/js/metadata/external_metadata_provider.js"></script>
-    <script src="../file_manager/foreground/js/metadata/file_system_metadata_provider.js"></script>
-    <script src="../file_manager/foreground/js/metadata/metadata_cache_item.js"></script>
-    <script src="../file_manager/foreground/js/metadata/metadata_item.js"></script>
-    <script src="../file_manager/foreground/js/metadata/metadata_model.js"></script>
-    <script src="../file_manager/foreground/js/metadata/multi_metadata_provider.js"></script>
-    <script src="../file_manager/foreground/js/metadata/thumbnail_model.js"></script>
-
-    <script src="js/audio_player.js"></script>
-    <script src="js/audio_player_model.js"></script>
-  </if>
+  <script src="js/audio_player_scripts.js"></script>
 </body>
 </html>
diff --git a/ui/file_manager/audio_player/elements/audio_player.html b/ui/file_manager/audio_player/elements/audio_player.html
index eddeb8d7..133b260 100644
--- a/ui/file_manager/audio_player/elements/audio_player.html
+++ b/ui/file_manager/audio_player/elements/audio_player.html
@@ -4,22 +4,31 @@
   -- found in the LICENSE file.
   -->
 
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="track_list.html">
 <link rel="import" href="control_panel.html">
 
-<polymer-element name="audio-player"
-                 attributes="playing currenttrackurl playcount">
+<dom-module id="audio-player">
+  <link rel="import" type="css" href="audio_player.css">
   <template>
-    <link rel="stylesheet" href="audio_player.css">
-
-    <track-list id="trackList" expanded?="{{model.expanded}}"
-                on-replay="{{onReplayCurrentTrack}}"></track-list>
+    <track-list id="trackList"
+        expanded$="[[expanded]]"
+        shuffle="[[shuffle]]"
+        current-track-index="{{currentTrackIndex}}"
+        on-replay="onReplayCurrentTrack"></track-list>
     <control-panel id="audioController"
-                   on-next-clicked="{{onControllerNextClicked}}"
-                   on-previous-clicked="{{onControllerPreviousClicked}}">
-    </control-panel>
-    <audio id="audio"></audio>
+        playing="{{playing}}"
+        time="{{time}}"
+        duration="[[duration]]"
+        shuffle="{{shuffle}}"
+        repeat="{{repeat}}"
+        volume="{{volume}}"
+        expanded="{{expanded}}"
+        on-next-clicked="onControllerNextClicked"
+        on-previous-clicked="onControllerPreviousClicked"></control-panel>
+    <audio id="audio"
+        volume="[[computeAudioVolume_(volume)]]"></audio>
   </template>
-  <script src="audio_player.js"></script>
-</polymer-element>
+</dom-module>
+
+<script src="audio_player.js"></script>
diff --git a/ui/file_manager/audio_player/elements/audio_player.js b/ui/file_manager/audio_player/elements/audio_player.js
index 979dc719..85f9f5c 100644
--- a/ui/file_manager/audio_player/elements/audio_player.js
+++ b/ui/file_manager/audio_player/elements/audio_player.js
@@ -9,92 +9,169 @@
 var AudioPlayerElement = function() {};
 
 AudioPlayerElement.prototype = {
-  // Child Elements
-  audioController: null,
-  audioElement: null,
-  trackList: null,
+  is: 'audio-player',
 
-  // Published values
-  playing: true,
-  currenttrackurl: '',
-  playcount: 0,
-
-  // Attributes of the element (lower characters only).
-  // These values must be used only to data binding and shouldn't be assigned
-  // any value nowhere except in the handler.
-  publish: {
+  properties: {
+    /**
+     * Flag whether the audio is playing or paused. True if playing, or false
+     * paused.
+     */
     playing: {
-      value: true,
-      reflect: true
+      type: Boolean,
+      observer: 'playingChanged',
+      reflectToAttribute: true
     },
+
+    /**
+     * Current elapsed time in the current music in millisecond.
+     */
+    time: {
+      type: Number,
+      observer: 'timeChanged'
+    },
+
+    /**
+     * Whether the shuffle button is ON.
+     */
+    shuffle: {
+      type: Boolean,
+      observer: 'shuffleChanged'
+    },
+
+    /**
+     * Whether the repeat button is ON.
+     */
+    repeat: {
+      type: Boolean,
+      observer: 'repeatChanged'
+    },
+
+    /**
+     * The audio volume. 0 is silent, and 100 is maximum loud.
+     */
+    volume: {
+      type: Number,
+      observer: 'volumeChanged'
+    },
+
+    /**
+     * Whether the expanded button is ON.
+     */
+    expanded: {
+      type: Boolean,
+      observer: 'expandedChanged'
+    },
+
+    /**
+     * Track index of the current track.
+     */
+    currentTrackIndex: {
+      type: Number,
+      observer: 'currentTrackIndexChanged'
+    },
+
+    /**
+     * Model object of the Audio Player.
+     * @type {AudioPlayerModel}
+     */
+    model: {
+      type: Object,
+      value: null,
+      observer: 'modelChanged'
+    },
+
+    /**
+     * URL of the current track. (exposed publicly for tests)
+     */
     currenttrackurl: {
+      type: String,
       value: '',
-      reflect: true
+      reflectToAttribute: true
     },
+
+    /**
+     * The number of played tracks. (exposed publicly for tests)
+     */
     playcount: {
+      type: Number,
       value: 0,
-      reflect: true
+      reflectToAttribute: true
     }
   },
 
   /**
-   * Model object of the Audio Player.
-   * @type {AudioPlayerModel}
+   * Handles change event for shuffle mode.
+   * @param {boolean} shuffle
    */
-  model: null,
+  shuffleChanged: function(shuffle) {
+    if (this.model)
+      this.model.shuffle = shuffle;
+  },
+
+  /**
+   * Handles change event for repeat mode.
+   * @param {boolean} repeat
+   */
+  repeatChanged: function(repeat) {
+    if (this.model)
+      this.model.repeat = repeat;
+  },
+
+  /**
+   * Handles change event for audio volume.
+   * @param {boolean} volume
+   */
+  volumeChanged: function(volume) {
+    if (this.model)
+      this.model.volume = volume;
+  },
+
+  /**
+   * Handles change event for expanded state of track list.
+   */
+  expandedChanged: function(expanded) {
+    if (this.model)
+      this.model.expanded = expanded;
+  },
 
   /**
    * Initializes an element. This method is called automatically when the
    * element is ready.
    */
   ready: function() {
-    this.audioController = this.$.audioController;
-    this.audioElement = this.$.audio;
-    this.trackList = this.$.trackList;
-
     this.addEventListener('keydown', this.onKeyDown_.bind(this));
 
-    this.audioElement.volume = 0;  // Temporary initial volume.
-    this.audioElement.addEventListener('ended', this.onAudioEnded.bind(this));
-    this.audioElement.addEventListener('error', this.onAudioError.bind(this));
+    this.$.audio.volume = 0;  // Temporary initial volume.
+    this.$.audio.addEventListener('ended', this.onAudioEnded.bind(this));
+    this.$.audio.addEventListener('error', this.onAudioError.bind(this));
 
     var onAudioStatusUpdatedBound = this.onAudioStatusUpdate_.bind(this);
-    this.audioElement.addEventListener('timeupdate', onAudioStatusUpdatedBound);
-    this.audioElement.addEventListener('ended', onAudioStatusUpdatedBound);
-    this.audioElement.addEventListener('play', onAudioStatusUpdatedBound);
-    this.audioElement.addEventListener('pause', onAudioStatusUpdatedBound);
-    this.audioElement.addEventListener('suspend', onAudioStatusUpdatedBound);
-    this.audioElement.addEventListener('abort', onAudioStatusUpdatedBound);
-    this.audioElement.addEventListener('error', onAudioStatusUpdatedBound);
-    this.audioElement.addEventListener('emptied', onAudioStatusUpdatedBound);
-    this.audioElement.addEventListener('stalled', onAudioStatusUpdatedBound);
-  },
-
-  /**
-   * Registers handlers for changing of external variables
-   */
-  observe: {
-    'trackList.currentTrackIndex': 'onCurrentTrackIndexChanged',
-    'audioController.playing': 'onControllerPlayingChanged',
-    'audioController.time': 'onControllerTimeChanged',
-    'model.volume': 'onVolumeChanged',
+    this.$.audio.addEventListener('timeupdate', onAudioStatusUpdatedBound);
+    this.$.audio.addEventListener('ended', onAudioStatusUpdatedBound);
+    this.$.audio.addEventListener('play', onAudioStatusUpdatedBound);
+    this.$.audio.addEventListener('pause', onAudioStatusUpdatedBound);
+    this.$.audio.addEventListener('suspend', onAudioStatusUpdatedBound);
+    this.$.audio.addEventListener('abort', onAudioStatusUpdatedBound);
+    this.$.audio.addEventListener('error', onAudioStatusUpdatedBound);
+    this.$.audio.addEventListener('emptied', onAudioStatusUpdatedBound);
+    this.$.audio.addEventListener('stalled', onAudioStatusUpdatedBound);
   },
 
   /**
    * Invoked when trackList.currentTrackIndex is changed.
-   * @param {number} oldValue old value.
    * @param {number} newValue new value.
+   * @param {number} oldValue old value.
    */
-  onCurrentTrackIndexChanged: function(oldValue, newValue) {
+  currentTrackIndexChanged: function(newValue, oldValue) {
     var currentTrackUrl = '';
 
     if (oldValue != newValue) {
-      var currentTrack = this.trackList.getCurrentTrack();
-      if (currentTrack && currentTrack.url != this.audioElement.src) {
-        this.audioElement.src = currentTrack.url;
-        currentTrackUrl = this.audioElement.src;
-        if (this.audioController.playing)
-          this.audioElement.play();
+      var currentTrack = this.$.trackList.getCurrentTrack();
+      if (currentTrack && currentTrack.url != this.$.audio.src) {
+        this.$.audio.src = currentTrack.url;
+        currentTrackUrl = this.$.audio.src;
+        if (this.playing)
+          this.$.audio.play();
       }
     }
 
@@ -103,69 +180,60 @@
   },
 
   /**
-   * Invoked when audioController.playing is changed.
-   * @param {boolean} oldValue old value.
+   * Invoked when playing is changed.
    * @param {boolean} newValue new value.
+   * @param {boolean} oldValue old value.
    */
-  onControllerPlayingChanged: function(oldValue, newValue) {
-    this.playing = newValue;
-
+  playingChanged: function(newValue, oldValue) {
     if (newValue) {
-      if (!this.audioElement.src) {
-        var currentTrack = this.trackList.getCurrentTrack();
-        if (currentTrack && currentTrack.url != this.audioElement.src) {
-          this.audioElement.src = currentTrack.url;
+      if (!this.$.audio.src) {
+        var currentTrack = this.$.trackList.getCurrentTrack();
+        if (currentTrack && currentTrack.url != this.$.audio.src) {
+          this.$.audio.src = currentTrack.url;
         }
       }
 
-      if (this.audioElement.src) {
-        this.currenttrackurl = this.audioElement.src;
-        this.audioElement.play();
+      if (this.$.audio.src) {
+        this.currenttrackurl = this.$.audio.src;
+        this.$.audio.play();
         return;
       }
     }
 
     // When the new status is "stopped".
     this.cancelAutoAdvance_();
-    this.audioElement.pause();
+    this.$.audio.pause();
     this.currenttrackurl = '';
     this.lastAudioUpdateTime_ = null;
   },
 
   /**
-   * Invoked when audioController.volume is changed.
-   * @param {number} oldValue old value.
-   * @param {number} newValue new value.
-   */
-  onVolumeChanged: function(oldValue, newValue) {
-    this.audioElement.volume = newValue / 100;
-  },
-
-  /**
    * Invoked when the model changed.
-   * @param {AudioPlayerModel} oldValue Old Value.
-   * @param {AudioPlayerModel} newValue New Value.
+   * @param {AudioPlayerModel} newModel New model.
+   * @param {AudioPlayerModel} oldModel Old model.
    */
-  modelChanged: function(oldValue, newValue) {
-    this.trackList.model = newValue;
-    this.audioController.model = newValue;
-
-    // Invoke the handler manually.
-    this.onVolumeChanged(0, newValue.volume);
+  modelChanged: function(newModel, oldModel) {
+    // Setting up the UI
+    if (newModel !== oldModel && newModel) {
+      this.shuffle = newModel.shuffle;
+      this.repeat = newModel.repeat;
+      this.volume = newModel.volume;
+      this.expanded = newModel.expanded;
+    }
   },
 
   /**
-   * Invoked when audioController.time is changed.
-   * @param {number} oldValue old time (in ms).
+   * Invoked when time is changed.
    * @param {number} newValue new time (in ms).
+   * @param {number} oldValue old time (in ms).
    */
-  onControllerTimeChanged: function(oldValue, newValue) {
+  timeChanged: function(newValue, oldValue) {
     // Ignores updates from the audio element.
     if (this.lastAudioUpdateTime_ === newValue)
       return;
 
-    if (this.audioElement.readyState !== 0)
-      this.audioElement.currentTime = this.audioController.time / 1000;
+    if (this.$.audio.readyState !== 0)
+      this.$.audio.currentTime = this.time / 1000;
   },
 
   /**
@@ -190,7 +258,7 @@
    */
   onAudioEnded: function() {
     this.playcount++;
-    this.advance_(true /* forward */, this.model.repeat);
+    this.advance_(true /* forward */, this.repeat);
   },
 
   /**
@@ -198,7 +266,7 @@
    * This handler is registered in this.ready().
    */
   onAudioError: function() {
-    this.scheduleAutoAdvance_(true /* forward */, this.model.repeat);
+    this.scheduleAutoAdvance_(true /* forward */, this.repeat);
   },
 
   /**
@@ -207,10 +275,9 @@
    * @private
    */
   onAudioStatusUpdate_: function() {
-    this.audioController.time =
-        (this.lastAudioUpdateTime_ = this.audioElement.currentTime * 1000);
-    this.audioController.duration = this.audioElement.duration * 1000;
-    this.audioController.playing = !this.audioElement.paused;
+    this.time = (this.lastAudioUpdateTime_ = this.$.audio.currentTime * 1000);
+    this.duration = this.$.audio.duration * 1000;
+    this.playing = !this.$.audio.paused;
   },
 
   /**
@@ -220,8 +287,8 @@
   onReplayCurrentTrack: function() {
     // Changes the current time back to the beginning, regardless of the current
     // status (playing or paused).
-    this.audioElement.currentTime = 0;
-    this.audioController.time = 0;
+    this.$.audio.currentTime = 0;
+    this.time = 0;
   },
 
   /**
@@ -233,21 +300,21 @@
   advance_: function(forward, repeat) {
     this.cancelAutoAdvance_();
 
-    var nextTrackIndex = this.trackList.getNextTrackIndex(forward, true);
+    var nextTrackIndex = this.$.trackList.getNextTrackIndex(forward, true);
     var isNextTrackAvailable =
-        (this.trackList.getNextTrackIndex(forward, repeat) !== -1);
+        (this.$.trackList.getNextTrackIndex(forward, repeat) !== -1);
 
-    this.audioController.playing = isNextTrackAvailable;
+    this.playing = isNextTrackAvailable;
 
     // If there is only a single file in the list, 'currentTrackInde' is not
     // changed and the handler is not invoked. Instead, plays here.
     // TODO(yoshiki): clean up the code around here.
     if (isNextTrackAvailable &&
-        this.trackList.currentTrackIndex == nextTrackIndex) {
-      this.audioElement.play();
+        this.$.trackList.currentTrackIndex == nextTrackIndex) {
+      this.$.audio.play();
     }
 
-    this.trackList.currentTrackIndex = nextTrackIndex;
+    this.$.trackList.currentTrackIndex = nextTrackIndex;
   },
 
   /**
@@ -303,19 +370,6 @@
   },
 
   /**
-   * The index of the current track.
-   * If the list has no tracks, the value must be -1.
-   *
-   * @type {number}
-   */
-  get currentTrackIndex() {
-    return this.trackList.currentTrackIndex;
-  },
-  set currentTrackIndex(value) {
-    this.trackList.currentTrackIndex = value;
-  },
-
-  /**
    * The list of the tracks in the playlist.
    *
    * When it changed, current operation including playback is stopped and
@@ -324,19 +378,19 @@
    * @type {Array<AudioPlayer.TrackInfo>}
    */
   get tracks() {
-    return this.trackList ? this.trackList.tracks : null;
+    return this.$.trackList ? this.$.trackList.tracks : null;
   },
   set tracks(tracks) {
-    if (this.trackList.tracks === tracks)
+    if (this.$.trackList.tracks === tracks)
       return;
 
     this.cancelAutoAdvance_();
 
-    this.trackList.tracks = tracks;
-    var currentTrack = this.trackList.getCurrentTrack();
-    if (currentTrack && currentTrack.url != this.audioElement.src) {
-      this.audioElement.src = currentTrack.url;
-      this.audioElement.play();
+    this.$.trackList.tracks = tracks;
+    var currentTrack = this.$.trackList.getCurrentTrack();
+    if (currentTrack && currentTrack.url != this.$.audio.src) {
+      this.$.audio.src = currentTrack.url;
+      this.$.audio.play();
     }
   },
 
@@ -344,7 +398,7 @@
    * Invoked when the audio player is being unloaded.
    */
   onPageUnload: function() {
-    this.audioElement.src = '';  // Hack to prevent crashing.
+    this.$.audio.src = '';  // Hack to prevent crashing.
   },
 
   /**
@@ -354,27 +408,26 @@
   onKeyDown_: function(event) {
     switch (event.keyIdentifier) {
       case 'Up':
-        if (this.audioController.volumeSliderShown && this.model.volume < 100)
+        if (this.$.audioController.volumeSliderShown && this.model.volume < 100)
           this.model.volume += 1;
         break;
       case 'Down':
-        if (this.audioController.volumeSliderShown && this.model.volume > 0)
+        if (this.$.audioController.volumeSliderShown && this.model.volume > 0)
           this.model.volume -= 1;
         break;
       case 'PageUp':
-        if (this.audioController.volumeSliderShown && this.model.volume < 91)
+        if (this.$.audioController.volumeSliderShown && this.model.volume < 91)
           this.model.volume += 10;
         break;
       case 'PageDown':
-        if (this.audioController.volumeSliderShown && this.model.volume > 9)
+        if (this.$.audioController.volumeSliderShown && this.model.volume > 9)
           this.model.volume -= 10;
         break;
       case 'MediaNextTrack':
         this.onControllerNextClicked();
         break;
       case 'MediaPlayPause':
-        var playing = this.audioController.playing;
-        this.onControllerPlayingChanged(playing, !playing);
+        this.playing = !this.playing;
         break;
       case 'MediaPreviousTrack':
         this.onControllerPreviousClicked();
@@ -384,6 +437,15 @@
         break;
     }
   },
+
+  /**
+   * Computes volume value for audio element. (should be in [0.0, 1.0])
+   * @param {number} volume Volume which is set in the UI. ([0, 100])
+   * @return {number}
+   */
+  computeAudioVolume_: function(volume) {
+    return volume / 100;
+  }
 };
 
-Polymer('audio-player', AudioPlayerElement.prototype);
+Polymer(AudioPlayerElement.prototype);
diff --git a/ui/file_manager/audio_player/elements/control_panel.html b/ui/file_manager/audio_player/elements/control_panel.html
index e8fd56ad..ce6aba3 100644
--- a/ui/file_manager/audio_player/elements/control_panel.html
+++ b/ui/file_manager/audio_player/elements/control_panel.html
@@ -4,29 +4,28 @@
   -- found in the LICENSE file.
   -->
 
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="volume_controller.html">
 
-<polymer-element name="control-panel">
+<dom-module id="control-panel">
+  <link rel="import" type="css" href="control_panel.css">
   <template>
-    <link rel="stylesheet" href="control_panel.css">
-
     <div class="controls">
       <div class="upper-controls time-controls">
         <div class="time media-control">
-          <div class="current">{{timeString_}}</div>
+          <div class="current">[[time2string_(time)]]</div>
         </div>
         <div class="progress media-control custom-slider">
           <input name="timeInput" type="range" touch-action="manipulation"
-                 min="0" max="{{duration}}" value="{{time}}">
+                 min="0" max="[[duration]]" value="{{time::input}}">
           <div class="bar">
-            <div class="filled" style="width: {{time/duration*100}}%;"></div>
+            <div class="filled" style$="[[computeProgressBarStyle_(time, duration)]]"></div>
             <div class="cap left"></div>
             <div class="cap right"></div>
           </div>
         </div>
         <div class="time media-control">
-          <div class="duration">{{durationString_}}</div>
+          <div class="duration">[[time2string_(duration)]]</div>
         </div>
       </div>
       <div class="lower-controls audio-controls">
@@ -35,7 +34,7 @@
           <label>
             <input id="shuffleCheckbox"
                    type="checkbox"
-                   checked="{{model.shuffle}}">
+                   checked="{{shuffle::change}}">
             <span class="icon"></span>
           </label>
         </button>
@@ -45,7 +44,7 @@
           <label>
             <input id="repeatCheckbox"
                    type="checkbox"
-                   checked="{{model.repeat}}">
+                   checked="{{repeat::change}}">
             <span class="icon"></span>
           </label>
         </button>
@@ -53,15 +52,15 @@
         <!-- Prev button in the bottom line. -->
         <button class="previous media-button"
                state="default"
-               on-click="{{previousClick}}">
+               on-click="previousClick">
           <div class="normal default"></div>
           <div class="disabled"></div>
         </button>
 
         <!-- Play button in the bottom line. -->
         <button class="play media-control media-button"
-                state='{{playing ? "playing" : "ended"}}'
-                on-click="{{playClick}}">
+                state$="[[computePlayState_(playing)]]"
+                on-click="playClick">
           <div class="normal playing"></div>
           <div class="normal ended"></div>
           <div class="disabled"></div>
@@ -70,7 +69,7 @@
         <!-- Next button in the bottom line. -->
         <button class="next media-button"
                 state="default"
-                on-click="{{nextClick}}">
+                on-click="nextClick">
           <div class="normal default"></div>
           <div class="disabled"></div>
         </button>
@@ -78,7 +77,7 @@
         <div id="volumeContainer"
              class="default-hidden"
              anchor-point="bottom center">
-          <volume-controller id="volumeSlider"
+          <volume-controller id="volumeSlider" value="{{volume}}"
                              width="32" height="85" value="50">
           </volume-controller>
 
@@ -89,10 +88,9 @@
         <button id="volumeButton"
                 class="volume media-button toggle"
                 state="default"
-                on-click="{{volumeButtonClick}}"
                 anchor-point="bottom center">
           <label>
-            <input type="checkbox" checked="{{volumeSliderShown}}">
+            <input type="checkbox" checked="{{volumeSliderShown::change}}">
             <span class="icon"></span>
           </label>
         </button>
@@ -102,12 +100,13 @@
                 class="playlist media-button toggle"
                 state="default">
           <label>
-            <input type="checkbox" checked="{{model.expanded}}">
+            <input type="checkbox" checked="{{expanded::change}}">
             <span class="icon"></span>
           </label>
         </button>
       </div>
     </div>
   </template>
-  <script src="control_panel.js"></script>
-</polymer-element>
+</dom-module>
+
+<script src="control_panel.js"></script>
diff --git a/ui/file_manager/audio_player/elements/control_panel.js b/ui/file_manager/audio_player/elements/control_panel.js
index e4de2f6..d616ffb 100644
--- a/ui/file_manager/audio_player/elements/control_panel.js
+++ b/ui/file_manager/audio_player/elements/control_panel.js
@@ -26,21 +26,88 @@
   }
 
   /**
-   * Converts the time into human friendly string.
-   * @param {number} time Time to be converted.
-   * @return {string} String representation of the given time
-   */
-  function time2string(time) {
-    return ~~(time / 60000) + ':' + ('0' + ~~(time / 1000 % 60)).slice(-2);
-  }
-
-  /**
    * @constructor
    * @extends {PolymerElement}
    */
   var ControlPanelElement = function() {};
 
   ControlPanelElement.prototype = {
+    is: 'control-panel',
+
+    properties: {
+      /**
+       * Flag whether the audio is playing or paused. True if playing, or false
+       * paused.
+       */
+      playing: {
+        type: Boolean,
+        value: false,
+        notify: true
+      },
+
+      /**
+       * Current elapsed time in the current music in millisecond.
+       */
+      time: {
+        type: Number,
+        value: 0,
+        notify: true
+      },
+
+      /**
+       * Total length of the current music in millisecond.
+       */
+      duration: {
+        type: Number,
+        value: 0
+      },
+
+      /**
+       * Whether the shuffle button is ON.
+       */
+      shuffle: {
+        type: Boolean,
+        value: false,
+        notify: true
+      },
+
+      /**
+       * Whether the repeat button is ON.
+       */
+      repeat: {
+        type: Boolean,
+        value: false,
+        notify: true
+      },
+
+      /**
+       * The audio volume. 0 is silent, and 100 is maximum loud.
+       */
+      volume: {
+        type: Number,
+        notify: true
+      },
+
+      /**
+       * Whether the expanded button is ON.
+       */
+      expanded: {
+        type: Boolean,
+        value: false,
+        notify: true
+      },
+
+      /**
+       * Whether the volume slider is expanded or not.
+       */
+      volumeSliderShown: {
+        type: Boolean,
+        value: false,
+        observer: 'volumeSliderShownChanged',
+        notify: true
+      }
+    },
+
     /**
      * Initializes an element. This method is called automatically when the
      * element is ready.
@@ -48,73 +115,11 @@
     ready: function() {
       var onFocusoutBound = this.onVolumeControllerFocusout_.bind(this);
 
-      this.volumeSlider = this.$.volumeSlider;
-      this.volumeButton = this.$.volumeButton;
-      this.volumeContainer = this.$.volumeContainer;
-
-      this.volumeSlider.addEventListener('focusout', onFocusoutBound);
-      this.volumeButton.addEventListener('focusout', onFocusoutBound);
+      this.$.volumeSlider.addEventListener('focusout', onFocusoutBound);
+      this.$.volumeButton.addEventListener('focusout', onFocusoutBound);
     },
 
     /**
-     * Model object of the Audio Player.
-     * @type {AudioPlayerModel}
-     */
-    model: null,
-
-    /**
-     * Invoked when the model changed.
-     * @param {AudioPlayerModel} oldValue Old Value.
-     * @param {AudioPlayerModel} newValue New Value.
-     */
-    modelChanged: function(oldValue, newValue) {
-      this.volumeSlider.model = newValue;
-    },
-
-    /**
-     * Current elapsed time in the current music in millisecond.
-     * @type {number}
-     */
-    time: 0,
-
-    /**
-     * String representation of 'time'.
-     * @type {number}
-     * @private
-     */
-    get timeString_() {
-      return time2string(this.time);
-    },
-
-    /**
-     * Total length of the current music in millisecond.
-     * @type {number}
-     */
-    duration: 0,
-
-    /**
-     * String representation of 'duration'.
-     * @type {string}
-     * @private
-     */
-    get durationString_() {
-      return time2string(this.duration);
-    },
-
-    /**
-     * Flag whether the volume slider is expanded or not.
-     * @type {boolean}
-     */
-    volumeSliderShown: false,
-
-    /**
-     * Flag whether the audio is playing or paused. True if playing, or false
-     * paused.
-     * @type {boolean}
-     */
-    playing: false,
-
-    /**
      * Invoked when the next button is clicked.
      */
     nextClick: function() {
@@ -136,12 +141,11 @@
     },
 
     /**
-     * Invoked the volume button is clicked.
-     * @param {!Event} event The event.
+     * Invoked when the property 'volumeSliderShown' changes.
+     * @param {boolean} shown
      */
-    volumeButtonClick: function(event) {
-      this.showVolumeController_(this.volumeSliderShown);
-      event.stopPropagation();
+    volumeSliderShownChanged: function(shown) {
+      this.showVolumeController_(shown);
     },
 
     /**
@@ -153,9 +157,8 @@
       if (this.volumeSliderShown) {
         // If the focus goes out of the volume, hide the volume control.
         if (!event.relatedTarget ||
-            (event.relatedTarget !== this.volumeButton &&
-             event.relatedTarget !== this.volumeSlider)) {
-          this.showVolumeController_(false);
+            (event.relatedTarget !== this.$.volumeButton &&
+             event.relatedTarget !== this.$.volumeSlider)) {
           this.volumeSliderShown = false;
         }
       }
@@ -169,12 +172,37 @@
     showVolumeController_: function(show) {
       if (show) {
         matchBottomLine(this.$.volumeContainer, this.$.volumeButton);
-        this.volumeContainer.style.visibility = 'visible';
+        this.$.volumeContainer.style.visibility = 'visible';
       } else {
-        this.volumeContainer.style.visibility = 'hidden';
+        this.$.volumeContainer.style.visibility = 'hidden';
       }
     },
+
+    /**
+     * Converts the time into human friendly string.
+     * @param {number} time Time to be converted.
+     * @return {string} String representation of the given time
+     */
+    time2string_: function(time) {
+      return ~~(time / 60000) + ':' + ('0' + ~~(time / 1000 % 60)).slice(-2);
+    },
+
+    /**
+     * Computes state for play button based on 'playing' property.
+     * @return {string}
+     */
+    computePlayState_: function(playing) {
+      return playing ? "playing" : "ended";
+    },
+
+    /**
+     * Computes style for '.filled' element of progress bar.
+     * @return {string}
+     */
+    computeProgressBarStyle_: function(time, duration) {
+      return 'width: ' + (time / duration * 100) + '%;';
+    }
   };
 
-  Polymer('control-panel', ControlPanelElement.prototype);
+  Polymer(ControlPanelElement.prototype);
 })();  // Anonymous closure
diff --git a/ui/file_manager/audio_player/elements/track_list.html b/ui/file_manager/audio_player/elements/track_list.html
index eeeff3a..b31e45f 100644
--- a/ui/file_manager/audio_player/elements/track_list.html
+++ b/ui/file_manager/audio_player/elements/track_list.html
@@ -4,20 +4,20 @@
   -- found in the LICENSE file.
   -->
 
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 
-<polymer-element name="track-list" attributes="tracks">
+<dom-module id="track-list">
+  <link rel="import" type="css" href="track_list.css">
   <template>
-    <link rel="stylesheet" href="track_list.css">
-
-    <template id="tracks" repeat="{{track, index in tracks}}">
-      <div class="track" active?="{{track.active}}" index="{{index}}" on-click="{{trackClicked}}">
+    <template is="dom-repeat" id="tracks" items="[[tracks]]">
+      <div class="track" active$="[[item.active]]" index$="[[index]]" on-click="trackClicked">
         <div class="data">
-          <div class="data-title">{{track.title}}</div>
-          <div class="data-artist">{{track.artist}}</div>
+          <div class="data-title">[[item.title]]</div>
+          <div class="data-artist">[[item.artist]]</div>
         </div>
       </div>
     </template>
   </template>
-  <script src="track_list.js"></script>
-</polymer-element>
+</dom-module>
+
+<script src="track_list.js"></script>
diff --git a/ui/file_manager/audio_player/elements/track_list.js b/ui/file_manager/audio_player/elements/track_list.js
index e887f17..b53fa03 100644
--- a/ui/file_manager/audio_player/elements/track_list.js
+++ b/ui/file_manager/audio_player/elements/track_list.js
@@ -12,6 +12,41 @@
   var TrackListElement = function() {};
 
   TrackListElement.prototype = {
+    is: 'track-list',
+
+    properties: {
+      /**
+       * List of tracks.
+       * @type {Array<AudioPlayer.TrackInfo>}
+       */
+      tracks: {
+        type: Array,
+        value: [],
+        observer: 'tracksChanged'
+      },
+
+      /**
+       * Track index of the current track.
+       * If the tracks property is empty, it should be -1. Otherwise, be a valid
+       * track number.
+       */
+      currentTrackIndex: {
+        type: Number,
+        value: -1,
+        observer: 'currentTrackIndexChanged',
+        notify: true
+      },
+
+      /**
+       * Whether shuffling play order is enabled or not.
+       */
+      shuffle: {
+        type: Boolean,
+        value: false,
+        observer: 'shuffleChanged'
+      }
+    },
+
     /**
      * Initializes an element. This method is called automatically when the
      * element is ready.
@@ -38,65 +73,37 @@
     },
 
     /**
-     * Registers handlers for changing of external variables
-     */
-    observe: {
-      'model.shuffle': 'onShuffleChanged',
-    },
-
-    /**
-     * Model object of the Audio Player.
-     * @type {AudioPlayerModel}
-     */
-    model: null,
-
-    /**
-     * List of tracks.
-     * @type {Array<AudioPlayer.TrackInfo>}
-     */
-    tracks: [],
-
-    /**
      * Play order of the tracks. Each value is the index of 'this.tracks'.
      * @type {Array<number>}
      */
     playOrder: [],
 
     /**
-     * Track index of the current track.
-     * If the tracks property is empty, it should be -1. Otherwise, be a valid
-     * track number.
-     *
-     * @type {number}
-     */
-    currentTrackIndex: -1,
-
-    /**
      * Invoked when 'shuffle' property is changed.
-     * @param {boolean} oldValue Old value.
      * @param {boolean} newValue New value.
+     * @param {boolean} oldValue Old value.
      */
-    onShuffleChanged: function(oldValue, newValue) {
+    shuffleChanged: function(newValue, oldValue) {
       this.generatePlayOrder(true /* keep the current track */);
     },
 
     /**
      * Invoked when the current track index is changed.
-     * @param {number} oldValue old value.
      * @param {number} newValue new value.
+     * @param {number} oldValue old value.
      */
-    currentTrackIndexChanged: function(oldValue, newValue) {
+    currentTrackIndexChanged: function(newValue, oldValue) {
       if (oldValue === newValue)
         return;
 
       if (!isNaN(oldValue) && 0 <= oldValue && oldValue < this.tracks.length)
-        this.tracks[oldValue].active = false;
+        this.set('tracks.' + oldValue + '.active', false);
 
       if (0 <= newValue && newValue < this.tracks.length) {
         var currentPlayOrder = this.playOrder.indexOf(newValue);
         if (currentPlayOrder !== -1) {
           // Success
-          this.tracks[newValue].active = true;
+          this.set('tracks.' + newValue + '.active', true);
 
           this.ensureTrackInViewport_(newValue /* trackIndex */);
           return;
@@ -112,10 +119,10 @@
 
     /**
      * Invoked when 'tracks' property is changed.
-     * @param {Array<AudioPlayer.TrackInfo>} oldValue Old value.
      * @param {Array<AudioPlayer.TrackInfo>} newValue New value.
+     * @param {Array<AudioPlayer.TrackInfo>} oldValue Old value.
      */
-    tracksChanged: function(oldValue, newValue) {
+    tracksChanged: function(newValue, oldValue) {
       // Note: Sometimes both oldValue and newValue are null though the actual
       // values are not null. Maybe it's a bug of Polymer.
 
@@ -126,7 +133,7 @@
         // Restore the active track.
         if (this.currentTrackIndex !== -1 &&
             this.currentTrackIndex < this.tracks.length) {
-          this.tracks[this.currentTrackIndex].active = true;
+          this.set('tracks.' + this.currentTrackIndex + '.active', true);
         }
 
         // Reset play order and current index.
@@ -145,7 +152,7 @@
       if (this.tracks.length === 0)
         this.currentTrackIndex = -1;
       else
-        this.tracks[this.currentTrackIndex].active = true;
+        this.set('tracks.' + this.currentTrackIndex + '.active', true);
     },
 
     /**
@@ -212,7 +219,7 @@
           this.tracks.
           map(function(unused, index) { return index; });
 
-      if (this.model && this.model.shuffle) {
+      if (this.shuffle) {
         // Randomizes the play order array (Schwarzian-transform algorithm).
         this.playOrder = this.playOrder
             .map(function(a) {
@@ -312,5 +319,5 @@
     },
   };  // TrackListElement.prototype for 'track-list'
 
-  Polymer('track-list', TrackListElement.prototype);
+  Polymer(TrackListElement.prototype);
 })();  // Anonymous closure
diff --git a/ui/file_manager/audio_player/elements/volume_controller.html b/ui/file_manager/audio_player/elements/volume_controller.html
index db64ec6..1431716 100644
--- a/ui/file_manager/audio_player/elements/volume_controller.html
+++ b/ui/file_manager/audio_player/elements/volume_controller.html
@@ -4,20 +4,20 @@
   -- found in the LICENSE file.
   -->
 
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 
-<polymer-element name="volume-controller" attributes="width height value">
+<dom-module id="volume-controller">
+  <link rel="import" type="css" href="volume_controller.css">
   <template>
-    <link rel="stylesheet" href="volume_controller.css">
-
     <div id="background"></div>
     <input name="rawValueInput" id="rawValueInput" touch-action="manipulation"
-           type="range" min="0" max="100" value="{{rawValue}}">
+           type="range" min="0" max="100" value="{{rawValue::input}}">
     <div id="bar">
-      <div class="filled" style="height: {{rawValue}}%;"></div>
+      <div class="filled" style$="[[computeFilledStyle_(rawValue)]]"></div>
       <div class="cap left"></div>
       <div class="cap right"></div>
     </div>
   </template>
-  <script src="volume_controller.js"></script>
-</polymer-element>
+</dom-module>
+
+<script src="volume_controller.js"></script>
diff --git a/ui/file_manager/audio_player/elements/volume_controller.js b/ui/file_manager/audio_player/elements/volume_controller.js
index 4e9fa62..abdfcaa 100644
--- a/ui/file_manager/audio_player/elements/volume_controller.js
+++ b/ui/file_manager/audio_player/elements/volume_controller.js
@@ -12,6 +12,52 @@
   var VolumeControllerElement = function() {};
 
   VolumeControllerElement.prototype = {
+    is: 'volume-controller',
+
+    properties: {
+      /**
+       * Width of the element in pixels. Must be specified before ready() is
+       * called. Dynamic change is not supported.
+       * @type {number}
+       */
+      width: {
+        type: Number,
+        value: 32
+      },
+
+      /**
+       * Height of the element in pixels. Must be specified before ready() is
+       * called. Dynamic change is not supported.
+       * @type {number}
+       */
+      height: {
+        type: Number,
+        value: 100
+      },
+
+      /**
+       * Volume. 0 is silent, and 100 is maximum.
+       * @type {number}
+       */
+      value: {
+        type: Number,
+        value: 50,
+        observer: 'valueChanged',
+        notify: true
+      },
+
+      /**
+       * Volume. 100 is silent, and 0 is maximum.
+       * @type {number}
+       */
+      rawValue: {
+        type: Number,
+        value: 0,
+        observer: 'rawValueChanged',
+        notify: true
+      }
+    },
+
     /**
      * Initializes an element. This method is called automatically when the
      * element is ready.
@@ -37,71 +83,23 @@
     },
 
     /**
-     * Registers handlers for changing of external variables
-     */
-    observe: {
-      'model.volume': 'onVolumeChanged',
-    },
-
-    /**
-     * Model object of the Audio Player.
-     * @type {AudioPlayerModel}
-     */
-    model: null,
-
-    /**
-     * Invoked when the model changed.
-     * @param {AudioPlayerModel} oldValue Old Value.
-     * @param {AudioPlayerModel} newValue New Value.
-     */
-    modelChanged: function(oldValue, newValue) {
-      this.onVolumeChanged((oldValue || {}).volume, (newValue || {}).volume);
-    },
-
-    /**
-     * Volume. 0 is silent, and 100 is maximum.
-     * @type {number}
-     */
-    value: 50,
-
-    /**
-     * Volume. 1000 is silent, and 0 is maximum.
-     * @type {number}
-     */
-    rawValue: 0,
-
-    /**
-     * Height of the element in pixels. Must be specified before ready() is
-     * called. Dynamic change is not supported.
-     * @type {number}
-     */
-    height: 100,
-
-    /**
-     * Width of the element in pixels. Must be specified before ready() is
-     * called. Dynamic change is not supported.
-     * @type {number}
-     */
-    width: 32,
-
-    /**
-     * Invoked when the 'volume' value in the model is changed.
-     * @param {number} oldValue Old value.
+     * Invoked when the 'volume' value is changed.
      * @param {number} newValue New value.
+     * @param {number} oldValue Old value.
      */
-    onVolumeChanged: function(oldValue, newValue) {
+    valueChanged: function(newValue, oldValue) {
       if (oldValue != newValue)
         this.rawValue = 100 - newValue;
     },
 
     /**
      * Invoked when the 'rawValue' property is changed.
-     * @param {number} oldValue Old value.
      * @param {number} newValue New value.
+     * @param {number} oldValue Old value.
      */
-    rawValueChanged: function(oldValue, newValue) {
-      if (oldValue != newValue)
-        this.model.volume = 100 - newValue;
+    rawValueChanged: function(newValue, oldValue) {
+      if (oldValue !== newValue)
+        this.value = 100 - newValue;
     },
 
     /**
@@ -120,7 +118,15 @@
           break;
       }
     },
+
+    /**
+     * Computes style for '.filled' element based on raw value.
+     * @return {string}
+     */
+    computeFilledStyle_: function(rawValue) {
+      return 'height: ' + rawValue + '%;';
+    }
   };
 
-  Polymer('volume-controller', VolumeControllerElement.prototype);
+  Polymer(VolumeControllerElement.prototype);
 })();  // Anonymous closure
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js
index 1646ff1..d715696 100644
--- a/ui/file_manager/audio_player/js/audio_player.js
+++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -24,7 +24,8 @@
   Object.observe(this.model_, function(changes) {
     for (var i = 0; i < changes.length; i++) {
       var change = changes[i];
-      if (change.name == 'expanded' && change.type == 'update') {
+      if (change.name == 'expanded' &&
+          (change.type == 'add' || change.type == 'update')) {
         this.onModelExpandedChanged(change.oldValue, change.object.expanded);
         break;
       }
@@ -49,7 +50,9 @@
     /** @type {AudioPlayerElement} */ (document.querySelector('audio-player'));
   // TODO(yoshiki): Move tracks into the model.
   this.player_.tracks = [];
-  this.player_.model = this.model_;
+  this.model_.initialize(function() {
+    this.player_.model = this.model_;
+  }.bind(this));
 
   // Run asynchronously after an event of model change is delivered.
   setTimeout(function() {
@@ -116,7 +119,7 @@
   window.appState = JSON.parse(JSON.stringify(playlist));  // cloning
   util.saveAppState();
 
-  this.isExpanded_ = this.model_.expanded;
+  this.isExpanded_ = this.player_.expanded;
 
   // Resolving entries has to be done after the volume manager is initialized.
   this.volumeManager_.ensureInitialized(function() {
@@ -218,12 +221,12 @@
 
   this.currentTrackIndex_ = newTrack;
   this.player_.currentTrackIndex = this.currentTrackIndex_;
-  this.player_.audioController.time = time;
+  this.player_.time = time;
 
   // Run asynchronously after an event of current track change is delivered.
   setTimeout(function() {
     if (!window.appReopen)
-      this.player_.audioElement.play();
+      this.player_.$.audio.play();
 
     window.appState.position = this.currentTrackIndex_;
     window.appState.time = 0;
@@ -284,11 +287,11 @@
   if (!this.isExpanded_ &&
       window.innerHeight >= AudioPlayer.EXPANDED_MODE_MIN_HEIGHT) {
     this.isExpanded_ = true;
-    this.model_.expanded = true;
+    this.player_.expanded = true;
   } else if (this.isExpanded_ &&
              window.innerHeight < AudioPlayer.EXPANDED_MODE_MIN_HEIGHT) {
     this.isExpanded_ = false;
-    this.model_.expanded = false;
+    this.player_.expanded = false;
   }
 };
 
@@ -383,7 +386,7 @@
 AudioPlayer.prototype.syncHeight_ = function() {
   var targetHeight;
 
-  if (this.model_.expanded) {
+  if (this.player_.expanded) {
     // Expanded.
     if (!this.lastExpandedHeight_ ||
         this.lastExpandedHeight_ < AudioPlayer.EXPANDED_MODE_MIN_HEIGHT) {
@@ -456,6 +459,6 @@
 };
 
 // Starts loading the audio player.
-window.addEventListener('polymer-ready', function(e) {
+window.addEventListener('DOMContentLoaded', function(e) {
   AudioPlayer.load();
 });
diff --git a/ui/file_manager/audio_player/js/audio_player_model.js b/ui/file_manager/audio_player/js/audio_player_model.js
index c8645ee9..7bbef274 100644
--- a/ui/file_manager/audio_player/js/audio_player_model.js
+++ b/ui/file_manager/audio_player/js/audio_player_model.js
@@ -6,7 +6,9 @@
  * The model class for audio player.
  * @constructor
  */
-function AudioPlayerModel() {
+function AudioPlayerModel() {}
+
+AudioPlayerModel.prototype.initialize = function(callback) {
   'use strict';
 
   /**
@@ -14,7 +16,7 @@
    * @type {!Object<*>}
    * @const
    */
-  var VALUES = Object.freeze(
+  var VALUES =
     /**
      * They will be used as properties of AudioPlayerModel.
      * @lends {AudioPlayerModel.prototype}
@@ -24,7 +26,7 @@
       repeat: false,
       volume: 100,
       expanded: false,
-    });
+    };
 
   /**
    * Prefix of the stored values in the storage.
@@ -48,9 +50,9 @@
   /**
    * Load the values in the model from the storage.
    * @param {AudioPlayerModel} model The model.
-   * @param {function()} callback Called when the load is completed.
+   * @param {function()} inCallback Called when the load is completed.
    */
-  function loadModel(model, callback) {
+  function loadModel(model, inCallback) {
     // Restores the values from the storage
     var objectsToBeRead = Object.keys(VALUES).
                           map(function(a) {
@@ -62,7 +64,7 @@
         // Strips the prefix.
         model[key.substr(STORAGE_PREFIX.length)] = result[key];
       }
-      callback();
+      inCallback();
     });
   };
 
@@ -79,5 +81,6 @@
     Object.observe(target, function(changes) {
       saveModel(target);
     });
+    callback();
   });
 }
diff --git a/ui/file_manager/file_manager/background/js/launcher_search.js b/ui/file_manager/file_manager/background/js/launcher_search.js
index 381831a2..670afd08 100644
--- a/ui/file_manager/file_manager/background/js/launcher_search.js
+++ b/ui/file_manager/file_manager/background/js/launcher_search.js
@@ -121,19 +121,27 @@
               // TODO(yawano): Use filetype_folder_shared.png for a shared
               //     folder.
               // TODO(yawano): Add archive launcher filetype icon.
-              var fileType = FileType.getIcon(result.entry);
-              if (fileType === 'UNKNOWN' || fileType === 'archive')
-                fileType = 'generic';
+              var icon = FileType.getIcon(result.entry);
+              if (icon === 'UNKNOWN' || icon === 'archive')
+                icon = 'generic';
 
               var useHighDpiIcon = window.devicePixelRatio > 1.0;
               var iconUrl = chrome.runtime.getURL(
                   'foreground/images/launcher_filetypes/' +
                   (useHighDpiIcon ? '2x/' : '') + 'launcher_filetype_' +
-                  fileType + '.png');
+                  icon + '.png');
+
+              // Hide extensions for hosted files.
+              var title = FileType.isHosted(result.entry) ?
+                  result.entry.name.substr(
+                      0,
+                      result.entry.name.length -
+                          FileType.getExtension(result.entry).length) :
+                  result.entry.name;
 
               return {
                 itemId: result.entry.toURL(),
-                title: result.entry.name,
+                title: title,
                 iconUrl: iconUrl,
                 // Relevance is set as 2 for all results as a temporary
                 // implementation. 2 is the middle value.
diff --git a/ui/file_manager/file_manager/background/js/media_scanner.js b/ui/file_manager/file_manager/background/js/media_scanner.js
index 365da20a..ca92eb5 100644
--- a/ui/file_manager/file_manager/background/js/media_scanner.js
+++ b/ui/file_manager/file_manager/background/js/media_scanner.js
@@ -147,6 +147,7 @@
         this.notify_(importer.ScanEvent.INVALIDATED, scan);
       }.bind(this));
 
+  scan.setCandidateCount(entries.length);
   var scanPromises = entries.map(this.onUniqueFileFound_.bind(this, scan));
 
   Promise.all(scanPromises)
@@ -178,6 +179,7 @@
  */
 importer.DefaultMediaScanner.prototype.scanMediaFiles_ =
     function(scan, entries) {
+  scan.setCandidateCount(entries.length);
   var handleFileEntry = this.onFileEntryFound_.bind(this, scan);
 
   /**
@@ -274,6 +276,7 @@
  */
 importer.DefaultMediaScanner.prototype.onFileEntryFound_ =
     function(scan, entry) {
+
   return this.getDisposition_(entry, importer.Destination.GOOGLE_DRIVE)
       .then(
           /**
@@ -300,7 +303,9 @@
 importer.DefaultMediaScanner.prototype.onUniqueFileFound_ =
     function(scan, entry) {
 
+  scan.onCandidatesProcessed(1);
   if (!importer.isEligibleType(entry)) {
+    this.notify_(importer.ScanEvent.UPDATED, scan);
     return Promise.resolve();
   }
 
@@ -329,7 +334,9 @@
  */
 importer.DefaultMediaScanner.prototype.onDuplicateFileFound_ =
     function(scan, entry, disposition) {
+  scan.onCandidatesProcessed(1);
   scan.addDuplicateEntry(entry, disposition);
+  this.notify_(importer.ScanEvent.UPDATED, scan);
   return Promise.resolve();
 };
 
@@ -358,6 +365,19 @@
 importer.ScanResult.prototype.canceled;
 
 /**
+ * @param {number} count Sets the total number of candidate entries
+ *     that were checked while scanning. Used when determining
+ *     total progress.
+ */
+importer.ScanResult.prototype.setCandidateCount;
+
+/**
+ * Event method called when a candidate has been processed.
+ * @param {number} count
+ */
+importer.ScanResult.prototype.onCandidatesProcessed;
+
+/**
  * Returns all files entries discovered so far. The list will be
  * complete only after scanning has completed and {@code isFinal}
  * returns {@code true}.
@@ -399,7 +419,12 @@
  *   scanDuration: number,
  *   newFileCount: number,
  *   duplicates: !Object<!importer.Disposition, number>,
- *   sizeBytes: number
+ *   sizeBytes: number,
+ *   candidates: {
+ *     total: number,
+ *     processed: number
+ *   },
+ *   progress: number
  * }}
  */
 importer.ScanResult.Statistics;
@@ -428,6 +453,12 @@
   /** @private {function(!FileEntry): !Promise.<string>} */
   this.createHashcode_ = hashGenerator;
 
+  /** @private {number} */
+  this.candidateCount_ = 0;
+
+  /** @private {number} */
+  this.candidatesProcessed_ = 0;
+
   /**
    * List of file entries found while scanning.
    * @private {!Array<!FileEntry>}
@@ -499,6 +530,16 @@
 };
 
 /** @override */
+importer.DefaultScanResult.prototype.setCandidateCount = function(count) {
+  this.candidateCount_ = count;
+};
+
+/** @override */
+importer.DefaultScanResult.prototype.onCandidatesProcessed = function(count) {
+  this.candidatesProcessed_ = this.candidatesProcessed_ + count;
+};
+
+/** @override */
 importer.DefaultScanResult.prototype.getFileEntries = function() {
   return this.fileEntries_;
 };
@@ -595,11 +636,35 @@
         this.lastScanActivity_.getTime() - this.scanStarted_.getTime(),
     newFileCount: this.fileEntries_.length,
     duplicates: this.duplicateStats_,
-    sizeBytes: this.totalBytes_
+    sizeBytes: this.totalBytes_,
+    candidates: {
+      total: this.candidateCount_,
+      processed: this.candidatesProcessed_
+    },
+    progress: this.calculateProgress_()
   };
 };
 
 /**
+ * @return {number} Progress as an integer from 0-100.
+ * @private
+ */
+importer.DefaultScanResult.prototype.calculateProgress_ = function() {
+  var progress = (this.candidateCount_ > 0) ?
+      Math.floor(this.candidatesProcessed_ / this.candidateCount_ * 100) :
+      0;
+
+  // In case candate count was off, or any other mischief has happened,
+  // we want to ensure progress never exceeds 100.
+  if (progress > 100) {
+    console.warn('Progress exceeded 100.');
+    progress = 100;
+  }
+
+  return progress;
+};
+
+/**
  * Watcher for directories.
  * @interface
  */
diff --git a/ui/file_manager/file_manager/background/js/media_scanner_unittest.js b/ui/file_manager/file_manager/background/js/media_scanner_unittest.js
index 14cd555..3852706 100644
--- a/ui/file_manager/file_manager/background/js/media_scanner_unittest.js
+++ b/ui/file_manager/file_manager/background/js/media_scanner_unittest.js
@@ -197,6 +197,39 @@
 }
 
 /**
+ * Verifies that scanning a simple single-level directory produces 100%
+ * progress at completion.
+ */
+function testProgress(callback) {
+  var filenames = [
+    'foo',
+    'foo.jpg',
+    'bar.gif',
+    'baz.avi',
+    'foo.mp3',
+    'bar.txt'
+  ];
+  var expectedFiles = [
+    '/testProgress/foo.jpg',
+    '/testProgress/bar.gif',
+    '/testProgress/baz.avi'
+  ];
+  reportPromise(
+      makeTestFileSystemRoot('testProgress')
+          .then(populateDir.bind(null, filenames))
+          .then(
+              /**
+               * Scans the directory.
+               * @param {!DirectoryEntry} root
+               */
+              function(root) {
+                return scanner.scanDirectory(root).whenFinal();
+              })
+          .then(assertProgress.bind(null, 100)),
+      callback);
+}
+
+/**
  * Verifies that scanning ignores previously imported entries.
  */
 function testIgnoresPreviousImports(callback) {
@@ -371,6 +404,29 @@
       callback);
 }
 
+/**
+ * Verifies that scanning a simple single-level directory structure works.
+ */
+function testDefaultScanResult() {
+  var hashGenerator = function(file) {
+    return file.toURL();
+  };
+  var scan = new importer.DefaultScanResult(hashGenerator);
+
+  // 0 before we set candidate count
+  assertProgress(0, scan);
+
+  scan.setCandidateCount(3);
+  assertProgress(0, scan);
+
+  scan.onCandidatesProcessed(1);
+  assertProgress(33, scan);
+  scan.onCandidatesProcessed(1);
+  assertProgress(66, scan);
+  scan.onCandidatesProcessed(1);
+  assertProgress(100, scan);
+}
+
 function testInvalidation(callback) {
   var invalidatePromise = new Promise(function(fulfill) {
     scanner.addObserver(fulfill);
@@ -393,22 +449,36 @@
 
 /**
  * Verifies the results of the media scan are as expected.
- * @param {!Array<string>} expected
- * @param {!importer.ScanResults} results
+ * @param {number} expected, 0-100
+ * @param {!importer.ScanResults} scan
+ * @return {!importer.ScanResults}
  */
-function assertFilesFound(expected, results) {
-  assertFileEntryPathsEqual(expected, results.getFileEntries());
+function assertProgress(expected, scan) {
+  assertEquals(expected, scan.getStatistics().progress);
+  return scan;
+}
+
+/**
+ * Verifies the results of the media scan are as expected.
+ * @param {!Array<string>} expected
+ * @param {!importer.ScanResults} scan
+ * @return {!importer.ScanResults}
+ */
+function assertFilesFound(expected, scan) {
+  assertFileEntryPathsEqual(expected, scan.getFileEntries());
+  return scan;
   // TODO(smckay): Add coverage for getScanDurationMs && getTotalBytes.
 }
 
 /**
  * Verifies the results of the media scan are as expected.
  * @param {!Array<string>} expected
- * @param {!importer.ScanResults} results
+ * @param {!importer.ScanResults} scan
+ * @return {!importer.ScanResults}
  */
-function assertDuplicatesFound(expected, results) {
-  assertFileEntryPathsEqual(expected, results.getDuplicateFileEntries());
-  // TODO(smckay): Add coverage for getScanDurationMs && getTotalBytes.
+function assertDuplicatesFound(expected, scan) {
+  assertFileEntryPathsEqual(expected, scan.getDuplicateFileEntries());
+  return scan;
 }
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 8533865..3bfb07c 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -505,6 +505,22 @@
   cursor: pointer;
 }
 
+#cloud-import-details .progress {
+  height: 4px;
+  background-color: #E0E0E0;
+  border-radius: 2px;
+  margin-top: 14px;
+  width: 100%;
+}
+
+#cloud-import-details .progress .value {
+  background-color: #1AC222;
+  border-radius: 2px;
+  height: 4px;
+  transition: width 0.1s linear;
+  width: 0%;
+}
+
 #cloud-import-details paper-button {
   align-self: flex-end;
   color: white;
diff --git a/ui/file_manager/file_manager/foreground/js/import_controller.js b/ui/file_manager/file_manager/foreground/js/import_controller.js
index 05a1180..e976b567 100644
--- a/ui/file_manager/file_manager/foreground/js/import_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/import_controller.js
@@ -569,6 +569,13 @@
   /** @private {Element} */
   this.detailsBanner_ = document.querySelector('#cloud-import-details .banner');
 
+  /** @private {Element} */
+  this.progressContainer_ =
+      document.querySelector('#cloud-import-details .progress');
+  /** @private {Element} */
+  this.progressBar_ =
+      document.querySelector('#cloud-import-details .progress .value');
+
   /** @private {function(!importer.ClickSource)} */
   this.clickListener_;
 
@@ -733,6 +740,7 @@
       this.sideButton_.hidden = false;
       this.importButton_.hidden = true;
       this.cancelButton_.hidden = false;
+      this.progressContainer_.hidden = true;
 
       this.toolbarIcon_.setAttribute('icon', 'autorenew');
       this.statusIcon_.setAttribute('icon', 'autorenew');
@@ -752,6 +760,7 @@
       this.sideButton_.hidden = false;
       this.importButton_.hidden = true;
       this.cancelButton_.hidden = true;
+      this.progressContainer_.hidden = true;
 
       this.toolbarIcon_.setAttribute('icon', 'cloud-off');
       this.statusIcon_.setAttribute('icon', 'image:photo');
@@ -767,6 +776,7 @@
       this.sideButton_.hidden = false;
       this.importButton_.hidden = true;
       this.cancelButton_.hidden = true;
+      this.progressContainer_.hidden = true;
 
       this.toolbarIcon_.setAttribute('icon', 'cloud-done');
       this.statusIcon_.setAttribute('icon', 'cloud-done');
@@ -786,6 +796,7 @@
       this.sideButton_.hidden = false;
       this.importButton_.hidden = false;
       this.cancelButton_.hidden = true;
+      this.progressContainer_.hidden = true;
 
       this.toolbarIcon_.setAttribute('icon', 'cloud-upload');
       this.statusIcon_.setAttribute('icon', 'image:photo');
@@ -805,6 +816,10 @@
       this.importButton_.hidden = true;
       // TODO(smckay): implement cancellation for scanning.
       this.cancelButton_.hidden = true;
+      this.progressContainer_.hidden = false;
+
+      var stats = opt_scan.getStatistics();
+      this.progressBar_.style.width = stats.progress + '%';
 
       this.toolbarIcon_.setAttribute('icon', 'autorenew');
       this.statusIcon_.setAttribute('icon', 'autorenew');
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
index 5b83620..b893a60 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
@@ -79,27 +79,46 @@
     function(requests, nameMap, propertiesList) {
   var results = [];
   for (var i = 0; i < propertiesList.length; i++) {
-    var properties = propertiesList[i];
+    var prop = propertiesList[i];
     var item = new MetadataItem();
-    item.availableOffline = properties.availableOffline;
-    item.availableWhenMetered = properties.availableWhenMetered;
-    item.contentMimeType = properties.contentMimeType || '';
-    item.croppedThumbnailUrl = properties.croppedThumbnailUrl;
-    item.customIconUrl = properties.customIconUrl || '';
-    item.dirty = properties.dirty;
-    item.externalFileUrl = properties.externalFileUrl;
-    item.hosted = properties.hosted;
-    item.imageHeight = properties.imageHeight;
-    item.imageRotation = properties.imageRotation;
-    item.imageWidth = properties.imageWidth;
-    item.modificationTime = new Date(properties.modificationTime);
-    item.pinned = properties.pinned;
-    item.present = properties.present;
-    item.shared = properties.shared;
-    item.sharedWithMe = properties.sharedWithMe;
-    item.size = requests[i].entry.isFile ? (properties.size || 0) : -1;
-    if (properties.thumbnailUrl || nameMap['thumbnailUrl'])
-      item.thumbnailUrl = properties.thumbnailUrl;
+    if (prop.availableOffline !== undefined || nameMap['availableOffline'])
+      item.availableOffline = prop.availableOffline;
+    if (prop.availableWhenMetered !== undefined ||
+        nameMap['availableWhenMetered'])
+      item.availableWhenMetered = prop.availableWhenMetered;
+    if (prop.contentMimeType !== undefined || nameMap['contentMimeType'])
+      item.contentMimeType = prop.contentMimeType || '';
+    if (prop.croppedThumbnailUrl !== undefined ||
+        nameMap['croppedThumbnailUrl'])
+      item.croppedThumbnailUrl = prop.croppedThumbnailUrl;
+    if (prop.customIconUrl !== undefined || nameMap['customIconUrl'])
+      item.customIconUrl = prop.customIconUrl || '';
+    if (prop.dirty !== undefined || nameMap['dirty'])
+      item.dirty = prop.dirty;
+    if (prop.externalFileUrl !== undefined || nameMap['externalFileUrl'])
+      item.externalFileUrl = prop.externalFileUrl;
+    if (prop.hosted !== undefined || nameMap['hosted'])
+      item.hosted = prop.hosted;
+    if (prop.imageHeight !== undefined || nameMap['imageHeight'])
+      item.imageHeight = prop.imageHeight;
+    if (prop.imageRotation !== undefined || nameMap['imageRotation'])
+      item.imageRotation = prop.imageRotation;
+    if (prop.imageWidth !== undefined || nameMap['imageWidth'])
+      item.imageWidth = prop.imageWidth;
+    if (prop.modificationTime !== undefined || nameMap['modificationTime'])
+      item.modificationTime = new Date(prop.modificationTime);
+    if (prop.pinned !== undefined || nameMap['pinned'])
+      item.pinned = prop.pinned;
+    if (prop.present !== undefined || nameMap['present'])
+      item.present = prop.present;
+    if (prop.shared !== undefined || nameMap['shared'])
+      item.shared = prop.shared;
+    if (prop.sharedWithMe !== undefined || nameMap['sharedWithMe'])
+      item.sharedWithMe = prop.sharedWithMe;
+    if (prop.size !== undefined || nameMap['size'])
+      item.size = requests[i].entry.isFile ? (prop.size || 0) : -1;
+    if (prop.thumbnailUrl !== undefined || nameMap['thumbnailUrl'])
+      item.thumbnailUrl = prop.thumbnailUrl;
     results.push(item);
   }
   return results;
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 8a44dec..3d24ff1f 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -290,6 +290,7 @@
             <iron-icon icon="cloud-queue"></iron-icon>
             <div class="content"></div>
           </div>
+          <div class="progress"><div class="value"></div></div>
           <paper-button class="import" tabindex="-1">
             <span i18n-content="CLOUD_IMPORT_COMMAND"></span>
           </paper-button>
@@ -393,156 +394,6 @@
     <div id="drag-container"></div>
     <iframe id="command-dispatcher" hidden aria-hidden="true"></iframe>
 
-    <!-- Don't load main_scripts.js when flattening is disabled. -->
-    <if expr="False"><!-- </if>
-      <script src="foreground/js/main_scripts.js"></script>
-    <if expr="False"> --></if>
-
-    <if expr="False">
-      <!-- This section is used when the file manager is loaded with
-           'filemgr-ext-path' command-line flag. -->
-      <!-- Keep the list in sync with js/main_scripts.js. -->
-
-      <!-- metrics.js initiates load performance tracking
-           so we want to parse it as early as possible -->
-      <script src="common/js/metrics_base.js"></script>
-      <script src="common/js/metrics_events.js"></script>
-      <script src="common/js/metrics.js"></script>
-      <script src="foreground/js/metrics_start.js"></script>
-
-      <!-- Loads the client of the image loader extension -->
-      <script src="common/js/lru_cache.js"></script>
-      <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/image_loader_client.js"></script>
-
-      <!-- Scripts for Chrome Webstore widget -->
-      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/app_installer.js"></script>
-      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/cws_webview_client.js"></script>
-      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/cws_widget_container.js"></script>
-      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/cws_widget_container_error_dialog.js"></script>
-
-      <script src="chrome://resources/js/load_time_data.js"></script>
-      <script src="chrome://resources/js/cr.js"></script>
-      <script src="chrome://resources/js/util.js"></script>
-      <script src="chrome://resources/js/i18n_template_no_process.js"></script>
-
-      <script src="chrome://resources/js/event_tracker.js"></script>
-      <script src="chrome://resources/js/cr/ui.js"></script>
-      <script src="chrome://resources/js/cr/event_target.js"></script>
-      <script src="chrome://resources/js/cr/ui/touch_handler.js"></script>
-      <script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
-      <script src="chrome://resources/js/cr/ui/dialogs.js"></script>
-      <script src="chrome://resources/js/cr/ui/list_item.js"></script>
-      <script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
-      <script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script>
-      <script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
-      <script src="chrome://resources/js/cr/ui/list.js"></script>
-      <script src="chrome://resources/js/cr/ui/tree.js"></script>
-      <script src="chrome://resources/js/cr/ui/autocomplete_list.js"></script>
-
-      <script src="chrome://resources/js/cr/ui/splitter.js"></script>
-      <script src="chrome://resources/js/cr/ui/table/table_splitter.js"></script>
-
-      <script src="chrome://resources/js/cr/ui/table/table_column.js"></script>
-      <script src="chrome://resources/js/cr/ui/table/table_column_model.js"></script>
-      <script src="chrome://resources/js/cr/ui/table/table_header.js"></script>
-      <script src="chrome://resources/js/cr/ui/table/table_list.js"></script>
-      <script src="chrome://resources/js/cr/ui/table.js"></script>
-
-      <script src="chrome://resources/js/cr/ui/grid.js"></script>
-
-      <script src="chrome://resources/js/cr/ui/command.js"></script>
-      <script src="chrome://resources/js/cr/ui/position_util.js"></script>
-      <script src="chrome://resources/js/cr/ui/menu_item.js"></script>
-      <script src="chrome://resources/js/cr/ui/menu.js"></script>
-      <script src="chrome://resources/js/cr/ui/menu_button.js"></script>
-      <script src="chrome://resources/js/cr/ui/context_menu_handler.js"></script>
-
-      <script src="chrome://resources/js/analytics.js"></script>
-
-      <!-- This script must be loaded before all other Files.app's scripts. -->
-      <script src="foreground/js/error_counter.js"></script>
-
-      <script src="common/js/async_util.js"></script>
-      <script src="common/js/file_type.js"></script>
-      <script src="common/js/volume_manager_common.js"></script>
-      <script src="common/js/importer_common.js"></script>
-      <script src="common/js/util.js"></script>
-      <script src="common/js/progress_center_common.js"></script>
-
-      <script src="foreground/js/ui/combobutton.js"></script>
-      <script src="foreground/js/ui/commandbutton.js"></script>
-      <script src="foreground/js/ui/file_manager_dialog_base.js"></script>
-      <script src="foreground/js/metadata/metadata_cache_set.js"></script>
-      <script src="foreground/js/metadata/new_metadata_provider.js"></script>
-      <script src="foreground/js/metadata/thumbnail_model.js"></script>
-
-      <script src="foreground/js/app_state_controller.js"></script>
-      <script src="foreground/js/column_visibility_controller.js"></script>
-      <script src="foreground/js/dialog_action_controller.js"></script>
-      <script src="foreground/js/dialog_type.js"></script>
-      <script src="foreground/js/directory_contents.js"></script>
-      <script src="foreground/js/directory_model.js"></script>
-      <script src="foreground/js/empty_folder_controller.js"></script>
-      <script src="foreground/js/file_manager.js"></script>
-      <script src="foreground/js/file_manager_commands.js"></script>
-      <script src="foreground/js/file_selection.js"></script>
-      <script src="foreground/js/file_tasks.js"></script>
-      <script src="foreground/js/file_transfer_controller.js"></script>
-      <script src="foreground/js/file_watcher.js"></script>
-      <script src="foreground/js/folder_shortcuts_data_model.js"></script>
-      <script src="foreground/js/sort_menu_controller.js"></script>
-      <script src="foreground/js/gear_menu_controller.js"></script>
-      <script src="foreground/js/import_controller.js"></script>
-      <script src="foreground/js/launch_param.js"></script>
-      <script src="foreground/js/metadata/content_metadata_provider.js"></script>
-      <script src="foreground/js/metadata/external_metadata_provider.js"></script>
-      <script src="foreground/js/metadata/file_system_metadata_provider.js"></script>
-      <script src="foreground/js/metadata/metadata_cache_item.js"></script>
-      <script src="foreground/js/metadata/metadata_item.js"></script>
-      <script src="foreground/js/metadata/metadata_model.js"></script>
-      <script src="foreground/js/metadata/multi_metadata_provider.js"></script>
-      <script src="foreground/js/metadata_update_controller.js"></script>
-      <script src="foreground/js/naming_controller.js"></script>
-      <script src="foreground/js/navigation_list_model.js"></script>
-      <script src="foreground/js/progress_center_item_group.js"></script>
-      <script src="foreground/js/scan_controller.js"></script>
-      <script src="foreground/js/search_controller.js"></script>
-      <script src="foreground/js/share_client.js"></script>
-      <script src="foreground/js/spinner_controller.js"></script>
-      <script src="foreground/js/task_controller.js"></script>
-      <script src="foreground/js/toolbar_controller.js"></script>
-      <script src="foreground/js/thumbnail_loader.js"></script>
-      <script src="foreground/js/list_thumbnail_loader.js"></script>
-      <script src="foreground/js/providers_model.js"></script>
-      <script src="foreground/js/ui/banners.js"></script>
-      <script src="foreground/js/ui/conflict_dialog.js"></script>
-      <script src="foreground/js/ui/default_action_dialog.js"></script>
-      <script src="foreground/js/ui/dialog_footer.js"></script>
-      <script src="foreground/js/ui/directory_tree.js"></script>
-      <script src="foreground/js/ui/drag_selector.js"></script>
-      <script src="foreground/js/ui/empty_folder.js"></script>
-      <script src="foreground/js/ui/error_dialog.js"></script>
-      <script src="foreground/js/ui/file_grid.js"></script>
-      <script src="foreground/js/ui/file_manager_ui.js"></script>
-      <script src="foreground/js/ui/file_list_selection_model.js"></script>
-      <script src="foreground/js/ui/file_table.js"></script>
-      <script src="foreground/js/ui/file_table_list.js"></script>
-      <script src="foreground/js/ui/gear_menu.js"></script>
-      <script src="foreground/js/ui/list_container.js"></script>
-      <script src="foreground/js/ui/location_line.js"></script>
-      <script src="foreground/js/ui/multi_profile_share_dialog.js"></script>
-      <script src="foreground/js/ui/progress_center_panel.js"></script>
-      <script src="foreground/js/ui/providers_menu.js"></script>
-      <script src="foreground/js/ui/scrollbar.js"></script>
-      <script src="foreground/js/ui/search_box.js"></script>
-      <script src="foreground/js/ui/share_dialog.js"></script>
-      <script src="foreground/js/ui/suggest_apps_dialog.js"></script>
-      <script src="foreground/js/main_window_component.js"></script>
-      <script src="foreground/js/volume_manager_wrapper.js"></script>
-
-      <!-- For accurate load performance tracking main.js should be
-           the last script to include. -->
-      <script src="foreground/js/main.js"></script>
-    </if>
+    <script src="foreground/js/main_scripts.js"></script>
   </body>
 </html>
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json
index 794f0a10..8498dd9 100644
--- a/ui/file_manager/file_manager/manifest.json
+++ b/ui/file_manager/file_manager/manifest.json
@@ -156,6 +156,7 @@
     "common/js/metrics_events.js",
     "common/js/metrics.js",
     "common/js/path_util.js",
+    "common/js/polymer_config.js",
     "common/js/util.js",
     "common/js/volume_manager_common.js",
     "foreground/js/metadata/byte_reader.js",
diff --git a/ui/file_manager/gallery/css/gallery.css b/ui/file_manager/gallery/css/gallery.css
index a8ef0bf..7aaee71d 100644
--- a/ui/file_manager/gallery/css/gallery.css
+++ b/ui/file_manager/gallery/css/gallery.css
@@ -43,7 +43,7 @@
 }
 
 /* Common background for both mosaic and slide mode. */
-.gallery > .content {
+.gallery .content {
   background-color: black;
 }
 
@@ -152,58 +152,44 @@
 
 /* Toolbar */
 
+.gallery > .header,
 .gallery > .toolbar {
   -webkit-box-align: stretch;
   -webkit-box-orient: horizontal;
   -webkit-box-pack: start;
-  background-color: rgba(40, 42, 45, 0.9);
+  background-color: rgba(30, 30, 30, 0.8);
   display: flex;
-  height: 48px;
   left: 0;
   opacity: 0;
-  overflow: hidden;
-  padding: 0;
+  padding: 0 10px;
   pointer-events: none;
   position: absolute;
   right: 0;
   transition: opacity 300ms ease;
 }
 
-.gallery > .toolbar.top {
+.gallery > .header {
+  -webkit-app-region: drag;
+  -webkit-box-align: center;
+  -webkit-box-pack: end;
+  border-bottom: 1px solid rgba(50, 50, 50, 0.8);
+  display: -webkit-box;
+  height: 45px;
   top: 0;
 }
 
-.gallery > .toolbar.bottom {
+.gallery .header button {
+  -webkit-app-region: no-drag;
+}
+
+.gallery > .toolbar {
+  border-top: 1px solid rgba(50, 50, 50, 0.8);
   bottom: 0;
   height: 55px;
+  overflow: hidden;
 }
 
-.gallery > .toolbar.bottom > .slide-mode-toolbar {
-  left: 0;
-  opacity: 1;
-  position: absolute;
-  visibility: visible;
-  width: 100%;
-}
-
-.gallery > .toolbar.bottom > .edit-mode-toolbar {
-  left: 0;
-  opacity: 0;
-  position: absolute;
-  visibility: hidden;
-  width: 100%;
-}
-
-.gallery[editing] > .toolbar.bottom > .slide-mode-toolbar {
-  opacity: 0;
-  visibility: hidden;
-}
-
-.gallery[editing] > .toolbar.bottom > .edit-mode-toolbar {
-  opacity: 1;
-  visibility: visible;
-}
-
+.gallery[tools]:not([slideshow]) > .header,
 .gallery[tools]:not([slideshow]) > .toolbar {
   opacity: 1;
   pointer-events: auto;
@@ -303,12 +289,12 @@
 /* Filename */
 
 .gallery .filename-spacer {
-  -webkit-margin-start: 16px;
-  flex: 1 0 auto;
+  flex: 0 1 auto;
   height: 100%;
   min-width: 140px;
   overflow: hidden;
   position: relative;
+  width: 252px;
 }
 
 .gallery .filename-spacer > * {
@@ -336,11 +322,16 @@
   padding: 0 3px;
   position: absolute;
   text-overflow: ellipsis;
-  top: 13px;
+  top: 15px;
   white-space: nowrap;
   width: 100%;
 }
 
+.gallery[editing] .filename-spacer .namebox {
+  height: 21px;
+  top: 5px;
+}
+
 .gallery .filename-spacer .namebox[disabled] {
   -webkit-user-select: none;
   cursor: default;
@@ -356,6 +347,62 @@
   cursor: text;
 }
 
+.gallery .filename-spacer .options {
+  -webkit-box-align: center;
+  -webkit-box-orient: horizontal;
+  -webkit-box-pack: start;
+  display: -webkit-box;
+  height: 0;
+  opacity: 0;
+  top: 50px;
+  visibility: hidden;
+}
+
+.gallery[editing] .filename-spacer .options {
+  height: auto;
+  opacity: 1;
+  top: 28px;
+  visibility: visible;
+}
+
+.gallery .filename-spacer .saved,
+.gallery .filename-spacer .overwrite-original {
+  cursor: inherit;
+  font-size: 90%;
+  margin-left: 3px;
+  margin-right: 18px;
+  opacity: 0;
+  pointer-events: none;
+  transition: all linear 120ms;
+}
+
+.gallery[editing] .filename-spacer .saved {
+  color: white;
+  opacity: 0.5;
+}
+
+.gallery[editing] .filename-spacer .overwrite-original,
+.gallery[editing] .filename-spacer .overwrite-original > * {
+  cursor: pointer;
+  opacity: 1;
+  pointer-events: auto;
+}
+
+.gallery[editing] .overwrite-original[disabled] {
+  opacity: 0.5;
+}
+
+.gallery[editing] .overwrite-original[disabled],
+.gallery[editing] .overwrite-original[disabled] > * {
+  cursor: default;
+  pointer-events: none;
+}
+
+.gallery .filename-spacer .saved[highlighted] {
+  transform: scaleX(1.1) scaleY(1.1) rotate(0);
+  opacity: 1;
+}
+
 /* Bubble */
 
 .gallery .toolbar .bubble {
@@ -382,7 +429,6 @@
 /* Toolbar buttons */
 
 .gallery .button-spacer {
-  align-items: center;
   display: flex;
   flex: none;
   justify-content: flex-end;
@@ -393,11 +439,11 @@
 
 .gallery .ribbon-spacer {
   height: 55px;
+  margin-bottom: -55px;
 }
 
 .gallery .toolbar .ribbon {
   height: 100%;
-  margin: 0 auto;
   overflow: hidden;
   transition: opacity 180ms linear, visibility 0ms linear;
   white-space: nowrap;
@@ -467,96 +513,28 @@
   -webkit-animation: fadeIn 500ms ease-in;
 }
 
-/* Editor toolbar. */
+/* Editor buttons */
 
-.gallery .edit-mode-toolbar .options {
-  align-items: center;
-  display: flex;
+.gallery .edit-bar-spacer {
+  -webkit-box-align: center;
+  -webkit-box-orient: horizontal;
+  -webkit-box-pack: center;
+  display: -webkit-box;
   height: 100%;
+  left: 280px;
   opacity: 0;
-  position: absolute;
-  visibility: hidden;
-  width: 100%;
-}
-
-.gallery .edit-mode-toolbar .edit-bar-spacer {
-  display: block;
-  height: 100%;
-  opacity: 0;
+  right: 280px;
   transition: opacity 180ms linear, visibility 0ms linear 180ms;
   visibility: hidden;
+  margin-bottom: -55px;
 }
 
-.gallery[editing] .edit-mode-toolbar .options {
-  opacity: 1;
-  visibility: visible;
-}
-
-.gallery .edit-mode-toolbar .saved,
-.gallery .edit-mode-toolbar .overwrite-original {
-  cursor: inherit;
-  font-size: 90%;
-  opacity: 0;
-  pointer-events: none;
-  transition: all linear 120ms;
-}
-
-.gallery .edit-mode-toolbar .overwrite-original {
-  -webkit-margin-start: 16px;
-  align-items: center;
-  display: flex;
-}
-
-.gallery .edit-mode-toolbar .saved {
-  -webkit-margin-start: 14px;
-}
-
-.gallery .edit-mode-toolbar .overwrite-original > input {
-  float: left;
-  margin: 0;
-}
-
-.gallery .edit-mode-toolbar .overwrite-original > .label {
-  -webkit-margin-start: 8px;
-  color: white;
-  float: left;
-}
-
-.gallery[editing] .edit-mode-toolbar .saved {
-  color: white;
-  opacity: 0.5;
-}
-
-.gallery[editing] .edit-mode-toolbar .overwrite-original,
-.gallery[editing] .edit-mode-toolbar .overwrite-original > * {
-  cursor: pointer;
-  opacity: 1;
-  pointer-events: auto;
-}
-
-.gallery[editing] .overwrite-original[disabled] {
-  opacity: 0.5;
-}
-
-.gallery[editing] .overwrite-original[disabled],
-.gallery[editing] .overwrite-original[disabled] > * {
-  cursor: default;
-  pointer-events: none;
-}
-
-.gallery .edit-mode-toolbar .saved[highlighted] {
-  transform: scaleX(1.1) scaleY(1.1) rotate(0);
-  opacity: 1;
-}
-
-/* Editor buttons. */
-
 .gallery .toolbar .edit-main {
-  align-items: center;
+  -webkit-box-orient: horizontal;
+  -webkit-box-pack: center;
   color: white;
-  display: flex;
+  display: -webkit-box;
   height: 55px;
-  justify-content: center;
   overflow: visible;
 }
 
@@ -567,7 +545,9 @@
   visibility: visible;
 }
 
+.gallery .header button,
 .gallery .toolbar button,
+.gallery .header button[disabled],
 .gallery .toolbar button[disabled] {
   background-color: rgba(0, 0, 0, 0);
   background-position: center;
@@ -584,8 +564,10 @@
   z-index: 10;
 }
 
+.gallery .header button,
 .gallery .toolbar button {
   height: 40px;
+  margin: 6px 0;
   min-width: 40px;  /* Reset. */
   width: 40px;
 }
@@ -618,13 +600,17 @@
 
 }
 
+.gallery .header button:hover,
 .gallery .toolbar button:hover {
   background-color: rgba(31, 31, 31, 1);
   color: white;
 }
 
+.gallery .header button:active,
 .gallery .toolbar button:active,
+.gallery .header button[pressed],
 .gallery .toolbar button[pressed],
+.gallery .header button[pressed]:hover,
 .gallery .toolbar button[pressed]:hover {
   background-color: rgba(240, 240, 240, 1);
   color: black;
@@ -731,72 +717,95 @@
   display: none;
 }
 
-.gallery > .toolbar paper-button {
-  background-position: center;
-  background-repeat: no-repeat;
-  height: 32px;
-  margin: 0 8px;
-  min-width: 32px;
-  width: 32px;
-}
-
-/* Since currently Gallery does not use shadow dom with Polymer, ::shadow
- * selector does not work correctly. */
-.gallery > .toolbar paper-button::shadow paper-ripple,
-.gallery > .toolbar paper-button > paper-ripple {
-  color: white;
-}
-
-.gallery > .toolbar paper-button.edit {
+.gallery[mode='slide'] > .toolbar button.mode {
   background-image: -webkit-image-set(
-      url(../images/100/edit.png) 1x,
-      url(../images/200/edit.png) 2x);
+      url(../images/100/icon_mosaic.png) 1x,
+      url(../images/200/icon_mosaic.png) 2x);
 }
 
-.gallery > .toolbar paper-button.print {
+.gallery[mode='slide'] > .toolbar button.mode:active {
   background-image: -webkit-image-set(
-      url(../images/100/print.png) 1x,
-      url(../images/200/print.png) 2x);
+      url(../images/100/icon_mosaic_selected.png) 1x,
+      url(../images/200/icon_mosaic_selected.png) 2x);
 }
 
-.gallery > .toolbar paper-button.delete {
+.gallery[mode='mosaic'] > .toolbar button.mode {
   background-image: -webkit-image-set(
-      url(../images/100/delete.png) 1x,
-      url(../images/200/delete.png) 2x);
+      url(../images/100/icon_1up.png) 1x,
+      url(../images/200/icon_1up.png) 2x);
 }
 
-.gallery > .toolbar paper-button.slide-mode {
+.gallery[mode='mosaic'] > .toolbar button.mode:active {
   background-image: -webkit-image-set(
-      url(../images/100/slide_view.png) 1x,
-      url(../images/200/slide_view.png) 2x);
+      url(../images/100/icon_1up_selected.png) 1x,
+      url(../images/200/icon_1up_selected.png) 2x);
 }
 
-.gallery > .toolbar paper-button.mosaic-mode {
+.gallery > .toolbar button.slideshow {
   background-image: -webkit-image-set(
-      url(../images/100/mosaic_view.png) 1x,
-      url(../images/200/mosaic_view.png) 2x);
+      url(../images/100/icon_slideshow.png) 1x,
+      url(../images/200/icon_slideshow.png) 2x);
 }
 
-.gallery > .toolbar paper-button.slideshow {
+.gallery > .toolbar button.slideshow:active,
+.gallery > .toolbar button.slideshow[pressed] {
   background-image: -webkit-image-set(
-      url(../images/100/slideshow.png) 1x,
-      url(../images/200/slideshow.png) 2x);
+      url(../images/100/icon_slideshow_selected.png) 1x,
+      url(../images/200/icon_slideshow_selected.png) 2x);
 }
 
-.gallery > .toolbar paper-button.share {
+.gallery > .toolbar button.delete {
   background-image: -webkit-image-set(
-      url(../images/100/share.png) 1x,
-      url(../images/200/share.png) 2x);
+      url(../images/100/icon_delete.png) 1x,
+      url(../images/200/icon_delete.png) 2x);
 }
 
-.gallery[editing] > .toolbar paper-button.edit {
-  opacity: 0.5;
-  pointer-events: none;
+.gallery > .toolbar button.delete:active {
+  background-image: -webkit-image-set(
+      url(../images/100/icon_delete_selected.png) 1x,
+      url(../images/200/icon_delete_selected.png) 2x);
 }
 
-.gallery[mode='slide'] > .toolbar paper-button.slide-mode,
-.gallery[mode='mosaic'] > .toolbar paper-button.mosaic-mode,
-.gallery > .toolbar paper-button[disabled] {
+.gallery > .toolbar button.edit {
+  background-image: -webkit-image-set(
+      url(../images/100/icon_edit.png) 1x,
+      url(../images/200/icon_edit.png) 2x);
+}
+
+.gallery > .toolbar button.edit:active,
+.gallery > .toolbar button.edit[pressed] {
+  background-image: -webkit-image-set(
+      url(../images/100/icon_edit_selected.png) 1x,
+      url(../images/200/icon_edit_selected.png) 2x);
+}
+
+.gallery > .toolbar button.print {
+  background-image: -webkit-image-set(
+      url(../images/100/icon_print.png) 1x,
+      url(../images/200/icon_print.png) 2x);
+}
+
+.gallery > .toolbar button.print:active,
+.gallery > .toolbar button.print[pressed] {
+  background-image: -webkit-image-set(
+      url(../images/100/icon_print_selected.png) 1x,
+      url(../images/200/icon_print_selected.png) 2x);
+}
+
+.gallery > .toolbar button.share {
+  background-image: -webkit-image-set(
+      url(../images/100/icon_share.png) 1x,
+      url(../images/200/icon_share.png) 2x);
+}
+
+.gallery > .toolbar button.share:active,
+.gallery > .toolbar button.share[pressed] {
+  background-image: -webkit-image-set(
+      url(../images/100/icon_share_selected.png) 1x,
+      url(../images/200/icon_share_selected.png) 2x);
+}
+
+.gallery > .toolbar button.share[disabled] {
   display: none;
 }
 
@@ -1141,13 +1150,13 @@
 
 /* Mosaic view. */
 .mosaic {
-  bottom: 0;
+  bottom: 55px;  /* Toolbar height. */
   left: 0;
   overflow-x: scroll;
   overflow-y: hidden;
   position: absolute;
   right: 0;
-  top: 55px; /* Toolbar height. */
+  top: 0;
 
   /* transition-duration is set in Javascript. */
   transition-property: transform;
@@ -1307,6 +1316,35 @@
   margin-left: -2px;
 }
 
+.gallery > .header > button {
+  -webkit-margin-start: 10px;
+  cursor: default;
+  height: 32px;
+  min-width: 32px;
+  width: 32px;
+}
+
+.gallery > .header > .minimize-button {
+  background: -webkit-image-set(
+      url(chrome://resources/images/apps/topbar_button_minimize.png) 1x,
+      url(chrome://resources/images/2x/apps/topbar_button_minimize.png) 2x)
+      center;
+}
+
+.gallery > .header > .maximize-button {
+  background: -webkit-image-set(
+      url(chrome://resources/images/apps/topbar_button_maximize.png) 1x,
+      url(chrome://resources/images/2x/apps/topbar_button_maximize.png) 2x)
+      center;
+}
+
+.gallery > .header > .close-button {
+  background: -webkit-image-set(
+      url(chrome://resources/images/apps/topbar_button_close.png) 1x,
+      url(chrome://resources/images/2x/apps/topbar_button_close.png) 2x)
+      center;
+}
+
 .debug-me .load-target-content-metadata::before,
 .debug-me .load-target-external-metadata::before,
 .debug-me .load-target-file-entry::before {
diff --git a/ui/file_manager/gallery/gallery.html b/ui/file_manager/gallery/gallery.html
index ba8a663..85d4dd6 100644
--- a/ui/file_manager/gallery/gallery.html
+++ b/ui/file_manager/gallery/gallery.html
@@ -12,118 +12,26 @@
   <link rel="stylesheet" href="../file_manager/foreground/css/share_dialog.css">
   <link rel="stylesheet" href="css/gallery.css">
 
-  <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-
-  <!-- Don't load gallery_scripts.js when flattening is disabled -->
-  <if expr="False"><!-- </if>
-    <script src="js/gallery_scripts.js"></script>
-  <if expr="False"> --></if>
-
-  <if expr="False">
-    <!-- This section is used when the file manager is loaded with
-         'filemgr-ext-path' command-line flag. -->
-    <!-- Keep the list in sync with gallery_scripts.js. -->
-    <script src="../file_manager/common/js/metrics_base.js"></script>
-    <script src="../file_manager/common/js/metrics.js"></script>
-    <script src="../file_manager/foreground/js/metrics_start.js"></script>
-
-    <!-- Loads the client of the image loader extension -->
-    <script src="../file_manager/common/js/lru_cache.js"></script>
-    <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/image_loader_client.js"></script>
-
-    <script src="chrome://resources/js/cr.js"></script>
-    <script src="chrome://resources/js/event_tracker.js"></script>
-    <script src="chrome://resources/js/load_time_data.js"></script>
-
-    <script src="chrome://resources/js/cr/ui.js"></script>
-    <script src="chrome://resources/js/cr/event_target.js"></script>
-    <script src="chrome://resources/js/cr/ui/touch_handler.js"></script>
-    <script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
-    <script src="chrome://resources/js/cr/ui/dialogs.js"></script>
-    <script src="chrome://resources/js/cr/ui/list_item.js"></script>
-    <script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
-    <script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script>
-    <script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
-    <script src="chrome://resources/js/cr/ui/list.js"></script>
-    <script src="chrome://resources/js/cr/ui/grid.js"></script>
-
-    <!-- Base classes. -->
-    <script src="../file_manager/foreground/js/metadata/metadata_cache_set.js"></script>
-    <script src="../file_manager/foreground/js/metadata/new_metadata_provider.js"></script>
-
-    <script src="../file_manager/common/js/async_util.js"></script>
-    <script src="../file_manager/common/js/file_type.js"></script>
-    <script src="../file_manager/common/js/volume_manager_common.js"></script>
-
-    <script src="../file_manager/foreground/js/metadata/content_metadata_provider.js"></script>
-    <script src="../file_manager/foreground/js/metadata/exif_constants.js"></script>
-    <script src="../file_manager/foreground/js/metadata/external_metadata_provider.js"></script>
-    <script src="../file_manager/foreground/js/metadata/file_system_metadata_provider.js"></script>
-    <script src="../file_manager/foreground/js/metadata/metadata_cache_item.js"></script>
-    <script src="../file_manager/foreground/js/metadata/metadata_item.js"></script>
-    <script src="../file_manager/foreground/js/metadata/metadata_model.js"></script>
-    <script src="../file_manager/foreground/js/metadata/multi_metadata_provider.js"></script>
-    <script src="../file_manager/foreground/js/metadata/thumbnail_model.js"></script>
-    <script src="../file_manager/foreground/js/mouse_inactivity_watcher.js"></script>
-    <script src="../file_manager/foreground/js/share_client.js"></script>
-    <script src="../file_manager/foreground/js/thumbnail_loader.js"></script>
-    <script src="../file_manager/foreground/js/ui/file_manager_dialog_base.js"></script>
-    <script src="../file_manager/foreground/js/ui/share_dialog.js"></script>
-    <script src="../file_manager/foreground/js/volume_manager_wrapper.js"></script>
-
-    <script src="js/image_editor/image_util.js"></script>
-    <script src="js/image_editor/viewport.js"></script>
-    <script src="js/image_editor/image_buffer.js"></script>
-    <script src="js/image_editor/image_view.js"></script>
-    <script src="js/image_editor/commands.js"></script>
-    <script src="js/image_editor/image_editor.js"></script>
-    <script src="js/image_editor/image_transform.js"></script>
-    <script src="js/image_editor/image_adjust.js"></script>
-    <script src="js/image_editor/filter.js"></script>
-    <script src="js/image_editor/image_encoder.js"></script>
-    <script src="js/image_editor/exif_encoder.js"></script>
-
-    <script src="js/entry_list_watcher.js"></script>
-    <script src="js/error_banner.js"></script>
-    <script src="js/gallery.js"></script>
-    <script src="js/gallery_data_model.js"></script>
-    <script src="js/gallery_item.js"></script>
-    <script src="js/mosaic_mode.js"></script>
-    <script src="js/ribbon.js"></script>
-    <script src="js/slide_mode.js"></script>
-  </if>
+  <script src="js/gallery_scripts.js"></script>
 </head>
 <body>
   <div class="gallery">
     <div id="content" class="content"></div>
-    <div id="top-toolbar" class="toolbar top tool dimmable">
+    <div id="header" class="header tool dimmable"></div>
+    <div id="toolbar" class="toolbar tool dimmable">
       <div class="filename-spacer"></div>
-      <div class="button-spacer">
-        <paper-button class="button edit" i18n-values="title:GALLERY_EDIT" disabled></paper-button>
-        <paper-button class="button print" i18n-values="title:GALLERY_PRINT" disabled></paper-button>
-        <paper-button class="button delete" i18n-values="title:GALLERY_DELETE"></paper-button>
-        <paper-button class="button slide-mode" i18n-values="title:GALLERY_SLIDE"></paper-button>
-        <paper-button class="button mosaic-mode" i18n-values="title:GALLERY_MOSAIC"></paper-button>
-        <paper-button class="button slideshow" i18n-values="title:GALLERY_SLIDESHOW"></paper-button>
-        <paper-button class="button share" i18n-values="title:GALLERY_SHARE"></paper-button>
-      </div>
-    </div>
-    <div id="bottom-toolbar" class="toolbar bottom tool dimmable">
-      <div class="slide-mode-toolbar">
+      <div class="middle-spacer">
         <div class="ribbon-spacer"></div>
-      </div>
-
-      <div class="edit-mode-toolbar">
-        <div class="options">
-          <!-- TODO(yawano): Replace overwrite original checkbox with undo toast. -->
-          <div class="overwrite-original">
-            <input id="overwrite-checkbox" type="checkbox"></input>
-            <div class="label" for="overwrite-checkbox" i18n-content="GALLERY_OVERWRITE_ORIGINAL"></div>
-          </div>
-          <div class="saved" i18n-content="GALLERY_SAVED"></div>
-        </div>
         <div class="edit-bar-spacer"></div>
       </div>
+      <div class="button-spacer">
+        <button class="button mode"></button>
+        <button class="button slideshow"></button>
+        <button class="button edit"></button>
+        <button class="button print"></button>
+        <button class="delete"></button>
+        <button class="share"></button>
+      </div>
     </div>
     <div class="prompt-wrapper" pos="center">
       <div class="error-banner"></div>
diff --git a/ui/file_manager/gallery/images/100/delete.png b/ui/file_manager/gallery/images/100/delete.png
deleted file mode 100644
index 0d251bfe..0000000
--- a/ui/file_manager/gallery/images/100/delete.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/edit.png b/ui/file_manager/gallery/images/100/edit.png
deleted file mode 100644
index 175cde6..0000000
--- a/ui/file_manager/gallery/images/100/edit.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_1up.png b/ui/file_manager/gallery/images/100/icon_1up.png
new file mode 100644
index 0000000..546e87a
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_1up.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_1up_selected.png b/ui/file_manager/gallery/images/100/icon_1up_selected.png
new file mode 100644
index 0000000..a3043a8
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_1up_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_delete.png b/ui/file_manager/gallery/images/100/icon_delete.png
new file mode 100644
index 0000000..efb132aa
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_delete.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_delete_selected.png b/ui/file_manager/gallery/images/100/icon_delete_selected.png
new file mode 100644
index 0000000..f2f88d8
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_delete_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_edit.png b/ui/file_manager/gallery/images/100/icon_edit.png
new file mode 100644
index 0000000..fc72ecf
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_edit.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_edit_selected.png b/ui/file_manager/gallery/images/100/icon_edit_selected.png
new file mode 100644
index 0000000..61540b5
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_edit_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_mosaic.png b/ui/file_manager/gallery/images/100/icon_mosaic.png
new file mode 100644
index 0000000..6e49d3c
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_mosaic.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_mosaic_selected.png b/ui/file_manager/gallery/images/100/icon_mosaic_selected.png
new file mode 100644
index 0000000..86edb6e1e
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_mosaic_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_print.png b/ui/file_manager/gallery/images/100/icon_print.png
new file mode 100644
index 0000000..b2355367
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_print.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_print_selected.png b/ui/file_manager/gallery/images/100/icon_print_selected.png
new file mode 100644
index 0000000..657b9c8
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_print_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_share.png b/ui/file_manager/gallery/images/100/icon_share.png
new file mode 100644
index 0000000..36bb2218
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_share.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_share_selected.png b/ui/file_manager/gallery/images/100/icon_share_selected.png
new file mode 100644
index 0000000..438e8a25
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_share_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_slideshow.png b/ui/file_manager/gallery/images/100/icon_slideshow.png
new file mode 100644
index 0000000..72763d4
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_slideshow.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_slideshow_selected.png b/ui/file_manager/gallery/images/100/icon_slideshow_selected.png
new file mode 100644
index 0000000..4f80a48d
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/icon_slideshow_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/mosaic_view.png b/ui/file_manager/gallery/images/100/mosaic_view.png
deleted file mode 100644
index 115cee02..0000000
--- a/ui/file_manager/gallery/images/100/mosaic_view.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/print.png b/ui/file_manager/gallery/images/100/print.png
deleted file mode 100644
index c31be896..0000000
--- a/ui/file_manager/gallery/images/100/print.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/share.png b/ui/file_manager/gallery/images/100/share.png
deleted file mode 100644
index 73434ac..0000000
--- a/ui/file_manager/gallery/images/100/share.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/slide_view.png b/ui/file_manager/gallery/images/100/slide_view.png
deleted file mode 100644
index b033319..0000000
--- a/ui/file_manager/gallery/images/100/slide_view.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/slideshow.png b/ui/file_manager/gallery/images/100/slideshow.png
deleted file mode 100644
index 72434a86..0000000
--- a/ui/file_manager/gallery/images/100/slideshow.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/delete.png b/ui/file_manager/gallery/images/200/delete.png
deleted file mode 100644
index b3e9036..0000000
--- a/ui/file_manager/gallery/images/200/delete.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/edit.png b/ui/file_manager/gallery/images/200/edit.png
deleted file mode 100644
index 7444fc4..0000000
--- a/ui/file_manager/gallery/images/200/edit.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_1up.png b/ui/file_manager/gallery/images/200/icon_1up.png
new file mode 100644
index 0000000..58cbc28
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_1up.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_1up_selected.png b/ui/file_manager/gallery/images/200/icon_1up_selected.png
new file mode 100644
index 0000000..a0ca726f
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_1up_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_delete.png b/ui/file_manager/gallery/images/200/icon_delete.png
new file mode 100644
index 0000000..a55ac6c
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_delete.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_delete_selected.png b/ui/file_manager/gallery/images/200/icon_delete_selected.png
new file mode 100644
index 0000000..af54168a
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_delete_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_edit.png b/ui/file_manager/gallery/images/200/icon_edit.png
new file mode 100644
index 0000000..288bc5b
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_edit.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_edit_selected.png b/ui/file_manager/gallery/images/200/icon_edit_selected.png
new file mode 100644
index 0000000..bcf9933
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_edit_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_mosaic.png b/ui/file_manager/gallery/images/200/icon_mosaic.png
new file mode 100644
index 0000000..3e1a621
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_mosaic.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_mosaic_selected.png b/ui/file_manager/gallery/images/200/icon_mosaic_selected.png
new file mode 100644
index 0000000..d9e329d
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_mosaic_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_print.png b/ui/file_manager/gallery/images/200/icon_print.png
new file mode 100644
index 0000000..b5a9be0c
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_print.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_print_selected.png b/ui/file_manager/gallery/images/200/icon_print_selected.png
new file mode 100644
index 0000000..048a341
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_print_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_share.png b/ui/file_manager/gallery/images/200/icon_share.png
new file mode 100644
index 0000000..b1da6d9
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_share.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_share_selected.png b/ui/file_manager/gallery/images/200/icon_share_selected.png
new file mode 100644
index 0000000..b3cd00f
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_share_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_slideshow.png b/ui/file_manager/gallery/images/200/icon_slideshow.png
new file mode 100644
index 0000000..fec87c0
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_slideshow.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_slideshow_selected.png b/ui/file_manager/gallery/images/200/icon_slideshow_selected.png
new file mode 100644
index 0000000..4e1ed5a
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/icon_slideshow_selected.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/mosaic_view.png b/ui/file_manager/gallery/images/200/mosaic_view.png
deleted file mode 100644
index d5e77783..0000000
--- a/ui/file_manager/gallery/images/200/mosaic_view.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/print.png b/ui/file_manager/gallery/images/200/print.png
deleted file mode 100644
index ce9aee8..0000000
--- a/ui/file_manager/gallery/images/200/print.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/share.png b/ui/file_manager/gallery/images/200/share.png
deleted file mode 100644
index 734f566..0000000
--- a/ui/file_manager/gallery/images/200/share.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/slide_view.png b/ui/file_manager/gallery/images/200/slide_view.png
deleted file mode 100644
index acd2f8f2..0000000
--- a/ui/file_manager/gallery/images/200/slide_view.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/slideshow.png b/ui/file_manager/gallery/images/200/slideshow.png
deleted file mode 100644
index ffa67ad..0000000
--- a/ui/file_manager/gallery/images/200/slideshow.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/js/background.js b/ui/file_manager/gallery/js/background.js
index f3bbed6c..dbb98be 100644
--- a/ui/file_manager/gallery/js/background.js
+++ b/ui/file_manager/gallery/js/background.js
@@ -9,13 +9,11 @@
  */
 var windowCreateOptions = {
   id: 'gallery',
-  outerBounds: {
+  innerBounds: {
     minWidth: 820,
     minHeight: 554
   },
-  frame: {
-    color: '#1E2023'
-  }
+  frame: 'none'
 };
 
 /**
diff --git a/ui/file_manager/gallery/js/gallery.js b/ui/file_manager/gallery/js/gallery.js
index 67a6e68b..0297a60 100644
--- a/ui/file_manager/gallery/js/gallery.js
+++ b/ui/file_manager/gallery/js/gallery.js
@@ -17,7 +17,8 @@
  */
 function Gallery(volumeManager) {
   /**
-   * @type {{appWindow: chrome.app.window.AppWindow,
+   * @type {{appWindow: chrome.app.window.AppWindow, onClose: function(),
+   *     onMaximize: function(), onMinimize: function(),
    *     onAppRegionChanged: function(), readonlyDirName: string,
    *     displayStringFunction: function(), loadTimeData: Object,
    *     curDirEntry: Entry, searchResults: *}}
@@ -28,6 +29,15 @@
    */
   this.context_ = {
     appWindow: chrome.app.window.current(),
+    onClose: function() { window.close(); },
+    onMaximize: function() {
+      var appWindow = chrome.app.window.current();
+      if (appWindow.isMaximized())
+        appWindow.restore();
+      else
+        appWindow.maximize();
+    },
+    onMinimize: function() { chrome.app.window.current().minimize(); },
     onAppRegionChanged: function() {},
     readonlyDirName: '',
     displayStringFunction: function() { return ''; },
@@ -85,10 +95,33 @@
   var content = queryRequiredElement(document, '#content');
   content.addEventListener('click', this.onContentClick_.bind(this));
 
-  this.topToolbar_ = queryRequiredElement(document, '#top-toolbar');
-  this.bottomToolbar_ = queryRequiredElement(document, '#bottom-toolbar');
+  this.header_ = queryRequiredElement(document, '#header');
+  this.toolbar_ = queryRequiredElement(document, '#toolbar');
 
-  this.filenameSpacer_ = queryRequiredElement(this.topToolbar_,
+  var preventDefault = function(event) { event.preventDefault(); };
+
+  var minimizeButton = util.createChild(this.header_,
+                                        'minimize-button tool dimmable',
+                                        'button');
+  minimizeButton.tabIndex = -1;
+  minimizeButton.addEventListener('click', this.onMinimize_.bind(this));
+  minimizeButton.addEventListener('mousedown', preventDefault);
+
+  var maximizeButton = util.createChild(this.header_,
+                                        'maximize-button tool dimmable',
+                                        'button');
+  maximizeButton.tabIndex = -1;
+  maximizeButton.addEventListener('click', this.onMaximize_.bind(this));
+  maximizeButton.addEventListener('mousedown', preventDefault);
+
+  var closeButton = util.createChild(this.header_,
+                                     'close-button tool dimmable',
+                                     'button');
+  closeButton.tabIndex = -1;
+  closeButton.addEventListener('click', this.onClose_.bind(this));
+  closeButton.addEventListener('mousedown', preventDefault);
+
+  this.filenameSpacer_ = queryRequiredElement(this.toolbar_,
       '.filename-spacer');
   this.filenameEdit_ = util.createChild(this.filenameSpacer_,
                                         'namebox', 'input');
@@ -103,21 +136,16 @@
   this.filenameEdit_.addEventListener('keydown',
       this.onFilenameEditKeydown_.bind(this));
 
-  var buttonSpacer = queryRequiredElement(this.topToolbar_, '.button-spacer');
+  var middleSpacer = queryRequiredElement(this.toolbar_, '.middle-spacer');
+  var buttonSpacer = queryRequiredElement(this.toolbar_, '.button-spacer');
 
   this.prompt_ = new ImageEditor.Prompt(this.container_, strf);
 
   this.errorBanner_ = new ErrorBanner(this.container_);
 
-  var slideModeButton = queryRequiredElement(
-      this.topToolbar_, '.button.slide-mode');
-  slideModeButton.addEventListener(
-      'click', this.onSlideModeButtonClicked_.bind(this));
-
-  var mosaicModeButton = queryRequiredElement(
-      this.topToolbar_, '.button.mosaic-mode');
-  mosaicModeButton.addEventListener(
-      'click', this.onMosaicModeButtonClicked_.bind(this));
+  this.modeButton_ = queryRequiredElement(this.toolbar_, 'button.mode');
+  this.modeButton_.addEventListener('click',
+      this.toggleMode_.bind(this, undefined));
 
   this.mosaicMode_ = new MosaicMode(content,
                                     this.errorBanner_,
@@ -128,8 +156,7 @@
 
   this.slideMode_ = new SlideMode(this.container_,
                                   content,
-                                  this.topToolbar_,
-                                  this.bottomToolbar_,
+                                  this.toolbar_,
                                   this.prompt_,
                                   this.errorBanner_,
                                   this.dataModel_,
@@ -145,10 +172,10 @@
     cr.dispatchSimpleEvent(this, 'image-displayed');
   }.bind(this));
 
-  this.deleteButton_ = queryRequiredElement(this.topToolbar_, '.button.delete');
+  this.deleteButton_ = this.initToolbarButton_('delete', 'GALLERY_DELETE');
   this.deleteButton_.addEventListener('click', this.delete_.bind(this));
 
-  this.shareButton_ = queryRequiredElement(this.topToolbar_, '.button.share');
+  this.shareButton_ = this.initToolbarButton_('share', 'GALLERY_SHARE');
   this.shareButton_.addEventListener(
       'click', this.onShareButtonClick_.bind(this));
 
@@ -237,6 +264,20 @@
 };
 
 /**
+ * Initializes a toolbar button.
+ *
+ * @param {string} className Class to add.
+ * @param {string} title Button title.
+ * @return {!HTMLElement} Newly created button.
+ * @private
+ */
+Gallery.prototype.initToolbarButton_ = function(className, title) {
+  var button = queryRequiredElement(this.toolbar_, 'button.' + className);
+  button.title = str(title);
+  return button;
+};
+
+/**
  * Loads the content.
  *
  * @param {!Array<!Entry>} selectedEntries Array of selected entries.
@@ -378,6 +419,45 @@
 };
 
 /**
+ * Handles user's 'Close' action.
+ * @private
+ */
+Gallery.prototype.onClose_ = function() {
+  this.executeWhenReady(this.context_.onClose);
+};
+
+/**
+ * Handles user's 'Maximize' action (Escape or a click on the X icon).
+ * @private
+ */
+Gallery.prototype.onMaximize_ = function() {
+  this.executeWhenReady(this.context_.onMaximize);
+};
+
+/**
+ * Handles user's 'Maximize' action (Escape or a click on the X icon).
+ * @private
+ */
+Gallery.prototype.onMinimize_ = function() {
+  this.executeWhenReady(this.context_.onMinimize);
+};
+
+/**
+ * Executes a function when the editor is done with the modifications.
+ * @param {function()} callback Function to execute.
+ */
+Gallery.prototype.executeWhenReady = function(callback) {
+  this.currentMode_.executeWhenReady(callback);
+};
+
+/**
+ * @return {!Object} File manager private API.
+ */
+Gallery.getFileManagerPrivate = function() {
+  return chrome.fileManagerPrivate || window.top.chrome.fileManagerPrivate;
+};
+
+/**
  * @return {boolean} True if some tool is currently active.
  */
 Gallery.prototype.hasActiveTool = function() {
@@ -398,9 +478,6 @@
  * Sets the current mode, update the UI.
  * @param {!(SlideMode|MosaicMode)} mode Current mode.
  * @private
- *
- * TODO(yawano): Since this method is confusing with changeCurrentMode_. Rename
- *     or remove this method.
  */
 Gallery.prototype.setCurrentMode_ = function(mode) {
   if (mode !== this.slideMode_ && mode !== this.mosaicMode_)
@@ -409,81 +486,7 @@
   this.currentMode_ = mode;
   this.container_.setAttribute('mode', this.currentMode_.getName());
   this.updateSelectionAndState_();
-};
-
-/**
- * Handles click event of SlideModeButton.
- * @param {!Event} event An event.
- * @private
- */
-Gallery.prototype.onSlideModeButtonClicked_ = function(event) {
-  this.changeCurrentMode_(this.slideMode_, event);
-};
-
-/**
- * Handles click event of MosaicModeButton.
- * @param {!Event} event An event.
- * @private
- */
-Gallery.prototype.onMosaicModeButtonClicked_ = function(event) {
-  this.changeCurrentMode_(this.mosaicMode_, event);
-};
-
-/**
- * Change current mode.
- * @param {!(SlideMode|MosaicMode)} mode Target mode.
- * @param {Event=} opt_event Event that caused this call.
- * @private
- */
-Gallery.prototype.changeCurrentMode_ = function(mode, opt_event) {
-  return new Promise(function(fulfill, reject) {
-    // Do not re-enter while changing the mode.
-    if (this.currentMode_ === mode || this.changingMode_) {
-      fulfill();
-      return;
-    }
-
-    if (opt_event)
-      this.onUserAction_();
-
-    this.changingMode_ = true;
-
-    var onModeChanged = function() {
-      this.changingMode_ = false;
-      fulfill();
-    }.bind(this);
-
-    var tileIndex = Math.max(0, this.selectionModel_.selectedIndex);
-
-    var mosaic = this.mosaicMode_.getMosaic();
-    var tileRect = mosaic.getTileRect(tileIndex);
-
-    if (mode === this.mosaicMode_) {
-      this.setCurrentMode_(this.mosaicMode_);
-      mosaic.transform(
-          tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */);
-      this.slideMode_.leave(
-          tileRect,
-          function() {
-            // Animate back to normal position.
-            mosaic.transform(null, null);
-            mosaic.show();
-            onModeChanged();
-          }.bind(this));
-      this.bottomToolbar_.hidden = true;
-    } else {
-      this.setCurrentMode_(this.slideMode_);
-      this.slideMode_.enter(
-          tileRect,
-          function() {
-            // Animate to zoomed position.
-            mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect());
-            mosaic.hide();
-          }.bind(this),
-          onModeChanged);
-      this.bottomToolbar_.hidden = false;
-    }
-  }.bind(this));
+  this.updateButtons_();
 };
 
 /**
@@ -493,13 +496,50 @@
  * @private
  */
 Gallery.prototype.toggleMode_ = function(opt_callback, opt_event) {
-  var targetMode = this.currentMode_ === this.slideMode_ ?
-      this.mosaicMode_ : this.slideMode_;
+  if (!this.modeButton_)
+    return;
 
-  this.changeCurrentMode_(targetMode, opt_event).then(function() {
-    if (opt_callback)
-      opt_callback();
-  });
+  if (this.changingMode_) // Do not re-enter while changing the mode.
+    return;
+
+  if (opt_event)
+    this.onUserAction_();
+
+  this.changingMode_ = true;
+
+  var onModeChanged = function() {
+    this.changingMode_ = false;
+    if (opt_callback) opt_callback();
+  }.bind(this);
+
+  var tileIndex = Math.max(0, this.selectionModel_.selectedIndex);
+
+  var mosaic = this.mosaicMode_.getMosaic();
+  var tileRect = mosaic.getTileRect(tileIndex);
+
+  if (this.currentMode_ === this.slideMode_) {
+    this.setCurrentMode_(this.mosaicMode_);
+    mosaic.transform(
+        tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */);
+    this.slideMode_.leave(
+        tileRect,
+        function() {
+          // Animate back to normal position.
+          mosaic.transform(null, null);
+          mosaic.show();
+          onModeChanged();
+        }.bind(this));
+  } else {
+    this.setCurrentMode_(this.slideMode_);
+    this.slideMode_.enter(
+        tileRect,
+        function() {
+          // Animate to zoomed position.
+          mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect());
+          mosaic.hide();
+        }.bind(this),
+        onModeChanged);
+  }
 };
 
 /**
@@ -848,6 +888,19 @@
 };
 
 /**
+ * Updates buttons.
+ * @private
+ */
+Gallery.prototype.updateButtons_ = function() {
+  if (this.modeButton_) {
+    var oppositeMode =
+        this.currentMode_ === this.slideMode_ ? this.mosaicMode_ :
+                                                this.slideMode_;
+    this.modeButton_.title = str(oppositeMode.getTitle());
+  }
+};
+
+/**
  * Enters the debug mode.
  */
 Gallery.prototype.debugMe = function() {
diff --git a/ui/file_manager/gallery/js/image_editor/viewport.js b/ui/file_manager/gallery/js/image_editor/viewport.js
index 930c304..10c49f7 100644
--- a/ui/file_manager/gallery/js/image_editor/viewport.js
+++ b/ui/file_manager/gallery/js/image_editor/viewport.js
@@ -487,7 +487,8 @@
  * @param {number} width Width of image.
  * @param {number} height Height of image.
  * @param {!ImageRect} screenRect Rectangle in window coordinate system. The
- *     origin of the coordinate system at the left upper of the window.
+ *     origin of the coordinate system is located at the left upper of the
+ *     window.
  */
 Viewport.prototype.getScreenRectTransformation = function(
     width, height, screenRect) {
@@ -521,14 +522,13 @@
       wholeWidthMax, wholeHeightMax, wholeWidthMax, wholeHeightMax);
   var wholeWidth = wholeWidthMax * fittingScale;
   var wholeHeight = wholeHeightMax * fittingScale;
-  var wholeLeft = (this.screenBounds_.width - wholeWidth) / 2;
-  var wholeTop = (this.screenBounds_.height - wholeHeight) / 2;
+  var wholeRect = this.getCenteredRect_(wholeWidth, wholeHeight, 0, 0);
   return this.getScreenRectTransformation(
       width,
       height,
       new ImageRect(
-          wholeLeft + cropRect.left * fittingScale,
-          wholeTop + cropRect.top * fittingScale,
+          wholeRect.left + cropRect.left * fittingScale,
+          wholeRect.top + cropRect.top * fittingScale,
           cropRect.width * fittingScale,
           cropRect.height * fittingScale));
 };
@@ -597,13 +597,11 @@
       rotatedWidth, rotatedHeight, rotatedMaxWidth, rotatedMaxHeight);
 
   // Offset for centering.
-  var dx = (this.screenBounds_.width - width) / 2;
-  var dy = (this.screenBounds_.height - height) / 2;
-
+  var rect = this.getCenteredRect_(width, height, offsetX, offsetY);
   return formatString(
       'translate($1px,$2px) scale($3) rotate($4deg)',
-      dx + offsetX,
-      dy + offsetY,
+      rect.left,
+      rect.top,
       fittingScale * zoom,
       rotation * 90);
 };
diff --git a/ui/file_manager/gallery/js/slide_mode.js b/ui/file_manager/gallery/js/slide_mode.js
index fd80c428..2476ba27 100644
--- a/ui/file_manager/gallery/js/slide_mode.js
+++ b/ui/file_manager/gallery/js/slide_mode.js
@@ -8,8 +8,7 @@
  *
  * @param {!HTMLElement} container Main container element.
  * @param {!HTMLElement} content Content container element.
- * @param {!HTMLElement} topToolbar Top toolbar element.
- * @param {!HTMLElement} bottomToolbar Toolbar element.
+ * @param {!HTMLElement} toolbar Toolbar element.
  * @param {!ImageEditor.Prompt} prompt Prompt.
  * @param {!ErrorBanner} errorBanner Error banner.
  * @param {!cr.ui.ArrayDataModel} dataModel Data model.
@@ -26,9 +25,9 @@
  * @suppress {checkStructDictInheritance}
  * @extends {cr.EventTarget}
  */
-function SlideMode(container, content, topToolbar, bottomToolbar, prompt,
-    errorBanner, dataModel, selectionModel, metadataModel, thumbnailModel,
-    context, volumeManager, toggleMode, displayStringFunction) {
+function SlideMode(container, content, toolbar, prompt, errorBanner, dataModel,
+    selectionModel, metadataModel, thumbnailModel, context, volumeManager,
+    toggleMode, displayStringFunction) {
   /**
    * @type {!HTMLElement}
    * @private
@@ -54,14 +53,7 @@
    * @private
    * @const
    */
-  this.topToolbar_ = topToolbar;
-
-  /**
-   * @type {!HTMLElement}
-   * @private
-   * @const
-   */
-  this.bottomToolbar_ = bottomToolbar;
+  this.toolbar_ = toolbar;
 
   /**
    * @type {!ImageEditor.Prompt}
@@ -226,30 +218,34 @@
    * @private
    * @const
    */
-  this.options_ = queryRequiredElement(this.bottomToolbar_, '.options');
+  this.options_ = util.createChild(queryRequiredElement(
+      this.toolbar_, '.filename-spacer'), 'options');
 
   /**
    * @type {!HTMLElement}
    * @private
    * @const
    */
-  this.savedLabel_ = queryRequiredElement(this.options_, '.saved');
+  this.savedLabel_ = util.createChild(this.options_, 'saved');
+  this.savedLabel_.textContent = this.displayStringFunction_('GALLERY_SAVED');
 
   /**
    * @type {!HTMLElement}
    * @private
    * @const
    */
-  this.overwriteOriginalBox_ = queryRequiredElement(
-      this.options_, '.overwrite-original');
+  this.overwriteOriginalBox_ = util.createChild(
+      this.options_, 'overwrite-original');
 
   /**
    * @type {!HTMLElement}
    * @private
    * @const
    */
-  this.overwriteOriginal_ = queryRequiredElement(
-      this.overwriteOriginalBox_, '#overwrite-checkbox')
+  this.overwriteOriginal_ = util.createChild(
+      this.overwriteOriginalBox_, '', 'input');
+  this.overwriteOriginal_.type = 'checkbox';
+  this.overwriteOriginal_.id = 'overwrite-checkbox';
   chrome.storage.local.get(SlideMode.OVERWRITE_KEY, function(values) {
     var value = values[SlideMode.OVERWRITE_KEY];
     // Out-of-the box default is 'true'
@@ -261,10 +257,20 @@
 
   /**
    * @type {!HTMLElement}
+   * @const
+   */
+  var overwriteLabel = util.createChild(
+      this.overwriteOriginalBox_, '', 'label');
+  overwriteLabel.textContent =
+      this.displayStringFunction_('GALLERY_OVERWRITE_ORIGINAL');
+  overwriteLabel.setAttribute('for', 'overwrite-checkbox');
+
+  /**
+   * @type {!HTMLElement}
    * @private
    * @const
    */
-  this.bubble_ = util.createChild(this.bottomToolbar_, 'bubble');
+  this.bubble_ = util.createChild(this.toolbar_, 'bubble');
   this.bubble_.hidden = true;
 
   /**
@@ -321,8 +327,7 @@
    * @private
    * @const
    */
-  this.ribbonSpacer_ = queryRequiredElement(this.bottomToolbar_,
-      '.ribbon-spacer');
+  this.ribbonSpacer_ = queryRequiredElement(this.toolbar_, '.ribbon-spacer');
 
   /**
    * @type {!Ribbon}
@@ -339,8 +344,8 @@
    * @type {!HTMLElement}
    * @const
    */
-  var slideShowButton = queryRequiredElement(this.topToolbar_,
-      '.button.slideshow');
+  var slideShowButton = queryRequiredElement(this.toolbar_, 'button.slideshow');
+  slideShowButton.title = this.displayStringFunction_('GALLERY_SLIDESHOW');
   slideShowButton.addEventListener('click',
       this.startSlideshow.bind(this, SlideMode.SLIDESHOW_INTERVAL_FIRST));
 
@@ -361,7 +366,9 @@
    * @private
    * @const
    */
-  this.editButton_ = queryRequiredElement(this.topToolbar_, '.button.edit');
+  this.editButton_ = queryRequiredElement(this.toolbar_, 'button.edit');
+  this.editButton_.title = this.displayStringFunction_('GALLERY_EDIT');
+  this.editButton_.disabled = true;  // Disabled by default.
   this.editButton_.addEventListener('click', this.toggleEditor.bind(this));
 
   /**
@@ -369,7 +376,9 @@
    * @private
    * @const
    */
-  this.printButton_ = queryRequiredElement(this.topToolbar_, '.button.print');
+  this.printButton_ = queryRequiredElement(this.toolbar_, 'button.print');
+  this.printButton_.title = this.displayStringFunction_('GALLERY_PRINT');
+  this.printButton_.disabled = true;  // Disabled by default.
   this.printButton_.addEventListener('click', this.print_.bind(this));
 
   /**
@@ -377,8 +386,7 @@
    * @private
    * @const
    */
-  this.editBarSpacer_ = queryRequiredElement(this.bottomToolbar_,
-      '.edit-bar-spacer');
+  this.editBarSpacer_ = queryRequiredElement(this.toolbar_, '.edit-bar-spacer');
 
   /**
    * @type {!HTMLElement}
@@ -1108,7 +1116,7 @@
 
   if (this.isSlideshowOn_()) {
     switch (keyID) {
-      case 'U+001B':  // Escape
+      case 'U+001B':  // Escape exits the slideshow.
       case 'MediaStop':
         this.stopSlideshow_(event);
         break;
diff --git a/ui/file_manager/gallery/manifest.json b/ui/file_manager/gallery/manifest.json
index fc3f893bc..6ac41fe4 100644
--- a/ui/file_manager/gallery/manifest.json
+++ b/ui/file_manager/gallery/manifest.json
@@ -17,7 +17,6 @@
     "256": "images/icon256.png"
   },
   "permissions": [
-    "app.window.fullscreen.overrideEsc",
     "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj",
     "chrome://extension-icon/",
     "chrome://resources/",
diff --git a/ui/file_manager/integration_tests/gallery/open_image_files.js b/ui/file_manager/integration_tests/gallery/open_image_files.js
index 2a26dff..b999a1e 100644
--- a/ui/file_manager/integration_tests/gallery/open_image_files.js
+++ b/ui/file_manager/integration_tests/gallery/open_image_files.js
@@ -16,7 +16,7 @@
   var launchedPromise = launch(testVolumeName, volumeType, [ENTRIES.desktop]);
   return launchedPromise.then(function(args) {
     var WIDTH = 880;
-    var HEIGHT = 603; /* Inner height 570px + native header 33px. */
+    var HEIGHT = 570;
     var appId = args.appId;
     var resizedWindowPromise = gallery.callRemoteTestUtil(
         'resizeWindow', appId, [WIDTH, HEIGHT]
diff --git a/ui/file_manager/integration_tests/gallery/photo_editor.js b/ui/file_manager/integration_tests/gallery/photo_editor.js
index 499a44c..2e3e742 100644
--- a/ui/file_manager/integration_tests/gallery/photo_editor.js
+++ b/ui/file_manager/integration_tests/gallery/photo_editor.js
@@ -30,7 +30,7 @@
 
     // Lauch the photo editor.
     var photoEditorPromise = slideImagePromise.then(function() {
-      return gallery.waitAndClickElement(appId, '.button.edit');
+      return gallery.waitAndClickElement(appId, 'button.edit');
     });
 
     return photoEditorPromise.then(function() {
diff --git a/ui/file_manager/integration_tests/gallery/slide_mode.js b/ui/file_manager/integration_tests/gallery/slide_mode.js
index d29f88c..a8398258 100644
--- a/ui/file_manager/integration_tests/gallery/slide_mode.js
+++ b/ui/file_manager/integration_tests/gallery/slide_mode.js
@@ -78,7 +78,7 @@
     appId = args.appId;
     return gallery.waitForSlideImage(appId, 800, 600, 'My Desktop Background');
   }).then(function() {
-    return gallery.waitAndClickElement(appId, '.button.delete');
+    return gallery.waitAndClickElement(appId, 'button.delete');
   }).then(function() {
     return gallery.waitAndClickElement(appId, '.cr-dialog-ok');
   }).then(function() {
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 5d7973c..aaea6cbd 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -251,9 +251,7 @@
   ]
 
   # Text rendering conditions (complicated so separated out).
-  if (is_android || is_ios) {
-    # We don't support RenderText on these platforms.
-  } else {
+  if (use_aura || is_mac) {
     # Mac doesn't use RenderTextHarfBuzz by default yet.
     sources += [
       "harfbuzz_font_skia.cc",
@@ -266,6 +264,18 @@
       "render_text_mac.h",
       "text_utils_skia.cc",
     ]
+  } else {
+    # We don't support RenderText on these platforms.
+  }
+
+  if (is_android && use_aura) {
+    sources -= [
+      "platform_font_android.cc",
+      "text_utils_android.cc",
+    ]
+    set_sources_assignment_filter([])
+    sources += [ "platform_font_linux.cc" ]
+    set_sources_assignment_filter(sources_assignment_filter)
   }
 
   # iOS.
@@ -280,16 +290,19 @@
 
   # Android.
   if (is_android) {
-    sources -= [
-      "animation/throb_animation.cc",
-      "canvas_skia.cc",
-      "selection_model.cc",
-    ]
-
     if (use_aura) {
-      sources -= [ "screen_android.cc" ]
+      sources -= [
+        "canvas_notimplemented.cc",
+        "screen_android.cc",
+      ]
+      sources += [ "font_fallback_android.cc" ]
     } else {
-      sources -= [ "path.cc" ]
+      sources -= [
+        "animation/throb_animation.cc",
+        "canvas_skia.cc",
+        "path.cc",
+        "selection_model.cc",
+      ]
     }
 
     if (!is_debug) {
diff --git a/ui/gfx/font_fallback_android.cc b/ui/gfx/font_fallback_android.cc
new file mode 100644
index 0000000..37f9b69
--- /dev/null
+++ b/ui/gfx/font_fallback_android.cc
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/font_fallback.h"
+
+#include <string>
+#include <vector>
+
+namespace gfx {
+
+std::vector<std::string> GetFallbackFontFamilies(
+    const std::string& font_family) {
+  return std::vector<std::string>();
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/platform_font_linux.cc b/ui/gfx/platform_font_linux.cc
index 9aeaaa0..eb5b7a3 100644
--- a/ui/gfx/platform_font_linux.cc
+++ b/ui/gfx/platform_font_linux.cc
@@ -27,7 +27,11 @@
 // The font family name which is used when a user's application font for
 // GNOME/KDE is a non-scalable one. The name should be listed in the
 // IsFallbackFontAllowed function in skia/ext/SkFontHost_fontconfig_direct.cpp.
+#if defined(OS_ANDROID)
+const char* kFallbackFontFamilyName = "serif";
+#else
 const char* kFallbackFontFamilyName = "sans";
+#endif
 
 // The default font, used for the default constructor.
 base::LazyInstance<scoped_refptr<PlatformFontLinux>>::Leaky g_default_font =
diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h
index 87a66f3..405dcd6 100644
--- a/ui/gfx/render_text.h
+++ b/ui/gfx/render_text.h
@@ -637,6 +637,10 @@
   FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_SufficientWidth);
   FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_Newline);
   FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_WordWrapBehavior);
+  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_LineBreakerBehavior);
+  FRIEND_TEST_ALL_PREFIXES(RenderTextTest,
+                           Multiline_SurrogatePairsOrCombiningChars);
+  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_ZeroWidthChars);
   FRIEND_TEST_ALL_PREFIXES(RenderTextTest, NewlineWithoutMultilineFlag);
   FRIEND_TEST_ALL_PREFIXES(RenderTextTest, GlyphBounds);
   FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_GlyphBounds);
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc
index 32a9e55..2274c7c 100644
--- a/ui/gfx/render_text_harfbuzz.cc
+++ b/ui/gfx/render_text_harfbuzz.cc
@@ -16,6 +16,7 @@
 #include "base/trace_event/trace_event.h"
 #include "third_party/harfbuzz-ng/src/hb.h"
 #include "third_party/icu/source/common/unicode/ubidi.h"
+#include "third_party/icu/source/common/unicode/utf16.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkTypeface.h"
 #include "ui/gfx/canvas.h"
@@ -24,6 +25,7 @@
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/harfbuzz_font_skia.h"
 #include "ui/gfx/range/range_f.h"
+#include "ui/gfx/text_utils.h"
 #include "ui/gfx/utf16_indexing.h"
 
 #if defined(OS_WIN)
@@ -49,9 +51,7 @@
 // therefore it needs to be trigerred as fallbacks. See crbug.com/448909
 bool IsUnusualBlockCode(UBlockCode block_code) {
   return block_code == UBLOCK_GEOMETRIC_SHAPES ||
-         block_code == UBLOCK_MISCELLANEOUS_SYMBOLS ||
-         block_code == UBLOCK_DINGBATS ||
-         block_code == UBLOCK_EMOTICONS;
+         block_code == UBLOCK_MISCELLANEOUS_SYMBOLS;
 }
 
 bool IsBracket(UChar32 character) {
@@ -90,15 +90,12 @@
   return run_break;
 }
 
-// If the given scripts match, returns the one that isn't USCRIPT_COMMON or
-// USCRIPT_INHERITED, i.e. the more specific one. Otherwise returns
-// USCRIPT_INVALID_CODE.
+// If the given scripts match, returns the one that isn't USCRIPT_INHERITED,
+// i.e. the more specific one. Otherwise returns USCRIPT_INVALID_CODE.
 UScriptCode ScriptIntersect(UScriptCode first, UScriptCode second) {
-  if (first == second ||
-      (second > USCRIPT_INVALID_CODE && second <= USCRIPT_INHERITED)) {
+  if (first == second || second == USCRIPT_INHERITED)
     return first;
-  }
-  if (first > USCRIPT_INVALID_CODE && first <= USCRIPT_INHERITED)
+  if (first == USCRIPT_INHERITED)
     return second;
   return USCRIPT_INVALID_CODE;
 }
@@ -166,6 +163,9 @@
   *script = scripts[0];
 
   while (char_iterator.Advance()) {
+    // Special handling to merge white space into the previous run.
+    if (u_isUWhiteSpace(char_iterator.get()))
+      continue;
     ScriptSetIntersect(char_iterator.get(), scripts, &scripts_size);
     if (scripts_size == 0U)
       return char_iterator.array_pos();
@@ -223,7 +223,6 @@
   HarfBuzzLineBreaker(size_t max_width,
                       int min_baseline,
                       float min_height,
-                      bool multiline,
                       WordWrapBehavior word_wrap_behavior,
                       const base::string16& text,
                       const BreakList<size_t>* words,
@@ -231,35 +230,63 @@
       : max_width_((max_width == 0) ? SK_ScalarMax : SkIntToScalar(max_width)),
         min_baseline_(min_baseline),
         min_height_(min_height),
-        multiline_(multiline),
         word_wrap_behavior_(word_wrap_behavior),
         text_(text),
         words_(words),
         run_list_(run_list),
-        text_x_(0),
-        line_x_(0),
         max_descent_(0),
-        max_ascent_(0) {
-    DCHECK_EQ(multiline_, (words_ != nullptr));
+        max_ascent_(0),
+        text_x_(0),
+        available_width_(max_width_) {
     AdvanceLine();
   }
 
-  // Breaks the run at given |run_index| into Line structs.
-  void AddRun(int run_index) {
-    const internal::TextRunHarfBuzz* run = run_list_.runs()[run_index];
-    base::char16 first_char = text_[run->range.start()];
-    if (multiline_ && first_char == '\n') {
-      AdvanceLine();
-    } else if (multiline_ && (line_x_ + SkFloatToScalar(run->width)) >
-               max_width_) {
-      BreakRun(run_index);
-    } else {
-      AddSegment(run_index, run->range, run->width);
+  // Constructs a single line for |text_| using |run_list_|.
+  void ConstructSingleLine() {
+    for (size_t i = 0; i < run_list_.size(); i++) {
+      const internal::TextRunHarfBuzz& run = *(run_list_.runs()[i]);
+      internal::LineSegment segment;
+      segment.run = i;
+      segment.char_range = run.range;
+      segment.x_range = Range(SkScalarCeilToInt(text_x_),
+                              SkScalarCeilToInt(text_x_ + run.width));
+      segment.width = run.width;
+      AddLineSegment(segment);
+    }
+  }
+
+  // Constructs multiple lines for |text_| based on words iteration approach.
+  void ConstructMultiLines() {
+    DCHECK(words_);
+    for (auto iter = words_->breaks().begin(); iter != words_->breaks().end();
+         iter++) {
+      const Range word_range = words_->GetRange(iter);
+      std::vector<internal::LineSegment> word_segments;
+      SkScalar word_width = GetWordWidth(word_range, &word_segments);
+
+      // If the last word is '\n', we should advance a new line after adding
+      // the word to the current line.
+      bool new_line = false;
+      if (!word_segments.empty() &&
+          text_[word_segments.back().char_range.start()] == '\n') {
+        new_line = true;
+        word_width -= word_segments.back().width;
+        word_segments.pop_back();
+      }
+
+      // If the word is not the first word in the line and it can't fit into
+      // the current line, advance a new line.
+      if (word_width > available_width_ && available_width_ != max_width_)
+        AdvanceLine();
+      if (!word_segments.empty())
+        AddWordToLine(word_segments);
+      if (new_line)
+        AdvanceLine();
     }
   }
 
   // Finishes line breaking and outputs the results. Can be called at most once.
-  void Finalize(std::vector<internal::Line>* lines, SizeF* size) {
+  void FinalizeLines(std::vector<internal::Line>* lines, SizeF* size) {
     DCHECK(!lines_.empty());
     // Add an empty line to finish the line size calculation and remove it.
     AdvanceLine();
@@ -276,113 +303,188 @@
     return &lines_[handle.first].segments[handle.second];
   }
 
-  // Breaks a run into segments that fit in the last line in |lines_| and adds
-  // them. Adds a new Line to the back of |lines_| whenever a new segment can't
-  // be added without the Line's width exceeding |max_width_|.
-  void BreakRun(int run_index) {
-    const internal::TextRunHarfBuzz& run = *(run_list_.runs()[run_index]);
-    SkScalar width = 0;
-    size_t next_char = run.range.start();
+  // Finishes the size calculations of the last Line in |lines_|. Adds a new
+  // Line to the back of |lines_|.
+  void AdvanceLine() {
+    if (!lines_.empty()) {
+      internal::Line* line = &lines_.back();
+      std::sort(line->segments.begin(), line->segments.end(),
+                [this](const internal::LineSegment& s1,
+                       const internal::LineSegment& s2) -> bool {
+                  return run_list_.logical_to_visual(s1.run) <
+                         run_list_.logical_to_visual(s2.run);
+                });
+      line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_));
+      line->baseline = std::max(min_baseline_, SkScalarRoundToInt(max_ascent_));
+      line->preceding_heights = std::ceil(total_size_.height());
+      total_size_.set_height(total_size_.height() + line->size.height());
+      total_size_.set_width(std::max(total_size_.width(), line->size.width()));
+    }
+    max_descent_ = 0;
+    max_ascent_ = 0;
+    available_width_ = max_width_;
+    lines_.push_back(internal::Line());
+  }
 
-    // Break the run until it fits the current line.
-    while (next_char < run.range.end()) {
-      const size_t current_char = next_char;
-      size_t end_char = next_char;
-      const bool skip_line =
-          BreakRunAtWidth(run, current_char, &width, &end_char, &next_char);
-      AddSegment(run_index, Range(current_char, end_char),
-                 SkScalarToFloat(width));
-      if (skip_line)
-        AdvanceLine();
+  // Adds word to the current line. A word may contain multiple segments. If the
+  // word is the first word in line and its width exceeds |available_width_|,
+  // ignore/truncate/wrap it according to |word_wrap_behavior_|.
+  void AddWordToLine(const std::vector<internal::LineSegment>& word_segments) {
+    DCHECK(!lines_.empty());
+    DCHECK(!word_segments.empty());
+
+    bool has_truncated = false;
+    for (const internal::LineSegment& segment : word_segments) {
+      if (has_truncated)
+        break;
+      if (segment.width <= available_width_ ||
+          word_wrap_behavior_ == IGNORE_LONG_WORDS) {
+        AddLineSegment(segment);
+      } else {
+        DCHECK(word_wrap_behavior_ == TRUNCATE_LONG_WORDS ||
+               word_wrap_behavior_ == WRAP_LONG_WORDS);
+        has_truncated = (word_wrap_behavior_ == TRUNCATE_LONG_WORDS);
+
+        const internal::TextRunHarfBuzz& run = *(run_list_.runs()[segment.run]);
+        internal::LineSegment remaining_segment = segment;
+        while (!remaining_segment.char_range.is_empty()) {
+          size_t cutoff_pos = GetCutoffPos(remaining_segment);
+          SkScalar width = run.GetGlyphWidthForCharRange(
+              Range(remaining_segment.char_range.start(), cutoff_pos));
+          if (width > 0) {
+            internal::LineSegment cut_segment;
+            cut_segment.run = remaining_segment.run;
+            cut_segment.char_range =
+                Range(remaining_segment.char_range.start(), cutoff_pos);
+            cut_segment.width = width;
+            cut_segment.x_range = Range(remaining_segment.x_range.start(),
+                                        SkScalarCeilToInt(text_x_ + width));
+            AddLineSegment(cut_segment);
+            // Updates old segment range.
+            remaining_segment.char_range.set_start(cutoff_pos);
+            remaining_segment.x_range.set_start(SkScalarCeilToInt(text_x_));
+            remaining_segment.width -= width;
+          }
+          if (has_truncated)
+            break;
+          if (!remaining_segment.char_range.is_empty())
+            AdvanceLine();
+        }
+      }
     }
   }
 
-  // Starting from |start_char|, finds a suitable line break position at or
-  // before available width using word break. If the current position is at the
-  // beginning of a line, this function will not roll back to |start_char| and
-  // |*next_char| will be greater than |start_char| (to avoid constructing empty
-  // lines). It stores the end of the segment range to |end_char|, which can be
-  // smaller than |*next_char| for certain word wrapping behavior.
-  // Returns whether to skip the line before |*next_char|.
-  // TODO(ckocagil): We might have to reshape after breaking at ligatures.
-  //                 See whether resolving the TODO above resolves this too.
-  // TODO(ckocagil): Do not reserve width for whitespace at the end of lines.
-  bool BreakRunAtWidth(const internal::TextRunHarfBuzz& run,
-                       size_t start_char,
-                       SkScalar* width,
-                       size_t* end_char,
-                       size_t* next_char) {
-    DCHECK(words_);
-    DCHECK(run.range.Contains(Range(start_char, start_char + 1)));
-    SkScalar available_width = max_width_ - line_x_;
-    BreakList<size_t>::const_iterator word = words_->GetBreak(start_char);
-    BreakList<size_t>::const_iterator next_word = word + 1;
-    // Width from |std::max(word->first, start_char)| to the current character.
-    SkScalar word_width = 0;
-    *width = 0;
-
-    Range char_range;
-    SkScalar truncated_width = 0;
-    for (size_t i = start_char; i < run.range.end(); i += char_range.length()) {
-      // |word| holds the word boundary at or before |i|, and |next_word| holds
-      // the word boundary right after |i|. Advance both |word| and |next_word|
-      // when |i| reaches |next_word|.
-      if (next_word != words_->breaks().end() && i >= next_word->first) {
-        if (*width > available_width) {
-          DCHECK_NE(WRAP_LONG_WORDS, word_wrap_behavior_);
-          *next_char = i;
-          if (word_wrap_behavior_ != TRUNCATE_LONG_WORDS)
-            *end_char = *next_char;
-          else
-            *width = truncated_width;
-          return true;
-        }
-        word = next_word++;
-        word_width = 0;
-      }
-
-      Range glyph_range;
-      run.GetClusterAt(i, &char_range, &glyph_range);
-      DCHECK_LT(0U, char_range.length());
-
-      SkScalar char_width = ((glyph_range.end() >= run.glyph_count)
-                                 ? SkFloatToScalar(run.width)
-                                 : run.positions[glyph_range.end()].x()) -
-                            run.positions[glyph_range.start()].x();
-
-      *width += char_width;
-      word_width += char_width;
-
-      // TODO(mukai): implement ELIDE_LONG_WORDS.
-      if (*width > available_width) {
-        if (line_x_ != 0 || word_width < *width) {
-          // Roll back one word.
-          *width -= word_width;
-          *next_char = std::max(word->first, start_char);
-          *end_char = *next_char;
-          return true;
-        } else if (word_wrap_behavior_ == WRAP_LONG_WORDS) {
-          if (char_width < *width) {
-            // Roll back one character.
-            *width -= char_width;
-            *next_char = i;
-          } else {
-            // Continue from the next character.
-            *next_char = i + char_range.length();
-          }
-          *end_char = *next_char;
-          return true;
-        }
-      } else {
-        *end_char = char_range.end();
-        truncated_width = *width;
+  // Add a line segment to the current line. Note that, in order to keep the
+  // visual order correct for ltr and rtl language, we need to merge segments
+  // that belong to the same run.
+  void AddLineSegment(const internal::LineSegment& segment) {
+    DCHECK(!lines_.empty());
+    internal::Line* line = &lines_.back();
+    const internal::TextRunHarfBuzz& run = *(run_list_.runs()[segment.run]);
+    if (!line->segments.empty()) {
+      internal::LineSegment& last_segment = line->segments.back();
+      // Merge segments that belong to the same run.
+      if (last_segment.run == segment.run) {
+        DCHECK_EQ(last_segment.char_range.end(), segment.char_range.start());
+        DCHECK_EQ(last_segment.x_range.end(), segment.x_range.start());
+        last_segment.char_range.set_end(segment.char_range.end());
+        last_segment.width += segment.width;
+        last_segment.x_range.set_end(
+            SkScalarCeilToInt(text_x_ + segment.width));
+        if (run.is_rtl && last_segment.char_range.end() == run.range.end())
+          UpdateRTLSegmentRanges();
+        line->size.set_width(line->size.width() + segment.width);
+        text_x_ += segment.width;
+        available_width_ -= segment.width;
+        return;
       }
     }
+    line->segments.push_back(segment);
 
-    if (word_wrap_behavior_ == TRUNCATE_LONG_WORDS)
-      *width = truncated_width;
-    *end_char = *next_char = run.range.end();
-    return false;
+    SkPaint paint;
+    paint.setTypeface(run.skia_face.get());
+    paint.setTextSize(SkIntToScalar(run.font_size));
+    paint.setAntiAlias(run.render_params.antialiasing);
+    SkPaint::FontMetrics metrics;
+    paint.getFontMetrics(&metrics);
+
+    line->size.set_width(line->size.width() + segment.width);
+    // TODO(dschuyler): Account for stylized baselines in string sizing.
+    max_descent_ = std::max(max_descent_, metrics.fDescent);
+    // fAscent is always negative.
+    max_ascent_ = std::max(max_ascent_, -metrics.fAscent);
+
+    if (run.is_rtl) {
+      rtl_segments_.push_back(
+          SegmentHandle(lines_.size() - 1, line->segments.size() - 1));
+      // If this is the last segment of an RTL run, reprocess the text-space x
+      // ranges of all segments from the run.
+      if (segment.char_range.end() == run.range.end())
+        UpdateRTLSegmentRanges();
+    }
+    text_x_ += segment.width;
+    available_width_ -= segment.width;
+  }
+
+  // Finds the end position |end_pos| in |segment| where the preceding width is
+  // no larger than |available_width_|.
+  size_t GetCutoffPos(const internal::LineSegment& segment) const {
+    DCHECK(!segment.char_range.is_empty());
+    const internal::TextRunHarfBuzz& run = *(run_list_.runs()[segment.run]);
+    size_t end_pos = segment.char_range.start();
+    SkScalar width = 0;
+    while (end_pos < segment.char_range.end()) {
+      const SkScalar char_width =
+          run.GetGlyphWidthForCharRange(Range(end_pos, end_pos + 1));
+      if (width + char_width > available_width_)
+        break;
+      width += char_width;
+      end_pos++;
+    }
+
+    const size_t valid_end_pos = FindValidBoundaryBefore(text_, end_pos);
+    if (end_pos != valid_end_pos) {
+      end_pos = valid_end_pos;
+      width = run.GetGlyphWidthForCharRange(
+          Range(segment.char_range.start(), end_pos));
+    }
+
+    // |max_width_| might be smaller than a single character. In this case we
+    // need to put at least one character in the line. Note that, we should
+    // not separate surrogate pair or combining characters.
+    // See RenderTextTest.Multiline_MinWidth for an example.
+    if (width == 0 && available_width_ == max_width_)
+      end_pos = FindValidBoundaryAfter(text_, end_pos + 1);
+
+    return end_pos;
+  }
+
+  // Gets the glyph width for |word_range|, and splits the |word| into different
+  // segments based on its runs.
+  SkScalar GetWordWidth(const Range& word_range,
+                        std::vector<internal::LineSegment>* segments) const {
+    DCHECK(words_);
+    if (word_range.is_empty() || segments == nullptr)
+      return 0;
+    size_t run_start_index = run_list_.GetRunIndexAt(word_range.start());
+    size_t run_end_index = run_list_.GetRunIndexAt(word_range.end() - 1);
+    SkScalar width = 0;
+    for (size_t i = run_start_index; i <= run_end_index; i++) {
+      const internal::TextRunHarfBuzz& run = *(run_list_.runs()[i]);
+      const Range char_range = run.range.Intersect(word_range);
+      DCHECK(!char_range.is_empty());
+      const SkScalar char_width = run.GetGlyphWidthForCharRange(char_range);
+      width += char_width;
+
+      internal::LineSegment segment;
+      segment.run = i;
+      segment.char_range = char_range;
+      segment.width = char_width;
+      segment.x_range = Range(SkScalarCeilToInt(text_x_ + width - char_width),
+                              SkScalarCeilToInt(text_x_ + width));
+      segments->push_back(segment);
+    }
+    return width;
   }
 
   // RTL runs are broken in logical order but displayed in visual order. To find
@@ -402,78 +504,9 @@
     rtl_segments_.clear();
   }
 
-  // Finishes the size calculations of the last Line in |lines_|. Adds a new
-  // Line to the back of |lines_|.
-  void AdvanceLine() {
-    if (!lines_.empty()) {
-      internal::Line* line = &lines_.back();
-      std::sort(line->segments.begin(), line->segments.end(),
-                [this](const internal::LineSegment& s1,
-                       const internal::LineSegment& s2) -> bool {
-                  return run_list_.logical_to_visual(s1.run) <
-                         run_list_.logical_to_visual(s2.run);
-                });
-      line->size.set_height(std::max(min_height_, max_descent_ + max_ascent_));
-      line->baseline =
-          std::max(min_baseline_, SkScalarRoundToInt(max_ascent_));
-      line->preceding_heights = std::ceil(total_size_.height());
-      total_size_.set_height(total_size_.height() + line->size.height());
-      total_size_.set_width(std::max(total_size_.width(), line->size.width()));
-    }
-    max_descent_ = 0;
-    max_ascent_ = 0;
-    line_x_ = 0;
-    lines_.push_back(internal::Line());
-  }
-
-  // Adds a new segment with the given properties to |lines_.back()|.
-  void AddSegment(int run_index, Range char_range, float width) {
-    if (char_range.is_empty()) {
-      DCHECK_EQ(0, width);
-      return;
-    }
-    const internal::TextRunHarfBuzz& run = *(run_list_.runs()[run_index]);
-
-    internal::LineSegment segment;
-    segment.run = run_index;
-    segment.char_range = char_range;
-    segment.x_range = Range(
-        SkScalarCeilToInt(text_x_),
-        SkScalarCeilToInt(text_x_ + SkFloatToScalar(width)));
-    segment.width = width;
-
-    internal::Line* line = &lines_.back();
-    line->segments.push_back(segment);
-
-    SkPaint paint;
-    paint.setTypeface(run.skia_face.get());
-    paint.setTextSize(SkIntToScalar(run.font_size));
-    paint.setAntiAlias(run.render_params.antialiasing);
-    SkPaint::FontMetrics metrics;
-    paint.getFontMetrics(&metrics);
-
-    line->size.set_width(line->size.width() + width);
-    // TODO(dschuyler): Account for stylized baselines in string sizing.
-    max_descent_ = std::max(max_descent_, metrics.fDescent);
-    // fAscent is always negative.
-    max_ascent_ = std::max(max_ascent_, -metrics.fAscent);
-
-    if (run.is_rtl) {
-      rtl_segments_.push_back(
-          SegmentHandle(lines_.size() - 1, line->segments.size() - 1));
-      // If this is the last segment of an RTL run, reprocess the text-space x
-      // ranges of all segments from the run.
-      if (char_range.end() == run.range.end())
-        UpdateRTLSegmentRanges();
-    }
-    text_x_ += SkFloatToScalar(width);
-    line_x_ += SkFloatToScalar(width);
-  }
-
   const SkScalar max_width_;
   const int min_baseline_;
   const float min_height_;
-  const bool multiline_;
   const WordWrapBehavior word_wrap_behavior_;
   const base::string16& text_;
   const BreakList<size_t>* const words_;
@@ -482,13 +515,14 @@
   // Stores the resulting lines.
   std::vector<internal::Line> lines_;
 
-  // Text space and line space x coordinates of the next segment to be added.
-  SkScalar text_x_;
-  SkScalar line_x_;
-
   float max_descent_;
   float max_ascent_;
 
+  // Text space x coordinates of the next segment to be added.
+  SkScalar text_x_;
+  // Stores available width in the current line.
+  SkScalar available_width_;
+
   // Size of the multiline text, not including the currently processed line.
   SizeF total_size_;
 
@@ -532,29 +566,6 @@
 
 TextRunHarfBuzz::~TextRunHarfBuzz() {}
 
-void TextRunHarfBuzz::GetClusterAt(size_t pos,
-                                   Range* chars,
-                                   Range* glyphs) const {
-  DCHECK(range.Contains(Range(pos, pos + 1)));
-  DCHECK(chars);
-  DCHECK(glyphs);
-
-  if (glyph_count == 0) {
-    *chars = range;
-    *glyphs = Range();
-    return;
-  }
-
-  if (is_rtl) {
-    GetClusterAtImpl(pos, range, glyph_to_char.rbegin(), glyph_to_char.rend(),
-        true, chars, glyphs);
-    return;
-  }
-
-  GetClusterAtImpl(pos, range, glyph_to_char.begin(), glyph_to_char.end(),
-      false, chars, glyphs);
-}
-
 Range TextRunHarfBuzz::CharRangeToGlyphRange(const Range& char_range) const {
   DCHECK(range.Contains(char_range));
   DCHECK(!char_range.is_reversed());
@@ -578,6 +589,29 @@
   return missing;
 }
 
+void TextRunHarfBuzz::GetClusterAt(size_t pos,
+                                   Range* chars,
+                                   Range* glyphs) const {
+  DCHECK(range.Contains(Range(pos, pos + 1)));
+  DCHECK(chars);
+  DCHECK(glyphs);
+
+  if (glyph_count == 0) {
+    *chars = range;
+    *glyphs = Range();
+    return;
+  }
+
+  if (is_rtl) {
+    GetClusterAtImpl(pos, range, glyph_to_char.rbegin(), glyph_to_char.rend(),
+                     true, chars, glyphs);
+    return;
+  }
+
+  GetClusterAtImpl(pos, range, glyph_to_char.begin(), glyph_to_char.end(),
+                   false, chars, glyphs);
+}
+
 RangeF TextRunHarfBuzz::GetGraphemeBounds(
     base::i18n::BreakIterator* grapheme_iterator,
     size_t text_index) {
@@ -626,6 +660,19 @@
                 preceding_run_widths + cluster_end_x);
 }
 
+SkScalar TextRunHarfBuzz::GetGlyphWidthForCharRange(
+    const Range& char_range) const {
+  if (char_range.is_empty())
+    return 0;
+
+  DCHECK(range.Contains(char_range));
+  Range glyph_range = CharRangeToGlyphRange(char_range);
+  return ((glyph_range.end() == glyph_count)
+              ? SkFloatToScalar(width)
+              : positions[glyph_range.end()].x()) -
+         positions[glyph_range.start()].x();
+}
+
 TextRunList::TextRunList() : width_(0.0f) {}
 
 TextRunList::~TextRunList() {}
@@ -660,6 +707,14 @@
   }
 }
 
+size_t TextRunList::GetRunIndexAt(size_t position) const {
+  for (size_t i = 0; i < runs_.size(); ++i) {
+    if (runs_[i]->range.start() <= position && runs_[i]->range.end() > position)
+      return i;
+  }
+  return runs_.size();
+}
+
 }  // namespace internal
 
 RenderTextHarfBuzz::RenderTextHarfBuzz()
@@ -1008,16 +1063,18 @@
     internal::TextRunList* run_list = GetRunList();
     HarfBuzzLineBreaker line_breaker(
         display_rect().width(), font_list().GetBaseline(),
-        std::max(font_list().GetHeight(), min_line_height()), multiline(),
+        std::max(font_list().GetHeight(), min_line_height()),
         word_wrap_behavior(), GetDisplayText(),
         multiline() ? &GetLineBreaks() : nullptr, *run_list);
 
     tracking_profile.reset();
 
-    for (size_t i = 0; i < run_list->size(); ++i)
-      line_breaker.AddRun(i);
+    if (multiline())
+      line_breaker.ConstructMultiLines();
+    else
+      line_breaker.ConstructSingleLine();
     std::vector<internal::Line> lines;
-    line_breaker.Finalize(&lines, &total_size_);
+    line_breaker.FinalizeLines(&lines, &total_size_);
     set_lines(&lines);
   }
 }
@@ -1152,14 +1209,13 @@
 void RenderTextHarfBuzz::ItemizeTextToRuns(
     const base::string16& text,
     internal::TextRunList* run_list_out) {
-  const bool is_text_rtl = GetTextDirection(text) == base::i18n::RIGHT_TO_LEFT;
   DCHECK_NE(0U, text.length());
 
   // If ICU fails to itemize the text, we create a run that spans the entire
   // text. This is needed because leaving the runs set empty causes some clients
   // to misbehave since they expect non-zero text metrics from a non-empty text.
   base::i18n::BiDiLineIterator bidi_iterator;
-  if (!bidi_iterator.Open(text, is_text_rtl, false)) {
+  if (!bidi_iterator.Open(text, GetTextDirection(text))) {
     internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz;
     run->range = Range(0, text.length());
     run_list_out->add(run);
@@ -1321,8 +1377,8 @@
   // http://crbug.com/467459. On some Windows configurations the default font
   // could be a raster font like System, which would not give us a reasonable
   // fallback font list.
-  if (!LowerCaseEqualsASCII(primary_family, "segoe ui") &&
-      !LowerCaseEqualsASCII(uniscribe_family, "segoe ui")) {
+  if (!base::LowerCaseEqualsASCII(primary_family, "segoe ui") &&
+      !base::LowerCaseEqualsASCII(uniscribe_family, "segoe ui")) {
     std::vector<std::string> default_fallback_families =
         GetFallbackFontFamilies("Segoe UI");
     fallback_families.insert(fallback_families.end(),
diff --git a/ui/gfx/render_text_harfbuzz.h b/ui/gfx/render_text_harfbuzz.h
index 6d8fa8d..e8b28e43 100644
--- a/ui/gfx/render_text_harfbuzz.h
+++ b/ui/gfx/render_text_harfbuzz.h
@@ -54,6 +54,10 @@
   // Returns whether the given shaped run contains any missing glyphs.
   bool HasMissingGlyphs() const;
 
+  // Returns the glyph width for the given character range. |char_range| is in
+  // text-space (0 corresponds to |GetDisplayText()[0]|).
+  SkScalar GetGlyphWidthForCharRange(const Range& char_range) const;
+
   float width;
   float preceding_run_widths;
   Range range;
@@ -115,6 +119,9 @@
   // Do not use this when multiline is enabled.
   float width() const { return width_; }
 
+  // Get the run index applicable to |position| (at or preceeding |position|).
+  size_t GetRunIndexAt(size_t position) const;
+
  private:
   // Text runs in logical order.
   ScopedVector<TextRunHarfBuzz> runs_;
@@ -179,6 +186,10 @@
   FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_NonExistentFont);
   FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_UniscribeFallback);
   FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_UnicodeFallback);
+  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_LineBreakerBehavior);
+  FRIEND_TEST_ALL_PREFIXES(RenderTextTest,
+                           Multiline_SurrogatePairsOrCombiningChars);
+  FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_ZeroWidthChars);
 
   // Specify the width of a glyph for test. The width of glyphs is very
   // platform-dependent and environment-dependent. Otherwise multiline test
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
index 5607a3ad..2448620 100644
--- a/ui/gfx/render_text_unittest.cc
+++ b/ui/gfx/render_text_unittest.cc
@@ -22,6 +22,7 @@
 #include "ui/gfx/range/range.h"
 #include "ui/gfx/range/range_f.h"
 #include "ui/gfx/render_text_harfbuzz.h"
+#include "ui/gfx/text_utils.h"
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
@@ -90,16 +91,6 @@
 }
 #endif  // !defined(OS_MACOSX)
 
-// Test utility for Multiline_Newline test case. Empty |expected_range| means
-// the blank line which has no segments. Otherwise |segments| should contain
-// exactly one line segment whose range equals to |expected_range|.
-void VerifyLineSegments(const Range& expected_range,
-                        const std::vector<internal::LineSegment>& segments) {
-  EXPECT_EQ(expected_range.is_empty() ? 0ul : 1ul, segments.size());
-  if (!expected_range.is_empty())
-    EXPECT_EQ(expected_range, segments[0].char_range);
-}
-
 // The class which records the drawing operations so that the test case can
 // verify where exactly the glyphs are drawn.
 class TestSkiaTextRenderer : public internal::SkiaTextRenderer {
@@ -2128,8 +2119,8 @@
     { L"\x0627\x0644\x0644\x063A\x0629 "
       L"\x0627\x0644\x0639\x0631\x0628\x064A\x0629",
       Range(0, 6), Range(6, 13), false },
-    { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9"
-      L"\x05DA\x05DB\x05DD", Range(0, 4), Range(4, 12), false }
+    { L"\x062A\x0641\x0627\x062D \x05EA\x05E4\x05D5\x05D6\x05D9"
+      L"\x05DA\x05DB\x05DD", Range(0, 5), Range(5, 13), false }
   };
 
   RenderTextHarfBuzz render_text;
@@ -2229,8 +2220,15 @@
 
     for (size_t j = 0; j < kTestStrings[i].lines_count; ++j) {
       SCOPED_TRACE(base::StringPrintf("Line %" PRIuS "", j));
-      VerifyLineSegments(kTestStrings[i].line_char_ranges[j],
-                         render_text.lines_[j].segments);
+      // There might be multiple segments in one line. Merge all the segments
+      // ranges in the same line.
+      const size_t segment_size = render_text.lines()[j].segments.size();
+      Range line_range;
+      if (segment_size > 0)
+        line_range = Range(
+            render_text.lines()[j].segments[0].char_range.start(),
+            render_text.lines()[j].segments[segment_size - 1].char_range.end());
+      EXPECT_EQ(kTestStrings[i].line_char_ranges[j], line_range);
     }
   }
 }
@@ -2365,6 +2363,154 @@
   }
 }
 
+TEST_F(RenderTextTest, Multiline_LineBreakerBehavior) {
+  const int kGlyphSize = 5;
+  const struct {
+    const wchar_t* const text;
+    const WordWrapBehavior behavior;
+    const Range char_ranges[3];
+  } kTestScenarios[] = {
+      { L"a single run", IGNORE_LONG_WORDS,
+        {Range(0, 2), Range(2, 9), Range(9, 12) } },
+      // 3 words: "That's ", ""good". ", "aaa" and 7 runs: "That", "'", "s ",
+      // """, "good", "". ", "aaa". They all mixed together.
+      { L"That's \"good\". aaa", IGNORE_LONG_WORDS,
+        {Range(0, 7), Range(7, 15), Range(15, 18) } },
+      // Test "\"" should be put into a new line correctly.
+      { L"a \"good\" one.", IGNORE_LONG_WORDS,
+        {Range(0, 2), Range(2, 9), Range(9, 13) } },
+      // Test for full-width space.
+      { L"That's\x3000good.\x3000yyy", IGNORE_LONG_WORDS,
+        {Range(0, 7), Range(7, 13), Range(13, 16) } },
+      { L"a single run", TRUNCATE_LONG_WORDS,
+        {Range(0, 2), Range(2, 6), Range(9, 12) } },
+      { L"That's \"good\". aaa", TRUNCATE_LONG_WORDS,
+        {Range(0, 4), Range(7, 11), Range(15, 18) } },
+      { L"That's good. aaa", TRUNCATE_LONG_WORDS,
+        {Range(0, 4), Range(7, 11), Range(13, 16) } },
+      { L"a \"good\" one.", TRUNCATE_LONG_WORDS,
+        {Range(0, 2), Range(2, 6), Range(9, 13) } },
+      { L"asingleword", WRAP_LONG_WORDS,
+        {Range(0, 4), Range(4, 8), Range(8, 11) } },
+      { L"That's good", WRAP_LONG_WORDS,
+        {Range(0, 4), Range(4, 7), Range(7, 11) } },
+      { L"That's \"g\".", WRAP_LONG_WORDS,
+        {Range(0, 4), Range(4, 7), Range(7, 11) } },
+  };
+
+  RenderTextHarfBuzz render_text;
+  render_text.SetMultiline(true);
+  render_text.set_glyph_width_for_test(kGlyphSize);
+  render_text.SetDisplayRect(Rect(0, 0, kGlyphSize * 4, 0));
+
+  Canvas canvas;
+
+  for (size_t i = 0; i < arraysize(kTestScenarios); ++i) {
+    SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
+    render_text.SetText(WideToUTF16(kTestScenarios[i].text));
+    render_text.SetWordWrapBehavior(kTestScenarios[i].behavior);
+    render_text.Draw(&canvas);
+
+    ASSERT_EQ(3u, render_text.lines().size());
+    for (size_t j = 0; j < render_text.lines().size(); ++j) {
+      SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j));
+      // Merge all the segments ranges in the same line.
+      size_t segment_size = render_text.lines()[j].segments.size();
+      Range line_range;
+      if (segment_size > 0)
+        line_range = Range(
+            render_text.lines()[j].segments[0].char_range.start(),
+            render_text.lines()[j].segments[segment_size - 1].char_range.end());
+      EXPECT_EQ(kTestScenarios[i].char_ranges[j], line_range);
+      EXPECT_EQ(kTestScenarios[i].char_ranges[j].length() * kGlyphSize,
+                render_text.lines()[j].size.width());
+    }
+  }
+}
+
+// Test that Surrogate pairs or combining character sequences do not get
+// separated by line breaking.
+TEST_F(RenderTextTest, Multiline_SurrogatePairsOrCombiningChars) {
+  RenderTextHarfBuzz render_text;
+  render_text.SetMultiline(true);
+  render_text.SetWordWrapBehavior(WRAP_LONG_WORDS);
+
+  // Below is 'MUSICAL SYMBOL G CLEF' (U+1D11E), which is represented in UTF-16
+  // as two code units forming a surrogate pair: 0xD834 0xDD1E.
+  const base::char16 kSurrogate[] = {0xD834, 0xDD1E, 0};
+  const base::string16 text_surrogate(kSurrogate);
+  const int kSurrogateWidth =
+      GetStringWidth(kSurrogate, render_text.font_list());
+
+  // Below is a Devanagari two-character combining sequence U+0921 U+093F. The
+  // sequence forms a single display character and should not be separated.
+  const base::char16 kCombiningChars[] = {0x921, 0x93F, 0};
+  const base::string16 text_combining(kCombiningChars);
+  const int kCombiningCharsWidth =
+      GetStringWidth(kCombiningChars, render_text.font_list());
+
+  const struct {
+    const base::string16 text;
+    const int display_width;
+    const Range char_ranges[3];
+  } kTestScenarios[] = {
+      { text_surrogate + text_surrogate + text_surrogate,
+        kSurrogateWidth / 2 * 3,
+        { Range(0, 2), Range(2, 4),  Range(4, 6) } },
+      { text_surrogate + UTF8ToUTF16(" ") + kCombiningChars,
+        std::min(kSurrogateWidth, kCombiningCharsWidth) / 2,
+        { Range(0, 2), Range(2, 3), Range(3, 5) } },
+  };
+
+  Canvas canvas;
+
+  for (size_t i = 0; i < arraysize(kTestScenarios); ++i) {
+    SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
+    render_text.SetText(kTestScenarios[i].text);
+    render_text.SetDisplayRect(Rect(0, 0, kTestScenarios[i].display_width, 0));
+    render_text.Draw(&canvas);
+
+    ASSERT_EQ(3u, render_text.lines().size());
+    for (size_t j = 0; j < render_text.lines().size(); ++j) {
+      SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j));
+      // There is only one segment in each line.
+      EXPECT_EQ(kTestScenarios[i].char_ranges[j],
+                render_text.lines()[j].segments[0].char_range);
+    }
+  }
+}
+
+// Test that Zero width characters have the correct line breaking behavior.
+TEST_F(RenderTextTest, Multiline_ZeroWidthChars) {
+  RenderTextHarfBuzz render_text;
+  render_text.SetMultiline(true);
+  render_text.SetWordWrapBehavior(WRAP_LONG_WORDS);
+
+  const base::char16 kZeroWidthSpace = {0x200B};
+  const base::string16 text(UTF8ToUTF16("test") + kZeroWidthSpace +
+                            UTF8ToUTF16("\n") + kZeroWidthSpace +
+                            UTF8ToUTF16("test."));
+  const int kTestWidth =
+      GetStringWidth(UTF8ToUTF16("test"), render_text.font_list());
+  const Range char_ranges[3] = {Range(0, 5), Range(6, 11), Range(11, 12)};
+
+  Canvas canvas;
+  render_text.SetText(text);
+  render_text.SetDisplayRect(Rect(0, 0, kTestWidth, 0));
+  render_text.Draw(&canvas);
+
+  ASSERT_EQ(3u, render_text.lines().size());
+  for (size_t j = 0; j < render_text.lines().size(); ++j) {
+    SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j));
+    int segment_size = render_text.lines()[j].segments.size();
+    ASSERT_GT(segment_size, 0);
+    Range line_range(
+        render_text.lines()[j].segments[0].char_range.start(),
+        render_text.lines()[j].segments[segment_size - 1].char_range.end());
+    EXPECT_EQ(char_ranges[j], line_range);
+  }
+}
+
 TEST_F(RenderTextTest, NewlineWithoutMultilineFlag) {
   const wchar_t* kTestStrings[] = {
     L"abc\ndef", L"a \n b ", L"ab\n", L"a\n\nb", L"\nab", L"\n",
@@ -2584,15 +2730,43 @@
 
 TEST_F(RenderTextTest, HarfBuzz_RunDirection) {
   RenderTextHarfBuzz render_text;
-  const base::string16 mixed =
-      WideToUTF16(L"\x05D0\x05D1" L"1234" L"\x05D2\x05D3");
+  const base::string16 mixed = WideToUTF16(
+      L"\x05D0\x05D1"
+      L"1234"
+      L"\x05D2\x05D3"
+      L"abc");
   render_text.SetText(mixed);
+
+  // Get the run list for both display directions.
+  render_text.SetDirectionalityMode(DIRECTIONALITY_FORCE_LTR);
   render_text.EnsureLayout();
   internal::TextRunList* run_list = render_text.GetRunList();
-  ASSERT_EQ(3U, run_list->size());
+  ASSERT_EQ(4U, run_list->size());
   EXPECT_TRUE(run_list->runs()[0]->is_rtl);
   EXPECT_FALSE(run_list->runs()[1]->is_rtl);
   EXPECT_TRUE(run_list->runs()[2]->is_rtl);
+  EXPECT_FALSE(run_list->runs()[3]->is_rtl);
+
+  // The Latin letters should appear to the right of the other runs.
+  EXPECT_EQ(2U, run_list->logical_to_visual(0));
+  EXPECT_EQ(1U, run_list->logical_to_visual(1));
+  EXPECT_EQ(0U, run_list->logical_to_visual(2));
+  EXPECT_EQ(3U, run_list->logical_to_visual(3));
+
+  render_text.SetDirectionalityMode(DIRECTIONALITY_FORCE_RTL);
+  render_text.EnsureLayout();
+  run_list = render_text.GetRunList();
+  ASSERT_EQ(4U, run_list->size());
+  EXPECT_TRUE(run_list->runs()[0]->is_rtl);
+  EXPECT_FALSE(run_list->runs()[1]->is_rtl);
+  EXPECT_TRUE(run_list->runs()[2]->is_rtl);
+  EXPECT_FALSE(run_list->runs()[3]->is_rtl);
+
+  // The Latin letters should appear to the left of the other runs.
+  EXPECT_EQ(3U, run_list->logical_to_visual(0));
+  EXPECT_EQ(2U, run_list->logical_to_visual(1));
+  EXPECT_EQ(1U, run_list->logical_to_visual(2));
+  EXPECT_EQ(0U, run_list->logical_to_visual(3));
 }
 
 TEST_F(RenderTextTest, HarfBuzz_BreakRunsByUnicodeBlocks) {
@@ -2610,10 +2784,11 @@
   render_text.SetText(WideToUTF16(L"x \x25B6 y"));
   render_text.EnsureLayout();
   run_list = render_text.GetRunList();
-  ASSERT_EQ(3U, run_list->size());
+  ASSERT_EQ(4U, run_list->size());
   EXPECT_EQ(Range(0, 2), run_list->runs()[0]->range);
   EXPECT_EQ(Range(2, 3), run_list->runs()[1]->range);
-  EXPECT_EQ(Range(3, 5), run_list->runs()[2]->range);
+  EXPECT_EQ(Range(3, 4), run_list->runs()[2]->range);
+  EXPECT_EQ(Range(4, 5), run_list->runs()[3]->range);
 }
 
 TEST_F(RenderTextTest, HarfBuzz_BreakRunsByEmoji) {
diff --git a/ui/gfx/text_elider.cc b/ui/gfx/text_elider.cc
index fcfc71f6..7619f86 100644
--- a/ui/gfx/text_elider.cc
+++ b/ui/gfx/text_elider.cc
@@ -19,16 +19,13 @@
 #include "base/i18n/char_iterator.h"
 #include "base/i18n/rtl.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/numerics/safe_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "third_party/icu/source/common/unicode/rbbi.h"
-#include "third_party/icu/source/common/unicode/uchar.h"
 #include "third_party/icu/source/common/unicode/uloc.h"
 #include "third_party/icu/source/common/unicode/umachine.h"
-#include "third_party/icu/source/common/unicode/utf16.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/render_text.h"
@@ -104,22 +101,6 @@
 }
 #endif
 
-// Returns true if the code point |c| is a combining mark character in Unicode.
-bool CharIsMark(UChar32 c) {
-  int8_t char_type = u_charType(c);
-  return char_type == U_NON_SPACING_MARK || char_type == U_ENCLOSING_MARK ||
-         char_type == U_COMBINING_SPACING_MARK;
-}
-
-// Gets the code point of |str| at the given code unit position |index|. If
-// |index| is a surrogate code unit, returns the whole code point (unless the
-// code unit is unpaired, in which case it just returns the surrogate value).
-UChar32 GetCodePointAt(const base::string16& str, size_t index) {
-  UChar32 c;
-  U16_GET(str.data(), 0, index, str.size(), c);
-  return c;
-}
-
 }  // namespace
 
 // U+2026 in utf8
@@ -144,56 +125,23 @@
 
   if (elide_at_beginning_)
     return ellipsis_text +
-           text_.substr(FindValidBoundaryBefore(text_.length() - length));
+           text_.substr(
+               FindValidBoundaryBefore(text_, text_.length() - length));
 
   if (!elide_in_middle_)
-    return text_.substr(0, FindValidBoundaryBefore(length)) + ellipsis_text;
+    return text_.substr(0, FindValidBoundaryBefore(text_, length)) +
+           ellipsis_text;
 
   // We put the extra character, if any, before the cut.
   const size_t half_length = length / 2;
-  const size_t prefix_length = FindValidBoundaryBefore(length - half_length);
+  const size_t prefix_length =
+      FindValidBoundaryBefore(text_, length - half_length);
   const size_t suffix_start =
-      FindValidBoundaryAfter(text_.length() - half_length);
+      FindValidBoundaryAfter(text_, text_.length() - half_length);
   return text_.substr(0, prefix_length) + ellipsis_text +
          text_.substr(suffix_start);
 }
 
-size_t StringSlicer::FindValidBoundaryBefore(size_t index) const {
-  size_t length = text_.length();
-  DCHECK_LE(index, length);
-  if (index == length)
-    return index;
-
-  // If |index| straddles a combining character sequence, go back until we find
-  // a base character.
-  while (index > 0 && CharIsMark(GetCodePointAt(text_, index)))
-    --index;
-
-  // If |index| straddles a UTF-16 surrogate pair, go back.
-  U16_SET_CP_START(text_.data(), 0, index);
-  return index;
-}
-
-size_t StringSlicer::FindValidBoundaryAfter(size_t index) const {
-  DCHECK_LE(index, text_.length());
-  if (index == text_.length())
-    return index;
-
-  int32_t text_index = base::checked_cast<int32_t>(index);
-  int32_t text_length = base::checked_cast<int32_t>(text_.length());
-
-  // If |index| straddles a combining character sequence, go forward until we
-  // find a base character.
-  while (text_index < text_length &&
-         CharIsMark(GetCodePointAt(text_, text_index))) {
-    ++text_index;
-  }
-
-  // If |index| straddles a UTF-16 surrogate pair, go forward.
-  U16_SET_CP_LIMIT(text_.data(), 0, text_index, text_length);
-  return static_cast<size_t>(text_index);
-}
-
 base::string16 ElideFilename(const base::FilePath& filename,
                              const FontList& font_list,
                              float available_pixel_width) {
diff --git a/ui/gfx/text_elider.h b/ui/gfx/text_elider.h
index 1269caf..4e58a9f9 100644
--- a/ui/gfx/text_elider.h
+++ b/ui/gfx/text_elider.h
@@ -51,10 +51,6 @@
   base::string16 CutString(size_t length, bool insert_ellipsis) const;
 
  private:
-  // Returns a valid cut boundary at or before/after |index|.
-  size_t FindValidBoundaryBefore(size_t index) const;
-  size_t FindValidBoundaryAfter(size_t index) const;
-
   // The text to be sliced.
   const base::string16& text_;
 
diff --git a/ui/gfx/text_utils.cc b/ui/gfx/text_utils.cc
index a31ef3d..c62b88b 100644
--- a/ui/gfx/text_utils.cc
+++ b/ui/gfx/text_utils.cc
@@ -5,9 +5,33 @@
 #include "ui/gfx/text_utils.h"
 
 #include "base/i18n/char_iterator.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
+#include "third_party/icu/source/common/unicode/utf16.h"
 
 namespace gfx {
 
+namespace {
+
+// Returns true if the code point |c| is a combining mark character in Unicode.
+bool CharIsMark(UChar32 c) {
+  int8_t char_type = u_charType(c);
+  return char_type == U_NON_SPACING_MARK || char_type == U_ENCLOSING_MARK ||
+         char_type == U_COMBINING_SPACING_MARK;
+}
+
+// Gets the code point of |str| at the given code unit position |index|. If
+// |index| is a surrogate code unit, returns the whole code point (unless the
+// code unit is unpaired, in which case it just returns the surrogate value).
+UChar32 GetCodePointAt(const base::string16& str, size_t index) {
+  UChar32 c;
+  U16_GET(str.data(), 0, index, str.size(), c);
+  return c;
+}
+
+}  // namespace
+
 base::string16 RemoveAcceleratorChar(const base::string16& s,
                                      base::char16 accelerator_char,
                                      int* accelerated_char_pos,
@@ -46,4 +70,40 @@
   return accelerator_removed;
 }
 
+size_t FindValidBoundaryBefore(const base::string16& text, size_t index) {
+  size_t length = text.length();
+  DCHECK_LE(index, length);
+  if (index == length)
+    return index;
+
+  // If |index| straddles a combining character sequence, go back until we find
+  // a base character.
+  while (index > 0 && CharIsMark(GetCodePointAt(text, index)))
+    --index;
+
+  // If |index| straddles a UTF-16 surrogate pair, go back.
+  U16_SET_CP_START(text.data(), 0, index);
+  return index;
+}
+
+size_t FindValidBoundaryAfter(const base::string16& text, size_t index) {
+  DCHECK_LE(index, text.length());
+  if (index == text.length())
+    return index;
+
+  int32_t text_index = base::checked_cast<int32_t>(index);
+  int32_t text_length = base::checked_cast<int32_t>(text.length());
+
+  // If |index| straddles a combining character sequence, go forward until we
+  // find a base character.
+  while (text_index < text_length &&
+         CharIsMark(GetCodePointAt(text, text_index))) {
+    ++text_index;
+  }
+
+  // If |index| straddles a UTF-16 surrogate pair, go forward.
+  U16_SET_CP_LIMIT(text.data(), 0, text_index, text_length);
+  return static_cast<size_t>(text_index);
+}
+
 }  // namespace gfx
diff --git a/ui/gfx/text_utils.h b/ui/gfx/text_utils.h
index 088f97ce..193baf0 100644
--- a/ui/gfx/text_utils.h
+++ b/ui/gfx/text_utils.h
@@ -31,6 +31,16 @@
 GFX_EXPORT float GetStringWidthF(const base::string16& text,
                                  const FontList& font_list);
 
+// Returns a valid cut boundary at or before |index|. The surrogate pair and
+// combining characters should not be separated.
+GFX_EXPORT size_t
+FindValidBoundaryBefore(const base::string16& text, size_t index);
+
+// Returns a valid cut boundary at or after |index|. The surrogate pair and
+// combining characters should not be separated.
+GFX_EXPORT size_t
+FindValidBoundaryAfter(const base::string16& text, size_t index);
+
 }  // namespace gfx
 
 #endif  // UI_GFX_TEXT_UTILS_H_
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index 2dc614038..f5f41342 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -268,6 +268,8 @@
     "gl_mock.cc",
     "gl_mock.h",
     "gl_mock_autogen_gl.h",
+    "gpu_timing_fake.cc",
+    "gpu_timing_fake.h",
   ]
 
   configs += [ "//third_party/khronos:khronos_headers" ]
@@ -281,13 +283,25 @@
 test("gl_unittests") {
   sources = [
     "gl_api_unittest.cc",
+    "gpu_timing_unittest.cc",
     "test/run_all_unittests.cc",
   ]
 
+  if (is_win || is_android || is_linux) {
+    sources += [
+      "egl_api_unittest.cc",
+      "test/egl_initialization_displays_unittest.cc",
+    ]
+  }
+
+  include_dirs = [ "//third_party/khronos" ]
+
   deps = [
     ":gl",
+    ":gl_unittest_utils",
     "//base",
     "//base/test:test_support",
+    "//testing/gmock",
     "//testing/gtest",
   ]
 }
diff --git a/ui/gl/egl_api_unittest.cc b/ui/gl/egl_api_unittest.cc
new file mode 100644
index 0000000..fc8a4ff
--- /dev/null
+++ b/ui/gl/egl_api_unittest.cc
@@ -0,0 +1,105 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_egl_api_implementation.h"
+#include "ui/gl/gl_switches.h"
+
+namespace gfx {
+
+class EGLApiTest : public testing::Test {
+ public:
+  void SetUp() override {
+    fake_extension_string_ = "";
+
+    // TODO(dyen): Add a way to bind mock drivers for testing.
+    g_driver_egl.ClearBindings();
+    g_driver_egl.fn.eglInitializeFn = &FakeInitialize;
+    g_driver_egl.fn.eglQueryStringFn = &FakeQueryString;
+    g_driver_egl.fn.eglGetCurrentDisplayFn = &FakeGetCurrentDisplay;
+    g_driver_egl.fn.eglGetDisplayFn = &FakeGetDisplay;
+    g_driver_egl.fn.eglGetErrorFn = &FakeGetError;
+  }
+
+  void TearDown() override {
+    g_current_egl_context = nullptr;
+    api_.reset(nullptr);
+    g_driver_egl.ClearBindings();
+
+    fake_extension_string_ = "";
+  }
+
+  void InitializeAPI(base::CommandLine* command_line) {
+    api_.reset(new RealEGLApi());
+    g_current_egl_context = api_.get();
+    if (command_line)
+      api_->InitializeWithCommandLine(&g_driver_egl, command_line);
+    else
+      api_->Initialize(&g_driver_egl);
+    api_->InitializeFilteredExtensions();
+  }
+
+  void SetFakeExtensionString(const char* fake_string) {
+    fake_extension_string_ = fake_string;
+  }
+
+  static EGLBoolean GL_BINDING_CALL FakeInitialize(EGLDisplay display,
+                                                   EGLint * major,
+                                                   EGLint * minor) {
+    return EGL_TRUE;
+  }
+
+  static const char* GL_BINDING_CALL FakeQueryString(EGLDisplay dpy,
+                                                     EGLint name) {
+    return fake_extension_string_;
+  }
+
+  static EGLDisplay GL_BINDING_CALL FakeGetCurrentDisplay() {
+    return nullptr;
+  }
+
+  static EGLDisplay GL_BINDING_CALL FakeGetDisplay(
+      EGLNativeDisplayType native_display) {
+    return EGL_NO_DISPLAY;
+  }
+
+  static EGLint GL_BINDING_CALL FakeGetError() {
+    return EGL_SUCCESS;
+  }
+
+  const char* GetExtensions() {
+    EGLDisplay display = api_->eglGetCurrentDisplayFn();
+    return api_->eglQueryStringFn(display, EGL_EXTENSIONS);
+  }
+
+ protected:
+  static const char* fake_extension_string_;
+
+  scoped_ptr<RealEGLApi> api_;
+};
+
+const char* EGLApiTest::fake_extension_string_ = "";
+
+TEST_F(EGLApiTest, DisabledExtensionStringTest) {
+  static const char* kFakeExtensions = "EGL_EXT_1 EGL_EXT_2"
+                                       " EGL_EXT_3 EGL_EXT_4";
+  static const char* kFakeDisabledExtensions = "EGL_EXT_1,EGL_EXT_2,EGL_FAKE";
+  static const char* kFilteredExtensions = "EGL_EXT_3 EGL_EXT_4";
+
+  SetFakeExtensionString(kFakeExtensions);
+  InitializeAPI(nullptr);
+
+  EXPECT_STREQ(kFakeExtensions, GetExtensions());
+
+  base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+  command_line.AppendSwitchASCII(switches::kDisableGLExtensions,
+                                 kFakeDisabledExtensions);
+  InitializeAPI(&command_line);
+
+  EXPECT_STREQ(kFilteredExtensions, GetExtensions());
+}
+
+}  // namespace gfx
diff --git a/ui/gl/gl.gyp b/ui/gl/gl.gyp
index 9a2c401..fe0ef58 100644
--- a/ui/gl/gl.gyp
+++ b/ui/gl/gl.gyp
@@ -283,6 +283,8 @@
         'gl_mock.cc',
         'gl_mock.h',
         'gl_mock_autogen_gl.h',
+        'gpu_timing_fake.cc',
+        'gpu_timing_fake.h',
       ],
     },
   ],
diff --git a/ui/gl/gl_api_unittest.cc b/ui/gl/gl_api_unittest.cc
index 43c107e..9b15bec4 100644
--- a/ui/gl/gl_api_unittest.cc
+++ b/ui/gl/gl_api_unittest.cc
@@ -151,4 +151,4 @@
   }
 }
 
-}  // namespace gpu
+}  // namespace gfx
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h
index 55432fa..082d240f 100644
--- a/ui/gl/gl_bindings.h
+++ b/ui/gl/gl_bindings.h
@@ -386,7 +386,6 @@
   ProcsEGL debug_fn;
   ExtensionsEGL ext;
 
- private:
   static std::string GetPlatformExtensions();
   static std::string GetClientExtensions();
 };
diff --git a/ui/gl/gl_egl_api_implementation.cc b/ui/gl/gl_egl_api_implementation.cc
index 53a1bf6..8acaf0f 100644
--- a/ui/gl/gl_egl_api_implementation.cc
+++ b/ui/gl/gl_egl_api_implementation.cc
@@ -3,6 +3,11 @@
 // found in the LICENSE file.
 
 #include "ui/gl/gl_egl_api_implementation.h"
+
+#include "base/command_line.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "ui/gl/gl_context.h"
 #include "ui/gl/gl_implementation.h"
 
 namespace gfx {
@@ -16,6 +21,8 @@
   g_real_egl->Initialize(&g_driver_egl);
   g_current_egl_context = g_real_egl;
   g_driver_egl.InitializeStaticBindings();
+
+  g_real_egl->InitializeFilteredExtensions();
 }
 
 void InitializeDebugGLBindingsEGL() {
@@ -55,7 +62,56 @@
 }
 
 void RealEGLApi::Initialize(DriverEGL* driver) {
+  InitializeWithCommandLine(driver, base::CommandLine::ForCurrentProcess());
+}
+
+void RealEGLApi::InitializeWithCommandLine(DriverEGL* driver,
+                                           base::CommandLine* command_line) {
+  DCHECK(command_line);
   InitializeBase(driver);
+
+  const std::string disabled_extensions = command_line->GetSwitchValueASCII(
+      switches::kDisableGLExtensions);
+  if (!disabled_extensions.empty()) {
+    Tokenize(disabled_extensions, ", ;", &disabled_exts_);
+  }
+}
+
+void RealEGLApi::InitializeFilteredExtensions() {
+  if (!disabled_exts_.empty() && filtered_exts_.empty()) {
+    std::vector<std::string> platform_extensions_vec;
+    std::string platform_ext = DriverEGL::GetPlatformExtensions();
+    base::SplitString(platform_ext, ' ', &platform_extensions_vec);
+
+    std::vector<std::string> client_extensions_vec;
+    std::string client_ext = DriverEGL::GetClientExtensions();
+    base::SplitString(client_ext, ' ', &client_extensions_vec);
+
+    // Filter out extensions from the command line.
+    for (const std::string& disabled_ext : disabled_exts_) {
+      platform_extensions_vec.erase(std::remove(platform_extensions_vec.begin(),
+                                                platform_extensions_vec.end(),
+                                                disabled_ext),
+                                    platform_extensions_vec.end());
+      client_extensions_vec.erase(std::remove(client_extensions_vec.begin(),
+                                              client_extensions_vec.end(),
+                                              disabled_ext),
+                                  client_extensions_vec.end());
+    }
+
+    // Construct filtered extensions string for GL_EXTENSIONS string lookups.
+    filtered_exts_ = JoinString(platform_extensions_vec, " ");
+    if (!platform_extensions_vec.empty() && !client_extensions_vec.empty())
+      filtered_exts_ += " ";
+    filtered_exts_ += JoinString(client_extensions_vec, " ");
+  }
+}
+
+const char* RealEGLApi::eglQueryStringFn(EGLDisplay dpy, EGLint name) {
+  if (!filtered_exts_.empty() && name == EGL_EXTENSIONS) {
+    return filtered_exts_.c_str();
+  }
+  return EGLApiBase::eglQueryStringFn(dpy, name);
 }
 
 TraceEGLApi::~TraceEGLApi() {
diff --git a/ui/gl/gl_egl_api_implementation.h b/ui/gl/gl_egl_api_implementation.h
index a2ff28d..46f5f842 100644
--- a/ui/gl/gl_egl_api_implementation.h
+++ b/ui/gl/gl_egl_api_implementation.h
@@ -5,10 +5,15 @@
 #ifndef UI_GL_GL_EGL_API_IMPLEMENTATION_H_
 #define UI_GL_GL_EGL_API_IMPLEMENTATION_H_
 
+#include <vector>
+
 #include "base/compiler_specific.h"
 #include "gl_bindings.h"
 #include "ui/gl/gl_export.h"
 
+namespace base {
+class CommandLine;
+}
 namespace gfx {
 
 class GLContext;
@@ -39,6 +44,16 @@
   RealEGLApi();
   ~RealEGLApi() override;
   void Initialize(DriverEGL* driver);
+  void InitializeWithCommandLine(DriverEGL* driver,
+                                 base::CommandLine* command_line);
+  void InitializeFilteredExtensions();
+
+  const char* eglQueryStringFn(EGLDisplay dpy, EGLint name) override;
+
+ private:
+  // Filtered EGL_EXTENSIONS we return to eglQueryStringFn() calls.
+  std::vector<std::string> disabled_exts_;
+  std::string filtered_exts_;
 };
 
 
diff --git a/ui/gl/gl_tests.gyp b/ui/gl/gl_tests.gyp
index bd924445..0886ffc1 100644
--- a/ui/gl/gl_tests.gyp
+++ b/ui/gl/gl_tests.gyp
@@ -12,13 +12,19 @@
       'type': '<(gtest_target_type)',
       'sources': [
         'test/run_all_unittests.cc',
+        'gpu_timing_unittest.cc',
         'gl_api_unittest.cc',
       ],
+      'include_dirs': [
+        '<(DEPTH)/third_party/khronos',
+      ],
       'dependencies': [
         '<(DEPTH)/base/base.gyp:base',
         '<(DEPTH)/base/base.gyp:test_support_base',
+        '<(DEPTH)/testing/gmock.gyp:gmock',
         '<(DEPTH)/testing/gtest.gyp:gtest',
-        'gl.gyp:gl',
+        '<(DEPTH)/ui/gl/gl.gyp:gl',
+        '<(DEPTH)/ui/gl/gl.gyp:gl_unittest_utils',
       ],
       'conditions': [
         ['OS == "android"', {
@@ -28,14 +34,9 @@
         }],
         ['OS in ("win", "android", "linux")', {
           'sources': [
+            'egl_api_unittest.cc',
             'test/egl_initialization_displays_unittest.cc',
           ],
-          'dependencies': [
-            '<(DEPTH)/ui/gl/gl.gyp:gl',
-          ],
-          'include_dirs': [
-            '<(DEPTH)/third_party/khronos',
-          ],
         }],
       ],
     }
diff --git a/ui/gl/gl_version_info.cc b/ui/gl/gl_version_info.cc
index aff97b8..5eff43a 100644
--- a/ui/gl/gl_version_info.cc
+++ b/ui/gl/gl_version_info.cc
@@ -50,7 +50,7 @@
                        &is_es, &is_es3);
   }
   if (renderer_str) {
-    is_angle = StartsWithASCII(renderer_str, "ANGLE", true);
+    is_angle = base::StartsWithASCII(renderer_str, "ANGLE", true);
   }
 }
 
diff --git a/ui/gl/gpu_timing.cc b/ui/gl/gpu_timing.cc
index 01a0e192..dc720df5 100644
--- a/ui/gl/gpu_timing.cc
+++ b/ui/gl/gpu_timing.cc
@@ -52,7 +52,7 @@
       int64 now =
           cpu_time.is_null()
           ? (base::TraceTicks::Now() - base::TraceTicks()).InMicroseconds()
-              : cpu_time.Run();
+          : cpu_time.Run();
       offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond;
       offset_valid_ = (timer_type_ == kTimerTypeARB);
     } else {
@@ -251,6 +251,12 @@
   cpu_time_for_testing_ = cpu_time;
 }
 
+int64 GPUTimingClient::GetCurrentCPUTime() {
+  return cpu_time_for_testing_.is_null()
+         ? (base::TraceTicks::Now() - base::TraceTicks()).InMicroseconds()
+         : cpu_time_for_testing_.Run();
+}
+
 GPUTimingClient::~GPUTimingClient() {
 }
 
diff --git a/ui/gl/gpu_timing.h b/ui/gl/gpu_timing.h
index d62dc6f6..6d1cceda 100644
--- a/ui/gl/gpu_timing.h
+++ b/ui/gl/gpu_timing.h
@@ -130,6 +130,7 @@
   void InvalidateTimerOffset();
 
   void SetCpuTimeForTesting(const base::Callback<int64(void)>& cpu_time);
+  int64 GetCurrentCPUTime();
 
  private:
   friend class base::RefCounted<GPUTimingClient>;
diff --git a/ui/gl/gpu_timing_fake.cc b/ui/gl/gpu_timing_fake.cc
new file mode 100644
index 0000000..486a0c96
--- /dev/null
+++ b/ui/gl/gpu_timing_fake.cc
@@ -0,0 +1,233 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gl/gpu_timing_fake.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+namespace gfx {
+
+using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::AtMost;
+using ::testing::Exactly;
+using ::testing::Invoke;
+using ::testing::NotNull;
+
+GPUTimingFake::GPUTimingFake() {
+  Reset();
+}
+
+GPUTimingFake::~GPUTimingFake() {
+}
+
+void GPUTimingFake::Reset() {
+  current_time_ = 0;
+  next_query_id_ = 23;
+  allocated_queries_.clear();
+  query_results_.clear();
+  current_elapsed_query_.Reset();
+}
+
+void GPUTimingFake::SetCurrentGLTime(GLint64 current_time) {
+  current_time_ = current_time;
+}
+
+void GPUTimingFake::SetDisjoint() {
+  disjointed_ = true;
+}
+
+void GPUTimingFake::ExpectGetErrorCalls(MockGLInterface& gl) {
+  EXPECT_CALL(gl, GetError()).Times(AtLeast(0))
+      .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGetError));
+}
+
+void GPUTimingFake::ExpectDisjointCalls(MockGLInterface& gl) {
+  EXPECT_CALL(gl, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(AtLeast(1))
+      .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGetIntegerv));
+}
+
+void GPUTimingFake::ExpectNoDisjointCalls(MockGLInterface& gl) {
+  EXPECT_CALL(gl, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(Exactly(0));
+}
+
+void GPUTimingFake::ExpectGPUTimerQuery(
+    MockGLInterface& gl, bool elapsed_query) {
+  if (elapsed_query) {
+    // Currently do not support elapsed queries.
+    return;
+  }
+
+  EXPECT_CALL(gl, GenQueries(2, NotNull())).Times(AtLeast(1))
+      .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLGenQueries));
+
+  if (elapsed_query) {
+    // Time Elapsed based queries.
+    EXPECT_CALL(gl, BeginQuery(GL_TIME_ELAPSED, _))
+        .WillRepeatedly(
+            Invoke(this, &GPUTimingFake::FakeGLBeginQuery));
+
+    EXPECT_CALL(gl, EndQuery(GL_TIME_ELAPSED))
+        .WillRepeatedly(Invoke(this, &GPUTimingFake::FakeGLEndQuery));
+  } else {
+    // Time Stamp based queries.
+    EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, _))
+        .WillRepeatedly(
+            Invoke(this, &GPUTimingFake::FakeGLGetInteger64v));
+
+    EXPECT_CALL(gl, QueryCounter(_, GL_TIMESTAMP)).Times(AtLeast(2))
+        .WillRepeatedly(
+             Invoke(this, &GPUTimingFake::FakeGLQueryCounter));
+  }
+
+  EXPECT_CALL(gl, GetQueryObjectiv(_, GL_QUERY_RESULT_AVAILABLE,
+                                        NotNull()))
+      .WillRepeatedly(
+          Invoke(this, &GPUTimingFake::FakeGLGetQueryObjectiv));
+
+  EXPECT_CALL(gl, GetQueryObjectui64v(_, GL_QUERY_RESULT, NotNull()))
+      .WillRepeatedly(
+           Invoke(this, &GPUTimingFake::FakeGLGetQueryObjectui64v));
+
+  EXPECT_CALL(gl, DeleteQueries(2, NotNull())).Times(AtLeast(1))
+      .WillRepeatedly(
+           Invoke(this, &GPUTimingFake::FakeGLDeleteQueries));
+}
+
+void GPUTimingFake::ExpectOffsetCalculationQuery(
+    MockGLInterface& gl) {
+  EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, NotNull()))
+      .Times(AtMost(1))
+      .WillRepeatedly(
+          Invoke(this, &GPUTimingFake::FakeGLGetInteger64v));
+}
+
+void GPUTimingFake::ExpectNoOffsetCalculationQuery(
+    MockGLInterface& gl) {
+  EXPECT_CALL(gl, GetInteger64v(GL_TIMESTAMP, NotNull())).Times(Exactly(0));
+}
+
+void GPUTimingFake::FakeGLGenQueries(GLsizei n, GLuint* ids) {
+  for (GLsizei i = 0; i < n; i++) {
+    ids[i] = next_query_id_++;
+    allocated_queries_.insert(ids[i]);
+  }
+}
+
+void GPUTimingFake::FakeGLDeleteQueries(GLsizei n, const GLuint* ids) {
+  for (GLsizei i = 0; i < n; i++) {
+    allocated_queries_.erase(ids[i]);
+    query_results_.erase(ids[i]);
+    if (current_elapsed_query_.query_id_ == ids[i])
+      current_elapsed_query_.Reset();
+  }
+}
+
+void GPUTimingFake::FakeGLBeginQuery(GLenum target, GLuint id) {
+  switch(target) {
+    case GL_TIME_ELAPSED:
+      ASSERT_FALSE(current_elapsed_query_.active_);
+      current_elapsed_query_.Reset();
+      current_elapsed_query_.active_ = true;
+      current_elapsed_query_.query_id_ = id;
+      current_elapsed_query_.begin_time_ = current_time_;
+      break;
+    default:
+      FAIL() << "Invalid target passed to BeginQuery: " << target;
+  }
+}
+
+void GPUTimingFake::FakeGLEndQuery(GLenum target) {
+  switch(target) {
+    case GL_TIME_ELAPSED: {
+      ASSERT_TRUE(current_elapsed_query_.active_);
+      QueryResult& query = query_results_[current_elapsed_query_.query_id_];
+      query.type_ = QueryResult::kQueryResultType_Elapsed;
+      query.begin_time_ = current_elapsed_query_.begin_time_;
+      query.value_ = current_time_;
+      current_elapsed_query_.active_ = false;
+    } break;
+    default:
+      FAIL() << "Invalid target passed to BeginQuery: " << target;
+  }
+}
+
+void GPUTimingFake::FakeGLGetQueryObjectiv(GLuint id, GLenum pname,
+                                                    GLint* params) {
+  switch (pname) {
+    case GL_QUERY_RESULT_AVAILABLE: {
+      std::map<GLuint, QueryResult>::iterator it = query_results_.find(id);
+      if (it != query_results_.end() && it->second.value_ <= current_time_)
+        *params = 1;
+      else
+        *params = 0;
+    } break;
+    default:
+      FAIL() << "Invalid variable passed to GetQueryObjectiv: " << pname;
+  }
+}
+
+void GPUTimingFake::FakeGLQueryCounter(GLuint id, GLenum target) {
+  switch (target) {
+    case GL_TIMESTAMP: {
+      ASSERT_TRUE(allocated_queries_.find(id) != allocated_queries_.end());
+      QueryResult& query = query_results_[id];
+      query.type_ = QueryResult::kQueryResultType_TimeStamp;
+      query.value_ = current_time_;
+    } break;
+
+    default:
+      FAIL() << "Invalid variable passed to QueryCounter: " << target;
+  }
+}
+
+void GPUTimingFake::FakeGLGetInteger64v(GLenum pname, GLint64 * data) {
+  switch (pname) {
+    case GL_TIMESTAMP:
+      *data = current_time_;
+      break;
+    default:
+      FAIL() << "Invalid variable passed to GetInteger64v: " << pname;
+  }
+}
+
+void GPUTimingFake::FakeGLGetQueryObjectui64v(GLuint id, GLenum pname,
+                                                       GLuint64* params) {
+  switch (pname) {
+    case GL_QUERY_RESULT: {
+      std::map<GLuint, QueryResult>::iterator it = query_results_.find(id);
+      ASSERT_TRUE(it != query_results_.end());
+      switch (it->second.type_) {
+        case QueryResult::kQueryResultType_TimeStamp:
+          *params = it->second.value_;
+          break;
+        case QueryResult::kQueryResultType_Elapsed:
+          *params = it->second.value_ - it->second.begin_time_;
+          break;
+        default:
+          FAIL() << "Invalid Query Result Type: " << it->second.type_;
+      }
+    } break;
+    default:
+      FAIL() << "Invalid variable passed to GetQueryObjectui64v: " << pname;
+  }
+}
+
+void GPUTimingFake::FakeGLGetIntegerv(GLenum pname, GLint* params) {
+  switch (pname) {
+    case GL_GPU_DISJOINT_EXT:
+      *params = static_cast<GLint>(disjointed_);
+      disjointed_ = false;
+      break;
+    default:
+      FAIL() << "Invalid variable passed to GetIntegerv: " << pname;
+  }
+}
+
+GLenum GPUTimingFake::FakeGLGetError() {
+  return GL_NO_ERROR;
+}
+
+}  // namespace gfx
diff --git a/ui/gl/gpu_timing_fake.h b/ui/gl/gpu_timing_fake.h
new file mode 100644
index 0000000..625a394d
--- /dev/null
+++ b/ui/gl/gpu_timing_fake.h
@@ -0,0 +1,82 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GL_GPU_TIMING_FAKE_H_
+#define UI_GL_GPU_TIMING_FAKE_H_
+
+#include <map>
+#include <set>
+
+#include "ui/gl/gl_bindings.h"
+
+namespace gfx {
+class MockGLInterface;
+
+class GPUTimingFake {
+ public:
+  GPUTimingFake();
+  ~GPUTimingFake();
+
+  void Reset();
+
+  // Used to set the current GPU time queries will return.
+  void SetCurrentGLTime(GLint64 current_time);
+
+  // Used to signal a disjoint occurred for disjoint timer queries.
+  void SetDisjoint();
+
+  // GPUTimer fake queries which can be called multiple times.
+  void ExpectGetErrorCalls(MockGLInterface& gl);
+  void ExpectDisjointCalls(MockGLInterface& gl);
+  void ExpectNoDisjointCalls(MockGLInterface& gl);
+
+  // GPUTimer fake queries which can only be called once per setup.
+  void ExpectGPUTimerQuery(MockGLInterface& gl, bool elapsed_query);
+  void ExpectOffsetCalculationQuery(MockGLInterface& gl);
+  void ExpectNoOffsetCalculationQuery(MockGLInterface& gl);
+
+  // Fake GL Functions.
+  void FakeGLGenQueries(GLsizei n, GLuint* ids);
+  void FakeGLDeleteQueries(GLsizei n, const GLuint* ids);
+  void FakeGLBeginQuery(GLenum target, GLuint id);
+  void FakeGLEndQuery(GLenum target);
+  void FakeGLGetQueryObjectiv(GLuint id, GLenum pname, GLint* params);
+  void FakeGLQueryCounter(GLuint id, GLenum target);
+  void FakeGLGetInteger64v(GLenum pname, GLint64 * data);
+  void FakeGLGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params);
+  void FakeGLGetIntegerv(GLenum pname, GLint* params);
+  GLenum FakeGLGetError();
+
+ protected:
+  bool disjointed_ = false;
+  GLint64 current_time_ = 0;
+  GLuint next_query_id_ = 0;
+  std::set<GLuint> allocated_queries_;
+  struct QueryResult {
+    enum QueryResultType {
+      kQueryResultType_Invalid,
+      kQueryResultType_TimeStamp,
+      kQueryResultType_Elapsed
+    } type_ = kQueryResultType_Invalid;
+    GLint64 begin_time_ = 0;
+    GLint64 value_ = 0;
+  };
+  std::map<GLuint, QueryResult> query_results_;
+  struct ElapsedQuery {
+    bool active_ = false;
+    GLuint query_id_ = 0;
+    GLint64 begin_time_ = 0;
+
+    void Reset() {
+      active_ = false;
+      query_id_ = 0;
+      begin_time_ = 0;
+    }
+  };
+  ElapsedQuery current_elapsed_query_;
+};
+
+}  // namespace gfx
+
+#endif  // UI_GL_GPU_TIMING_FAKE_H_
diff --git a/ui/gl/gpu_timing_unittest.cc b/ui/gl/gpu_timing_unittest.cc
new file mode 100644
index 0000000..a567ce6
--- /dev/null
+++ b/ui/gl/gpu_timing_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_context_stub_with_extensions.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_mock.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gpu_preference.h"
+#include "ui/gl/gpu_timing.h"
+
+namespace gfx {
+
+class GPUTimingTest : public testing::Test {
+ public:
+  void SetUp() override {
+    setup_ = false;
+    fake_cpu_time_ = 0;
+  }
+
+  void TearDown() override {
+    context_ = nullptr;
+  }
+
+  void SetupGLContext(const char* gl_version, const char* gl_extensions) {
+    ASSERT_FALSE(setup_) << "Cannot setup GL context twice.";
+    gfx::SetGLGetProcAddressProc(gfx::MockGLInterface::GetGLProcAddress);
+    gfx::GLSurface::InitializeOneOffWithMockBindingsForTests();
+    gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+    ::gfx::MockGLInterface::SetGLInterface(gl_.get());
+
+    context_ = new gfx::GLContextStubWithExtensions;
+    context_->AddExtensionsString(gl_extensions);
+    context_->SetGLVersionString(gl_version);
+
+    setup_ = true;
+  }
+
+  scoped_refptr<GPUTimingClient> CreateGPUTimingClient() {
+    if (!setup_) {
+      SetupGLContext("2.0", "");
+    }
+    return context_->CreateGPUTimingClient();
+  }
+
+  void SetFakeCPUTime(int64_t fake_cpu_time) {
+    fake_cpu_time_ = fake_cpu_time;
+  }
+
+ protected:
+  static int64_t GetFakeCPUTime() {
+    return fake_cpu_time_;
+  }
+
+ private:
+  static int64_t fake_cpu_time_;
+
+  bool setup_ = false;
+  scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+  scoped_refptr<gfx::GLContextStubWithExtensions> context_;
+};
+
+int64_t GPUTimingTest::fake_cpu_time_ = 0;
+
+TEST_F(GPUTimingTest, FakeTimerTest) {
+  // Tests that we can properly set fake cpu times.
+  SetFakeCPUTime(123);
+
+  scoped_refptr<GPUTimingClient> gpu_timing_client = CreateGPUTimingClient();
+  gpu_timing_client->SetCpuTimeForTesting(base::Bind(&GetFakeCPUTime));
+  EXPECT_EQ(123, gpu_timing_client->GetCurrentCPUTime());
+
+  base::Callback<int64_t(void)> empty;
+  gpu_timing_client->SetCpuTimeForTesting(empty);
+  EXPECT_NE(123, gpu_timing_client->GetCurrentCPUTime());
+}
+
+}  // namespace gpu
diff --git a/ui/keyboard/keyboard_controller_proxy.cc b/ui/keyboard/keyboard_controller_proxy.cc
index 99821381..6b6483c 100644
--- a/ui/keyboard/keyboard_controller_proxy.cc
+++ b/ui/keyboard/keyboard_controller_proxy.cc
@@ -18,6 +18,7 @@
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/keyboard/keyboard_constants.h"
+#include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_switches.h"
 #include "ui/keyboard/keyboard_util.h"
 #include "ui/wm/core/shadow.h"
@@ -101,7 +102,9 @@
 
 KeyboardControllerProxy::KeyboardControllerProxy(
     content::BrowserContext* context)
-    : browser_context_(context), default_url_(kKeyboardURL) {
+    : browser_context_(context),
+      default_url_(kKeyboardURL),
+      keyboard_controller_(nullptr) {
 }
 
 KeyboardControllerProxy::~KeyboardControllerProxy() {
@@ -187,17 +190,22 @@
   if (keyboard_contents_->GetURL() != GetVirtualKeyboardUrl()) {
     if (keyboard_contents_->GetURL().GetOrigin() !=
         GetVirtualKeyboardUrl().GetOrigin()) {
-      // Sets keyboard window height to 0 before navigate to a keyboard in a
-      // different extension. This keeps the UX the same as Android.
-      gfx::Rect bounds = GetKeyboardWindow()->bounds();
-      bounds.set_y(bounds.y() + bounds.height());
-      bounds.set_height(0);
-      GetKeyboardWindow()->SetBounds(bounds);
+      // Sets keyboard window rectangle to 0 and close current page before
+      // navigate to a keyboard in a different extension. This keeps the UX the
+      // same as Android. Note we need to explicitly close current page as it
+      // might try to resize keyboard window in javascript on a resize event.
+      GetKeyboardWindow()->SetBounds(gfx::Rect());
+      keyboard_contents_->ClosePage();
+      keyboard_controller()->SetKeyboardMode(FULL_WIDTH);
     }
     LoadContents(GetVirtualKeyboardUrl());
   }
 }
 
+void KeyboardControllerProxy::SetController(KeyboardController* controller) {
+  keyboard_controller_ = controller;
+}
+
 void KeyboardControllerProxy::SetupWebContents(content::WebContents* contents) {
 }
 
diff --git a/ui/keyboard/keyboard_controller_proxy.h b/ui/keyboard/keyboard_controller_proxy.h
index f927849e..98051fa 100644
--- a/ui/keyboard/keyboard_controller_proxy.h
+++ b/ui/keyboard/keyboard_controller_proxy.h
@@ -106,7 +106,7 @@
   // KeyboardController owns KeyboardControllerProxy so KeyboardControllerProxy
   // or its subclasses should not take ownership of the |controller|.
   // |controller| can be null when KeyboardController is destroying.
-  virtual void SetController(KeyboardController* controller) {}
+  virtual void SetController(KeyboardController* controller);
 
  protected:
   // The implementation can choose to setup the WebContents before the virtual
@@ -122,6 +122,7 @@
   void OnWindowDestroyed(aura::Window* window) override;
 
   content::BrowserContext* browser_context() { return browser_context_; }
+  KeyboardController* keyboard_controller() { return keyboard_controller_; }
 
  private:
   friend class TestApi;
@@ -137,6 +138,7 @@
   content::BrowserContext* browser_context_;
 
   const GURL default_url_;
+  keyboard::KeyboardController* keyboard_controller_;
 
   scoped_ptr<content::WebContents> keyboard_contents_;
   scoped_ptr<wm::Shadow> shadow_;
diff --git a/ui/keyboard/keyboard_util.cc b/ui/keyboard/keyboard_util.cc
index e49e1be..4348dfb 100644
--- a/ui/keyboard/keyboard_util.cc
+++ b/ui/keyboard/keyboard_util.cc
@@ -14,7 +14,6 @@
 #include "base/strings/string16.h"
 #include "grit/keyboard_resources.h"
 #include "grit/keyboard_resources_map.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ime/text_input_client.h"
@@ -38,7 +37,6 @@
                          aura::WindowTreeHost* host) {
   ui::KeyEvent event(type, ui::VKEY_PROCESSKEY, ui::DomCode::NONE, ui::EF_NONE,
                      ui::DomKey::PROCESS, 0, ui::EventTimeForNow());
-  event.SetTranslated(true);
   ui::EventDispatchDetails details =
       host->event_processor()->OnEventFromSource(&event);
   CHECK(!details.dispatcher_destroyed);
@@ -291,12 +289,11 @@
 
   ui::KeyboardCode code = static_cast<ui::KeyboardCode>(key_code);
 
+  ui::InputMethod* input_method = host->GetInputMethod();
   if (code == ui::VKEY_UNKNOWN) {
     // Handling of special printable characters (e.g. accented characters) for
     // which there is no key code.
     if (event_type == ui::ET_KEY_RELEASED) {
-      ui::InputMethod* input_method = host->window()->GetProperty(
-          aura::client::kRootWindowInputMethodKey);
       if (!input_method)
         return false;
 
@@ -333,9 +330,13 @@
         code,
         dom_code,
         modifiers);
-    ui::EventDispatchDetails details =
-        host->event_processor()->OnEventFromSource(&event);
-    CHECK(!details.dispatcher_destroyed);
+    if (input_method) {
+      input_method->DispatchKeyEvent(event);
+    } else {
+      ui::EventDispatchDetails details =
+          host->event_processor()->OnEventFromSource(&event);
+      CHECK(!details.dispatcher_destroyed);
+    }
   }
   return true;
 }
diff --git a/ui/message_center/views/message_popup_collection.cc b/ui/message_center/views/message_popup_collection.cc
index 3f0bc2ae..a021eb7 100644
--- a/ui/message_center/views/message_popup_collection.cc
+++ b/ui/message_center/views/message_popup_collection.cc
@@ -171,8 +171,8 @@
     else
       base -= view_height + kToastMarginY;
 
-    if (views::ViewsDelegate::views_delegate) {
-      views::ViewsDelegate::views_delegate->NotifyAccessibilityEvent(
+    if (views::ViewsDelegate::GetInstance()) {
+      views::ViewsDelegate::GetInstance()->NotifyAccessibilityEvent(
           toast, ui::AX_EVENT_ALERT);
     }
 
diff --git a/ui/mojo/events/BUILD.gn b/ui/mojo/events/BUILD.gn
index 679509c..1652936 100644
--- a/ui/mojo/events/BUILD.gn
+++ b/ui/mojo/events/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/module_args/mojo.gni")
 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
diff --git a/ui/oobe/oobe_md_ui.cc b/ui/oobe/oobe_md_ui.cc
index 07e91b5..cb86c93 100644
--- a/ui/oobe/oobe_md_ui.cc
+++ b/ui/oobe/oobe_md_ui.cc
@@ -21,7 +21,7 @@
   const size_t prefix_length = arraysize(prefix) - 1;
   for (size_t i = 0; i < kOobeResourcesSize; ++i) {
     std::string name = kOobeResources[i].name;
-    DCHECK(StartsWithASCII(name, prefix, true));
+    DCHECK(base::StartsWithASCII(name, prefix, true));
     source->AddResourcePath(name.substr(prefix_length),
                             kOobeResources[i].value);
   }
diff --git a/ui/ozone/platform/drm/drm.gypi b/ui/ozone/platform/drm/drm.gypi
index dd427a9..8affc20a 100644
--- a/ui/ozone/platform/drm/drm.gypi
+++ b/ui/ozone/platform/drm/drm.gypi
@@ -14,6 +14,7 @@
       'dri',
       'drm',
     ],
+    'use_drm_atomic%': 0,
   },
   'targets': [
     {
@@ -108,6 +109,19 @@
         'ozone_platform_drm.h',
         'scanout_buffer.h',
       ],
+      'conditions': [
+        ['use_drm_atomic == 1', {
+          'sources': [
+            'gpu/hardware_display_plane_atomic.cc',
+            'gpu/hardware_display_plane_atomic.h',
+            'gpu/hardware_display_plane_manager_atomic.cc',
+            'gpu/hardware_display_plane_manager_atomic.h',
+          ],
+          'defines': [
+            'USE_DRM_ATOMIC=1',
+          ],
+        }],
+      ],
     },
     {
       'target_name': 'ozone_platform_drm_unittests',
diff --git a/ui/ozone/platform/drm/gpu/drm_device.cc b/ui/ozone/platform/drm/gpu/drm_device.cc
index 819780c..7f150143 100644
--- a/ui/ozone/platform/drm/gpu/drm_device.cc
+++ b/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -556,7 +556,7 @@
                                  const PageFlipCallback& callback) {
 #if defined(USE_DRM_ATOMIC)
   if (test_only)
-    flags |= DRM_MODE_TEST_ONLY;
+    flags |= DRM_MODE_ATOMIC_TEST_ONLY;
   else
     flags |= DRM_MODE_PAGE_FLIP_EVENT;
   scoped_ptr<PageFlipPayload> payload(
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
index 1fcc7ca2..29ed57e 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
@@ -65,7 +65,8 @@
   }
   plane_list->plane_list.clear();
   if (!drm_->CommitProperties(plane_list->atomic_property_set.get(), 0, is_sync,
-                              test_only, base::Bind(&AtomicPageFlipCallback))) {
+                              test_only,
+                              base::Bind(&AtomicPageFlipCallback, crtcs))) {
     PLOG(ERROR) << "Failed to commit properties";
     return false;
   }
diff --git a/ui/ozone/public/system_input_injector.h b/ui/ozone/public/system_input_injector.h
index 3c379c0..a13051f4 100644
--- a/ui/ozone/public/system_input_injector.h
+++ b/ui/ozone/public/system_input_injector.h
@@ -39,11 +39,13 @@
   // factor.
   virtual void InjectMouseWheel(int delta_x, int delta_y) = 0;
 
-  // Simulates a key press.  SystemInputInjector maps |physical_key| to the
-  // correct logical key based on the current keyboard layout.
-  virtual void InjectKeyPress(DomCode physical_key,
+  // Simulates a key event.  SystemInputInjector maps |physical_key| to the
+  // correct logical key based on the current keyboard layout. |down| is true
+  // for presses. If |suppress_auto_repeat| is set, the platform must not
+  // auto-repeat the event.
+  virtual void InjectKeyEvent(DomCode physical_key,
                               bool down,
-                              bool enable_repeat) = 0;
+                              bool suppress_auto_repeat) = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SystemInputInjector);
diff --git a/ui/touch_selection/touch_selection_menu_runner.cc b/ui/touch_selection/touch_selection_menu_runner.cc
index 860a24b..bf70874 100644
--- a/ui/touch_selection/touch_selection_menu_runner.cc
+++ b/ui/touch_selection/touch_selection_menu_runner.cc
@@ -4,6 +4,8 @@
 
 #include "ui/touch_selection/touch_selection_menu_runner.h"
 
+#include "base/logging.h"
+
 namespace ui {
 namespace {
 
@@ -12,6 +14,7 @@
 }  // namespace
 
 TouchSelectionMenuRunner::~TouchSelectionMenuRunner() {
+  DCHECK_EQ(this, g_touch_selection_menu_runner);
   g_touch_selection_menu_runner = nullptr;
 }
 
@@ -20,11 +23,7 @@
 }
 
 TouchSelectionMenuRunner::TouchSelectionMenuRunner() {
-  // TODO(mohsen): Ideally we should DCHECK that |g_touch_selection_menu_runner|
-  // is not set here, in order to make sure we don't create multiple menu
-  // runners accidentally. Currently, this is not possible because we can have
-  // multiple ViewsDelegate's at the same time which should not happen. See
-  // crbug.com/492991.
+  DCHECK(!g_touch_selection_menu_runner);
   g_touch_selection_menu_runner = this;
 }
 
diff --git a/ui/views/accessibility/native_view_accessibility_auralinux.cc b/ui/views/accessibility/native_view_accessibility_auralinux.cc
index 7205c7a2..37c43bb7 100644
--- a/ui/views/accessibility/native_view_accessibility_auralinux.cc
+++ b/ui/views/accessibility/native_view_accessibility_auralinux.cc
@@ -119,17 +119,17 @@
   AuraLinuxApplication()
       : platform_node_(ui::AXPlatformNode::Create(this)) {
     data_.role = ui::AX_ROLE_APPLICATION;
-    if (ViewsDelegate::views_delegate) {
+    if (ViewsDelegate::GetInstance()) {
       data_.AddStringAttribute(
           ui::AX_ATTR_NAME,
-          ViewsDelegate::views_delegate->GetApplicationName());
+          ViewsDelegate::GetInstance()->GetApplicationName());
     }
     ui::AXPlatformNodeAuraLinux::SetApplication(platform_node_);
-    if (ViewsDelegate::views_delegate) {
+    if (ViewsDelegate::GetInstance()) {
       // This should be on the a blocking pool thread so that we can open
       // libatk-bridge.so without blocking this thread.
       scoped_refptr<base::TaskRunner> init_task_runner =
-          ViewsDelegate::views_delegate->GetBlockingPoolTaskRunner();
+          ViewsDelegate::GetInstance()->GetBlockingPoolTaskRunner();
       if (init_task_runner)
         ui::AXPlatformNodeAuraLinux::StaticInitialize(init_task_runner);
     }
diff --git a/ui/views/bubble/bubble_border_unittest.cc b/ui/views/bubble/bubble_border_unittest.cc
index 404902c3..f22df5d 100644
--- a/ui/views/bubble/bubble_border_unittest.cc
+++ b/ui/views/bubble/bubble_border_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/views/test/views_test_base.h"
 
 namespace views {
diff --git a/ui/views/bubble/bubble_delegate.cc b/ui/views/bubble/bubble_delegate.cc
index 438b407..fd0f112 100644
--- a/ui/views/bubble/bubble_delegate.cc
+++ b/ui/views/bubble/bubble_delegate.cc
@@ -40,6 +40,8 @@
       Widget::InitParams::ACTIVATABLE_YES : Widget::InitParams::ACTIVATABLE_NO;
   bubble->OnBeforeBubbleWidgetInit(&bubble_params, bubble_widget);
   bubble_widget->Init(bubble_params);
+  if (bubble_params.parent)
+    bubble_widget->StackAbove(bubble_params.parent);
   return bubble_widget;
 }
 
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index b3b6418..24ff796 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -223,6 +223,11 @@
   return GetWindowBoundsForClientBounds(gfx::Rect(client_size)).size();
 }
 
+gfx::Size BubbleFrameView::GetMaximumSize() const {
+  // A bubble should be non-resizable, so its max size is its preferred size.
+  return GetPreferredSize();
+}
+
 void BubbleFrameView::Layout() {
   gfx::Rect bounds(GetContentsBounds());
   bounds.Inset(GetTitleInsets());
diff --git a/ui/views/bubble/bubble_frame_view.h b/ui/views/bubble/bubble_frame_view.h
index f756209..044b739 100644
--- a/ui/views/bubble/bubble_frame_view.h
+++ b/ui/views/bubble/bubble_frame_view.h
@@ -59,6 +59,7 @@
   gfx::Insets GetInsets() const override;
   gfx::Size GetPreferredSize() const override;
   gfx::Size GetMinimumSize() const override;
+  gfx::Size GetMaximumSize() const override;
   void Layout() override;
   const char* GetClassName() const override;
   void ChildPreferredSizeChanged(View* child) override;
diff --git a/ui/views/bubble/bubble_frame_view_unittest.cc b/ui/views/bubble/bubble_frame_view_unittest.cc
index 54b754e..50558a5 100644
--- a/ui/views/bubble/bubble_frame_view_unittest.cc
+++ b/ui/views/bubble/bubble_frame_view_unittest.cc
@@ -24,6 +24,8 @@
 const int kMargin = 6;
 const int kMinimumClientWidth = 100;
 const int kMinimumClientHeight = 200;
+const int kMaximumClientWidth = 300;
+const int kMaximumClientHeight = 300;
 const int kPreferredClientWidth = 150;
 const int kPreferredClientHeight = 250;
 const int kExpectedBorderWidth = 22;
@@ -45,6 +47,8 @@
           gfx::Size(kPreferredClientWidth, kPreferredClientHeight));
       contents_view->set_minimum_size(
           gfx::Size(kMinimumClientWidth, kMinimumClientHeight));
+      contents_view->set_maximum_size(
+          gfx::Size(kMaximumClientWidth, kMaximumClientHeight));
       contents_view_ = contents_view;
     }
     return contents_view_;
@@ -428,4 +432,13 @@
             minimum_size.height());
 }
 
+TEST_F(BubbleFrameViewTest, GetMaximumSize) {
+  TestBubbleFrameView frame(this);
+  gfx::Size maximum_size = frame.GetMaximumSize();
+  // Should ignore the contents view's maximum size and use the preferred size.
+  EXPECT_EQ(kPreferredClientWidth + kExpectedBorderWidth, maximum_size.width());
+  EXPECT_EQ(kPreferredClientHeight + kExpectedBorderHeight,
+            maximum_size.height());
+}
+
 }  // namespace views
diff --git a/ui/views/cocoa/bridged_content_view.h b/ui/views/cocoa/bridged_content_view.h
index 969af99..49b41dc 100644
--- a/ui/views/cocoa/bridged_content_view.h
+++ b/ui/views/cocoa/bridged_content_view.h
@@ -40,11 +40,19 @@
 
   // The last tooltip text, used to limit updates.
   base::string16 lastTooltipText_;
+
+  // Whether dragging on the view moves the window.
+  BOOL mouseDownCanMoveWindow_;
 }
 
 @property(readonly, nonatomic) views::View* hostedView;
 @property(assign, nonatomic) ui::TextInputClient* textInputClient;
 
+// Extends an atomic, readonly property on NSView to make it assignable.
+// This usually returns YES if the view is transparent. We want to control it
+// so that BridgedNativeWidget can dynamically enable dragging of the window.
+@property(assign) BOOL mouseDownCanMoveWindow;
+
 // Initialize the NSView -> views::View bridge. |viewToHost| must be non-NULL.
 - (id)initWithView:(views::View*)viewToHost;
 
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm
index 5325a58..e23db5b 100644
--- a/ui/views/cocoa/bridged_content_view.mm
+++ b/ui/views/cocoa/bridged_content_view.mm
@@ -93,6 +93,7 @@
 
 @synthesize hostedView = hostedView_;
 @synthesize textInputClient = textInputClient_;
+@synthesize mouseDownCanMoveWindow = mouseDownCanMoveWindow_;
 
 - (id)initWithView:(views::View*)viewToHost {
   DCHECK(viewToHost);
diff --git a/ui/views/cocoa/bridged_native_widget.h b/ui/views/cocoa/bridged_native_widget.h
index a4e4b1d9..5f52831ec 100644
--- a/ui/views/cocoa/bridged_native_widget.h
+++ b/ui/views/cocoa/bridged_native_widget.h
@@ -132,6 +132,12 @@
   // Called by the NSWindowDelegate when the window becomes or resigns key.
   void OnWindowKeyStatusChangedTo(bool is_key);
 
+  // Called by NSWindowDelegate when the application receives a mouse-down, but
+  // before the event is processed by NSWindows. Returning true here will cause
+  // the event to be cancelled and reposted at the CGSessionEventTap level. This
+  // is used to determine whether a mouse-down should drag the window.
+  virtual bool ShouldRepostPendingLeftMouseDown(NSPoint location_in_window);
+
   // Called by NativeWidgetMac when the window size constraints change.
   void OnSizeConstraintsChanged();
 
@@ -191,6 +197,10 @@
   // scale factor.
   void UpdateLayerProperties();
 
+  // Sets mouseDownCanMoveWindow on |bridged_view_| and triggers the NSWindow to
+  // update its draggable region.
+  void SetDraggable(bool draggable);
+
   // Overridden from CocoaMouseCaptureDelegate:
   void PostCapturedEvent(NSEvent* event) override;
   void OnMouseCaptureLost() override;
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm
index 3e281b5..a465d24 100644
--- a/ui/views/cocoa/bridged_native_widget.mm
+++ b/ui/views/cocoa/bridged_native_widget.mm
@@ -7,10 +7,12 @@
 #import <objc/runtime.h>
 
 #include "base/logging.h"
+#import "base/mac/foundation_util.h"
 #include "base/mac/mac_util.h"
 #import "base/mac/sdk_forward_declarations.h"
 #include "base/thread_task_runner_handle.h"
 #import "ui/base/cocoa/constrained_window/constrained_window_animation.h"
+#include "ui/base/hit_test.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/ime/input_method_factory.h"
 #include "ui/base/ui_base_switches_util.h"
@@ -78,6 +80,104 @@
   return gfx::Size([window contentRectForFrameRect:frame_rect].size);
 }
 
+BOOL WindowWantsMouseDownReposted(NSEvent* ns_event) {
+  id delegate = [[ns_event window] delegate];
+  return
+      [delegate
+          respondsToSelector:@selector(shouldRepostPendingLeftMouseDown:)] &&
+      [delegate shouldRepostPendingLeftMouseDown:[ns_event locationInWindow]];
+}
+
+// Check if a mouse-down event should drag the window. If so, repost the event.
+NSEvent* RepostEventIfHandledByWindow(NSEvent* ns_event) {
+  enum RepostState {
+    // Nothing reposted: hit-test new mouse-downs to see if they need to be
+    // ignored and reposted after changing draggability.
+    NONE,
+    // Expecting the next event to be the reposted event: let it go through.
+    EXPECTING_REPOST,
+    // If, while reposting, another mousedown was received: when the reposted
+    // event is seen, ignore it.
+    REPOST_CANCELLED,
+  };
+
+  // Which repost we're expecting to receive.
+  static RepostState repost_state = NONE;
+  // The event number of the reposted event. This let's us track whether an
+  // event is actually the repost since user-generated events have increasing
+  // event numbers. This is only valid while |repost_state != NONE|.
+  static NSInteger reposted_event_number;
+
+  NSInteger event_number = [ns_event eventNumber];
+
+  // The logic here is a bit convoluted because we want to mitigate race
+  // conditions if somehow a different mouse-down occurs between reposts.
+  // Specifically, we want to avoid:
+  // - BridgedNativeWidget's draggability getting out of sync (e.g. if it is
+  //   draggable outside of a repost cycle),
+  // - any repost loop.
+
+  if (repost_state == NONE) {
+    if (WindowWantsMouseDownReposted(ns_event)) {
+      repost_state = EXPECTING_REPOST;
+      reposted_event_number = event_number;
+      CGEventPost(kCGSessionEventTap, [ns_event CGEvent]);
+      return nil;
+    }
+
+    return ns_event;
+  }
+
+  if (repost_state == EXPECTING_REPOST) {
+    // Call through so that the window is made non-draggable again.
+    WindowWantsMouseDownReposted(ns_event);
+
+    if (reposted_event_number == event_number) {
+      // Reposted event received.
+      repost_state = NONE;
+      return nil;
+    }
+
+    // We were expecting a repost, but since this is a new mouse-down, cancel
+    // reposting and allow event to continue as usual.
+    repost_state = REPOST_CANCELLED;
+    return ns_event;
+  }
+
+  DCHECK_EQ(REPOST_CANCELLED, repost_state);
+  if (reposted_event_number == event_number) {
+    // Reposting was cancelled, now that we've received the event, we don't
+    // expect to see it again.
+    repost_state = NONE;
+    return nil;
+  }
+
+  return ns_event;
+}
+
+// Support window caption/draggable regions.
+// In AppKit, non-client regions are set by overriding
+// -[NSView mouseDownCanMoveWindow]. NSApplication caches this area as views are
+// installed and performs window moving when mouse-downs land in the area.
+// In Views, non-client regions are determined via hit-tests when the event
+// occurs.
+// To bridge the two models, we monitor mouse-downs with
+// +[NSEvent addLocalMonitorForEventsMatchingMask:handler:]. This receives
+// events after window dragging is handled, so for mouse-downs that land on a
+// draggable point, we cancel the event and repost it at the CGSessionEventTap
+// level so that window dragging will be handled again.
+void SetupDragEventMonitor() {
+  static id monitor = nil;
+  if (monitor)
+    return;
+
+  monitor = [NSEvent
+      addLocalMonitorForEventsMatchingMask:NSLeftMouseDownMask
+      handler:^NSEvent*(NSEvent* ns_event) {
+        return RepostEventIfHandledByWindow(ns_event);
+      }];
+}
+
 }  // namespace
 
 namespace views {
@@ -101,6 +201,7 @@
       in_fullscreen_transition_(false),
       window_visible_(false),
       wants_to_be_visible_(false) {
+  SetupDragEventMonitor();
   DCHECK(parent);
   window_delegate_.reset(
       [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]);
@@ -548,6 +649,44 @@
   }
 }
 
+bool BridgedNativeWidget::ShouldRepostPendingLeftMouseDown(
+    NSPoint location_in_window) {
+  if (!bridged_view_)
+    return false;
+
+  if ([bridged_view_ mouseDownCanMoveWindow]) {
+    // This is a re-post, the movement has already started, so we can make the
+    // window non-draggable again.
+    SetDraggable(false);
+    return false;
+  }
+
+  gfx::Point point(location_in_window.x,
+                   NSHeight([window_ frame]) - location_in_window.y);
+  bool should_move_window =
+      native_widget_mac()->GetWidget()->GetNonClientComponent(point) ==
+      HTCAPTION;
+
+  // Check that the point is not obscured by non-content NSViews.
+  for (NSView* subview : [[bridged_view_ superview] subviews]) {
+    if (subview == bridged_view_.get())
+      continue;
+
+    if (![subview mouseDownCanMoveWindow] &&
+        NSPointInRect(location_in_window, [subview frame])) {
+      should_move_window = false;
+      break;
+    }
+  }
+
+  if (!should_move_window)
+    return false;
+
+  // Make the window draggable, then return true to repost the event.
+  SetDraggable(true);
+  return true;
+}
+
 void BridgedNativeWidget::OnSizeConstraintsChanged() {
   // Don't modify the size constraints or fullscreen collection behavior while
   // in fullscreen or during a transition. OnFullscreenTransitionComplete will
@@ -793,10 +932,10 @@
 void BridgedNativeWidget::CreateCompositor() {
   DCHECK(!compositor_);
   DCHECK(!compositor_widget_);
-  DCHECK(ViewsDelegate::views_delegate);
+  DCHECK(ViewsDelegate::GetInstance());
 
   ui::ContextFactory* context_factory =
-      ViewsDelegate::views_delegate->GetContextFactory();
+      ViewsDelegate::GetInstance()->GetContextFactory();
   DCHECK(context_factory);
 
   AddCompositorSuperview();
@@ -886,4 +1025,14 @@
   return properties;
 }
 
+void BridgedNativeWidget::SetDraggable(bool draggable) {
+  [bridged_view_ setMouseDownCanMoveWindow:draggable];
+  // AppKit will not update its cache of mouseDownCanMoveWindow unless something
+  // changes. Previously we tried adding an NSView and removing it, but for some
+  // reason it required reposting the mouse-down event, and didn't always work.
+  // Calling the below seems to be an effective solution.
+  [window_ setMovableByWindowBackground:NO];
+  [window_ setMovableByWindowBackground:YES];
+}
+
 }  // namespace views
diff --git a/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm b/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
index b0962fb..f7c4329 100644
--- a/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
+++ b/ui/views/cocoa/bridged_native_widget_interactive_uitest.mm
@@ -9,9 +9,14 @@
 #import "base/mac/mac_util.h"
 #import "base/mac/sdk_forward_declarations.h"
 #import "ui/base/test/nswindow_fullscreen_notification_waiter.h"
+#include "ui/base/hit_test.h"
+#import "ui/base/test/windowed_nsnotification_observer.h"
+#import "ui/events/test/cocoa_test_event_utils.h"
 #include "ui/views/test/widget_test.h"
+#include "ui/views/window/native_frame_view.h"
 
 namespace views {
+namespace test {
 
 class BridgedNativeWidgetUITest : public test::WidgetTest {
  public:
@@ -144,4 +149,191 @@
   EXPECT_EQ(restored_bounds, widget_->GetRestoredBounds());
 }
 
+namespace {
+
+// This is used to wait for reposted events to be seen. We can't just use
+// RunPendingMessages() because CGEventPost might not be synchronous.
+class HitTestBridgedNativeWidget : public BridgedNativeWidget {
+ public:
+  explicit HitTestBridgedNativeWidget(NativeWidgetMac* widget)
+      : BridgedNativeWidget(widget) {}
+
+  // BridgedNativeWidget:
+  bool ShouldRepostPendingLeftMouseDown(NSPoint location_in_window) override {
+    bool draggable_before = [ns_view() mouseDownCanMoveWindow];
+    bool should_repost = BridgedNativeWidget::ShouldRepostPendingLeftMouseDown(
+        location_in_window);
+    bool draggable_after = [ns_view() mouseDownCanMoveWindow];
+
+    if (run_loop_ && draggable_before && !draggable_after)
+      run_loop_->Quit();
+
+    return should_repost;
+  }
+
+  void WaitForIsDraggableChange() {
+    base::RunLoop run_loop;
+    run_loop_ = &run_loop;
+    run_loop.Run();
+    run_loop_ = nullptr;
+  }
+
+ private:
+  base::RunLoop* run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(HitTestBridgedNativeWidget);
+};
+
+// This is used to return a customized result to NonClientHitTest.
+class HitTestNonClientFrameView : public NativeFrameView {
+ public:
+  explicit HitTestNonClientFrameView(Widget* widget)
+      : NativeFrameView(widget), hit_test_result_(HTNOWHERE) {}
+
+  // NonClientFrameView overrides:
+  int NonClientHitTest(const gfx::Point& point) override {
+    return hit_test_result_;
+  }
+
+  void set_hit_test_result(int component) { hit_test_result_ = component; }
+
+ private:
+  int hit_test_result_;
+
+  DISALLOW_COPY_AND_ASSIGN(HitTestNonClientFrameView);
+};
+
+void WaitForEvent(NSUInteger mask) {
+  // Pointer because the handler block captures local variables by copying.
+  base::RunLoop run_loop;
+  base::RunLoop* run_loop_ref = &run_loop;
+  id monitor = [NSEvent
+      addLocalMonitorForEventsMatchingMask:mask
+                                   handler:^NSEvent*(NSEvent* ns_event) {
+                                     run_loop_ref->Quit();
+                                     return ns_event;
+                                   }];
+  run_loop.Run();
+  [NSEvent removeMonitor:monitor];
+}
+
+}  // namespace
+
+// This is used to inject test versions of NativeFrameView and
+// BridgedNativeWidget.
+class HitTestNativeWidgetMac : public NativeWidgetMac {
+ public:
+  HitTestNativeWidgetMac(internal::NativeWidgetDelegate* delegate,
+                         NativeFrameView* native_frame_view)
+      : NativeWidgetMac(delegate), native_frame_view_(native_frame_view) {
+    NativeWidgetMac::bridge_.reset(new HitTestBridgedNativeWidget(this));
+  }
+
+  HitTestBridgedNativeWidget* bridge() {
+    return static_cast<HitTestBridgedNativeWidget*>(
+        NativeWidgetMac::bridge_.get());
+  }
+
+  // internal::NativeWidgetPrivate:
+  NonClientFrameView* CreateNonClientFrameView() override {
+    return native_frame_view_;
+  }
+
+ private:
+  // Owned by Widget.
+  NativeFrameView* native_frame_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(HitTestNativeWidgetMac);
+};
+
+TEST_F(BridgedNativeWidgetUITest, HitTest) {
+  Widget widget;
+  HitTestNonClientFrameView* frame_view =
+      new HitTestNonClientFrameView(&widget);
+  test::HitTestNativeWidgetMac* native_widget =
+      new test::HitTestNativeWidgetMac(&widget, frame_view);
+  Widget::InitParams init_params =
+      CreateParams(Widget::InitParams::TYPE_WINDOW);
+  init_params.native_widget = native_widget;
+  init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  init_params.bounds = gfx::Rect(100, 200, 400, 300);
+  widget.Init(init_params);
+  widget.Show();
+
+  // Dragging the window should work.
+  frame_view->set_hit_test_result(HTCAPTION);
+  {
+    EXPECT_EQ(100, [widget.GetNativeWindow() frame].origin.x);
+
+    NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
+        NSMakePoint(10, 10), widget.GetNativeWindow());
+    CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]);
+    native_widget->bridge()->WaitForIsDraggableChange();
+
+    base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer(
+        [[WindowedNSNotificationObserver alloc]
+            initForNotification:NSWindowDidMoveNotification]);
+    NSEvent* mouse_drag = cocoa_test_event_utils::MouseEventAtPointInWindow(
+        NSMakePoint(110, 110), NSLeftMouseDragged, widget.GetNativeWindow(), 0);
+    CGEventPost(kCGSessionEventTap, [mouse_drag CGEvent]);
+    [ns_observer wait];
+    EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
+
+    NSEvent* mouse_up = cocoa_test_event_utils::MouseEventAtPointInWindow(
+        NSMakePoint(10, 10), NSLeftMouseUp, widget.GetNativeWindow(), 0);
+    CGEventPost(kCGSessionEventTap, [mouse_up CGEvent]);
+    WaitForEvent(NSLeftMouseUpMask);
+    EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
+  }
+
+  // Mouse-downs on the window controls should not be intercepted.
+  {
+    EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
+
+    base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer(
+        [[WindowedNSNotificationObserver alloc]
+            initForNotification:NSWindowDidMiniaturizeNotification]);
+
+    // Position this on the minimize button.
+    NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
+        NSMakePoint(30, 290), widget.GetNativeWindow());
+    CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]);
+
+    NSEvent* mouse_up = cocoa_test_event_utils::MouseEventAtPointInWindow(
+        NSMakePoint(30, 290), NSLeftMouseUp, widget.GetNativeWindow(), 0);
+    EXPECT_FALSE([widget.GetNativeWindow() isMiniaturized]);
+    CGEventPost(kCGSessionEventTap, [mouse_up CGEvent]);
+    [ns_observer wait];
+    EXPECT_TRUE([widget.GetNativeWindow() isMiniaturized]);
+    [widget.GetNativeWindow() deminiaturize:nil];
+
+    // Position unchanged.
+    EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
+  }
+
+  // Non-draggable areas should do nothing.
+  frame_view->set_hit_test_result(HTCLIENT);
+  {
+    EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
+
+    NSEvent* mouse_down = cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
+        NSMakePoint(10, 10), widget.GetNativeWindow());
+    CGEventPost(kCGSessionEventTap, [mouse_down CGEvent]);
+    WaitForEvent(NSLeftMouseDownMask);
+
+    NSEvent* mouse_drag = cocoa_test_event_utils::MouseEventAtPointInWindow(
+        NSMakePoint(110, 110), NSLeftMouseDragged, widget.GetNativeWindow(), 0);
+    CGEventPost(kCGSessionEventTap, [mouse_drag CGEvent]);
+    WaitForEvent(NSLeftMouseDraggedMask);
+    EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
+
+    NSEvent* mouse_up = cocoa_test_event_utils::MouseEventAtPointInWindow(
+        NSMakePoint(110, 110), NSLeftMouseUp, widget.GetNativeWindow(), 0);
+    CGEventPost(kCGSessionEventTap, [mouse_up CGEvent]);
+    WaitForEvent(NSLeftMouseUpMask);
+    EXPECT_EQ(200, [widget.GetNativeWindow() frame].origin.x);
+  }
+}
+
+}  // namespace test
 }  // namespace views
diff --git a/ui/views/cocoa/views_nswindow_delegate.h b/ui/views/cocoa/views_nswindow_delegate.h
index dc0b2016..7dc64b6 100644
--- a/ui/views/cocoa/views_nswindow_delegate.h
+++ b/ui/views/cocoa/views_nswindow_delegate.h
@@ -59,6 +59,13 @@
 - (void)windowDidFailToEnterFullScreen:(NSWindow*)window;
 - (void)windowDidFailToExitFullScreen:(NSWindow*)window;
 
+// Called when the application receives a mouse-down, but before the event
+// is processed by NSWindows. Returns NO if the event should be processed as-is,
+// or YES if the event should be reposted to handle window dragging. Events are
+// reposted at the CGSessionEventTap level because window dragging happens there
+// before the application receives the event.
+- (BOOL)shouldRepostPendingLeftMouseDown:(NSPoint)locationInWindow;
+
 @end
 
 #endif  // UI_VIEWS_COCOA_VIEWS_NSWINDOW_DELEGATE_H_
diff --git a/ui/views/cocoa/views_nswindow_delegate.mm b/ui/views/cocoa/views_nswindow_delegate.mm
index 777348d9..d8f1a823 100644
--- a/ui/views/cocoa/views_nswindow_delegate.mm
+++ b/ui/views/cocoa/views_nswindow_delegate.mm
@@ -54,6 +54,10 @@
   parent_->OnWindowWillClose();
 }
 
+- (BOOL)shouldRepostPendingLeftMouseDown:(NSPoint)locationInWindow {
+  return parent_->ShouldRepostPendingLeftMouseDown(locationInWindow);
+}
+
 // NSWindowDelegate implementation.
 
 - (void)windowDidFailToEnterFullScreen:(NSWindow*)window {
diff --git a/ui/views/cocoa/widget_owner_nswindow_adapter.h b/ui/views/cocoa/widget_owner_nswindow_adapter.h
index 6b10e39..6d5517e 100644
--- a/ui/views/cocoa/widget_owner_nswindow_adapter.h
+++ b/ui/views/cocoa/widget_owner_nswindow_adapter.h
@@ -9,6 +9,7 @@
 #import "ui/views/cocoa/bridged_native_widget_owner.h"
 
 @class NSView;
+@class NSWindow;
 @class WidgetOwnerNSWindowAdapterBridge;
 
 namespace views {
@@ -37,6 +38,7 @@
 
   BridgedNativeWidget* child_;  // Weak. Owned by its NativeWidgetMac.
   base::scoped_nsobject<NSView> anchor_view_;
+  base::scoped_nsobject<NSWindow> anchor_window_;
   base::scoped_nsobject<WidgetOwnerNSWindowAdapterBridge> observer_bridge_;
 
   DISALLOW_COPY_AND_ASSIGN(WidgetOwnerNSWindowAdapter);
diff --git a/ui/views/cocoa/widget_owner_nswindow_adapter.mm b/ui/views/cocoa/widget_owner_nswindow_adapter.mm
index e3939fd..0fbe5d54 100644
--- a/ui/views/cocoa/widget_owner_nswindow_adapter.mm
+++ b/ui/views/cocoa/widget_owner_nswindow_adapter.mm
@@ -45,12 +45,19 @@
       anchor_view_([anchor_view retain]),
       observer_bridge_(
           [[WidgetOwnerNSWindowAdapterBridge alloc] initWithAdapter:this]) {
-  DCHECK([anchor_view_ window]);
+
+  // Although the |anchor_view| must be in an NSWindow when the child dialog is
+  // created, it's permitted for the |anchor_view| to be removed from its view
+  // hierarchy before the child dialog window is fully removed from screen. When
+  // this happens, [anchor_view_ window] will become nil, so retain both.
+  anchor_window_.reset([[anchor_view_ window] retain]);
+  DCHECK(anchor_window_);
+
   [[NSNotificationCenter defaultCenter]
       addObserver:observer_bridge_
          selector:@selector(windowWillClose:)
              name:NSWindowWillCloseNotification
-           object:[anchor_view_ window]];
+           object:anchor_window_];
 }
 
 void WidgetOwnerNSWindowAdapter::OnWindowWillClose() {
@@ -59,11 +66,10 @@
 }
 
 NSWindow* WidgetOwnerNSWindowAdapter::GetNSWindow() {
-  return [anchor_view_ window];
+  return anchor_window_;
 }
 
 gfx::Vector2d WidgetOwnerNSWindowAdapter::GetChildWindowOffset() const {
-  NSWindow* window = [anchor_view_ window];
   NSRect rect_in_window =
       [anchor_view_ convertRect:[anchor_view_ bounds] toView:nil];
   // Ensure we anchor off the top-left of |anchor_view_| (rect_in_window.origin
@@ -71,13 +77,13 @@
   // TODO(tapted): Use -[NSWindow convertRectToScreen:] when we ditch 10.6.
   NSRect rect_in_screen = NSZeroRect;
   rect_in_screen.origin =
-      [window convertBaseToScreen:NSMakePoint(NSMinX(rect_in_window),
-                                              NSMaxY(rect_in_window))];
+      [anchor_window_ convertBaseToScreen:NSMakePoint(NSMinX(rect_in_window),
+                                                      NSMaxY(rect_in_window))];
   return gfx::ScreenRectFromNSRect(rect_in_screen).OffsetFromOrigin();
 }
 
 bool WidgetOwnerNSWindowAdapter::IsVisibleParent() const {
-  return [[anchor_view_ window] isVisible];
+  return [anchor_window_ isVisible];
 }
 
 void WidgetOwnerNSWindowAdapter::RemoveChildWindow(BridgedNativeWidget* child) {
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 8d6a7a2..062c5f1 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -361,8 +361,8 @@
     pressed_lock_.reset(new MenuButton::PressedLock(button));
 
   // Make sure Chrome doesn't attempt to shut down while the menu is showing.
-  if (ViewsDelegate::views_delegate)
-    ViewsDelegate::views_delegate->AddRef();
+  if (ViewsDelegate::GetInstance())
+    ViewsDelegate::GetInstance()->AddRef();
 
   // We need to turn on nestable tasks as in some situations (pressing alt-f for
   // one) the menus are run from a task. If we don't do this and are invoked
@@ -373,8 +373,8 @@
   RunMessageLoop(nested_menu);
   message_loop_depth_--;
 
-  if (ViewsDelegate::views_delegate)
-    ViewsDelegate::views_delegate->ReleaseRef();
+  if (ViewsDelegate::GetInstance())
+    ViewsDelegate::GetInstance()->ReleaseRef();
 
   // Close any open menus.
   SetSelection(NULL, SELECTION_UPDATE_IMMEDIATELY | SELECTION_EXIT);
@@ -2125,8 +2125,8 @@
   // coordinates to be in pixels.
   // PostMessage() to metro windows isn't allowed (access will be denied). Don't
   // try to repost with Win32 if the window under the mouse press is in metro.
-  if (!ViewsDelegate::views_delegate ||
-      !ViewsDelegate::views_delegate->IsWindowInMetro(window)) {
+  if (!ViewsDelegate::GetInstance() ||
+      !ViewsDelegate::GetInstance()->IsWindowInMetro(window)) {
     gfx::Point screen_loc_pixels = gfx::win::DIPToScreenPoint(screen_loc);
     HWND target_window = window ? HWNDForNativeWindow(window) :
                                   WindowFromPoint(screen_loc_pixels.ToPOINT());
diff --git a/ui/views/controls/menu/menu_model_adapter.cc b/ui/views/controls/menu/menu_model_adapter.cc
index b04fd0b..f18d86f 100644
--- a/ui/views/controls/menu/menu_model_adapter.cc
+++ b/ui/views/controls/menu/menu_model_adapter.cc
@@ -9,7 +9,6 @@
 #include "ui/gfx/image/image.h"
 #include "ui/views/controls/menu/menu_item_view.h"
 #include "ui/views/controls/menu/submenu_view.h"
-#include "ui/views/views_delegate.h"
 
 namespace views {
 
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc
index d75ef1a0..8104a96f 100644
--- a/ui/views/controls/table/table_view.cc
+++ b/ui/views/controls/table/table_view.cc
@@ -235,7 +235,8 @@
   if (!sort.empty() && sort[0].column_id == column_id) {
     sort[0].ascending = !sort[0].ascending;
   } else {
-    SortDescriptor descriptor(column_id, true);
+    SortDescriptor descriptor(column_id, visible_columns_[
+        visible_column_index].column.initial_sort_is_ascending);
     sort.insert(sort.begin(), descriptor);
     // Only persist two sort descriptors.
     if (sort.size() > 2)
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 347de70d..cc2d492 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -284,9 +284,10 @@
   SetBorder(scoped_ptr<Border>(new FocusableBorder()));
   SetFocusable(true);
 
-  if (ViewsDelegate::views_delegate) {
-    password_reveal_duration_ = ViewsDelegate::views_delegate->
-        GetDefaultTextfieldObscuredRevealDuration();
+  if (ViewsDelegate::GetInstance()) {
+    password_reveal_duration_ =
+        ViewsDelegate::GetInstance()
+            ->GetDefaultTextfieldObscuredRevealDuration();
   }
 }
 
diff --git a/ui/views/controls/webview/webview.cc b/ui/views/controls/webview/webview.cc
index a131905..059540a 100644
--- a/ui/views/controls/webview/webview.cc
+++ b/ui/views/controls/webview/webview.cc
@@ -407,9 +407,9 @@
 content::WebContents* WebView::CreateWebContents(
       content::BrowserContext* browser_context) {
   content::WebContents* contents = NULL;
-  if (ViewsDelegate::views_delegate) {
-    contents = ViewsDelegate::views_delegate->CreateWebContents(
-        browser_context, NULL);
+  if (ViewsDelegate::GetInstance()) {
+    contents =
+        ViewsDelegate::GetInstance()->CreateWebContents(browser_context, NULL);
   }
 
   if (!contents) {
diff --git a/ui/views/controls/webview/webview_interactive_uitest.cc b/ui/views/controls/webview/webview_interactive_uitest.cc
index 88aab9f..a15dfaa 100644
--- a/ui/views/controls/webview/webview_interactive_uitest.cc
+++ b/ui/views/controls/webview/webview_interactive_uitest.cc
@@ -44,8 +44,7 @@
 
   void SetUp() override {
     gfx::GLSurface::InitializeOneOffForTests();
-    // The ViewsDelegate is deleted when the ViewsTestBase class is torn down.
-    WidgetTest::set_views_delegate(new WebViewTestViewsDelegate);
+    set_views_delegate(make_scoped_ptr(new WebViewTestViewsDelegate));
     WidgetTest::SetUp();
   }
 
diff --git a/ui/views/controls/webview/webview_unittest.cc b/ui/views/controls/webview/webview_unittest.cc
index 349ad3f..76ef42d6 100644
--- a/ui/views/controls/webview/webview_unittest.cc
+++ b/ui/views/controls/webview/webview_unittest.cc
@@ -129,8 +129,7 @@
   ~WebViewUnitTest() override {}
 
   void SetUp() override {
-    // The ViewsDelegate is deleted when the ViewsTestBase class is torn down.
-    WidgetTest::set_views_delegate(new WebViewTestViewsDelegate);
+    set_views_delegate(make_scoped_ptr(new WebViewTestViewsDelegate));
     browser_context_.reset(new content::TestBrowserContext);
     WidgetTest::SetUp();
     // Set the test content browser client to avoid pulling in needless
@@ -176,7 +175,6 @@
   content::TestBrowserThread file_blocking_thread_;
   content::TestBrowserThread io_thread_;
   scoped_ptr<content::TestBrowserContext> browser_context_;
-  scoped_ptr<WebViewTestViewsDelegate> views_delegate_;
   content::TestContentBrowserClient test_browser_client_;
 
   Widget* top_level_widget_;
diff --git a/ui/views/ime/input_method_bridge.cc b/ui/views/ime/input_method_bridge.cc
index cb7860e..88ceec7d 100644
--- a/ui/views/ime/input_method_bridge.cc
+++ b/ui/views/ime/input_method_bridge.cc
@@ -81,7 +81,8 @@
 }
 
 void InputMethodBridge::OnFocus() {
-  DCHECK(host_);
+  if (!host_)  // |host_| could be NULL after OnInputMethodDestroyed.
+    return;
 
   // Direct the shared IME to send TextInputClient messages to |this| object.
   if (shared_input_method_ || !host_->GetTextInputClient())
@@ -96,7 +97,8 @@
 }
 
 void InputMethodBridge::OnBlur() {
-  DCHECK(host_);
+  if (!host_)  // |host_| could be NULL after OnInputMethodDestroyed.
+    return;
 
   if (HasCompositionText()) {
     ConfirmCompositionText();
diff --git a/ui/views/ime/input_method_bridge_unittest.cc b/ui/views/ime/input_method_bridge_unittest.cc
index 64144cf4..5102645 100644
--- a/ui/views/ime/input_method_bridge_unittest.cc
+++ b/ui/views/ime/input_method_bridge_unittest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/base/ime/dummy_input_method_delegate.h"
 #include "ui/base/ime/input_method_minimal.h"
@@ -21,9 +20,6 @@
   ui::internal::DummyInputMethodDelegate input_method_delegate;
   ui::InputMethodMinimal input_method(&input_method_delegate);
 
-  GetContext()->SetProperty(aura::client::kRootWindowInputMethodKey,
-                            static_cast<ui::InputMethod*>(&input_method));
-
   Widget* toplevel = new Widget;
   Widget::InitParams toplevel_params =
       CreateParams(Widget::InitParams::TYPE_WINDOW);
@@ -42,9 +38,6 @@
   child->GetInputMethod()->OnFocus();
 
   toplevel->CloseNow();
-
-  GetContext()->SetProperty(aura::client::kRootWindowInputMethodKey,
-                            static_cast<ui::InputMethod*>(NULL));
 }
 
 }  // namespace views
diff --git a/ui/views/test/event_generator_delegate_mac.mm b/ui/views/test/event_generator_delegate_mac.mm
index 5bd4537b..4e4a32b 100644
--- a/ui/views/test/event_generator_delegate_mac.mm
+++ b/ui/views/test/event_generator_delegate_mac.mm
@@ -236,7 +236,7 @@
 
   // Overridden from ui::EventTarget:
   bool CanAcceptEvent(const ui::Event& event) override { return true; }
-  ui::EventTarget* GetParentTarget() override { return NULL; }
+  ui::EventTarget* GetParentTarget() override { return nullptr; }
   scoped_ptr<ui::EventTargetIterator> GetChildIterator() const override;
   ui::EventTargeter* GetEventTargeter() override { return this; }
 
@@ -254,6 +254,16 @@
   // Overridden from ui::EventDispatcherDelegate (via ui::EventProcessor):
   bool CanDispatchToTarget(EventTarget* target) override { return true; }
 
+  // Overridden from ui::EventTargeter:
+  ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
+                                      ui::Event* event) override {
+    return root;
+  }
+  ui::EventTarget* FindNextBestTarget(ui::EventTarget* previous_target,
+                                      ui::Event* event) override {
+    return nullptr;
+  }
+
   // Overridden from ui::test::EventGeneratorDelegate:
   void SetContext(ui::test::EventGenerator* owner,
                   gfx::NativeWindow root_window,
@@ -290,7 +300,7 @@
   DISALLOW_COPY_AND_ASSIGN(EventGeneratorDelegateMac);
 };
 
-EventGeneratorDelegateMac::EventGeneratorDelegateMac() : owner_(NULL) {
+EventGeneratorDelegateMac::EventGeneratorDelegateMac() : owner_(nullptr) {
   DCHECK(!ui::test::EventGenerator::default_delegate);
   ui::test::EventGenerator::default_delegate = this;
   // Install a fake "edit" menu. This is normally provided by Chrome's
@@ -318,12 +328,12 @@
 
 EventGeneratorDelegateMac::~EventGeneratorDelegateMac() {
   DCHECK_EQ(this, ui::test::EventGenerator::default_delegate);
-  ui::test::EventGenerator::default_delegate = NULL;
+  ui::test::EventGenerator::default_delegate = nullptr;
 }
 
 scoped_ptr<ui::EventTargetIterator>
 EventGeneratorDelegateMac::GetChildIterator() const {
-  // Return NULL to dispatch all events to the result of GetRootTarget().
+  // Return nullptr to dispatch all events to the result of GetRootTarget().
   return nullptr;
 }
 
diff --git a/ui/views/test/test_views_delegate_aura.cc b/ui/views/test/test_views_delegate_aura.cc
index a6329762b..ccd2bb2a 100644
--- a/ui/views/test/test_views_delegate_aura.cc
+++ b/ui/views/test/test_views_delegate_aura.cc
@@ -18,16 +18,12 @@
     : context_factory_(nullptr),
       use_desktop_native_widgets_(false),
       use_transparent_windows_(false) {
-  DCHECK(!ViewsDelegate::views_delegate);
-  ViewsDelegate::views_delegate = this;
 #if defined(USE_AURA)
   wm_state_.reset(new wm::WMState);
 #endif
 }
 
 TestViewsDelegate::~TestViewsDelegate() {
-  if (ViewsDelegate::views_delegate == this)
-    ViewsDelegate::views_delegate = NULL;
 }
 
 #if defined(OS_WIN)
diff --git a/ui/views/test/test_views_delegate_mac.mm b/ui/views/test/test_views_delegate_mac.mm
index 5d3c352c..652c397 100644
--- a/ui/views/test/test_views_delegate_mac.mm
+++ b/ui/views/test/test_views_delegate_mac.mm
@@ -12,13 +12,9 @@
     : context_factory_(nullptr),
       use_desktop_native_widgets_(false),
       use_transparent_windows_(false) {
-  DCHECK(!ViewsDelegate::views_delegate);
-  ViewsDelegate::views_delegate = this;
 }
 
 TestViewsDelegate::~TestViewsDelegate() {
-  if (ViewsDelegate::views_delegate == this)
-    ViewsDelegate::views_delegate = NULL;
 }
 
 void TestViewsDelegate::OnBeforeWidgetInit(
diff --git a/ui/views/test/views_test_base.cc b/ui/views/test/views_test_base.cc
index e508fd720..784ce2e 100644
--- a/ui/views/test/views_test_base.cc
+++ b/ui/views/test/views_test_base.cc
@@ -27,7 +27,7 @@
 void ViewsTestBase::SetUp() {
   testing::Test::SetUp();
   setup_called_ = true;
-  if (!views_delegate_.get())
+  if (!views_delegate_)
     views_delegate_.reset(new TestViewsDelegate());
 
   // The ContextFactory must exist before any Compositors are created.
@@ -53,6 +53,8 @@
   ui::ShutdownInputMethodForTesting();
   test_helper_->TearDown();
   ui::TerminateContextFactoryForTests();
+
+  views_delegate_.reset();
 }
 
 void ViewsTestBase::RunPendingMessages() {
diff --git a/ui/views/test/views_test_base.h b/ui/views/test/views_test_base.h
index 933f60c..17352eb 100644
--- a/ui/views/test/views_test_base.h
+++ b/ui/views/test/views_test_base.h
@@ -10,6 +10,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "ui/views/test/test_views_delegate.h"
+#include "ui/views/widget/widget.h"
 
 #if defined(OS_WIN)
 #include "ui/base/win/scoped_ole_initializer.h"
@@ -37,10 +38,10 @@
   Widget::InitParams CreateParams(Widget::InitParams::Type type);
 
  protected:
-  TestViewsDelegate& views_delegate() const { return *views_delegate_.get(); }
+  TestViewsDelegate* views_delegate() const { return views_delegate_.get(); }
 
-  void set_views_delegate(TestViewsDelegate* views_delegate) {
-    views_delegate_.reset(views_delegate);
+  void set_views_delegate(scoped_ptr<TestViewsDelegate> views_delegate) {
+    views_delegate_.swap(views_delegate);
   }
 
   base::MessageLoopForUI* message_loop() { return &message_loop_; }
diff --git a/ui/views/test/widget_test_aura.cc b/ui/views/test/widget_test_aura.cc
index 778f1f0c..1bc08c02 100644
--- a/ui/views/test/widget_test_aura.cc
+++ b/ui/views/test/widget_test_aura.cc
@@ -88,6 +88,7 @@
   return gfx::Size(hints.min_width, hints.min_height);
 #else
   NOTREACHED();
+  return gfx::Size();
 #endif
 }
 
diff --git a/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc b/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc
index ab1a88f..b5adfb3 100644
--- a/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc
+++ b/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc
@@ -6,7 +6,6 @@
 #include "ui/touch_selection/touch_selection_menu_runner.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/touchui/touch_selection_menu_runner_views.h"
-#include "ui/views/views_delegate.h"
 
 namespace views {
 namespace {
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 0b6efdf1..8dded15 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -83,9 +83,6 @@
 }  // namespace
 
 // static
-ViewsDelegate* ViewsDelegate::views_delegate = NULL;
-
-// static
 const char View::kViewClassName[] = "View";
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -737,6 +734,8 @@
 void View::Paint(const ui::PaintContext& parent_context) {
   if (!visible_)
     return;
+  if (size().IsEmpty())
+    return;
 
   gfx::Vector2d offset_to_parent;
   if (!layer()) {
@@ -1283,8 +1282,8 @@
 void View::NotifyAccessibilityEvent(
     ui::AXEvent event_type,
     bool send_native_event) {
-  if (ViewsDelegate::views_delegate)
-    ViewsDelegate::views_delegate->NotifyAccessibilityEvent(this, event_type);
+  if (ViewsDelegate::GetInstance())
+    ViewsDelegate::GetInstance()->NotifyAccessibilityEvent(this, event_type);
 
   if (send_native_event && GetWidget()) {
     if (!native_view_accessibility_)
diff --git a/ui/views/view_targeter.cc b/ui/views/view_targeter.cc
index 3c5af01..5e52ce9 100644
--- a/ui/views/view_targeter.cc
+++ b/ui/views/view_targeter.cc
@@ -67,20 +67,6 @@
   return previous_target->GetParentTarget();
 }
 
-bool ViewTargeter::SubtreeCanAcceptEvent(
-    ui::EventTarget* target,
-    const ui::LocatedEvent& event) const {
-  NOTREACHED();
-  return false;
-}
-
-bool ViewTargeter::EventLocationInsideBounds(
-    ui::EventTarget* target,
-    const ui::LocatedEvent& event) const {
-  NOTREACHED();
-  return false;
-}
-
 View* ViewTargeter::FindTargetForKeyEvent(View* root, const ui::KeyEvent& key) {
   if (root->GetFocusManager())
     return root->GetFocusManager()->GetFocusedView();
diff --git a/ui/views/view_targeter.h b/ui/views/view_targeter.h
index db52e66..3e460ca 100644
--- a/ui/views/view_targeter.h
+++ b/ui/views/view_targeter.h
@@ -5,9 +5,20 @@
 #ifndef UI_VIEWS_VIEW_TARGETER_H_
 #define UI_VIEWS_VIEW_TARGETER_H_
 
+#include "base/macros.h"
 #include "ui/events/event_targeter.h"
 #include "ui/views/views_export.h"
 
+namespace gfx {
+class Rect;
+}  // namespace gfx
+
+namespace ui {
+class GestureEvent;
+class KeyEvent;
+class ScrollEvent;
+}  // namespace ui
+
 namespace views {
 
 namespace internal {
@@ -36,10 +47,6 @@
                                       ui::Event* event) override;
   ui::EventTarget* FindNextBestTarget(ui::EventTarget* previous_target,
                                       ui::Event* event) override;
-  bool SubtreeCanAcceptEvent(ui::EventTarget* target,
-                             const ui::LocatedEvent& event) const override;
-  bool EventLocationInsideBounds(ui::EventTarget* target,
-                                 const ui::LocatedEvent& event) const override;
 
  private:
   View* FindTargetForKeyEvent(View* root, const ui::KeyEvent& key);
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
index 1a103b73..2bc5f39 100644
--- a/ui/views/view_unittest.cc
+++ b/ui/views/view_unittest.cc
@@ -33,7 +33,6 @@
 #include "ui/views/focus/view_storage.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/view.h"
-#include "ui/views/views_delegate.h"
 #include "ui/views/widget/native_widget.h"
 #include "ui/views/widget/root_view.h"
 #include "ui/views/window/dialog_client_view.h"
@@ -432,6 +431,41 @@
   did_paint_ = true;
 }
 
+TEST_F(ViewTest, PaintEmptyView) {
+  Widget* widget = new Widget;
+  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+  widget->Init(params);
+  View* root_view = widget->GetRootView();
+  root_view->SetBounds(0, 0, 25, 26);
+
+  // |v1| is empty.
+  TestView* v1 = new TestView;
+  v1->SetBounds(10, 11, 0, 1);
+  root_view->AddChildView(v1);
+
+  // |v11| is a child of an empty |v1|.
+  TestView* v11 = new TestView;
+  v11->SetBounds(3, 4, 6, 5);
+  v1->AddChildView(v11);
+
+  // |v2| is not.
+  TestView* v2 = new TestView;
+  v2->SetBounds(3, 4, 6, 5);
+  root_view->AddChildView(v2);
+
+  // Paint "everything".
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+
+  // The empty view has nothing to paint so it doesn't try build a cache, nor do
+  // its children which would be clipped by its (empty) self.
+  EXPECT_FALSE(v1->did_paint_);
+  EXPECT_FALSE(v11->did_paint_);
+  EXPECT_TRUE(v2->did_paint_);
+}
+
 TEST_F(ViewTest, PaintWithUnknownInvalidation) {
   Widget* widget = new Widget;
   Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
diff --git a/ui/views/views_delegate.cc b/ui/views/views_delegate.cc
index 507b038..a676ae1 100644
--- a/ui/views/views_delegate.cc
+++ b/ui/views/views_delegate.cc
@@ -12,18 +12,21 @@
 #endif
 
 namespace views {
+namespace {
 
-ViewsDelegate::ViewsDelegate()
-    : views_tsc_factory_(new ViewsTouchEditingControllerFactory) {
-  ui::TouchEditingControllerFactory::SetInstance(views_tsc_factory_.get());
+ViewsDelegate* views_delegate = nullptr;
 
-#if defined(USE_AURA)
-  touch_selection_menu_runner_.reset(new TouchSelectionMenuRunnerViews());
-#endif
 }
 
 ViewsDelegate::~ViewsDelegate() {
-  ui::TouchEditingControllerFactory::SetInstance(NULL);
+  ui::TouchEditingControllerFactory::SetInstance(nullptr);
+
+  DCHECK_EQ(this, views_delegate);
+  views_delegate = nullptr;
+}
+
+ViewsDelegate* ViewsDelegate::GetInstance() {
+  return views_delegate;
 }
 
 void ViewsDelegate::SaveWindowPlacement(const Widget* widget,
@@ -53,7 +56,7 @@
 
 #if defined(OS_WIN)
 HICON ViewsDelegate::GetDefaultWindowIcon() const {
-  return NULL;
+  return nullptr;
 }
 
 bool ViewsDelegate::IsWindowInMetro(gfx::NativeWindow window) const {
@@ -61,13 +64,13 @@
 }
 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
 gfx::ImageSkia* ViewsDelegate::GetDefaultWindowIcon() const {
-  return NULL;
+  return nullptr;
 }
 #endif
 
 NonClientFrameView* ViewsDelegate::CreateDefaultNonClientFrameView(
     Widget* widget) {
-  return NULL;
+  return nullptr;
 }
 
 void ViewsDelegate::AddRef() {
@@ -79,7 +82,7 @@
 content::WebContents* ViewsDelegate::CreateWebContents(
     content::BrowserContext* browser_context,
     content::SiteInstance* site_instance) {
-  return NULL;
+  return nullptr;
 }
 
 base::TimeDelta ViewsDelegate::GetDefaultTextfieldObscuredRevealDuration() {
@@ -91,7 +94,7 @@
 }
 
 ui::ContextFactory* ViewsDelegate::GetContextFactory() {
-  return NULL;
+  return nullptr;
 }
 
 std::string ViewsDelegate::GetApplicationName() {
@@ -110,4 +113,16 @@
   return nullptr;
 }
 
+ViewsDelegate::ViewsDelegate()
+    : views_tsc_factory_(new ViewsTouchEditingControllerFactory) {
+  DCHECK(!views_delegate);
+  views_delegate = this;
+
+  ui::TouchEditingControllerFactory::SetInstance(views_tsc_factory_.get());
+
+#if defined(USE_AURA)
+  touch_selection_menu_runner_.reset(new TouchSelectionMenuRunnerViews());
+#endif
+}
+
 }  // namespace views
diff --git a/ui/views/views_delegate.h b/ui/views/views_delegate.h
index 39c7f5a5..e2f33b0 100644
--- a/ui/views/views_delegate.h
+++ b/ui/views/views_delegate.h
@@ -60,8 +60,8 @@
 // framework. It is used to obtain various high level application utilities
 // and perform some actions such as window placement saving.
 //
-// The embedding app must set views_delegate to assign its ViewsDelegate
-// implementation.
+// The embedding app must set the ViewsDelegate instance by instantiating an
+// implementation of ViewsDelegate (the constructor will set the instance).
 class VIEWS_EXPORT ViewsDelegate {
  public:
 #if defined(OS_WIN)
@@ -73,9 +73,11 @@
   };
 #endif
 
-  ViewsDelegate();
   virtual ~ViewsDelegate();
 
+  // Returns the ViewsDelegate instance if there is one, or nullptr otherwise.
+  static ViewsDelegate* GetInstance();
+
   // Saves the position, size and "show" state for the window with the
   // specified name.
   virtual void SaveWindowPlacement(const Widget* widget,
@@ -160,8 +162,8 @@
   // Returns a blocking pool task runner given a TaskRunnerType.
   virtual scoped_refptr<base::TaskRunner> GetBlockingPoolTaskRunner();
 
-  // The active ViewsDelegate used by the views system.
-  static ViewsDelegate* views_delegate;
+ protected:
+  ViewsDelegate();
 
  private:
   scoped_ptr<ViewsTouchEditingControllerFactory> views_tsc_factory_;
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index 33629f9a..0d009776 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -51,7 +51,6 @@
 #include "ui/wm/core/compound_event_filter.h"
 #include "ui/wm/core/cursor_manager.h"
 #include "ui/wm/core/focus_controller.h"
-#include "ui/wm/core/input_method_event_filter.h"
 #include "ui/wm/core/native_cursor_manager.h"
 #include "ui/wm/core/shadow_controller.h"
 #include "ui/wm/core/shadow_types.h"
@@ -310,8 +309,6 @@
     tooltip_controller_.reset();
   }
 
-  root_window_event_filter_->RemoveHandler(input_method_event_filter_.get());
-
   window_tree_client_.reset();  // Uses host_->dispatcher() at destruction.
 
   capture_client_.reset();  // Uses host_->dispatcher() at destruction.
@@ -326,7 +323,7 @@
   focus_client_.reset();
 
   host_->RemoveObserver(this);
-  host_.reset();  // Uses input_method_event_filter_ at destruction.
+  host_.reset();
   // WindowEventDispatcher owns |desktop_window_tree_host_|.
   desktop_window_tree_host_ = NULL;
   content_window_ = NULL;
@@ -486,8 +483,6 @@
 
   position_client_.reset(new DesktopScreenPositionClient(host_->window()));
 
-  InstallInputMethodEventFilter();
-
   drag_drop_client_ = desktop_window_tree_host_->CreateDragDropClient(
       native_cursor_manager_);
   aura::client::SetDragDropClient(host_->window(),
@@ -637,8 +632,7 @@
   if (switches::IsTextInputFocusManagerEnabled())
     return new NullInputMethod();
 
-  ui::InputMethod* host = input_method_event_filter_->input_method();
-  return new InputMethodBridge(this, host, false);
+  return new InputMethodBridge(this, GetHostInputMethod(), false);
 }
 
 internal::InputMethodDelegate*
@@ -647,7 +641,7 @@
 }
 
 ui::InputMethod* DesktopNativeWidgetAura::GetHostInputMethod() {
-  return input_method_event_filter_->input_method();
+  return host()->GetInputMethod();
 }
 
 void DesktopNativeWidgetAura::CenterWindow(const gfx::Size& size) {
@@ -720,6 +714,8 @@
 }
 
 void DesktopNativeWidgetAura::StackAbove(gfx::NativeView native_view) {
+  if (content_window_)
+    desktop_window_tree_host_->StackAbove(native_view);
 }
 
 void DesktopNativeWidgetAura::StackAtTop() {
@@ -1223,16 +1219,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopNativeWidgetAura, private:
 
-void DesktopNativeWidgetAura::InstallInputMethodEventFilter() {
-  DCHECK(!input_method_event_filter_.get());
-
-  input_method_event_filter_.reset(new wm::InputMethodEventFilter(
-      host_->GetAcceleratedWidget()));
-  input_method_event_filter_->SetInputMethodPropertyInRootWindow(
-      host_->window());
-  root_window_event_filter_->AddHandler(input_method_event_filter_.get());
-}
-
 void DesktopNativeWidgetAura::UpdateWindowTransparency() {
   content_window_->SetTransparent(
       desktop_window_tree_host_->ShouldWindowContentsBeTransparent());
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index 0419fab..88ae74a 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -79,9 +79,6 @@
   // as by the time we get here |dispatcher_| is NULL.
   virtual void OnDesktopWindowTreeHostDestroyed(aura::WindowTreeHost* host);
 
-  wm::InputMethodEventFilter* input_method_event_filter() {
-    return input_method_event_filter_.get();
-  }
   wm::CompoundEventFilter* root_window_event_filter() {
     return root_window_event_filter_.get();
   }
@@ -241,9 +238,6 @@
   friend class FocusManagerEventHandler;
   friend class RootWindowDestructionObserver;
 
-  // Installs the input method filter.
-  void InstallInputMethodEventFilter();
-
   // To save a clear on platforms where the window is never transparent, the
   // window is only set as transparent when the glass frame is in use.
   void UpdateWindowTransparency();
@@ -279,8 +273,6 @@
   // Toplevel event filter which dispatches to other event filters.
   scoped_ptr<wm::CompoundEventFilter> root_window_event_filter_;
 
-  scoped_ptr<wm::InputMethodEventFilter> input_method_event_filter_;
-
   scoped_ptr<DropHelper> drop_helper_;
   int last_drop_operation_;
 
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
index 9a626d69..a9445f57 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
@@ -16,6 +16,7 @@
 #include "ui/events/test/event_generator.h"
 #include "ui/gfx/screen.h"
 #include "ui/views/test/test_views.h"
+#include "ui/views/test/test_views_delegate.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/test/widget_test.h"
 #include "ui/views/widget/widget.h"
@@ -364,7 +365,7 @@
 typedef WidgetTest DesktopAuraWidgetTest;
 
 TEST_F(DesktopAuraWidgetTest, FullscreenWindowDestroyedBeforeOwnerTest) {
-  ViewsDelegate::views_delegate = NULL;
+  set_views_delegate(nullptr);
   DesktopAuraTopLevelWindowTest fullscreen_window;
   ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow(
       gfx::Rect(0, 0, 200, 200), true));
@@ -375,7 +376,7 @@
 }
 
 TEST_F(DesktopAuraWidgetTest, FullscreenWindowOwnerDestroyed) {
-  ViewsDelegate::views_delegate = NULL;
+  set_views_delegate(nullptr);
 
   DesktopAuraTopLevelWindowTest fullscreen_window;
   ASSERT_NO_FATAL_FAILURE(fullscreen_window.CreateTopLevelWindow(
@@ -387,7 +388,7 @@
 }
 
 TEST_F(DesktopAuraWidgetTest, TopLevelOwnedPopupTest) {
-  ViewsDelegate::views_delegate = NULL;
+  set_views_delegate(nullptr);
   DesktopAuraTopLevelWindowTest popup_window;
   ASSERT_NO_FATAL_FAILURE(popup_window.CreateTopLevelWindow(
       gfx::Rect(0, 0, 200, 200), false));
@@ -400,7 +401,7 @@
 // This test validates that when a top level owned popup Aura window is
 // resized, the widget is resized as well.
 TEST_F(DesktopAuraWidgetTest, TopLevelOwnedPopupResizeTest) {
-  ViewsDelegate::views_delegate = NULL;
+  set_views_delegate(nullptr);
   DesktopAuraTopLevelWindowTest popup_window;
 
   popup_window.set_use_async_mode(false);
@@ -420,7 +421,7 @@
 // This test validates that when a top level owned popup Aura window is
 // repositioned, the widget is repositioned as well.
 TEST_F(DesktopAuraWidgetTest, TopLevelOwnedPopupRepositionTest) {
-  ViewsDelegate::views_delegate = NULL;
+  set_views_delegate(nullptr);
   DesktopAuraTopLevelWindowTest popup_window;
 
   popup_window.set_use_async_mode(false);
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host.h b/ui/views/widget/desktop_aura/desktop_window_tree_host.h
index dc31d7d..99e1c07 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host.h
@@ -81,6 +81,7 @@
   virtual bool IsVisible() const = 0;
 
   virtual void SetSize(const gfx::Size& size) = 0;
+  virtual void StackAbove(aura::Window* window) = 0;
   virtual void StackAtTop() = 0;
   virtual void CenterWindow(const gfx::Size& size) = 0;
   virtual void GetWindowPlacement(gfx::Rect* bounds,
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index a663f38..181155b 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -36,8 +36,8 @@
 #include "ui/views/widget/widget_hwnd_utils.h"
 #include "ui/views/win/fullscreen_handler.h"
 #include "ui/views/win/hwnd_message_handler.h"
+#include "ui/views/win/hwnd_util.h"
 #include "ui/wm/core/compound_event_filter.h"
-#include "ui/wm/core/input_method_event_filter.h"
 #include "ui/wm/core/window_animations.h"
 #include "ui/wm/public/scoped_tooltip_disabler.h"
 
@@ -234,6 +234,12 @@
   message_handler_->SetSize(expanded);
 }
 
+void DesktopWindowTreeHostWin::StackAbove(aura::Window* window) {
+  HWND hwnd = HWNDForNativeView(window);
+  if (hwnd)
+    message_handler_->StackAbove(hwnd);
+}
+
 void DesktopWindowTreeHostWin::StackAtTop() {
   message_handler_->StackAtTop();
 }
@@ -560,13 +566,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// DesktopWindowTreeHostWin, ui::EventSource implementation:
-
-ui::EventProcessor* DesktopWindowTreeHostWin::GetEventProcessor() {
-  return dispatcher();
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // DesktopWindowTreeHostWin, aura::AnimationHost implementation:
 
 void DesktopWindowTreeHostWin::SetHostTransitionOffsets(
@@ -682,10 +681,6 @@
   return GetWidget()->GetRootView()->GetNativeViewAccessible();
 }
 
-InputMethod* DesktopWindowTreeHostWin::GetInputMethod() {
-  return GetWidget()->GetInputMethodDirect();
-}
-
 bool DesktopWindowTreeHostWin::ShouldHandleSystemCommands() const {
   return GetWidget()->widget_delegate()->ShouldHandleSystemCommands();
 }
@@ -859,15 +854,13 @@
   msg.message = message;
   msg.wParam = w_param;
   msg.lParam = l_param;
-  return desktop_native_widget_aura_->input_method_event_filter()->
-      input_method()->OnUntranslatedIMEMessage(msg, result);
+  return GetInputMethod()->OnUntranslatedIMEMessage(msg, result);
 }
 
 void DesktopWindowTreeHostWin::HandleInputLanguageChange(
     DWORD character_set,
     HKL input_language_id) {
-  desktop_native_widget_aura_->input_method_event_filter()->
-      input_method()->OnInputLocaleChanged();
+  GetInputMethod()->OnInputLocaleChanged();
 }
 
 void DesktopWindowTreeHostWin::HandlePaintAccelerated(
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
index 413c0c13..4ef0c31 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
@@ -32,7 +32,6 @@
     : public DesktopWindowTreeHost,
       public aura::client::AnimationHost,
       public aura::WindowTreeHost,
-      public ui::EventSource,
       public HWNDMessageHandlerDelegate {
  public:
   DesktopWindowTreeHostWin(
@@ -58,6 +57,7 @@
   void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) override;
   bool IsVisible() const override;
   void SetSize(const gfx::Size& size) override;
+  void StackAbove(aura::Window* window) override;
   void StackAtTop() override;
   void CenterWindow(const gfx::Size& size) override;
   void GetWindowPlacement(gfx::Rect* bounds,
@@ -118,9 +118,6 @@
   void OnCursorVisibilityChangedNative(bool show) override;
   void MoveCursorToNative(const gfx::Point& location) override;
 
-  // Overridden frm ui::EventSource
-  ui::EventProcessor* GetEventProcessor() override;
-
   // Overridden from aura::client::AnimationHost
   void SetHostTransitionOffsets(
       const gfx::Vector2d& top_left_delta,
@@ -149,7 +146,6 @@
   void ResetWindowControls() override;
   gfx::NativeViewAccessible GetNativeViewAccessible() override;
   bool ShouldHandleSystemCommands() const override;
-  InputMethod* GetInputMethod() override;
   void HandleAppDeactivated() override;
   void HandleActivationChanged(bool active) override;
   bool HandleAppCommand(short command) override;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 4a8f64cf..26c9491 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -128,6 +128,25 @@
 const char kX11WindowRolePopup[] = "popup";
 const char kX11WindowRoleBubble[] = "bubble";
 
+// Returns the whole path from |window| to the root.
+std::vector<::Window> GetParentsList(XDisplay* xdisplay, ::Window window) {
+  ::Window parent_win, root_win;
+  Window* child_windows;
+  unsigned int num_child_windows;
+  std::vector<::Window> result;
+
+  while (window) {
+    result.push_back(window);
+    if (!XQueryTree(xdisplay, window,
+                    &root_win, &parent_win, &child_windows, &num_child_windows))
+      break;
+    if (child_windows)
+      XFree(child_windows);
+    window = parent_win;
+  }
+  return result;
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -415,6 +434,37 @@
   }
 }
 
+void DesktopWindowTreeHostX11::StackAbove(aura::Window* window) {
+  if (window && window->GetRootWindow()) {
+    ::Window window_below = window->GetHost()->GetAcceleratedWidget();
+    // Find all parent windows up to the root.
+    std::vector<::Window> window_below_parents =
+        GetParentsList(xdisplay_, window_below);
+    std::vector<::Window> window_above_parents =
+        GetParentsList(xdisplay_, xwindow_);
+
+    // Find their common ancestor.
+    auto it_below_window = window_below_parents.rbegin();
+    auto it_above_window = window_above_parents.rbegin();
+    for (; it_below_window != window_below_parents.rend() &&
+           it_above_window != window_above_parents.rend() &&
+           *it_below_window == *it_above_window;
+         ++it_below_window, ++it_above_window) {
+    }
+
+    if (it_below_window != window_below_parents.rend() &&
+        it_above_window != window_above_parents.rend()) {
+      // First stack |xwindow_| below so Z-order of |window| stays the same.
+      ::Window windows[] = {*it_below_window, *it_above_window};
+      if (XRestackWindows(xdisplay_, windows, 2) == 0) {
+        // Now stack them properly.
+        std::swap(windows[0], windows[1]);
+        XRestackWindows(xdisplay_, windows, 2);
+      }
+    }
+  }
+}
+
 void DesktopWindowTreeHostX11::StackAtTop() {
   XRaiseWindow(xdisplay_, xwindow_);
 }
@@ -1015,13 +1065,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// DesktopWindowTreeHostX11, ui::EventSource implementation:
-
-ui::EventProcessor* DesktopWindowTreeHostX11::GetEventProcessor() {
-  return dispatcher();
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // DesktopWindowTreeHostX11, private:
 
 void DesktopWindowTreeHostX11::InitX11Window(
@@ -1218,8 +1261,10 @@
 
   // If we have a delegate which is providing a default window icon, use that
   // icon.
-  gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
-      ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
+  gfx::ImageSkia* window_icon =
+      ViewsDelegate::GetInstance()
+          ? ViewsDelegate::GetInstance()->GetDefaultWindowIcon()
+          : NULL;
   if (window_icon) {
     SetWindowIcons(gfx::ImageSkia(), *window_icon);
   }
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index e2fd61f..f1d86f90 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -15,7 +15,6 @@
 #include "base/observer_list.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/cursor/cursor_loader_x11.h"
-#include "ui/events/event_source.h"
 #include "ui/events/platform/platform_event_dispatcher.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
@@ -43,7 +42,6 @@
 class VIEWS_EXPORT DesktopWindowTreeHostX11
     : public DesktopWindowTreeHost,
       public aura::WindowTreeHost,
-      public ui::EventSource,
       public ui::PlatformEventDispatcher {
  public:
   DesktopWindowTreeHostX11(
@@ -101,6 +99,7 @@
   void ShowMaximizedWithBounds(const gfx::Rect& restored_bounds) override;
   bool IsVisible() const override;
   void SetSize(const gfx::Size& requested_size) override;
+  void StackAbove(aura::Window* window) override;
   void StackAtTop() override;
   void CenterWindow(const gfx::Size& size) override;
   void GetWindowPlacement(gfx::Rect* bounds,
@@ -162,9 +161,6 @@
   void MoveCursorToNative(const gfx::Point& location) override;
   void OnCursorVisibilityChangedNative(bool show) override;
 
-  // Overridden frm ui::EventSource
-  ui::EventProcessor* GetEventProcessor() override;
-
  private:
   friend class DesktopWindowTreeHostX11HighDPITest;
   // Initializes our X11 surface to draw on. This method performs all
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index 92ff22ac..9c19540 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -16,6 +16,7 @@
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_observer.h"
+#include "ui/aura/window_tree_host.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/ui_base_switches_util.h"
 #include "ui/base/ui_base_types.h"
@@ -28,7 +29,6 @@
 #include "ui/views/drag_utils.h"
 #include "ui/views/ime/input_method_bridge.h"
 #include "ui/views/ime/null_input_method.h"
-#include "ui/views/views_delegate.h"
 #include "ui/views/widget/drop_helper.h"
 #include "ui/views/widget/native_widget_delegate.h"
 #include "ui/views/widget/root_view.h"
@@ -274,10 +274,7 @@
   if (switches::IsTextInputFocusManagerEnabled())
     return new NullInputMethod();
 
-  aura::Window* root_window = window_->GetRootWindow();
-  ui::InputMethod* host =
-      root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
-  return new InputMethodBridge(this, host, true);
+  return new InputMethodBridge(this, GetHostInputMethod(), true);
 }
 
 internal::InputMethodDelegate* NativeWidgetAura::GetInputMethodDelegate() {
@@ -286,7 +283,7 @@
 
 ui::InputMethod* NativeWidgetAura::GetHostInputMethod() {
   aura::Window* root_window = window_->GetRootWindow();
-  return root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
+  return root_window->GetHost()->GetInputMethod();
 }
 
 void NativeWidgetAura::CenterWindow(const gfx::Size& size) {
@@ -705,7 +702,7 @@
 }
 
 ui::NativeTheme* NativeWidgetAura::GetNativeTheme() const {
-#if !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
   return DesktopWindowTreeHost::GetNativeTheme(window_);
 #else
   return ui::NativeThemeAura::instance();
diff --git a/ui/views/widget/native_widget_mac.h b/ui/views/widget/native_widget_mac.h
index c09e8e5..2fd3bbc 100644
--- a/ui/views/widget/native_widget_mac.h
+++ b/ui/views/widget/native_widget_mac.h
@@ -10,6 +10,7 @@
 
 namespace views {
 namespace test {
+class HitTestNativeWidgetMac;
 class MockNativeWidgetMac;
 }
 
@@ -132,6 +133,7 @@
 
  private:
   friend class test::MockNativeWidgetMac;
+  friend class test::HitTestNativeWidgetMac;
 
   internal::NativeWidgetDelegate* delegate_;
   scoped_ptr<BridgedNativeWidget> bridge_;
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index 8a96379..7290fd13 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -44,7 +44,8 @@
 
   if (params.type == Widget::InitParams::TYPE_WINDOW) {
     return NSTitledWindowMask | NSClosableWindowMask |
-           NSMiniaturizableWindowMask | NSResizableWindowMask;
+           NSMiniaturizableWindowMask | NSResizableWindowMask |
+           NSTexturedBackgroundWindowMask;
   }
   return NSBorderlessWindowMask;
 }
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm
index 5434e93..05fd824 100644
--- a/ui/views/widget/native_widget_mac_unittest.mm
+++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -409,12 +409,16 @@
 TEST_F(NativeWidgetMacTest, NonWidgetParent) {
   NSWindow* native_parent = MakeNativeParent();
 
+  base::scoped_nsobject<NSView> anchor_view(
+      [[NSView alloc] initWithFrame:[[native_parent contentView] bounds]]);
+  [[native_parent contentView] addSubview:anchor_view];
+
   // Note: Don't use WidgetTest::CreateChildPlatformWidget because that makes
   // windows of TYPE_CONTROL which are automatically made visible. But still
   // mark it as a child to test window positioning.
   Widget* child = new Widget;
   Widget::InitParams init_params;
-  init_params.parent = [native_parent contentView];
+  init_params.parent = anchor_view;
   init_params.child = true;
   child->Init(init_params);
 
@@ -444,11 +448,17 @@
   EXPECT_EQ(native_parent, [child->GetNativeWindow() parentWindow]);
 
   // Child should be positioned on screen relative to the parent, but note we
-  // positioned the parent in Cooca coordinates, so we need to convert.
+  // positioned the parent in Cocoa coordinates, so we need to convert.
   gfx::Point parent_origin = gfx::ScreenRectFromNSRect(ParentRect()).origin();
   EXPECT_EQ(gfx::Rect(150, parent_origin.y() + 50, 200, 100),
             child->GetWindowBoundsInScreen());
 
+  // Removing the anchor_view from its view hierarchy is permitted. This should
+  // not break the relationship between the two windows.
+  [anchor_view removeFromSuperview];
+  anchor_view.reset();
+  EXPECT_EQ(native_parent, bridged_native_widget->parent()->GetNSWindow());
+
   // Closing the parent should close and destroy the child.
   EXPECT_FALSE(child_observer.widget_closed());
   [native_parent close];
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index b4d2a48..0b4e247 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -314,8 +314,8 @@
       params.type != views::Widget::InitParams::TYPE_PANEL)
     params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
 
-  if (ViewsDelegate::views_delegate)
-    ViewsDelegate::views_delegate->OnBeforeWidgetInit(&params, this);
+  if (ViewsDelegate::GetInstance())
+    ViewsDelegate::GetInstance()->OnBeforeWidgetInit(&params, this);
 
   if (params.opacity == views::Widget::InitParams::INFER_OPACITY)
     params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
@@ -895,9 +895,9 @@
       widget_delegate_->CreateNonClientFrameView(this);
   if (!frame_view)
     frame_view = native_widget_->CreateNonClientFrameView();
-  if (!frame_view && ViewsDelegate::views_delegate) {
+  if (!frame_view && ViewsDelegate::GetInstance()) {
     frame_view =
-        ViewsDelegate::views_delegate->CreateDefaultNonClientFrameView(this);
+        ViewsDelegate::GetInstance()->CreateDefaultNonClientFrameView(this);
   }
   if (frame_view)
     return frame_view;
diff --git a/ui/views/widget/widget_delegate.cc b/ui/views/widget/widget_delegate.cc
index f37c436..e62aa928 100644
--- a/ui/views/widget/widget_delegate.cc
+++ b/ui/views/widget/widget_delegate.cc
@@ -116,11 +116,11 @@
 void WidgetDelegate::SaveWindowPlacement(const gfx::Rect& bounds,
                                          ui::WindowShowState show_state) {
   std::string window_name = GetWindowName();
-  if (!ViewsDelegate::views_delegate || window_name.empty())
+  if (!ViewsDelegate::GetInstance() || window_name.empty())
     return;
 
-  ViewsDelegate::views_delegate->SaveWindowPlacement(
-      GetWidget(), window_name, bounds, show_state);
+  ViewsDelegate::GetInstance()->SaveWindowPlacement(GetWidget(), window_name,
+                                                    bounds, show_state);
 }
 
 bool WidgetDelegate::GetSavedWindowPlacement(
@@ -128,10 +128,10 @@
     gfx::Rect* bounds,
     ui::WindowShowState* show_state) const {
   std::string window_name = GetWindowName();
-  if (!ViewsDelegate::views_delegate || window_name.empty())
+  if (!ViewsDelegate::GetInstance() || window_name.empty())
     return false;
 
-  return ViewsDelegate::views_delegate->GetSavedWindowPlacement(
+  return ViewsDelegate::GetInstance()->GetSavedWindowPlacement(
       widget, window_name, bounds, show_state);
 }
 
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc
index b8f138d..35c9cef 100644
--- a/ui/views/widget/widget_interactive_uitest.cc
+++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -894,7 +894,7 @@
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableTouchEditing);
 #if defined(OS_WIN)
-  views_delegate().set_use_desktop_native_widgets(true);
+  views_delegate()->set_use_desktop_native_widgets(true);
 #endif  // !defined(OS_WIN)
 
   Widget* widget = CreateWidget();
@@ -925,7 +925,7 @@
 
 TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) {
 #if defined(OS_WIN)
-  views_delegate().set_use_desktop_native_widgets(true);
+  views_delegate()->set_use_desktop_native_widgets(true);
 #endif  // !defined(OS_WIN)
 
   // Create first widget and view, activate the widget, and focus the view.
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc
index 28810988..6fb2a143 100644
--- a/ui/views/widget/widget_unittest.cc
+++ b/ui/views/widget/widget_unittest.cc
@@ -23,10 +23,8 @@
 #include "ui/views/bubble/bubble_delegate.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/test/test_views.h"
-#include "ui/views/test/test_views_delegate.h"
 #include "ui/views/test/test_widget_observer.h"
 #include "ui/views/test/widget_test.h"
-#include "ui/views/views_delegate.h"
 #include "ui/views/widget/native_widget_delegate.h"
 #include "ui/views/widget/root_view.h"
 #include "ui/views/widget/widget_deletion_observer.h"
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 76818369..b9b9f8ce 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -533,7 +533,10 @@
 }
 
 void HWNDMessageHandler::StackAbove(HWND other_hwnd) {
-  SetWindowPos(hwnd(), other_hwnd, 0, 0, 0, 0,
+  // Windows API allows to stack behind another windows only.
+  DCHECK(other_hwnd);
+  HWND next_window = GetNextWindow(other_hwnd, GW_HWNDPREV);
+  SetWindowPos(hwnd(), next_window ? next_window : HWND_TOP, 0, 0, 0, 0,
                SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
 }
 
@@ -857,16 +860,16 @@
 HICON HWNDMessageHandler::GetDefaultWindowIcon() const {
   if (use_system_default_icon_)
     return nullptr;
-  return ViewsDelegate::views_delegate
-             ? ViewsDelegate::views_delegate->GetDefaultWindowIcon()
+  return ViewsDelegate::GetInstance()
+             ? ViewsDelegate::GetInstance()->GetDefaultWindowIcon()
              : nullptr;
 }
 
 HICON HWNDMessageHandler::GetSmallWindowIcon() const {
   if (use_system_default_icon_)
     return nullptr;
-  return ViewsDelegate::views_delegate
-             ? ViewsDelegate::views_delegate->GetSmallWindowIcon()
+  return ViewsDelegate::GetInstance()
+             ? ViewsDelegate::GetInstance()->GetSmallWindowIcon()
              : nullptr;
 }
 
@@ -1004,12 +1007,12 @@
 
 int HWNDMessageHandler::GetAppbarAutohideEdges(HMONITOR monitor) {
   autohide_factory_.InvalidateWeakPtrs();
-  return ViewsDelegate::views_delegate ?
-      ViewsDelegate::views_delegate->GetAppbarAutohideEdges(
-          monitor,
-          base::Bind(&HWNDMessageHandler::OnAppbarAutohideEdgesChanged,
-                     autohide_factory_.GetWeakPtr())) :
-      ViewsDelegate::EDGE_BOTTOM;
+  return ViewsDelegate::GetInstance()
+             ? ViewsDelegate::GetInstance()->GetAppbarAutohideEdges(
+                   monitor,
+                   base::Bind(&HWNDMessageHandler::OnAppbarAutohideEdgesChanged,
+                              autohide_factory_.GetWeakPtr()))
+             : ViewsDelegate::EDGE_BOTTOM;
 }
 
 void HWNDMessageHandler::OnAppbarAutohideEdgesChanged() {
diff --git a/ui/views/win/hwnd_message_handler_delegate.h b/ui/views/win/hwnd_message_handler_delegate.h
index d5f5f813..e773b81 100644
--- a/ui/views/win/hwnd_message_handler_delegate.h
+++ b/ui/views/win/hwnd_message_handler_delegate.h
@@ -74,8 +74,6 @@
 
   virtual void ResetWindowControls() = 0;
 
-  virtual InputMethod* GetInputMethod() = 0;
-
   virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0;
 
   // Returns true if the window should handle standard system commands, such as
diff --git a/ui/views/win/windows_session_change_observer.cc b/ui/views/win/windows_session_change_observer.cc
index 627d4d0..c9db459 100644
--- a/ui/views/win/windows_session_change_observer.cc
+++ b/ui/views/win/windows_session_change_observer.cc
@@ -67,8 +67,8 @@
         base::Bind(&WtsRegistrationNotificationManager::OnWndProc,
                    base::Unretained(this))));
     scoped_refptr<base::TaskRunner> task_runner;
-    if (ViewsDelegate::views_delegate) {
-      task_runner = ViewsDelegate::views_delegate->GetBlockingPoolTaskRunner();
+    if (ViewsDelegate::GetInstance()) {
+      task_runner = ViewsDelegate::GetInstance()->GetBlockingPoolTaskRunner();
     }
 
     base::Closure wts_register =
diff --git a/ui/views/window/custom_frame_view.cc b/ui/views/window/custom_frame_view.cc
index 8fa013f..fe84615 100644
--- a/ui/views/window/custom_frame_view.cc
+++ b/ui/views/window/custom_frame_view.cc
@@ -333,9 +333,9 @@
   if (frame_->IsFullscreen())
     return false;
 
-  if (ViewsDelegate::views_delegate) {
-    return !ViewsDelegate::views_delegate->WindowManagerProvidesTitleBar(
-                frame_->IsMaximized());
+  if (ViewsDelegate::GetInstance()) {
+    return !ViewsDelegate::GetInstance()->WindowManagerProvidesTitleBar(
+        frame_->IsMaximized());
   }
 
   return true;
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css
deleted file mode 100644
index 8c8603e..0000000
--- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Copyright 2015 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-/* Note: we use display: block here to avoid positioning issues related to
-   the use of overflow: hidden. */
-:host {
-  display: block;
-  height: 50px;
-  overflow: hidden;
-  position: relative;
-  width: 50px;
-}
-
-#icon {
-  height: 100%;
-  position: absolute;
-  width: 100%;
-}
-
-#icon.multi-level {
-  height: 500%;
-}
-
-#icon.level0 {
-  top: 0px;
-}
-
-#icon.level1 {
-  top: -100%;
-}
-
-#icon.level2 {
-  top: -200%;
-}
-
-#icon.level3 {
-  top: -300%;
-}
-
-#icon.level4 {
-  top: -400%;
-}
-
-/* Connecting animation */
-
-#icon.connecting {
-  -webkit-animation: levels 1s infinite;
-  -webkit-animation-timing-function: steps(4, start);
-}
-
-@-webkit-keyframes levels {
-  from {
-    top: 0%;
-  }
-  to {
-    top: -400%;
-  }
-}
-
-/* Badges. */
-/* Note: These use left/right because we do not reverse the badges for RTL. */
-
-/* Upper-left corner */
-#technology {
-  height: 40%;
-  left: 0px;
-  position: absolute;
-  top: 0px;
-}
-
-/* Lower-right corner */
-#roaming,
-#secure {
-  height: 40%;
-  left: 60%;
-  position: absolute;
-  top: 60%;
-  width: 40%;
-}
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html
deleted file mode 100644
index d9905fe4..0000000
--- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_onc/cr_onc_data.html">
-
-<polymer-element name="cr-network-icon">
-  <template>
-    <link rel="stylesheet" href="cr_network_icon.css">
-    <img id="icon" src="{{iconType | toImageSrc}}" alt="">
-    <img id="technology" alt="" src="{{technology | toBadgeImageSrc}}"
-        hidden?="{{!technology}}">
-    <img id="roaming" alt=""
-        src="chrome://resources/cr_elements/cr_network_icon/badge_roaming.png"
-        hidden?="{{!roaming}}">
-    <img id="secure" alt=""
-        src="chrome://resources/cr_elements/cr_network_icon/badge_secure.png"
-        hidden?="{{!secure}}">
-  </template>
-  <script src="cr_network_icon.js"></script>
-</polymer-element>
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js
deleted file mode 100644
index 35f5172..0000000
--- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js
+++ /dev/null
@@ -1,276 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Polymer element for rendering network icons based on ONC
- * state properties.
- */
-
-(function() {
-/**
- * @typedef {{
- *   showBadges: boolean,
- *   showDisconnected: boolean,
- *   strength: number
- * }}
- */
-var IconParams;
-
-/** @const {string} */ var RESOURCE_IMAGE_BASE =
-    'chrome://resources/cr_elements/cr_network_icon/';
-
-/** @const {string} */ var RESOURCE_IMAGE_EXT = '.png';
-
-/**
- * Gets the icon type from the network type. This allows multiple types
- * (i.e. Cellular, WiMAX) to map to the same icon type (i.e. mobile).
- * @param {CrOnc.Type} networkType The ONC network type.
- * @return {string} The icon type: ethernet, wifi, mobile, or vpn.
- */
-function getIconTypeFromNetworkType(networkType) {
-  if (networkType == CrOnc.Type.ETHERNET)
-    return 'ethernet';
-  else if (networkType == CrOnc.Type.WIFI)
-    return 'wifi';
-  else if (networkType == CrOnc.Type.CELLULAR)
-    return 'mobile';
-  else if (networkType == CrOnc.Type.WIMAX)
-    return 'mobile';
-  else if (networkType == CrOnc.Type.VPN)
-    return 'vpn';
-
-  console.error('Unrecognized network type for icon: ' + networkType);
-  return 'ethernet';
-}
-
-/**
- * Polymer class definition for 'cr-network-icon'.
- * @element cr-network-icon
- */
-Polymer('cr-network-icon', {
-  /**
-   * The icon type to use for the base image of the icon.
-   * @type string
-   */
-  iconType: 'ethernet',
-
-  /**
-   * Set to true to show a badge for roaming networks.
-   * @type boolean
-   */
-  roaming: false,
-
-  /**
-   * Set to true to show a badge for secure networks.
-   * @type boolean
-   */
-  secure: false,
-
-  /**
-   * Set to the name of a technology to show show a badge.
-   * @type string
-   */
-  technology: '',
-
-  publish: {
-    /**
-     * If set, the ONC data properties will be used to display the icon.
-     *
-     * @attribute networkState
-     * @type CrOncDataElement
-     * @default null
-     */
-    networkState: null,
-
-    /**
-     * If set, the ONC network type will be used to display the icon.
-     *
-     * @attribute networkType
-     * @type CrOnc.Type
-     * @default null
-     */
-    networkType: null,
-
-    /**
-     * If true, the icon is part of a list of networks and may be displayed
-     * differently, e.g. the disconnected image will never be shown for
-     * list items.
-     *
-     * @attribute isListItem
-     * @type boolean
-     * @default false
-     */
-    isListItem: false,
-  },
-
-  /** @override */
-  attached: function() {
-    var params = /** @type {IconParams} */ {
-      showBadges: false,
-      showDisconnected: true,
-      strength: 0,
-    };
-    this.setIcon_(params);
-  },
-
-  /**
-   * Polymer networkState changed method. Updates the icon based on the
-   * network state.
-   */
-  networkStateChanged: function() {
-    var params = /** @type {IconParams} */ {
-      showBadges: false,
-      showDisconnected: true,
-      strength: 0,
-    };
-    if (this.networkState) {
-      this.iconType = getIconTypeFromNetworkType(this.networkState.data.Type);
-      params.showBadges = true;
-      params.showDisconnected = !this.isListItem;
-      params.strength = this.networkState.getStrength();
-    };
-    this.setIcon_(params);
-  },
-
-  /**
-   * Polymer networkType changed method. Updates the icon based on the type
-   * of network, showing a disconnected icon where appropriate and no badges.
-   */
-  networkTypeChanged: function() {
-    this.iconType = getIconTypeFromNetworkType(this.networkType);
-    var params = /** @type {IconParams} */ {
-      showBadges: false,
-      showDisconnected: true,
-      strength: 0,
-    };
-    this.setIcon_(params);
-  },
-
-  /**
-   * Returns the url for an image based on identifier |id|.
-   * @param {string} src The identifier describing the image.
-   * @return {string} The url to use for the image 'src' property.
-   */
-  toImageSrc: function(id) {
-    return id ? RESOURCE_IMAGE_BASE + id + RESOURCE_IMAGE_EXT : '';
-  },
-
-  /**
-   * Returns the url for a badge image based on identifier |id|.
-   * @param {string} id The identifier describing the badge.
-   * @return {string} The url to use for the badge image 'src' property.
-   */
-  toBadgeImageSrc: function(id) {
-    return id ? this.toImageSrc('badge_' + id) : '';
-  },
-
-  /**
-   * Sets the icon and badge based on the current state and |strength|.
-   * @param {!IconParams} params The set of params describing the icon.
-   * @private
-   */
-  setIcon_: function(params) {
-    var icon = this.$.icon;
-
-    var multiLevel = (this.iconType == 'wifi' || this.iconType == 'mobile');
-
-    if (this.networkState && multiLevel) {
-      this.setMultiLevelIcon_(params);
-    } else {
-      icon.className = multiLevel ? 'multi-level level0' : '';
-    }
-
-    this.setIconBadges_(params);
-  },
-
-  /**
-   * Toggles icon classes based on strength and connecting properties.
-   * |this.networkState| is expected to be specified.
-   * @param {!IconParams} params The set of params describing the icon.
-   * @private
-   */
-  setMultiLevelIcon_: function(params) {
-    // Set the strength or connecting properties.
-    var networkState = this.networkState;
-
-    var connecting = false;
-    var strength = -1;
-    if (networkState.connecting()) {
-      strength = 0;
-      connecting = true;
-    } else if (networkState.connected() || !params.showDisconnected) {
-      strength = params.strength || 0;
-    }
-
-    var icon = this.$.icon;
-    icon.classList.toggle('multi-level', true);
-    icon.classList.toggle('connecting', connecting);
-    icon.classList.toggle('level0', strength < 0);
-    icon.classList.toggle('level1', strength >= 0 && strength <= 25);
-    icon.classList.toggle('level2', strength > 25 && strength <= 50);
-    icon.classList.toggle('level3', strength > 50 && strength <= 75);
-    icon.classList.toggle('level4', strength > 75);
-  },
-
-  /**
-   * Sets the icon badge visibility properties: roaming, secure, technology.
-   * @param {!IconParams} params The set of params describing the icon.
-   * @private
-   */
-  setIconBadges_: function(params) {
-    var networkState = this.networkState;
-
-    var type =
-        (params.showBadges && networkState) ? networkState.data.Type : '';
-    if (type == CrOnc.Type.WIFI) {
-      this.roaming = false;
-      this.secure = networkState.getWiFiSecurity() != 'None';
-      this.technology = '';
-    } else if (type == CrOnc.Type.WIMAX) {
-      this.roaming = false;
-      this.secure = false;
-      this.technology = '4g';
-    } else if (type == CrOnc.Type.CELLULAR) {
-      this.roaming =
-          networkState.getCellularRoamingState() == CrOnc.RoamingState.ROAMING;
-      this.secure = false;
-      var oncTechnology = networkState.getCellularTechnology();
-      switch (oncTechnology) {
-        case CrOnc.NetworkTechnology.CDMA1XRTT:
-          this.technology = '1x';
-          break;
-        case CrOnc.NetworkTechnology.EDGE:
-          this.technology = 'edge';
-          break;
-        case CrOnc.NetworkTechnology.EVDO:
-          this.technology = 'evdo';
-          break;
-        case CrOnc.NetworkTechnology.GPRS:
-        case CrOnc.NetworkTechnology.GSM:
-          this.technology = 'gsm';
-          break;
-        case CrOnc.NetworkTechnology.HSPA:
-          this.technology = 'hspa';
-          break;
-        case CrOnc.NetworkTechnology.HSPA_PLUS:
-          this.technology = 'hspa_plus';
-          break;
-        case CrOnc.NetworkTechnology.LTE:
-          this.technology = 'lte';
-          break;
-        case CrOnc.NetworkTechnology.LTE_ADVANCED:
-          this.technology = 'lte_advanced';
-          break;
-        case CrOnc.NetworkTechnology.UMTS:
-          this.technology = '3g';
-          break;
-      }
-    } else {
-      this.roaming = false;
-      this.secure = false;
-      this.technology = '';
-    }
-  },
-});
-})();
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon_externs.js b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon_externs.js
deleted file mode 100644
index b15b1f5..0000000
--- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon_externs.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// TODO(jlklein/stevenjb): Delete this once auto generated.
-
-/**
- * @fileoverview Closure compiler externs for CrNetworkIconElement.
- *
- * @externs
- */
-
-/** @constructor @extends {HTMLElement} */
-var CrNetworkIconElement = function() {};
-
-/** @type {CrOncDataElement} */
-CrNetworkIconElement.prototype.networkState;
-
-/** @type {CrOnc.Type} */
-CrNetworkIconElement.prototype.networkType;
-
-/** @type {boolean} */
-CrNetworkIconElement.prototype.isListItem;
diff --git a/ui/webui/resources/cr_elements/cr_network_list/cr_network_list.css b/ui/webui/resources/cr_elements/cr_network_list/cr_network_list.css
deleted file mode 100644
index b4d5de05..0000000
--- a/ui/webui/resources/cr_elements/cr_network_list/cr_network_list.css
+++ /dev/null
@@ -1,15 +0,0 @@
-/* Copyright 2015 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-#container {
-  border: 1px solid;
-  max-height: 1000px;
-  min-height: 50px;
-  overflow-y: auto;
-}
-
-/* Note: the 'flex' attribute on core-list doesn't work as expected. */
-#networkList {
-  flex: 1;
-}
diff --git a/ui/webui/resources/cr_elements/cr_network_list/cr_network_list.html b/ui/webui/resources/cr_elements/cr_network_list/cr_network_list.html
deleted file mode 100644
index 0c68570..0000000
--- a/ui/webui/resources/cr_elements/cr_network_list/cr_network_list.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/core-list/core-list.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_collapse/cr_collapse.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_network_list_item/cr_network_list_item.html">
-
-<polymer-element name="cr-network-list">
-  <template>
-    <link rel="stylesheet" href="cr_network_list.css">
-    <cr-collapse on-core-resize="{{onResized_}}" opened="{{opened}}">
-      <div id="container" vertical layout flex>
-        <core-list id="networkList"
-            data="{{networks}}"
-            on-core-activate="{{onSelected_}}">
-          <template>
-            <cr-network-list-item networkState="{{model}}" isListItem>
-            </cr-network-list-item>
-          </template>
-        </core-list>
-      </div>
-    </cr-collapse>
-  </template>
-  <script src="cr_network_list.js"></script>
-</polymer-element>
diff --git a/ui/webui/resources/cr_elements/cr_network_list/cr_network_list.js b/ui/webui/resources/cr_elements/cr_network_list/cr_network_list.js
deleted file mode 100644
index 4fcd048..0000000
--- a/ui/webui/resources/cr_elements/cr_network_list/cr_network_list.js
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Polymer element for displaying a collapsable list of networks.
- */
-
-/**
- * Polymer class definition for 'cr-network-list'.
- * @element cr-network-list
- */
-Polymer('cr-network-list', {
-  publish: {
-    /**
-     * The maximum height in pixels for the list.
-     *
-     * @attribute maxHeight
-     * @type {number}
-     * @default 1000
-     */
-    maxHeight: 1000,
-
-    /**
-     * The list of network state properties for the items to display.
-     *
-     * @attribute networks
-     * @type {?Array<!CrOncDataElement>}
-     * @default null
-     */
-    networks: null,
-
-    /**
-     * True if the list is opened.
-     *
-     * @attribute opened
-     * @type {boolean}
-     * @default false
-     */
-    opened: false,
-  },
-
-  /** @override */
-  created: function() {
-    this.networks = [];
-  },
-
-  /**
-   * Polymer maxHeight changed method.
-   */
-  maxHeightChanged: function() {
-    this.$.container.style.maxHeight = this.maxHeight + "px";
-  },
-
-  /**
-   * Called when the cr-collapse element changes size (i.e. is opened).
-   * @private
-   */
-  onResized_: function() {
-    if (this.opened)
-      this.$.networkList.updateSize();
-  },
-
-  /**
-   * Event triggered when a list item is selected.
-   * @param {!{detail: CrOncDataElement}} event
-   * @private
-   */
-  onSelected_: function(event) {
-    this.fire('selected', event.detail.item.networkState);
-  }
-});
diff --git a/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.css b/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.css
deleted file mode 100644
index b4d8466..0000000
--- a/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.css
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright 2015 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-#divOuter {
-  border-style: none;
-  display: flex;
-  flex-direction: row;
-  margin: 0;
-  padding: 4px;
-}
-
-#divOuter.listItem:hover {
-  background-color: lightgrey;
-}
-
-#divIcon {
-  display: flex;
-  flex: 0 0 auto;
-  flex-direction: column;
-  justify-content: center;
-}
-
-#icon {
-  height: 32px;
-  width: 32px;
-}
-
-#divDetail {
-  display: flex;
-  flex: 1 0 auto;
-  flex-direction: row;
-}
-
-#divText {
-  display: flex;
-  flex: 1 0 auto;
-  flex-direction: column;
-  justify-content: center;
-}
-
-#networkName {
-  -webkit-margin-start: 8px;
-  font-size: 16px;
-}
-
-#networkState {
-  -webkit-margin-start: 8px;
-  color: grey;
-  font-size: 14px;
-}
-
-.connected {
-  font-weight: bold;
-}
diff --git a/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.html b/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.html
deleted file mode 100644
index 3e9532ab..0000000
--- a/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_network_icon/cr_network_icon.html">
-
-<polymer-element name="cr-network-list-item">
-  <template>
-    <link rel="stylesheet" href="cr_network_list_item.css">
-    <div id="divOuter" class="{{ {listItem: isListItem} | tokenList }}">
-      <div id="divIcon">
-        <cr-network-icon id="icon"
-            networkState="{{networkState}}" isListItem="{{isListItem}}">
-        </cr-network-icon>
-      </div>
-      <div id="divText">
-        <span id="networkName"></span>
-        <span id="networkState" hidden?="{{isListItem}}"></span>
-      </div>
-    </div>
-  </template>
-  <script src="cr_network_list_item.js"></script>
-</polymer-element>
diff --git a/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.js b/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.js
deleted file mode 100644
index 5180403..0000000
--- a/ui/webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.js
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Polymer element for displaying information about a network
- * in a list or summary based on ONC state properties.
- */
-(function() {
-
-/**
- * TODO(stevenjb): Replace getText with a proper localization function that
- * handles string substitution.
- * Performs argument substitution, replacing %1, %2, etc in 'text' with
- * corresponding entries in |args|.
- * @param {string} text The string to perform the substitution on.
- * @param {?Array<string>} args The arguments to replace %1, %2, etc with.
- */
-function getText(text, args) {
-  var res = text;
-  if (!args)
-    return res;
-  for (var i = 0; i < args.length; ++i) {
-    var key = '%' + (i + 1);
-    res = res.replace(key, args[i]);
-  }
-  return res;
-}
-
-/**
- * Returns the appropriate connection state text.
- * @param {string} state The connection state.
- * @param {string} name The name of the network.
- */
-function getConnectionStateText(state, name) {
-  if (state == 'Connected')
-    return getText('Connected to %1', [name]);
-  if (state == 'Connecting')
-    return getText('Connecting to %1...', [name]);
-  if (state == 'NotConnected')
-    return getText('Not Connected');
-  return getText(state);
-};
-
-/**
- * Polymer class definition for 'cr-network-list-item'.
- * @element cr-network-list-item
- */
-Polymer('cr-network-list-item', {
-  publish: {
-    /**
-     * The ONC data properties used to display the list item.
-     *
-     * @attribute networkState
-     * @type {?CrOncDataElement}
-     * @default null
-     */
-    networkState: null,
-
-    /**
-     * If true, the element is part of a list of networks and only displays
-     * the network icon and name. Otherwise the element is assumed to be a
-     * stand-alone item (e.g. as part of a summary) and displays the name
-     * of the network type plus the network name and connection state.
-     *
-     * @attribute isListItem
-     * @type {boolean}
-     * @default false
-     */
-    isListItem: false,
-  },
-
-  /**
-   * Polymer networkState changed method. Updates the element based on the
-   * network state.
-   */
-  networkStateChanged: function() {
-    if (!this.networkState)
-      return;
-
-    var network = this.networkState.data;
-    var isDisconnected = this.networkState.disconnected();
-    if (this.isListItem) {
-      this.$.networkName.textContent = getText(network.Name);
-      this.$.networkName.classList.toggle('connected', !isDisconnected);
-    } else if (network.Name && network.ConnectionState) {
-      this.$.networkName.textContent = getText(network.Type);
-      this.$.networkName.classList.toggle('connected', false);
-      this.$.networkState.textContent =
-          getConnectionStateText(network.ConnectionState, network.Name);
-      this.$.networkState.classList.toggle('connected', !isDisconnected);
-    } else {
-      this.$.networkName.textContent = getText(network.Type);
-      this.$.networkName.classList.toggle('connected', false);
-      this.$.networkState.textContent = getText('Disabled');
-      this.$.networkState.classList.toggle('connected', false);
-    }
-  },
-});
-})();
diff --git a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.html b/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.html
deleted file mode 100644
index 5fed3abc..0000000
--- a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
-
-<script src="cr_onc_types.js"></script>
-
-<polymer-element name="cr-onc-data">
-  <script src="cr_onc_data.js"></script>
-</polymer-element>
diff --git a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js b/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js
deleted file mode 100644
index 9c9c067..0000000
--- a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview ONC network configuration support class. Wraps a dictionary
- * object containing ONC managed or unmanaged dictionaries. Also provides
- * special accessors for ONC properties. Used by consumers of the
- * chrome.networkingPrivate API. See components/onc/docs/onc_spec.html.
- */
-Polymer('cr-onc-data', {
-  publish: {
-    /**
-     * ONC configuration property dictionary, e.g. the result of a
-     * chrome.networkingPrivate.getProperties() call.
-     *
-     * @attribute data
-     * @type {chrome.networkingPrivate.NetworkStateProperties}
-     * @default null
-     */
-    data: null,
-  },
-
-  /** @override */
-  created: function() {
-    this.data =
-        /** @type {chrome.networkingPrivate.NetworkStateProperties} */({});
-  },
-
-  /**
-   * TODO(stevenjb): Handle Managed property dictionaries.
-   * @param {string} key The property key.
-   * @return {?} The property value if it exists, otherwise undefined.
-   */
-  getProperty: function(key) {
-    var data = this.data;
-    while (true) {
-      var index = key.indexOf('.');
-      if (index < 0)
-        break;
-      var keyComponent = key.substr(0, index);
-      if (!(keyComponent in data))
-        return undefined;
-      data = data[keyComponent];
-      key = key.substr(index + 1);
-    }
-    return data[key];
-  },
-
-  /** @return {boolean} True if the network is connected. */
-  connected: function() {
-    return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTED;
-  },
-
-  /** @return {boolean} True if the network is connecting. */
-  connecting: function() {
-    return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTING;
-  },
-
-  /** @return {boolean} True if the network is disconnected. */
-  disconnected: function() {
-    return this.data.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED;
-  },
-
-  /** @return {number} The signal strength of the network. */
-  getStrength: function() {
-    var type = this.data.Type;
-    var key = type + '.SignalStrength';
-    return this.getProperty(key) || 0;
-  },
-
-  /** @return {CrOnc.Security} The ONC security type. */
-  getWiFiSecurity: function() {
-    return this.getProperty('WiFi.Security') || CrOnc.Security.NONE;
-  },
-
-  /** @return {CrOnc.RoamingState} The ONC roaming state. */
-  getCellularRoamingState: function() {
-    return this.getProperty('Cellular.RoamingState') ||
-        CrOnc.RoamingState.UNKNOWN;
-  },
-
-  /** @return {CrOnc.NetworkTechnology} The ONC network technology. */
-  getCellularTechnology: function() {
-    return this.getProperty('Cellular.NetworkTechnology') ||
-        CrOnc.NetworkTechnology.UNKNOWN;
-  }
-});
-
-// Temporary constructor method. TODO(stevenjb): Replace with proper
-// construction after switching to Polymer 0.8.
-
-var CrOncDataElement = {};
-
-/**
- * Helper method to create and return a typed cr-onc-data Polymer element.
- * Sets the data property of the element to |state|.
- *
- * @param {!chrome.networkingPrivate.NetworkStateProperties} state The network
- *     state properties.
- * @return {!CrOncDataElement} A cr-onc-data element.
- */
-CrOncDataElement.create = function(state) {
-  var oncData = /** @type {!CrOncDataElement} */ (
-      document.createElement('cr-onc-data'));
-  oncData.data = state;
-  return oncData;
-};
diff --git a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data_externs.js b/ui/webui/resources/cr_elements/cr_onc/cr_onc_data_externs.js
deleted file mode 100644
index c4c18d8..0000000
--- a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data_externs.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// TODO(jlklein/stevenjb): Delete this once auto generated.
-
-/**
- * @fileoverview Closure compiler externs for CrOncDataElement.
- *
- * @externs
- */
-
-/** @constructor @extends {HTMLElement} */
-var CrOncDataElement = function() {};
-
-/** @type {chrome.networkingPrivate.NetworkStateProperties} */
-CrOncDataElement.prototype.data;
diff --git a/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js b/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js
deleted file mode 100644
index 4dfa32f0..0000000
--- a/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Typedefs for CrOncDataElement.data. Note: These 'types' define
- * a subset of ONC properties in the ONC data dictionary. The first letter is
- * capitalized to match the ONC spec and avoid an extra layer of translation.
- * See components/onc/docs/onc_spec.html for the complete spec.
- */
-
-var CrOnc = {};
-
-/** @enum {string} */
-CrOnc.Type = {
-  CELLULAR: 'Cellular',
-  ETHERNET: 'Ethernet',
-  VPN: 'VPN',
-  WIFI: 'WiFi',
-  WIMAX: 'WiMAX',
-};
-
-/** @enum {string} */
-CrOnc.ConnectionState = {
-  CONNECTED: 'Connected',
-  CONNECTING: 'Connecting',
-  NOT_CONNECTED: 'NotConnected',
-};
-
-/** @enum {string} */
-CrOnc.NetworkTechnology = {
-  CDMA1XRTT: 'CDMA1XRTT',
-  EDGE: 'EDGE',
-  EVDO: 'EVDO',
-  GPRS: 'GPRS',
-  GSM: 'GSM',
-  HSPA: 'HSPA',
-  HSPA_PLUS: 'HSPAPlus',
-  LTE: 'LTE',
-  LTE_ADVANCED: 'LTEAdvanced',
-  UMTS: 'UMTS',
-  UNKNOWN: 'Unknown',
-};
-
-/** @enum {string} */
-CrOnc.RoamingState = {
-  HOME: 'Home',
-  REQUIRED: 'Required',
-  ROAMING: 'Roaming',
-  UNKNOWN: 'Unknown',
-};
-
-/** @enum {string} */
-CrOnc.Security = {
-  NONE: 'None',
-  WEP_8021X: 'WEP-8021X',
-  WEP_PSK: 'WEP-PSK',
-  WPA_EAP: 'WPA-EAP',
-  WPA_PSK: 'WPA-PSK',
-};
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.css b/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.css
index e20fe49..a5c05b8 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.css
+++ b/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.css
@@ -6,3 +6,7 @@
   display: inline-block;
   vertical-align: middle;
 }
+
+paper-button[toggles][active] {
+    background-color: lightgrey;
+}
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.html b/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.html
index b544e52c..842f040 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.html
+++ b/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.html
@@ -4,7 +4,8 @@
 <dom-module id="cr-button">
   <link rel="import" type="css" href="cr_button.css">
   <template>
-    <paper-button disabled="[[disabled]]" raised="[[raised]]">
+    <paper-button active="{{active}}" disabled="[[disabled]]"
+        raised="[[raised]]" toggles="[[toggles]]" noink$="[[toggles]]">
       <content></content>
     </paper-button>
   </template>
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.js b/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.js
index e430294..f1dab205 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.js
+++ b/ui/webui/resources/cr_elements/v1_0/cr_button/cr_button.js
@@ -38,5 +38,23 @@
       value: false,
       reflectToAttribute: true
     },
+
+    /**
+     * If true, clicking the button toggles the active state.
+     */
+    toggles: {
+      type: Boolean,
+      value: false
+    },
+
+    /**
+     * If true, the button is in the active state. Mostly useful when
+     * |toggles| is true.
+     */
+    active: {
+      type: Boolean,
+      value: false,
+      notify: true
+    }
   },
 });
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html b/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html
index 27fba22..bee4b3c 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html
@@ -1,5 +1,5 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_types.html">
 
 <dom-module id="cr-network-icon">
   <link rel="import" type="css" href="cr_network_icon.css">
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.js b/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.js
index d795a76..64958bff 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.js
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.js
@@ -53,13 +53,9 @@
 
   properties: {
     /**
-     * If set, the ONC data properties will be used to display the icon.
-     * NOTE: Because this is a Polymer element, it can not be set using
-     * data binding; it must be set directly. TODO(stevenjb): Use
-     * NetworkStateProperties instead and replace CrOncDataElement with a
-     * set of utility functions.
+     * If set, the ONC state properties will be used to display the icon.
      *
-     * @type {?CrOncDataElement}
+     * @type {?CrOnc.NetworkStateProperties}
      */
     networkState: {
       type: Object,
@@ -136,11 +132,13 @@
       return;
 
     this.networkType = null;
-    this.iconType_ = getIconTypeFromNetworkType(this.networkState.data.Type);
+    this.iconType_ = getIconTypeFromNetworkType(this.networkState.Type);
+    var strength = /** @type {number} */ (
+        CrOnc.getTypeProperty(this.networkState, 'SignalStrength') || 0);
     var params = /** @type {IconParams} */ {
       showBadges: true,
       showDisconnected: !this.isListItem,
-      strength: this.networkState.getStrength(),
+      strength: strength
     };
     this.setIcon_(params);
   },
@@ -170,7 +168,7 @@
    */
   isListItemChanged_: function() {
     if (this.networkState)
-      this.networkStateChaged_();
+      this.networkStateChanged_();
     else if (this.networkType)
       this.networkTypeChanged_();
   },
@@ -225,12 +223,14 @@
     // Set the strength or connecting properties.
     var networkState = this.networkState;
 
+    var connectionState = networkState.ConnectionState;
     var connecting = false;
     var strength = -1;
-    if (networkState.connecting()) {
+    if (connectionState == CrOnc.ConnectionState.CONNECTING) {
       strength = 0;
       connecting = true;
-    } else if (networkState.connected() || !params.showDisconnected) {
+    } else if (connectionState == CrOnc.ConnectionState.CONNECTED ||
+               !params.showDisconnected) {
       strength = params.strength || 0;
     }
 
@@ -253,20 +253,22 @@
     var networkState = this.networkState;
 
     var type =
-        (params.showBadges && networkState) ? networkState.data.Type : '';
+        (params.showBadges && networkState) ? networkState.Type : '';
     if (type == CrOnc.Type.WIFI) {
       this.roaming_ = false;
-      this.secure_ = networkState.getWiFiSecurity() != 'None';
+      var security = CrOnc.getTypeProperty(networkState, 'Security');
+      this.secure_ = security && security != 'None';
       this.technology_ = '';
     } else if (type == CrOnc.Type.WIMAX) {
       this.roaming_ = false;
       this.secure_ = false;
       this.technology_ = '4g';
     } else if (type == CrOnc.Type.CELLULAR) {
-      this.roaming_ =
-          networkState.getCellularRoamingState() == CrOnc.RoamingState.ROAMING;
+      this.roaming_ = CrOnc.getTypeProperty(networkState, 'RoamingState') ==
+                      CrOnc.RoamingState.ROAMING;
       this.secure_ = false;
-      var oncTechnology = networkState.getCellularTechnology();
+      var oncTechnology =
+          CrOnc.getTypeProperty(networkState, 'NetworkTechnology');
       switch (oncTechnology) {
         case CrOnc.NetworkTechnology.CDMA1XRTT:
           this.technology_ = '1x';
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon_externs.js b/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon_externs.js
index b15b1f5..47bf294f 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon_externs.js
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon_externs.js
@@ -13,7 +13,7 @@
 /** @constructor @extends {HTMLElement} */
 var CrNetworkIconElement = function() {};
 
-/** @type {CrOncDataElement} */
+/** @type {CrOnc.NetworkStateProperties} */
 CrNetworkIconElement.prototype.networkState;
 
 /** @type {CrOnc.Type} */
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.html b/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.html
index af8f941..cd6e052 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.html
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.html
@@ -1,7 +1,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_collapse/cr_collapse.html">
 <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html">
-<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_types.html">
 
 <dom-module id="cr-network-list">
   <link rel="import" type="css" href="cr_network_list.css">
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.js b/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.js
index 98db0d92..694f9917 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.js
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.js
@@ -8,9 +8,6 @@
 
 (function() {
 
-/** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
-var NetworkStateProperties;
-
 /**
  * Polymer class definition for 'cr-network-list'.
  * TODO(stevenjb): Update with iron-list(?) once implemented in Polymer 1.0.
@@ -32,7 +29,7 @@
     /**
      * The list of network state properties for the items to display.
      *
-     * @type {!Array<!NetworkStateProperties>}
+     * @type {!Array<!CrOnc.NetworkStateProperties>}
      */
     networks: {
       type: Array,
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html b/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html
index d9c37e8..292d8c44 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html
@@ -1,5 +1,5 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_types.html">
 <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html">
 
 <dom-module id="cr-network-list-item">
@@ -7,7 +7,8 @@
   <template>
     <div id="divOuter" class$="[[isListItemClass_(isListItem)]]">
       <div id="divIcon">
-        <cr-network-icon id="icon" isListItem="[[isListItem]]">
+        <cr-network-icon id="icon" isListItem="[[isListItem]]"
+            network-state="[[networkState]]">
         </cr-network-icon>
       </div>
       <div id="divText">
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.js b/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.js
index 6b0e2e2..cfeb77e4 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.js
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.js
@@ -8,9 +8,6 @@
  */
 (function() {
 
-/** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
-var NetworkStateProperties;
-
 /**
  * TODO(stevenjb): Replace getText with a proper localization function that
  * handles string substitution.
@@ -56,7 +53,7 @@
     /**
      * The ONC data properties used to display the list item.
      *
-     * @type {?NetworkStateProperties}
+     * @type {?CrOnc.NetworkStateProperties}
      */
     networkState: {
       type: Object,
@@ -84,9 +81,6 @@
     if (!this.networkState)
       return;
 
-    // Set icon.networkState explicitly since networkState is an element.
-    this.$.icon.networkState = CrOncDataElement.create(this.networkState);
-
     var network = this.networkState;
     var isDisconnected =
         network.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED;
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.html b/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.html
deleted file mode 100644
index 08501b3..0000000
--- a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-
-<script src="cr_onc_types.js"></script>
-
-<dom-module id="cr-onc-data">
-  <script src="cr_onc_data.js"></script>
-</dom-module>
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.js b/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.js
deleted file mode 100644
index 1eee57f2..0000000
--- a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.js
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview ONC network configuration support class. Wraps a dictionary
- * object containing ONC managed or unmanaged dictionaries. Also provides
- * special accessors for ONC properties. Used by consumers of the
- * chrome.networkingPrivate API. See components/onc/docs/onc_spec.html.
- */
-Polymer({
-  is: 'cr-onc-data',
-
-  properties: {
-    /**
-     * ONC configuration property dictionary, e.g. the result of a
-     * chrome.networkingPrivate.getProperties() call.
-     *
-     * @type {?chrome.networkingPrivate.NetworkStateProperties}
-     */
-    data: {
-      type: Object,
-      value: function() { return {}; },
-    },
-  },
-
-  /** @return {boolean} True if the network is connected. */
-  connected: function() {
-    return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTED;
-  },
-
-  /** @return {boolean} True if the network is connecting. */
-  connecting: function() {
-    return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTING;
-  },
-
-  /** @return {boolean} True if the network is disconnected. */
-  disconnected: function() {
-    return this.data.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED;
-  },
-
-  /** @return {number} The signal strength of the network. */
-  getStrength: function() {
-    var type = this.data.Type;
-    var strength = 0;
-    if (type == 'WiFi')
-      strength = this.data.WiFi ? this.data.WiFi.SignalStrength : 0;
-    else if (type == 'Cellular')
-      strength = this.data.Cellular ? this.data.Cellular.SignalStrength : 0;
-    else if (type == 'WiMAX')
-      strength = this.data.WiMAX ? this.data.WiMAX.SignalStrength : 0;
-    return strength;
-  },
-
-  /** @return {CrOnc.Security} The ONC security type. */
-  getWiFiSecurity: function() {
-    return (this.data.WiFi && this.data.WiFi.Security) ?
-        this.data.WiFi.Security : CrOnc.Security.NONE;
-  },
-
-  /** @return {CrOnc.RoamingState} The ONC roaming state. */
-  getCellularRoamingState: function() {
-    return (this.data.Cellular && this.data.Cellular.RoamingState) ?
-        this.data.Cellular.RoamingState : CrOnc.RoamingState.UNKNOWN;
-  },
-
-  /** @return {CrOnc.NetworkTechnology} The ONC network technology. */
-  getCellularTechnology: function() {
-    return (this.data.Cellular && this.data.Cellular.NetworkTechnology) ?
-        this.data.Cellular.NetworkTechnology : CrOnc.NetworkTechnology.UNKNOWN;
-  }
-});
-
-// Temporary constructor method. TODO(stevenjb): Replace with proper
-// construction after switching to Polymer 0.8.
-
-var CrOncDataElement = {};
-
-/**
- * Helper method to create and return a typed cr-onc-data Polymer element.
- * Sets the data property of the element to |state|.
- *
- * @param {!chrome.networkingPrivate.NetworkStateProperties} state The network
- *     state properties.
- * @return {!CrOncDataElement} A cr-onc-data element.
- */
-CrOncDataElement.create = function(state) {
-  if (!state) {
-    console.error('CrOncDataElement.create called with null state');
-    return null;
-  }
-  var oncData = /** @type {!CrOncDataElement} */ (
-      document.createElement('cr-onc-data'));
-  oncData.data = state;
-  return oncData;
-};
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data_externs.js b/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data_externs.js
deleted file mode 100644
index c4c18d8..0000000
--- a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data_externs.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// TODO(jlklein/stevenjb): Delete this once auto generated.
-
-/**
- * @fileoverview Closure compiler externs for CrOncDataElement.
- *
- * @externs
- */
-
-/** @constructor @extends {HTMLElement} */
-var CrOncDataElement = function() {};
-
-/** @type {chrome.networkingPrivate.NetworkStateProperties} */
-CrOncDataElement.prototype.data;
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_types.html b/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_types.html
new file mode 100644
index 0000000..6794ad39
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_types.html
@@ -0,0 +1 @@
+<script src="cr_onc_types.js"></script>
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_types.js b/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_types.js
index 4dfa32f0..ef3c5623 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_types.js
+++ b/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_types.js
@@ -3,14 +3,42 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview Typedefs for CrOncDataElement.data. Note: These 'types' define
- * a subset of ONC properties in the ONC data dictionary. The first letter is
- * capitalized to match the ONC spec and avoid an extra layer of translation.
+ * @fileoverview This file has two parts:
+ *
+ * 1. Typedefs for network properties. Note: These 'types' define a subset of
+ * ONC properties in the ONC data dictionary. The first letter is capitalized to
+ * match the ONC spec and avoid an extra layer of translation.
  * See components/onc/docs/onc_spec.html for the complete spec.
+ * TODO(stevenjb): Replace with chrome.networkingPrivate.NetworkStateProperties
+ * once that is fully defined.
+ *
+ * 2. Helper functions to facilitate extracting and setting ONC properties.
  */
 
 var CrOnc = {};
 
+/** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
+CrOnc.NetworkStateProperties;
+
+/** @typedef {string|number|boolean|Array<Object>} */
+CrOnc.NetworkStateProperty;
+
+/** @typedef {{
+ *    Active: CrOnc.NetworkStateProperty,
+ *    Effective: CrOnc.NetworkStateProperty,
+ *    UserPolicy: CrOnc.NetworkStateProperty,
+ *    DevicePolicy: CrOnc.NetworkStateProperty,
+ *    UserSetting: CrOnc.NetworkStateProperty,
+ *    SharedSetting: CrOnc.NetworkStateProperty,
+ *    UserEditable: boolean,
+ *    DeviceEditable: boolean
+ * }}
+ */
+CrOnc.ManagedProperty;
+
+/** @typedef {CrOnc.NetworkStateProperty|!CrOnc.ManagedProperty} */
+CrOnc.ManagedNetworkStateProperty;
+
 /** @enum {string} */
 CrOnc.Type = {
   CELLULAR: 'Cellular',
@@ -58,3 +86,95 @@
   WPA_EAP: 'WPA-EAP',
   WPA_PSK: 'WPA-PSK',
 };
+
+/**
+ * Helper function to retrieve the active ONC property value.
+ * @param {!CrOnc.ManagedNetworkStateProperty} property The property, which may
+ *     be a managed dictionary or the property itself.
+ * @return {!CrOnc.NetworkStateProperty|undefined} The active property value
+ *     if it exists, otherwise undefined.
+ */
+CrOnc.getActiveValue = function(property) {
+  // If this is not a dictionary, return the value.
+  if (Array.isArray(property) || typeof property != 'object')
+    return /** @type {!CrOnc.NetworkStateProperty} */ (property);
+
+  // Otherwise return the Active value if it exists.
+  if ('Active' in property)
+    return property['Active'];
+
+  // If no Active value is defined, return the effective value.
+  if ('Effective' in property) {
+    var effective = property.Effective;
+    if (effective in property)
+      return property[effective];
+  }
+
+  console.error('getActiveValue called on invalid ONC object: ' + property);
+  return undefined;
+};
+
+/**
+ * Returns either a managed property dictionary or an unmanaged value associated
+ * with a key.
+ * @param {!CrOnc.NetworkStateProperties} state The ONC network state.
+ * @param {string} key The property key which may be nested, e.g. 'Foo.Bar'.
+ * @return {!CrOnc.ManagedNetworkStateProperty|undefined} The property value or
+ *   dictionary if it exists, otherwise undefined.
+ */
+CrOnc.getProperty = function(state, key) {
+  while (true) {
+    var index = key.indexOf('.');
+    if (index < 0)
+      break;
+    var keyComponent = key.substr(0, index);
+    if (!state.hasOwnProperty(keyComponent))
+      return undefined;
+    state = state[keyComponent];
+    key = key.substr(index + 1);
+  }
+  return state[key];
+};
+
+/**
+ * Calls getProperty with '{state.Type}.key', e.g. WiFi.AutoConnect.
+ * @param {!CrOnc.NetworkStateProperties} state The ONC network state.
+ * @param {string} key The type property key, e.g. 'AutoConnect'.
+ * @return {!CrOnc.ManagedNetworkStateProperty|undefined} The property value or
+ *     dictionary if it exists, otherwise undefined.
+ */
+CrOnc.getTypeProperty = function(state, key) {
+  var typeKey = state.Type + '.' + key;
+  return CrOnc.getProperty(state, typeKey);
+};
+
+/**
+ * Sets the value of a property in an ONC dictionary.
+ * @param {!CrOnc.NetworkStateProperties} state The ONC network state to modify.
+ * @param {string} key The property key which may be nested, e.g. 'Foo.Bar'.
+ * @param {!CrOnc.NetworkStateProperty} value The property value to set.
+ */
+CrOnc.setProperty = function(state, key, value) {
+  while (true) {
+    var index = key.indexOf('.');
+    if (index < 0)
+      break;
+    var keyComponent = key.substr(0, index);
+    if (!state.hasOwnProperty(keyComponent))
+      state[keyComponent] = {};
+    state = state[keyComponent];
+    key = key.substr(index + 1);
+  }
+  state[key] = value;
+};
+
+/**
+ * Calls setProperty with '{state.Type}.key', e.g. WiFi.AutoConnect.
+ * @param {!CrOnc.NetworkStateProperties} state The ONC network state.
+ * @param {string} key The type property key, e.g. 'AutoConnect'.
+ * @param {!CrOnc.NetworkStateProperty} value The property value to set.
+ */
+CrOnc.setTypeProperty = function(state, key, value) {
+  var typeKey = state.Type + '.' + key;
+  CrOnc.setProperty(state, typeKey, value);
+};
diff --git a/ui/webui/resources/cr_elements/v1_0/demo_element.html b/ui/webui/resources/cr_elements/v1_0/demo_element.html
index 8501c29f..44fe7a5 100644
--- a/ui/webui/resources/cr_elements/v1_0/demo_element.html
+++ b/ui/webui/resources/cr_elements/v1_0/demo_element.html
@@ -5,15 +5,16 @@
 <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_expand_button/cr_expand_button.html">
 <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_input/cr_input.html">
 <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html">
-<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_types.html">
 <link rel="import" href="chrome://resources/cr_elements/v1_0/cr_toggle_button/cr_toggle_button.html">
 
 <dom-module id="cr-demo-element">
   <template>
-    <div>
+    <div class="layout vertical">
       <h3>cr-button</h3>
       <cr-button>Button</cr-button>
       <cr-button raised>Raised Button</cr-button>
+      <cr-button toggles>Toggle Button</cr-button>
     </div>
     <div>
       <h3>cr-checkbox</h3>
@@ -25,11 +26,23 @@
     </div>
     <div>
       <h3>cr-collapse</h3>
-      <cr-expand-button expanded="{{collapseOpened}}"></cr-expand-button>
-      <span>Toggle Collapse</span>
+      <div class="layout horizontal center">
+        <span>Collapse 1</span>
+        <cr-expand-button expanded="{{collapseOpened}}"></cr-expand-button>
+      </div>
       <cr-collapse opened="[[collapseOpened]]">
-        <div>
-          <span>Collapsable section</span>
+        <div class="layout vertical">
+          <span>Collapsable Section 1</span>
+          <cr-checkbox>Advanced option 1</cr-checkbox>
+          <cr-checkbox>Advanced option 2</cr-checkbox>
+        </div>
+      </cr-collapse>
+      <cr-button toggles active="{{collapseOpened2}}">
+        Collapse 2
+      </cr-button>
+      <cr-collapse opened="[[collapseOpened2]]">
+        <div class="layout vertical">
+          <span>Collapsable Section 2</span>
         </div>
       </cr-collapse>
     </div>
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index 4719fb8..8ed63c3 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -43,42 +43,6 @@
   <structure name="IDR_CR_ELEMENTS_CR_EXPAND_BUTTON_JS"
              file="../../webui/resources/cr_elements/cr_expand_button/cr_expand_button.js"
              type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_NETWORK_ICON_CSS"
-             file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.css"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_NETWORK_ICON_HTML"
-             file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.html"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_NETWORK_ICON_JS"
-             file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.js"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_NETWORK_LIST_CSS"
-             file="../../webui/resources/cr_elements/cr_network_list/cr_network_list.css"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_NETWORK_LIST_HTML"
-             file="../../webui/resources/cr_elements/cr_network_list/cr_network_list.html"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_NETWORK_LIST_JS"
-             file="../../webui/resources/cr_elements/cr_network_list/cr_network_list.js"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_NETWORK_LIST_ITEM_CSS"
-             file="../../webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.css"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_NETWORK_LIST_ITEM_HTML"
-             file="../../webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.html"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_NETWORK_LIST_ITEM_JS"
-             file="../../webui/resources/cr_elements/cr_network_list_item/cr_network_list_item.js"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_ONC_TYPES_JS"
-             file="../../webui/resources/cr_elements/cr_onc/cr_onc_types.js"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_ONC_DATA_HTML"
-             file="../../webui/resources/cr_elements/cr_onc/cr_onc_data.html"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_CR_ONC_DATA_JS"
-             file="../../webui/resources/cr_elements/cr_onc/cr_onc_data.js"
-             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_EVENTS_HTML"
              file="../../webui/resources/cr_elements/cr_events/cr_events.html"
              type="chrome_html" />
@@ -192,15 +156,12 @@
   <structure name="IDR_CR_ELEMENTS_1_0_CR_NETWORK_LIST_ITEM_JS"
              file="../../webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.js"
              type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_ONC_TYPES_HTML"
+             file="../../webui/resources/cr_elements/v1_0/cr_onc/cr_onc_types.html"
+             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_1_0_CR_ONC_TYPES_JS"
              file="../../webui/resources/cr_elements/v1_0/cr_onc/cr_onc_types.js"
              type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_1_0_CR_ONC_DATA_HTML"
-             file="../../webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.html"
-             type="chrome_html" />
-  <structure name="IDR_CR_ELEMENTS_1_0_CR_ONC_DATA_JS"
-             file="../../webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.js"
-             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_1_0_CR_TOGGLE_BUTTON_CSS"
              file="../../webui/resources/cr_elements/v1_0/cr_toggle_button/cr_toggle_button.css"
              type="chrome_html" />
diff --git a/ui/webui/resources/js/compiled_resources.gyp b/ui/webui/resources/js/compiled_resources.gyp
index 40b1571..ca47667 100644
--- a/ui/webui/resources/js/compiled_resources.gyp
+++ b/ui/webui/resources/js/compiled_resources.gyp
@@ -9,6 +9,9 @@
     },
     {
       'target_name': 'cr',
+      'variables': {
+        'externs': ['../../../../third_party/closure_compiler/externs/chrome_send_externs.js'],
+      },
       'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'],
     },
     {
@@ -29,7 +32,7 @@
     {
       'target_name': 'util',
       'variables': {
-        'depends': ['cr.js'],
+        'depends': ['compiled_resources.gyp:cr'],
         # TODO(jlklein): Get <(VARIABLES) in transient externs/depends working.
         'externs': ['../../../../third_party/closure_compiler/externs/chrome_send_externs.js'],
       },
diff --git a/ui/webui/resources/js/cr.js b/ui/webui/resources/js/cr.js
index 03cf6ff..d5ae7f1 100644
--- a/ui/webui/resources/js/cr.js
+++ b/ui/webui/resources/js/cr.js
@@ -312,6 +312,88 @@
     });
   }
 
+  /**
+   * The mapping used by the sendWithCallback mechanism to tie the callback
+   * supplied to an invocation of sendWithCallback with the WebUI response
+   * sent by the browser in response to the chrome.send call. The mapping is
+   * from ID to callback function; the ID is generated by sendWithCallback and
+   * is unique across all invocations of said method.
+   * @type {!Map<string, Function>}
+   */
+  var chromeSendCallbackMap = new Map();
+
+  /**
+   * The named method the WebUI handler calls directly in response to a
+   * chrome.send call that expects a callback. The handler requires no knowledge
+   * of the specific name of this method, as the name is passed to the handler
+   * as the first argument in the arguments list of chrome.send. The handler
+   * must pass the ID, also sent via the chrome.send arguments list, as the
+   * first argument of the JS invocation; additionally, the handler may
+   * supply any number of other arguments that will be forwarded to the
+   * callback.
+   * @param {string} id The unique ID identifying the callback method this
+   *    response is tied to.
+   */
+  function webUIResponse(id) {
+    chromeSendCallbackMap.get(id).apply(
+        null, Array.prototype.slice.call(arguments, 1));
+    chromeSendCallbackMap.delete(id);
+  }
+
+  /**
+   * A variation of chrome.send which allows the client to receive a direct
+   * callback without requiring the handler to have specific knowledge of any
+   * JS internal method names or state. The callback will be removed from the
+   * mapping once it has fired.
+   * @param {string} methodName The name of the WebUI handler API.
+   * @param {Array=} opt_args Arguments for the method call sent to the WebUI
+   *     handler.
+   * @param {Function} callback A callback function which is called (indirectly)
+   *     by the WebUI handler.
+   */
+  function sendWithCallback(methodName, opt_args, callback) {
+    var id = methodName + createUid();
+    chromeSendCallbackMap.set(id, callback);
+    var methodArgs = ['cr.webUIResponse', id];
+    if (opt_args) methodArgs = methodArgs.concat(opt_args);
+    chrome.send(methodName, methodArgs);
+  }
+
+  /**
+   * A registry of callbacks keyed by event name. Used by addWebUIListener to
+   * register listeners.
+   * @type {!Map<string, Array<Function>>}
+   */
+  var webUIListenerMap = new Map();
+
+  /**
+   * The named method the WebUI handler calls directly when an event occurs.
+   * The WebUI handler must supply the name of the event as the first argument
+   * of the JS invocation; additionally, the handler may supply any number of
+   * other arguments that will be forwarded to the listener callbacks.
+   * @param {string} event The name of the event that has occurred.
+   */
+  function webUIListenerCallback(event) {
+    var listenerCallbacks = webUIListenerMap.get(event);
+    for (var i = 0; i < listenerCallbacks.length; i++) {
+      var callback = listenerCallbacks[i];
+      callback.apply(null, Array.prototype.slice.call(arguments, 1));
+    }
+  }
+
+  /**
+   * Registers a listener for an event fired from WebUI handlers. Any number of
+   * listeners may register for a single event.
+   * @param {string} event The event to listen to.
+   * @param {Function} callback The callback run when the event is fired.
+   */
+  function addWebUIListener(event, callback) {
+    if (!webUIListenerMap.has(event))
+      webUIListenerMap.set(event, [callback]);
+    else
+      webUIListenerMap.get(event).push(callback);
+  }
+
   return {
     addSingletonGetter: addSingletonGetter,
     createUid: createUid,
@@ -322,6 +404,10 @@
     exportPath: exportPath,
     getUid: getUid,
     makePublic: makePublic,
+    webUIResponse: webUIResponse,
+    sendWithCallback: sendWithCallback,
+    webUIListenerCallback: webUIListenerCallback,
+    addWebUIListener: addWebUIListener,
     PropertyKind: PropertyKind,
 
     get doc() {
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp
index 2a7b8c7..ba30ce2 100644
--- a/ui/webui/resources/polymer_resources.grdp
+++ b/ui/webui/resources/polymer_resources.grdp
@@ -632,6 +632,56 @@
              file="../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior-extracted.js"
              type="chrome_html" />
 
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_OPAQUE_ANIMATION_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/opaque-animation-extracted.js"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_OPAQUE_ANIMATION_HTML"
+
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/opaque-animation.html"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_DOWN_ANIMATION_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-down-animation-extracted.js"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_DOWN_ANIMATION_HTML"
+
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-down-animation.html"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_UP_ANIMATION_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-up-animation-extracted.js"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_SLIDE_UP_ANIMATION_HTML"
+
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/slide-up-animation.html"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_TRANSFORM_ANIMATION_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/transform-animation-extracted.js"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_ANIMATIONS_TRANSFORM_ANIMATION_HTML"
+
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/animations/transform-animation.html"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATABLE_BEHAVIOR_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animatable-behavior-extracted.js"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATABLE_BEHAVIOR_HTML"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animatable-behavior.html"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_BEHAVIOR_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-behavior-extracted.js"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_BEHAVIOR_HTML"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-behavior.html"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_RUNNER_BEHAVIOR_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-runner-behavior-extracted.js"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_NEON_ANIMATION_RUNNER_BEHAVIOR_HTML"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/neon-animation-runner-behavior.html"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_NEON_ANIMATION_WEB_ANIMATIONS_HTML"
+             file="../../../third_party/polymer/v1_0/components-chromium/neon-animation/web-animations.html"
+             type="chrome_html" />
+
   <structure name="IDR_POLYMER_1_0_PAPER_BEHAVIORS_PAPER_BUTTON_BEHAVIOR_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-button-behavior.html"
              type="chrome_html" />
@@ -809,6 +859,9 @@
   <structure name="IDR_POLYMER_08_PAPER_RADIO_GROUP_PAPER_RADIO_GROUP_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/paper-radio-group/paper-radio-group.html"
              type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_WEB_ANIMATIONS_JS_WEB_ANIMATIONS_NEXT_LITE_MIN_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/web-animations-js/web-animations-next-lite.min.js"
+             type="chrome_html" />
 
   <!-- more-routing and deps -->
   <structure name="IDR_POLYMER_1_0_MORE_ROUTING_DRIVER"
diff --git a/ui/wm/BUILD.gn b/ui/wm/BUILD.gn
index d149b48d..421d0a4 100644
--- a/ui/wm/BUILD.gn
+++ b/ui/wm/BUILD.gn
@@ -31,8 +31,6 @@
     "core/focus_rules.h",
     "core/image_grid.cc",
     "core/image_grid.h",
-    "core/input_method_event_filter.cc",
-    "core/input_method_event_filter.h",
     "core/masked_window_targeter.cc",
     "core/masked_window_targeter.h",
     "core/native_cursor_manager.h",
@@ -122,7 +120,6 @@
     "core/cursor_manager_unittest.cc",
     "core/focus_controller_unittest.cc",
     "core/image_grid_unittest.cc",
-    "core/input_method_event_filter_unittest.cc",
     "core/nested_accelerator_controller_unittest.cc",
     "core/shadow_controller_unittest.cc",
     "core/transient_window_manager_unittest.cc",
diff --git a/ui/wm/core/easy_resize_window_targeter.cc b/ui/wm/core/easy_resize_window_targeter.cc
index 445028c..c286bc2 100644
--- a/ui/wm/core/easy_resize_window_targeter.cc
+++ b/ui/wm/core/easy_resize_window_targeter.cc
@@ -5,6 +5,7 @@
 #include "ui/wm/core/easy_resize_window_targeter.h"
 
 #include "ui/aura/window.h"
+#include "ui/events/event.h"
 #include "ui/gfx/geometry/insets_f.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/wm/public/transient_window_client.h"
@@ -24,9 +25,8 @@
 }
 
 bool EasyResizeWindowTargeter::EventLocationInsideBounds(
-    ui::EventTarget* target,
+    aura::Window* window,
     const ui::LocatedEvent& event) const {
-  aura::Window* window = static_cast<aura::Window*>(target);
   if (ShouldUseExtendedBounds(window)) {
     // Note that |event|'s location is in |window|'s parent's coordinate system,
     // so convert it to |window|'s coordinate system first.
@@ -48,7 +48,7 @@
 bool EasyResizeWindowTargeter::ShouldUseExtendedBounds(
     const aura::Window* window) const {
   // Use the extended bounds only for immediate child windows of |container_|.
-  // Use the default targetter otherwise.
+  // Use the default targeter otherwise.
   if (window->parent() != container_)
     return false;
 
diff --git a/ui/wm/core/easy_resize_window_targeter.h b/ui/wm/core/easy_resize_window_targeter.h
index 2543a23b..c6a47af 100644
--- a/ui/wm/core/easy_resize_window_targeter.h
+++ b/ui/wm/core/easy_resize_window_targeter.h
@@ -31,8 +31,8 @@
     touch_extend_ = touch_extend;
   }
 
-  // ui::EventTargeter:
-  bool EventLocationInsideBounds(ui::EventTarget* target,
+  // aura::WindowTargeter:
+  bool EventLocationInsideBounds(aura::Window* window,
                                  const ui::LocatedEvent& event) const override;
 
  private:
diff --git a/ui/wm/core/input_method_event_filter.cc b/ui/wm/core/input_method_event_filter.cc
deleted file mode 100644
index e3ea50d..0000000
--- a/ui/wm/core/input_method_event_filter.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/wm/core/input_method_event_filter.h"
-
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/input_method_factory.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/events/event.h"
-#include "ui/events/event_processor.h"
-
-namespace wm {
-
-////////////////////////////////////////////////////////////////////////////////
-// InputMethodEventFilter, public:
-
-InputMethodEventFilter::InputMethodEventFilter(gfx::AcceleratedWidget widget)
-    : input_method_(ui::CreateInputMethod(this, widget)) {
-  // TODO(shuchen): Check if the root window is currently focused and determine
-  // whether to call OnFocus.
-  input_method_->OnFocus();
-}
-
-InputMethodEventFilter::~InputMethodEventFilter() {
-}
-
-void InputMethodEventFilter::SetInputMethodPropertyInRootWindow(
-    aura::Window* root_window) {
-  root_window->SetProperty(aura::client::kRootWindowInputMethodKey,
-                           input_method_.get());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// InputMethodEventFilter, EventFilter implementation:
-
-void InputMethodEventFilter::OnKeyEvent(ui::KeyEvent* event) {
-  // We're processing key events as follows (details are simplified).
-  //
-  // At the beginning, key events have a ET_KEY_{PRESSED,RELEASED} event type,
-  // and they're passed from step 1 through step 3.
-  //   1. EventProcessor::OnEventFromSource()
-  //   2. InputMethodEventFilter::OnKeyEvent()
-  //   3. InputMethod::DispatchKeyEvent()
-  // where InputMethod may call DispatchKeyEventPostIME() if IME didn't consume
-  // the key event.  Otherwise, step 4 through step 6 are skipped and we fall
-  // down to step 7 directly.
-  //   4. InputMethodEventFilter::DispatchKeyEventPostIME()
-  // where the key event is marked as TRANSLATED and the event type becomes
-  // ET_TRANSLATED_KEY_{PRESS,RELEASE}.  Then, we dispatch the event again from
-  // the beginning.
-  //   5. EventProcessor::OnEventFromSource()     [second time]
-  //   6. InputMethodEventFilter::OnKeyEvent()    [second time]
-  // where we know that the event was already processed once by IME and
-  // re-dispatched, we don't pass the event to IME again.  Instead we unmark the
-  // event as not translated (as same as the original state), and let the event
-  // dispatcher continue to dispatch the event to the rest event handlers.
-  //   7. EventHandler::OnKeyEvent()
-  if (event->IsTranslated()) {
-    // The |event| was already processed by IME, so we don't pass the event to
-    // IME again.  Just let the event dispatcher continue to dispatch the event.
-    event->SetTranslated(false);
-  } else {
-    if (input_method_->DispatchKeyEvent(*event))
-      event->StopPropagation();
-  }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// InputMethodEventFilter, ui::InputMethodDelegate implementation:
-
-bool InputMethodEventFilter::DispatchKeyEventPostIME(
-    const ui::KeyEvent& event) {
-#if defined(OS_WIN)
-  DCHECK(!event.HasNativeEvent() || !event.is_char());
-#endif
-  // Since the underlying IME didn't consume the key event, we're going to
-  // dispatch the event again from the beginning of the tree of event targets.
-  // This time we have to skip dispatching the event to the IME, we mark the
-  // event as TRANSLATED so we can distinguish this event as a second time
-  // dispatched event.
-  // For the target where to dispatch the event, always tries the current
-  // focused text input client's attached window. And fallback to the target
-  // carried by event.
-  aura::Window* target_window = NULL;
-  ui::TextInputClient* input = input_method_->GetTextInputClient();
-  if (input)
-    target_window = input->GetAttachedWindow();
-  if (!target_window)
-    target_window = static_cast<aura::Window*>(event.target());
-  if (!target_window)
-    return false;
-  ui::EventProcessor* target_dispatcher =
-      target_window->GetRootWindow()->GetHost()->event_processor();
-  ui::KeyEvent aura_event(event);
-  aura_event.SetTranslated(true);
-  ui::EventDispatchDetails details =
-      target_dispatcher->OnEventFromSource(&aura_event);
-  CHECK(!details.dispatcher_destroyed);
-  return aura_event.handled();
-}
-
-}  // namespace wm
diff --git a/ui/wm/core/input_method_event_filter.h b/ui/wm/core/input_method_event_filter.h
deleted file mode 100644
index c6bd65af..0000000
--- a/ui/wm/core/input_method_event_filter.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_WM_CORE_INPUT_METHOD_EVENT_FILTER_H_
-#define UI_WM_CORE_INPUT_METHOD_EVENT_FILTER_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/base/ime/input_method_delegate.h"
-#include "ui/events/event_handler.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/wm/wm_export.h"
-
-namespace ui {
-class EventProcessor;
-class InputMethod;
-}
-
-namespace wm {
-
-// An event filter that forwards a KeyEvent to a system IME, and dispatches a
-// TranslatedKeyEvent to the root window as needed.
-class WM_EXPORT InputMethodEventFilter
-    : public ui::EventHandler,
-      public ui::internal::InputMethodDelegate {
- public:
-  explicit InputMethodEventFilter(gfx::AcceleratedWidget widget);
-  ~InputMethodEventFilter() override;
-
-  void SetInputMethodPropertyInRootWindow(aura::Window* root_window);
-
-  ui::InputMethod* input_method() const { return input_method_.get(); }
-
- private:
-  // Overridden from ui::EventHandler:
-  void OnKeyEvent(ui::KeyEvent* event) override;
-
-  // Overridden from ui::internal::InputMethodDelegate:
-  bool DispatchKeyEventPostIME(const ui::KeyEvent& event) override;
-
-  scoped_ptr<ui::InputMethod> input_method_;
-
-  DISALLOW_COPY_AND_ASSIGN(InputMethodEventFilter);
-};
-
-}  // namespace wm
-
-#endif  // UI_WM_CORE_INPUT_METHOD_EVENT_FILTER_H_
diff --git a/ui/wm/core/input_method_event_filter_unittest.cc b/ui/wm/core/input_method_event_filter_unittest.cc
deleted file mode 100644
index 5da0358..0000000
--- a/ui/wm/core/input_method_event_filter_unittest.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/wm/core/input_method_event_filter.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/test_windows.h"
-#include "ui/aura/window_event_dispatcher.h"
-#include "ui/base/ime/dummy_text_input_client.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/text_input_focus_manager.h"
-#include "ui/base/ui_base_switches_util.h"
-#include "ui/events/test/event_generator.h"
-#include "ui/events/test/test_event_handler.h"
-#include "ui/wm/core/compound_event_filter.h"
-#include "ui/wm/core/default_activation_client.h"
-#include "ui/wm/public/activation_client.h"
-
-#if !defined(OS_WIN) && !defined(USE_X11)
-// On platforms except Windows and X11, ui::test::EventGenerator::PressKey
-// generates a key event without native_event(), which is not supported by
-// ui::MockInputMethod.
-#define TestInputMethodKeyEventPropagation \
-DISABLED_TestInputMethodKeyEventPropagation
-#endif
-
-namespace wm {
-
-class TestTextInputClient : public ui::DummyTextInputClient {
- public:
-  explicit TestTextInputClient(aura::Window* window) : window_(window) {}
-
-  aura::Window* GetAttachedWindow() const override { return window_; }
-
- private:
-  aura::Window* window_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestTextInputClient);
-};
-
-class InputMethodEventFilterTest : public aura::test::AuraTestBase {
- public:
-  InputMethodEventFilterTest() {}
-  ~InputMethodEventFilterTest() override {}
-
-  // testing::Test overrides:
-  void SetUp() override {
-    aura::test::AuraTestBase::SetUp();
-
-    root_window()->AddPreTargetHandler(&root_filter_);
-    input_method_event_filter_.reset(
-        new InputMethodEventFilter(host()->GetAcceleratedWidget()));
-    input_method_event_filter_->SetInputMethodPropertyInRootWindow(
-        root_window());
-    root_filter_.AddHandler(input_method_event_filter_.get());
-    root_filter_.AddHandler(&test_filter_);
-
-    test_window_.reset(aura::test::CreateTestWindowWithDelegate(
-        &test_window_delegate_, -1, gfx::Rect(), root_window()));
-    test_input_client_.reset(new TestTextInputClient(test_window_.get()));
-
-    input_method_event_filter_->input_method()->SetFocusedTextInputClient(
-        test_input_client_.get());
-  }
-
-  void TearDown() override {
-    test_window_.reset();
-    root_filter_.RemoveHandler(&test_filter_);
-    root_filter_.RemoveHandler(input_method_event_filter_.get());
-    root_window()->RemovePreTargetHandler(&root_filter_);
-
-    input_method_event_filter_.reset();
-    test_input_client_.reset();
-    aura::test::AuraTestBase::TearDown();
-  }
-
- protected:
-  CompoundEventFilter root_filter_;
-  ui::test::TestEventHandler test_filter_;
-  scoped_ptr<InputMethodEventFilter> input_method_event_filter_;
-  aura::test::TestWindowDelegate test_window_delegate_;
-  scoped_ptr<aura::Window> test_window_;
-  scoped_ptr<TestTextInputClient> test_input_client_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(InputMethodEventFilterTest);
-};
-
-TEST_F(InputMethodEventFilterTest, TestInputMethodProperty) {
-  // Tests if InputMethodEventFilter adds a window property on its
-  // construction.
-  EXPECT_TRUE(root_window()->GetProperty(
-      aura::client::kRootWindowInputMethodKey));
-}
-
-// Tests if InputMethodEventFilter dispatches a ui::ET_TRANSLATED_KEY_* event to
-// the root window.
-TEST_F(InputMethodEventFilterTest, TestInputMethodKeyEventPropagation) {
-  // Send a fake key event to the root window. InputMethodEventFilter, which is
-  // automatically set up by AshTestBase, consumes it and sends a new
-  // ui::ET_TRANSLATED_KEY_* event to the root window, which will be consumed by
-  // the test event filter.
-  ui::test::EventGenerator generator(root_window());
-  EXPECT_EQ(0, test_filter_.num_key_events());
-  generator.PressKey(ui::VKEY_SPACE, 0);
-  EXPECT_EQ(1, test_filter_.num_key_events());
-  generator.ReleaseKey(ui::VKEY_SPACE, 0);
-  EXPECT_EQ(2, test_filter_.num_key_events());
-}
-
-TEST_F(InputMethodEventFilterTest, TestEventDispatching) {
-  ui::KeyEvent evt(ui::ET_KEY_PRESSED,
-                   ui::VKEY_PROCESSKEY,
-                   ui::EF_IME_FABRICATED_KEY);
-  // Calls DispatchKeyEventPostIME() without a focused text input client.
-  if (switches::IsTextInputFocusManagerEnabled())
-    ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(NULL);
-  else
-    input_method_event_filter_->input_method()->SetFocusedTextInputClient(NULL);
-  input_method_event_filter_->input_method()->DispatchKeyEvent(evt);
-  // Verifies 0 key event happened because InputMethodEventFilter::
-  // DispatchKeyEventPostIME() returns false.
-  EXPECT_EQ(0, test_filter_.num_key_events());
-
-  // Calls DispatchKeyEventPostIME() with a focused text input client.
-  if (switches::IsTextInputFocusManagerEnabled()) {
-    ui::TextInputFocusManager::GetInstance()->FocusTextInputClient(
-        test_input_client_.get());
-  } else {
-    input_method_event_filter_->input_method()->SetFocusedTextInputClient(
-        test_input_client_.get());
-  }
-  input_method_event_filter_->input_method()->DispatchKeyEvent(evt);
-  // Verifies 1 key event happened because InputMethodEventFilter::
-  // DispatchKeyEventPostIME() returns true.
-  EXPECT_EQ(1, test_filter_.num_key_events());
-}
-
-}  // namespace wm
diff --git a/ui/wm/core/masked_window_targeter.cc b/ui/wm/core/masked_window_targeter.cc
index 5cbdb19..74e8bc8 100644
--- a/ui/wm/core/masked_window_targeter.cc
+++ b/ui/wm/core/masked_window_targeter.cc
@@ -5,6 +5,7 @@
 #include "ui/wm/core/masked_window_targeter.h"
 
 #include "ui/aura/window.h"
+#include "ui/events/event.h"
 #include "ui/gfx/path.h"
 
 namespace wm {
@@ -16,9 +17,8 @@
 MaskedWindowTargeter::~MaskedWindowTargeter() {}
 
 bool MaskedWindowTargeter::EventLocationInsideBounds(
-    ui::EventTarget* target,
+    aura::Window* window,
     const ui::LocatedEvent& event) const {
-  aura::Window* window = static_cast<aura::Window*>(target);
   if (window == masked_window_) {
     gfx::Path mask;
     if (!GetHitTestMask(window, &mask))
diff --git a/ui/wm/core/masked_window_targeter.h b/ui/wm/core/masked_window_targeter.h
index cc209f3..00617bf 100644
--- a/ui/wm/core/masked_window_targeter.h
+++ b/ui/wm/core/masked_window_targeter.h
@@ -24,8 +24,8 @@
   // coordinate system). Returns whether a valid mask has been set in |mask|.
   virtual bool GetHitTestMask(aura::Window* window, gfx::Path* mask) const = 0;
 
-  // ui::EventTargeter:
-  bool EventLocationInsideBounds(ui::EventTarget* target,
+  // aura::WindowTargeter:
+  bool EventLocationInsideBounds(aura::Window* target,
                                  const ui::LocatedEvent& event) const override;
 
  private:
diff --git a/ui/wm/core/window_modality_controller.cc b/ui/wm/core/window_modality_controller.cc
index b18fe9c76..8b7d66a 100644
--- a/ui/wm/core/window_modality_controller.cc
+++ b/ui/wm/core/window_modality_controller.cc
@@ -68,8 +68,11 @@
        ++it) {
     aura::Window* transient = *it;
     if (IsModalTransientChild(transient, original)) {
-      return GetTransientChildren(transient).empty() ?
-          transient : GetModalTransientChild(transient, original);
+      if (GetTransientChildren(transient).empty())
+        return transient;
+
+      aura::Window* modal_child = GetModalTransientChild(transient, original);
+      return modal_child ? modal_child : transient;
     }
   }
   return NULL;
diff --git a/ui/wm/test/wm_test_helper.cc b/ui/wm/test/wm_test_helper.cc
index c74ddfe..83166be9 100644
--- a/ui/wm/test/wm_test_helper.cc
+++ b/ui/wm/test/wm_test_helper.cc
@@ -10,7 +10,6 @@
 #include "ui/aura/window.h"
 #include "ui/wm/core/compound_event_filter.h"
 #include "ui/wm/core/default_activation_client.h"
-#include "ui/wm/core/input_method_event_filter.h"
 
 namespace wm {
 
@@ -28,11 +27,6 @@
   root_window_event_filter_.reset(new wm::CompoundEventFilter);
   host_->window()->AddPreTargetHandler(root_window_event_filter_.get());
 
-  input_method_filter_.reset(new wm::InputMethodEventFilter(
-      host_->GetAcceleratedWidget()));
-  input_method_filter_->SetInputMethodPropertyInRootWindow(host_->window());
-  root_window_event_filter_->AddHandler(input_method_filter_.get());
-
   new wm::DefaultActivationClient(host_->window());
 
   capture_client_.reset(
@@ -40,7 +34,6 @@
 }
 
 WMTestHelper::~WMTestHelper() {
-  root_window_event_filter_->RemoveHandler(input_method_filter_.get());
 }
 
 aura::Window* WMTestHelper::GetDefaultParent(aura::Window* context,
diff --git a/ui/wm/test/wm_test_helper.h b/ui/wm/test/wm_test_helper.h
index 9b92e28..c0c09f60 100644
--- a/ui/wm/test/wm_test_helper.h
+++ b/ui/wm/test/wm_test_helper.h
@@ -31,7 +31,6 @@
 namespace wm {
 
 class CompoundEventFilter;
-class InputMethodEventFilter;
 
 // Creates a minimal environment for running the shell. We can't pull in all of
 // ash here, but we can create attach several of the same things we'd find in
@@ -54,7 +53,6 @@
 
   scoped_ptr<wm::CompoundEventFilter> root_window_event_filter_;
   scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;
-  scoped_ptr<wm::InputMethodEventFilter> input_method_filter_;
   scoped_ptr<aura::client::FocusClient> focus_client_;
 
   DISALLOW_COPY_AND_ASSIGN(WMTestHelper);
diff --git a/ui/wm/wm.gyp b/ui/wm/wm.gyp
index 8ce5e515..e7415a8c 100644
--- a/ui/wm/wm.gyp
+++ b/ui/wm/wm.gyp
@@ -56,8 +56,6 @@
         'core/focus_rules.h',
         'core/image_grid.cc',
         'core/image_grid.h',
-        'core/input_method_event_filter.cc',
-        'core/input_method_event_filter.h',
         'core/masked_window_targeter.cc',
         'core/masked_window_targeter.h',
         'core/native_cursor_manager.h',
@@ -147,7 +145,6 @@
         'core/cursor_manager_unittest.cc',
         'core/focus_controller_unittest.cc',
         'core/image_grid_unittest.cc',
-        'core/input_method_event_filter_unittest.cc',
         'core/nested_accelerator_controller_unittest.cc',
         'core/shadow_controller_unittest.cc',
         'core/shadow_unittest.cc',
diff --git a/url/gurl.cc b/url/gurl.cc
index 46ca408..52aad73 100644
--- a/url/gurl.cc
+++ b/url/gurl.cc
@@ -14,6 +14,7 @@
 #include "url/gurl.h"
 
 #include "base/logging.h"
+#include "base/strings/string_util.h"
 #include "url/url_canon_stdstring.h"
 #include "url/url_util.h"
 
@@ -382,9 +383,9 @@
 bool GURL::SchemeIs(const char* lower_ascii_scheme) const {
   if (parsed_.scheme.len <= 0)
     return lower_ascii_scheme == NULL;
-  return url::LowerCaseEqualsASCII(spec_.data() + parsed_.scheme.begin,
-                                   spec_.data() + parsed_.scheme.end(),
-                                   lower_ascii_scheme);
+  return base::LowerCaseEqualsASCII(spec_.data() + parsed_.scheme.begin,
+                                    spec_.data() + parsed_.scheme.end(),
+                                    lower_ascii_scheme);
 }
 
 bool GURL::SchemeIsHTTPOrHTTPS() const {
@@ -521,10 +522,10 @@
   const char* start_pos = spec_.data() + parsed_.host.begin +
                           host_len - domain_len;
 
-  if (!url::LowerCaseEqualsASCII(start_pos,
-                                 last_pos + 1,
-                                 lower_ascii_domain,
-                                 lower_ascii_domain + domain_len))
+  if (!base::LowerCaseEqualsASCII(start_pos,
+                                  last_pos + 1,
+                                  lower_ascii_domain,
+                                  lower_ascii_domain + domain_len))
     return false;
 
   // Check whether host has right domain start with dot, make sure we got
diff --git a/url/url_util.cc b/url/url_util.cc
index 008a5e4..28a8931 100644
--- a/url/url_util.cc
+++ b/url/url_util.cc
@@ -9,6 +9,7 @@
 
 #include "base/debug/leak_annotations.h"
 #include "base/logging.h"
+#include "base/strings/string_util.h"
 #include "url/url_canon_internal.h"
 #include "url/url_file.h"
 #include "url/url_util_internal.h"
@@ -17,23 +18,6 @@
 
 namespace {
 
-// ASCII-specific tolower.  The standard library's tolower is locale sensitive,
-// so we don't want to use it here.
-template<class Char>
-inline Char ToLowerASCII(Char c) {
-  return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
-}
-
-// Backend for LowerCaseEqualsASCII.
-template<typename Iter>
-inline bool DoLowerCaseEqualsASCII(Iter a_begin, Iter a_end, const char* b) {
-  for (Iter it = a_begin; it != a_end; ++it, ++b) {
-    if (!*b || ToLowerASCII(*it) != *b)
-      return false;
-  }
-  return *b == 0;
-}
-
 const int kNumStandardURLSchemes = 8;
 const char* kStandardURLSchemes[kNumStandardURLSchemes] = {
   kHttpScheme,
@@ -72,9 +56,9 @@
                                      const char* compare_to) {
   if (!component.is_nonempty())
     return compare_to[0] == 0;  // When component is empty, match empty scheme.
-  return LowerCaseEqualsASCII(&spec[component.begin],
-                              &spec[component.end()],
-                              compare_to);
+  return base::LowerCaseEqualsASCII(&spec[component.begin],
+                                    &spec[component.end()],
+                                    compare_to);
 }
 
 // Returns true if the given scheme identified by |scheme| within |spec| is one
@@ -86,8 +70,8 @@
 
   InitStandardSchemes();
   for (size_t i = 0; i < standard_schemes->size(); i++) {
-    if (LowerCaseEqualsASCII(&spec[scheme.begin], &spec[scheme.end()],
-                             standard_schemes->at(i)))
+    if (base::LowerCaseEqualsASCII(&spec[scheme.begin], &spec[scheme.end()],
+                                   standard_schemes->at(i)))
       return true;
   }
   return false;
@@ -486,31 +470,6 @@
                              charset_converter, output, out_parsed);
 }
 
-// Front-ends for LowerCaseEqualsASCII.
-bool LowerCaseEqualsASCII(const char* a_begin,
-                          const char* a_end,
-                          const char* b) {
-  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
-}
-
-bool LowerCaseEqualsASCII(const char* a_begin,
-                          const char* a_end,
-                          const char* b_begin,
-                          const char* b_end) {
-  while (a_begin != a_end && b_begin != b_end &&
-         ToLowerASCII(*a_begin) == *b_begin) {
-    a_begin++;
-    b_begin++;
-  }
-  return a_begin == a_end && b_begin == b_end;
-}
-
-bool LowerCaseEqualsASCII(const base::char16* a_begin,
-                          const base::char16* a_end,
-                          const char* b) {
-  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
-}
-
 void DecodeURLEscapeSequences(const char* input,
                               int length,
                               CanonOutputW* output) {
diff --git a/url/url_util.h b/url/url_util.h
index bf05e87..55a83eb 100644
--- a/url/url_util.h
+++ b/url/url_util.h
@@ -166,23 +166,6 @@
 
 // String helper functions ----------------------------------------------------
 
-// Compare the lower-case form of the given string against the given ASCII
-// string.  This is useful for doing checking if an input string matches some
-// token, and it is optimized to avoid intermediate string copies.
-//
-// The versions of this function that don't take a b_end assume that the b
-// string is NULL terminated.
-URL_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
-                                     const char* a_end,
-                                     const char* b);
-URL_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
-                                     const char* a_end,
-                                     const char* b_begin,
-                                     const char* b_end);
-URL_EXPORT bool LowerCaseEqualsASCII(const base::char16* a_begin,
-                                     const base::char16* a_end,
-                                     const char* b);
-
 // Unescapes the given string using URL escaping rules.
 URL_EXPORT void DecodeURLEscapeSequences(const char* input,
                                          int length,